Python: Adicionar argumentos ao método Bind (wxPython)

O método Bind() no wxPython permite associar métodos a eventos. Por exemplo:

Bind(wx.EVT_BUTTON, sys.exit(), id=ID_BUTTON)

Ao clicar, o método exit() é disparado.

Para permitir que o método disparado receba argumentos, podemos utilizar:

botao =  wx.Button(self, -1, "Instalar")

Bind(wx.EVT_BUTTON, lambda event: Metodo(event, 'argumento'), botao)

def Metodo(self, argumento):
    print argumento
Posted in Python | 2 Comments

Python: Introspeção de atributos e métodos com vars(), locals() e dir()

Para descobrir os atributos de um objeto podemos utilizar:

objeto.__dict__

vars(objeto)

Para descobrir os atributos de uma classe:

vars(Classe())

Se utilizar vars() sem argumentos, funciona como locals(), listando todas as variáveis.

Para listar métodos e atributos de um objeto:

dir(objeto)
Posted in Python | Tagged , , , | Leave a comment

JavaScript: Fazer o label do checkbox ser clicável

É comum usar checkboxes nas configurações ou na interface de seu site. Ao clicar nela alguma coisa é ligada, ao clicar novamente é desligada. Simples, não?

[X] Fundo colorido

O código para fazer uma opção destas é trivial:

<input id="fundo" onClick="trocaFundo()" type="checkbox">
Fundo colorido

No evento onClick é chamada a função trocaFundo(), que se encarrega de ligar ou desligar as cores no fundo do site. Até aí tudo bem.

O que é chato mesmo, é o usuário ter que mirar precisamente na caixinha do checkbox para poder ligar/desligar a opção. Uma interface mais amigável deveria permitir que o usuário também pudesse clicar no próprio texto de descrição (label) da opção, o “Fundo colorido”. Com mais área para cliques, o uso do site torna-se mais confortável.

Para fazer esse label clicável, basta adicionar o evento onClick nele também. E o que esse evento fará? Você pode colocar ali um “trocaFundo()” também, para ficar igual ao onClick do checkbox.

<input id="fundo" onClick="trocaFundo()" type="checkbox">
<span onClick="trocaFundo()">Fundo colorido</span>

Mas duplicar coisas não é bom. Se você ainda não aprendeu isso, pode deixar que a experiência um dia te ensinará. E se a trocaFundo() recebesse um this para identificar de onde veio o clique, também não funcionaria.

Uma solução mais robusta é fazer com que ao clicar no label, seja feito um clique “virtual” na própria checkbox. Deste modo, para a lógica do seu programa, é como se o usuário tivesse de fato clicado na checkbox.

<input id="fundo" onClick="trocaFundo()" type="checkbox">
<span onClick="document.getElementById('fundo').click()">
Fundo colorido
</span>

Atualização:
Quando escrevi este texto, eu não sabia que a tag LABEL era clicável e que ao clicar nela, o checkbox atrelado a ela era marcado/desmarcado. Muito obrigado a todos que comentaram sobre isso!

Assim sendo, não é preciso essa gambiarra JavaScript que eu sugeri, basta apenas usar a tag correta:

<input id="fundo" onClick="trocaFundo()" type="checkbox">
<label for="fundo">Fundo colorido</label>

O atributo for leva o nome do checkbox ao qual esta label está atrelada. E pronto, só isso. O navegador se encarregará de fazer o resto.

Posted in JavaScript | Tagged , , , , | 13 Comments

C: Escondendo o conteúdo de structs com tipos incompletos

Algumas vezes é possível utilizar alguns paradigmas de orientação à objetos em C. Ao se projetar uma biblioteca, podemos encapsular o conteúdo das structs usando tipos incompletos e provendo funções para manipular o conteúdo destas.

Imagine uma biblioteca que cria um “objeto” para representar uma pessoa. Esta biblioteca provê um cabeçalho person.h com funções para manipular o “objeto”.

typedef struct person person;

person *person_new(char *name, int age);
void person_free(person *handler);
void person_print(person *handler);

Note que não existe uma descrição da struct person no cabeçalho. A única forma então de manipular esta struct é usando as funções, porque os atributos da struct não são conhecidos. Esta struct portanto caracteriza um tipo incompleto, mas apenas do ponto de vista dos usuários da biblioteca. Em sua implementação, a biblioteca conhece o conteúdo de person e consegue manipulá-los, como vemos a seguir.

#include <string.h>
#include <stdio.h>
#include <stdlib.h>

#include "person.h"

struct person {
    char *name;
    int age;
};

person *person_new(char *name, int age)
{
    person *new = malloc(sizeof(*new));

    new->name = strdup(name);
    new->age = age;

    return new;
}

void person_free(person *handler)
{
    free(handler->name);
    free(handler);
}

void person_print(person *handler)
{
    printf("%s - %d\n", handler->name, handler->age);
}

A vantagem de se encapsular os dados, forçando esta política através da técnica apresentada, é que a implementação da biblioteca pode ser alterada sem impacto em seus clientes. person_new poderia checar a validade do atributo age, retornando um ponteiro nulo caso seja passado uma idade negativa. O código seguinte ilustra um possível cliente da biblioteca, note que não há referência aos atributos de struct person.

#include <person.h>

int main(void)
{
    person *mike = person_new("Mike", 21);

    person_print(mike);
    person_free(mike);

    return 0;
}

A primeira vez que vi uma biblioteca fazendo uso extenso desta técnica foi no projeto OpenSync, que inspirou este post.

Posted in C | Tagged , , , , , , | 9 Comments

Shell: Extrair os números do CPF formatado

O tr é um comando muito versátil, especialmente útil para apagar caracteres indesejados.

Digamos que você peça ao usuário para digitar o número do CPF. Esse número poderá vir das mais diferentes formas, com espaços, hífens, pontos, ponto-e-vírgula e sabe mais o que que a criatividade da pessoa pode produzir.

Para preservar sua sanidade, tudo o que você quer são os números, ignorando toda a pontuação, espaços e outros caracteres. Com o tr é fácil.

$ echo 123.456.789-00 | tr -d 0-9
..-

A opção -d apaga coisas e o 0-9 representa os números de zero a nove. Ah, note que não é necessário o uso de colchetes ao redor “[0-9]”, como muita gente costuma fazer.

Mas este comando apagou os números e deixou a pontuação, quando o desejado é o justamente o contrário. Então basta usar a opção -c, que inverte o sentido da expressão, fazendo o tr apagar tudo exceto os números:

$ echo 123.456.789-00 | tr -c -d 0-9
12345678900
Posted in Shell | Tagged , , , , , | 2 Comments

C/C++: cannot open shared object file

As bibliotecas compartilhadas são carregadas no início da execução de um programa. No Linux, o dynamic loader procura pelas bibliotecas em /lib e /usr/lib. Caso a biblioteca não esteja presente neste caminho, recebemos uma mensagem de erro parecida com a mensagem a seguir:

error while loading shared libraries: libfoo.so:
  cannot open shared object file: No such file or directory

Imagine um ambiente de desenvolvimento, onde estamos codificando uma biblioteca. Não queremos instalar esta biblioteca no sistema só para testá-la. Uma alternativa é configurar a variável de ambiente LD_LIBRARY_PATH, apontando para o diretório onde se encontra o binário da biblioteca. Assim o dynamic loader vai procurar pela biblioteca também neste diretório.

$ export LD_LIBRARY_PATH=/home/user/libfoo/

Uma segunda opção seria no momento em que seu programa é “linkado”, passar o caminho da biblioteca para a opção -rpath do linker. Isto coloca o caminho de busca pela biblioteca dentro da estrutura do executável (ELF). A opção -Wl do gcc serve para passar parâmetros para o linker (usando “,” no lugar de espaço) que é chamado automaticamente após a compilação.

$ gcc -shared -Wall -o libfoo.so foo.c
$ gcc -Wall -o test test.c -L/home/user/libfoo/ -lfoo
$ ./test # Erro! Não acha a biblioteca libfoo.so
$ gcc -Wall -Wl,-rpath,/home/user/libfoo/ -o test test.c \
  -L/home/user/libfoo/ -lfoo
$ ./test # Funciona!
Posted in C, CPP, Linux | Tagged , , , , , , , | 7 Comments

Tcl/Tk: sondagem do sistema com variáveis

Às vezes, ajuda muito poder examinar determinadas condições do sistema enquanto um programa/script é executado, mais ou menos como quem está voando e verifica as condições meteorológicas. Não só em procedimentos de depuração, embora eu ache que estes sejam os casos mais comuns.

Na dica anterior, eu falei de introspecção com o comando [info]. Agora, veja que informações importantes pode-se obter de determinadas variáveis. Assim como a linguagem Bash tem uma série de variáveis reservadas para informações de depuração, Tcl/Tk tem as suas.

  • env: contém um array com as variáveis de ambiente e seus respectivos valores. Tanto a forma quanto o conteúdo são muito parecidos com o que é retornado pelos comandos ‘env’ e ‘printenv’ em Bash. Para examinar um array, use o comando parray, e.g. [parray env].
  • tcl_platform: outro array, este contém informações sobre a plataforma. O item mais valioso costuma ser $tcl_platform(platform), que indica se o ambiente é Windows, Linux/Unix ou Mac, entre outros. Com esta informação, fica fácil adaptar um programa para que ele rode em diversas plataformas sem engasgar nem pedir ajuda ao usuário. Exemplos da minha máquina:
    tcl_platform(platform)    = unix
    tcl_platform(os)          = Linux
    tcl_platform(osVersion)   = 2.6.24-23-generic
    tcl_platform(machine)     = i686
    tcl_platform(byteOrder)   = littleEndian
  • tcl_patchLevel: é uma variável escalar que contém o número exato da versão de Tcl/Tk que está sendo usada para executar o programa. Por exemplo, 8.5.4. Serve para gerar mensagens de erro e admoestar o usuário caso ele esteja usando uma versão muito antiga de Tcl/Tk. Muita coisa importante só foi incorporada a partir da versão 8.4.0 (setembro de 2002).
  • errorInfo: variável escalar, contém o texto de erro do último erro registrado durante a execução do programa. A maioria das linguagens interrompe a execução do programa em caso de erro. Em Tcl/Tk, é muito fácil ajustar o programa para ignorar erros e seguir em frente. Neste caso, o último erro ocorrido fica registrado nesta variável.
  • argv: variável escalar, contém a lista dos argumentos com que o programa foi executado. Informação indispensável para a execução da maioria dos scripts. Se o programa não for executado com nenhum argumento, argv retorna vazia.
  • argc: variável escalar, contém o número de argumentos com que o programa foi executado. É o mesmo que [llength $argv]. Serve para confirmar se o programa foi executado com o número mínimo, máximo ou exato de argumentos que o programa exige. Se o programa não for executado com nenhum argumento, argc retorna o número 0.

Mais informações em http://www.tcl.tk/man/tcl8.5/TclCmd/tclvars.htm

Posted in Tcl-Tk | Tagged , , , , , , , | 1 Comment

Shell: Extrair o último caractere da linha

Com o comando cut é fácil extrair o primeiro, segundo ou qualquer outro caractere da linha. Porém, é preciso saber a posição exata deste caractere para informá-la ao cut.

$ echo abcdef | cut -c 1
a
$ echo abcdef | cut -c 2
b
$ echo abcdef | cut -c 3
c

E se você quiser extrair o último caractere, independente do tamanho da linha em questão?

A primeira solução é saber qual a posição exata deste último caractere. Supondo que a linha está guardada em uma variável, use o modificador # para obter o tamanho do conteúdo da variável, ou seja, o tamanho da linha.

$ linha="abcdef"
$ echo ${#linha}
6

Agora sim, você pode usar esse truque para obter o último caractere:

$ echo $linha | cut -c ${#linha}
f

Há ainda uma outra solução, que envolve pensar diferente. Em vez de contornar a limitação do cut apelando para a expansão de variáveis do shell, que tal modificar nosso problema para que ele se enquadre nas possibilidades do cut?

  • O problema: extrair o último caractere.
  • O cut: sabe extrair o primeiro caractere.
  • Solução: tem como fazer o último caractere ser o primeiro?

O comando rev inverte a linha, fazendo com que o último caractere seja o primeiro, e vice-versa:

$ echo abcdef | rev
fedcba

Agora sim, já que nossa linha-problema foi modificada para satisfazer o cut, podemos usá-lo normalmente:

$ echo abcdef | rev | cut -c 1
f
Posted in Shell | Tagged , , , , , , | 3 Comments

Google recomenda CODARE

Pelo menos o Google Reader (leitor de feeds RSS/Atom), recomenda:

google-recomenda-codare

;)

Obrigado ao Rodrigo Stulzer pelo aviso e envio da imagem!

Posted in __codare | Tagged | 6 Comments

C: Múltiplos programas no mesmo binário

Um mesmo aplicativo pode se comportar de forma diferente dependendo da forma como é invocado. No exemplo a seguir, o mesmo programa é usado para calcular a raiz quadrada e potência de dois de um dado argumento.

#include <libgen.h>
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char **argv)
{
    double res;
    char *program = basename(argv[0]);

    if (argc != 2)
        return 1;

    if (!strcmp(program, "sqrt")) {
        res = sqrt(atof(argv[1]));
        printf("%f\n", res);
        return 0;
    }

    if (!strcmp(program, "pow2")) {
        res = pow(atof(argv[1]), 2);
        printf("%f\n", res);
        return 0;
    }

    printf("Invalid program: %s\n", program);

    return 1;
}

O truque consiste em analisar o primeiro argumento que corresponde ao caminho do binário do programa. No exemplo, decidimos qual ação tomar comparando o nome do programa com “sqrt” e “pow2”. Para não fazer múltiplas cópias do binário gerado, fazemos links simbólicos.

$ gcc -Wall -lm -o test test.c
$ ln -s test sqrt
$ ln -s test pow2

$ ./test 5
Invalid program: test

$ ./pow2 5
25.000000

$ ./sqrt 5
2.236068

A técnica é extensamente utilizada no BusyBox e pode facilmente ser implementada em qualquer outra linguagem de programação.

Posted in C | Tagged , , | 5 Comments