quinta-feira, 29 de março de 2007

A Linguagem Haskell: Listas - Parte 2

haskell Listas

As listas são parecidas com as tuplas mas diferente destas você pode ter quantidades variadas de elementos, em contra-partida homogêneos (de mesmo tipo). Uma lista é representada por elementos separados por vírgulas todos eles cercados por colchetes.

Prelude> [5,2]
[5,2]
Prelude> [1,2,3]
[1,2,3]
Prelude> [] -- uma lista vazia
[]


Como as listas são mutáveis, podemos com facilidade acrescentar elementos a elas. O operador para fazer isso chama-se cons, representado por dois pontos. A sintaxe para isso é mostrada nos exemplos abaixo:

Prelude> 3 : [2,2]
[3,2,2]
Prelude> 3 : []
[3]
Prelude> 1 : 6 : [7, 5]
[1,6,7,5]
Prelude> 3: [] == [3]
True
Prelude> 'c' : 'a' : 's' : 'a' : []
"casa"
Prelude> "casa" == 'c' : 'a' : 's' : 'a' : []
True

A sintaxe de [5,2] é um açucar sintático de 5 : 2 : []. Relembrando que as listas somente aceitam elementos homogêneos. Para não esquecermos, vejamos mais exemplos:

Prelude> ['c','a','s','a']
"casa"
Prelude> [ (1,1), (1,2), (1,3)]
[ (1,1), (1,2), (1,3)]
Prelude> [ [2], [7], [-1] ]
[ [2], [7], [-1] ]


Podemos concatenar listas com o operador '++'.

Prelude> [1] ++ [3,4]
[1,3,4]
Prelude> [1] ++ [3] ++ [4]
[1,3,4]
Prelude> "ca" ++ "sa" -- claro que vale para strings
"casa"


Se desejamos realizar operações aritméticas com números que são strings, usamos a função read para converter. Já quando queremos tratar um número como uma string, convertemos o mesmo com a função show. Os exemplos demonstram isso:


Prelude> read ('3' : []) + 5
8
Prelude> read "20" * read "5"
100
Prelude> tail "came' ++ show 32
"ame32"

Existem duas funções em Python que foram herdadas de Haskell, penso eu. É a map e a filter. Map toma uma função e uma lista como argumentos, e retorna uma lista do resultado da operação da função sobre cada elemento da lista-argumento. Já filter somente adiciona na nova lista os elementos que operados com a função retorne True. Exemplos são melhores que minha explicação:

Prelude> map Char.toUpper "escola"
"ESCOLA"
Prelude> filter Char.isUpper "Kodumaro"
"K"



Com isso terminamos mais um post sobre Haskell. No tutorial anterior esqueci de colocar os links para os materiais de referência. Eles podem ser encontrados no site oficial da linguagem. No entanto, minha leitura principal é Yet Another Haskell Tutorial.

Exercício: Use map para converter uma string em uma lista de booleanos, cada elemento na nova lista representando se o elemento original estava em maiúsculas ou não. Exemplo: “teSte” produzirá [False, False, True, False, False]

Prelude> :quit

segunda-feira, 26 de março de 2007

Usando SQL com Lua

Lua Já há bastante tempo existe em programação a ideia de separar os dados da lógica do programa e, quando queremos poder fazer consultas estruturadas, bancos de dados relacionais são ótimos.

Primeiro as consultas eram feitas usando um pré-processamento que lia códigos estranhos à linguagem inseridos entre marcações de início e fim, mais ou menos assim:
EXEC SQL
DECLARE CUR CURSOR FOR
SELECT * FROM cadastro
WHERE grupo = 1
END-EXEC.


Mas era necessário rodar o pré-compilador, que substituía esses trechos por códigos mais complexos, o que era no mínimo desconfortável.

Mais tarde pensaram em fazer diferente: módulos com funções que recebem strings representando os comandos SQL (Structured Query Language) e os executam, «escondendo» assim toda complexidade do acesso sem necessidade de uma pré-compilação.

Outras sintaxes para acesso, também abstraindo a complexidade, foram desenvolvidas, como SQLObject e SQLAlchemy, mas nenhuma tão simples e popular quanto a simples passagem de uma string como parâmetro de uma função.

Por exemplo, em Python, temos o módulo MySQLdb:
import MySQLdb as mysql

conn = mysql.connect(
host="localhost",
user="batalema",
password="sEnH4",
db="empresa"
)

conn.query("""
SELECT * FROM cadastro WHERE grupo = 1
""")
cur = conn.use_result()


A conexão deve ser fechada com conn.close(). Os resultados de uma consulta são lidos com um tipo especial de reiterador chamado cursor. Isso permite que tabelas de centenas (ou milhares) de linhas (tuplas) sejam tratadas com muito pouco uso de memória. Já escrevi alguns artigos sobre o assunto.

LuaSQL


Seguindo o exemplo de Python, PHP e outras linguagens, Lua também envia os comandos SQL por meio de strings como parâmetros de funções para uma conexão e percorre os resultados com um cursor.

O módulo de Lua para acesso a SQL é LuaSQL, que é parte do projeto Kepler, uma plataforma para desenvolvimento web usando Lua. Por isso é recomendável instalar tanto Lua quanto LuaSQL através da instalação completa de Kepler 1.1 – no momento em que este artigo foi escrito, só havia disponíveis snapshots (release-cadidates). Também é recomendável a instalação de todos os pacotes opcionais (--with-optional=lualogging,luasql,luaexpat,luazip,md5).

Podemos ver agora como fazer os acessos usando LuaSQL.

O módulo traz submódulos de acesso a diversos SGBDs diferentes: MySQL (luasql.mysql), Oracle (luasql.oci8), PostgreSQL (luasql.postgres), SQLite (luasql.sqlite) e MS SQL Server (via ODBC: luasql.odbc). Vamos usar o padrão, luasql.mysql.

Em LuaSQL, antes de conectar ao SGBD, é preciso criar um ambiente de conexão:
require "luasql.mysql"

local env = assert(luasql.mysql())


A partir do ambiente podemos iniciar a conexão:
local conn = assert(
env:connect("empresa", "batalema", "sEnH4", "localhost")
)


A ordem dos parâmetros (para luasql.mysql e luasql.postgresql, para outros ambientes veja o manual) é:
  1. Fonte (nome da base de dados)
  2. Usuário
  3. Senha
  4. Servidor


Efetuada a conexão, podemos criar nosso cursor. Precisaremos ainda de uma tabela Lua para receber cada uma das linhas da tabela SQL, chamadas tuplas:
local cur = conn:execute [[
SELECT * FROM cadastro WHERE grupo = 1
]]
local t = {}


O cursor possui dois métodos interessantes, um é numrows(), que retorna o número de tuplas da seleção, outro é fetch(), que retorna a próxima tupla ou nil se estiver chegado ao final.

O método fetch() recebe dois parâmetros: ¹a tabela que receberá a tupla e ²uma string que indica como a tupla será interpretada pela tabela Lua.

Há duas opções para o 2º parâmetro:
  • "n": os registros serão recebidos como pares índice-valor e a tabela será uma tabela indexada;
  • "a": os registros serão recebidos como pares chave-valor e a tabela será uma tabela associativa.


Então, para listar os resultados podemos fazer algo bem simples:
while cur:fetch(t, "a") do
table.foreach(t, print)
end


Para finalizar precisamos fechar o cursor, a conexão e o ambiente:
cur:close()
conn:close()
env:close()


Outros comandos SQL


O comando SELECT retorna um cursor para a tabela retornada, mas outros comandos não retornam cursores ou tabelas.

Em vez disso os demais comandos retornam o número de tuplas afetadas.

Conclusão


Se alguém ficou decepcionado, desculpe-me a falta de complexidade… mas o módulo é simples mesmo. =P

Aliás, todos os módulos do projeto Kepler são simples.

Para um pouco mais de «complexidade» (hehehe), veja o manual.

[]'s
La Batalema Pitonisto (Rodrigo Cacilhas)

PS: publicado também nas Reflexões de Monte Gasppa e Giulia C..

quarta-feira, 21 de março de 2007

A Linguagem Haskell

haskell (Publicação original:
http://claudiotorcato.wordpress.com/2007/03/21/a-linguagem-haskell/)

O blog comunitário Kodumaro é voltado para linguagens de programação. Pensei então em escolher uma linguagem a mais para comentar. As linguagens que programei durante a minha vida foram: Pascal, C, Object Pascal, Haskell, Prolog, LISP, Java, Python, PHP e VB, nessa ordem. Talvez hajam outras mas como não lembrei foram fracamente utilizadas. Então acabei escolhendo Haskell por ser uma linguagem diferente das demais.

Haskell é uma linguagem de propósito geral, puramente funcional com características diversas tais como, tipagem estática, funções de alta ordem, polimorfismo, classes de tipo e efeitos monádicos. Existem vários compiladores disponíveis livremente para diferentes plataformas.

Poderia dizer que é uma linguagem que irá surpreendê-los, assim como ocorreu comigo no tempo da faculdade. Aos interessados em acompanhar este tutorial recomendo baixar imediatamente alguma implementação de Haskell. Sugiro duas: Hugs e GHC (Vejam nesse site). Para usuários do Windows, eu diria que seria interessante usar a primeira. Já para os geeks do Linux, por favor procurem por GHC. Puxando um pouco para meu lado de usuário Linux da distribuição Ubuntu baixem com esse comando:
sudo aptitude install haskell-compiler


Antes de chegar nos exemplos, gostaria de explicar meu modo de operação para que acompanhem com comodidade. Um jeito cômodo – inclusive primeiramente conheci estudando Haskell – é o uso de um interpretador interativo. Esta ferramenta permite que você interaja com o programa em tempo real. Ou seja, ao inserir uma expressão na linha de comando e clicar no Enter, o interpretador processa a expressão retornando seu valor. A comodidade está no fato de você testar um algoritmo como mais rapidez para integrá-lo ao fonte de uma aplicação em desenvolvimento, ou estudar o funcionamento de alguma biblioteca.

O ghci é o interpretador do GHC. Num terminal de comandos do Linux (ou usando o Hugs no Windows) executemos:
chackero@lain:~$ ghci


Haskell é um resolvedor de expressões. Ele computaciona uma expressão até deixá-la no seu modo mais simples. Assim sendo, o modo mais simples da expressão 2 + 3 é 5. O que funciona para expressões aritméticas funciona para a resolução de funções. Por isso, a explicação. Vejamos no ghci:
Prelude> 2 + 4
6
Prelude> 2 * 4
8


Haskell possui infixação de operadores. É possível colocar o símbolo dos operadores antes dos operandos. Senão, vejamos:

Prelude> (+) 2 4
6
Prelude> (*) 2 4
8
Prelude> (*) 2.0 4
8.0


Para infixação é necessário o uso dos parênteses. No exemplo, vemos polimorfismo quando o operador de multiplicação aceita inteiros e reais como argumentos. Haskell possui funções embutidas. Na verdade, os operadores são açucares sintáticos de funções. Isso é percebido pela forma como se comportam. Alguns exemplos a seguir incluem funções que tratam também de strings.
Prelude> div 10 3
3
Prelude> abs (-23) -- parênteses necessários para que -23 seja tratado como argumento
23
Prelude> negate 10
-10
Prelude> reverse "Kodumaro"
"oramudoK"
Prelude> "Kodumaro" ++ " é legal" -- exemplo de concatenação de strings
"Kodumaro é legal"
Prelude> length "Teste"
5
Prelude> 'a' < 'z' -- operação entre tipo Char
True
Prelude> True && False -- &&: operador booleano E
False
Prelude> True || False -- ||: operador booleano OU
True


Dois sinais de menos iniciam um comentário. Comentários em Haskell só existem para uma linha, não para um conjunto delas.

Funções podem ser tratadas como operadores. Isso é visto no exemplo abaixo:
Prelude> 10 `div` 3
3


Além dos números, booleanos e strings, Haskell possui outros tipos de dados, como as tuplas e as listas. São tipos muito usados na linguagem.

Tupla é uma seqüência fixa de elementos. Esses elementos podem ser de tipos diferentes. Tuplas são representadas por elementos entre parênteses:
Prelude> ("Cláudio",29)
("Cláudio", 29)
Prelude> fst ("Cláudio", 29) -- fst retorna o primeiro elemento da tupla
"Cláudio"
Prelude> snd ("Cláudio", 29, "Computação") -- snd retorna o segundo
29
Prelude> () -- Uma tupla vazia
()


Acredito que exemplos explicam melhor que palavras. Exposto isso vamos às listas, tão importantes para Haskell.

Listas são seqüências de elementos de um mesmo tipo.
Prelude> [2,3,4]
[2,3,4]
Prelude> ['c','a','s','a']
['c','a','s','a']
Prelude> length [2,3,4] -- olha o exemplo de polimorfismo!
3
Prelude> [1..4] -- uma particularidade das listas.
[1,2,3,4]
Prelude> head [1..4] -- a cabeça da lista
[1]
Prelude> tail [1..4] -- a cauda da lista
[2,3,4]
Prelude> "Kodumaro" == ['k','o','d','u','m','a','r','o'] -- Uma string é uma lista de Char!
True
Prelude> head "Kodumaro" -- então isso funciona!
"K"
Prelude> elem 'm' "Kodumaro" -- existe 'm' na string "Koduramo"?
True
Prelude> elem 5 [1..4]
False


Esse primeiro post serve para dar uma amostra do que é Haskell. Ainda veremos muitas coisas daqui em diante. Estou revisando novamente a linguagem e sei que há muitas coisas que não consegui estudar na faculdade, como as tais mônadas, conceito complicado por sinal. Espero que tenham gostado. Obrigado!

Prelude> :quit

Compensa aprender python?

(Originalmente publicado em devlog.waltercruz.com)

Uma das vantagens de se ter um domínio próprio é contar com uma série de ferramentas para ver estatísticas diversas, entre elas, como as pessoas chegam no seu site. É curioso ver o que as pessoas procuraram nos mecanismos de busca. A partir dessas buscas, resolvi responder a algumas delas e escrever textos sobre essas buscas aqui no site. E a primeira pergunta é: 'Compensa aprender python?'

Sou um fã da linguagem, logo, não posso dizer que minha resposta seja imparcial, embora eu esteja tentando sê-lo.

A resposta é: depende. As linguagens 'de mercado' agora são Java, .NET (esse, mais do que uma linguagem) e, concorrendo num terceiro lugar para web, PHP. Uma pesquisa num jornal de domingo, ou em sites de empregos revelará dezenas de vagas nessas linguagens, e pouquíssimas em outras linguagens como python ou ruby, ou até outras mais antigas, como perl.

Mas, se você trabalha com uma linguagem de tipagem estática e compilada (C ou Java, por exemplo) aprender uma linguagem de tipagem dinâmica e interpretada pode levá-lo a executar algumas tarefas mais rapidamente do que seria com uma outra linguagem. Isso porque, com python, você pode ir testando direto no console, a sintaxe da linguagem é fácil e ela tem baterias incluídas - uma porção de bibliotecas para fazer quase tudo o que você quer.

E python é uma linguagem de uso geral, ao contrário de PHP, que é voltada para web (apesar do PHP-GTK fazer um esforço noutra direção). Você pode escrever programas para web (Django e TurboGears são apenas duas formas dentre várias), para desktop, robôs de busca, e muito mais. Muitas vezes, os empregos disponíveis para as linguagens da moda são para 'apertadores de parafuso', ou como diria o Fábio Akita, mais tela de cadastro. Um conhecimento de uma linguagem que não seja a da moda, pode te levar a trabalhar com coisas mais legais (por exemplo, Lua, a preferida para script em jogos, ou Python no celular). Seu interesse em python (ou outra linguagem que não seja a 'de mercado', como lua, ruby ou lisp) pode sinalizar a seu [futuro] empregador que você gosta de fato do que faz e está interessado em aprender. A escolha de aprender python deve ser muito mais calcada numa decisão pessoal do que pela observação do mercado. Pelo menos, na observação do mercado brasileiro.

Sugiro também a leitura de: http://www.1bit.com.br/content.1bit/weblog/meu_caso_com_o_python_2

sexta-feira, 16 de março de 2007

Conceitos básicos de programação

Poliedro Quando as pessoas começam a se interessar por programação, podem ficar confusas com tantos conceitos novos. Mas pior que isso, parece que cada grupo define cada conceito de forma diferente, atribuindo conotações positivas e negativas indiscriminadamente segundo seus interesses.

A confusão gerada por essa briga de egos é enorme e pode levar muitos incautos por caminhos tortuosos, então é preciso muito bom senso.

Vamos tentar aqui apresentar algumas poucas definições da forma mais imparcial possível – o que incrivelmente pode ofender alguns mais afoitos.

Básico da programação


Programação pode ser definido como o ato de descrever um algoritmo que resolva um problema proposto de forma aplicável. Não é a única definição, não é a melhor, mas é muito boa, não?

Um algoritmo é uma sequência de passos a ser executada para se chegar a um objeto, no caso, a solução de um problema proposto. Para que a descrição do algoritmo seja aplicável, tem de ser feita usando um protocolo linguístico que o executor reconheça. Este protocolo é chamado linguagem de programação.

Como utilizamos computadores para realizar a execução do programa, a linguagem de programação precisa ser reconhecida pelo computador que realizará aquela tarefa específica.

Essencialmente computadores reconhecem apenas uma linguagem específica, formada por instruções relacionadas a microinstruções registradas no microprograma do processador. Esta linguagem é chamada linguagem ou código de máquina e é extremamente incompreensível. =P

No entanto é preciso que o programa esteja em linguagem de máquina para que o computador possa executá-lo, o que é um problema e tanto.

A forma usada para solucionar a questão é relativamente simples: a criação de «tradutores» que permitam que o programa seja escrito em linguagens mais inteligíveis para então ser «traduzido» para a linguagem de máquina. Há alguns tipos diferentes de tradução, como montagem, compilação, interpretação e interpilação. Veremos mais a frente.

Nível de abstração


O uso de tradutores permite que a linguagem usada para a programação apresente um certo nível de abstração da forma como a máquina funciona. Linguagens que se aproximam muito do funcionamento da máquina são chamadas de baixo nível, já linguagens que se afastam do funcionamento são chamados de alto nível.

Por exemplo, a linguagem Assembly possui uma instrução para cada instrução de máquina, sendo assim uma linguagem de baixo nível. Isso traz dois inconvenientes: ¹é preciso entender como cada processador funciona para a criação do programa e ²o programa se torna pouco portável, sendo necessário reescrevê-lo para cada tipo de diferente de processador.

Por outro lado, traz uma grande vantagem: como não há uma «tradução» propriamente dita, apenas uma conversão de símbolos (tokens), a execução do programa se torna extremamente eficiente.

Isso ocorre porque toda tradução semântica gera verborragia, ou seja, excesso de comandos para fazer coisas simples. Quanto maior a diferença entre a linguagem original e a de destino, maior a probabilidade de verborragia, mas não necessariamente.

Quando definimos nível de abstração, entramos numa questão delicada, pois há um tremendo mal entendido sobre o que seja uma linguagem de alto nível.

Por exemplo: a linguagem C é uma linguagem de alto nível, pois abstrai do funcionamento da máquina, se aproximando da linguagem matemática. No entanto pessoas com dificuldade em matemática não entende isso.

Tipos de «tradução»


Há muitas variações de como a tradução de uma linguagem de mais alto nível para a linguagem de máquina é feita.

A mais simples é a montagem, que é quando cada instrução da linguagem de mais alto nível é traduzida diretamente para uma instrução da linguagem de máquina. O programa que faz esta montagem é chamado montador. Ex.: Assembly.

Um pouco mais complicada é a compilação: a partir do programa em linguagem de mais alto nível é gerado um programa de mais baixo nível equivalente, que é montado, gerando o código objeto (programa em código de máquina). Ex.: C.

Na compilação há em geral mais de um programa trabalhando, basicamente o compilador, que gera um objeto que faz chamadas a procedimentos que não possui, e o linkeditor, que liga ao objeto outros objetos, chamados bibliotecas, que possuem os procedimentos necessários, gerando o objeto final ou código de máquina.

Outra alternativa é a interpretação. Há um programa chamado interpretador que funciona como se fosse uma máquina virtual, com suas próprias instruções, e o programa é feito usando tais instruções. Ex.: Tcl/Tk.

Por final, há variações destas três formas citadas.

Por exemplo, há linguagens cuja compilação não gera código de máquina, mas um código intermediário, chamado bytecode, que é interpretado por um interpretador chamado máquina virtual (pois é… máquina virtual é um tipo de interpretador). Por exemplo, Java trabalha assim.

Uma variação deste tipo de compilação é a usada em Smalltalk, pois não é gerado um bytecode, mas a compilação altera o comportamento da máquina virtual.

Por último existe a interpilação, que possui duas variações: ¹o interpilador recebe o código e gera um objeto em código de máquina, mas somente em memória, e este objeto é executado diretamente da memória (ex.: Perl); ou ²o interpilador recebe o código e gera um bytecode em memória que é executado por uma máquina virtual (como Python e Lua).

Algumas linguagens podem trabalhar com traduções diferentes. Por exemplo, Perl pode ser interpilado ou compilado. Python e Lua podem ser interpilados com máquina virtual, ou compilados para bytecode (que será também interpretado por uma máquina virtual).

Manipulação de dados


A principal parte da programação é a manipulação de dados: armazenamento, leitura e alteração.

Para armazenamento e leitura usamos posições de memória e registradores do processador.

Em linguagens de mais baixo nível, usamos os próprios endereços de memória e o nomes do registrador, mas em linguagens de nível mais alto, usamos variáveis, que são «apelidos» para tais endereços e nomes.

Também é necessário saber que quantidade de memória cada dado ocupa e como ele deve se comporta. Isso é chamado tipagem.

Transferência de informações


Muitas vezes é necessário que um determinado dado seja transferido de uma variável para outra. Esta transferência é camada passagem e há dois tipos de passagem: passagem por valor e passagem por referência.

  • Passagem por valor


A passagem por valor ocorre quando cada variável contém o dado em si. Assim quando passamos um dado de uma variável para outra o dado é duplicado para a segunda variável.

Então a alteração do dado na variável de destino não altera o dado na variável de origem.

  • Passagem por referência


A passagem por referência ocorre quando a variável não contém o dado em si, mas um ponteiro para a posição de memória onde o dado se encontra. Assim quando passamos uma referência de uma variável para outra o dado não é duplicado, apenas as duas variáveis apontam para a mesma posição de memória.

Então a alteração do dado na variável de destino altera consequentemente o dado na variável de origem, pois ambos são o mesmo dado.

Algumas linguagens, como C/C++, permitem o programador escolher usar valores ou ponteiros, enquanto outras linguagens (na verdade a maioria delas) usam valor para alguns tipos determinados e ponteiro (na verdade referência, que é um ponteiro implícito) para outros.

Tipagem


Tipagem é a definição da quantidade de memória que um determinado dado ocupa e como esse dado deve interagir com os demais.

Há duas classificações de tipagem, veremos a seguir.

  • Tipagem estática × tipagem dinâmica


Esta é uma definição discreta. Há duas formas distintas de tratar os tipos de dados: ou o tipo está associado ao dado, ou está associado à variável que o referencia.

Quando o tipo está associado ao dado em si, chamamos de tipagem dinâmica.
Quando o tipo está associado à variável, chamamos de tipagem estática.

Dizemos dinâmica ou estática em relação à variável, ou seja, na tipagem dinâmica uma mesma variável pode conter dados de tipos diferentes, dinamicamente, enquanto na tipagem estática uma variável conterá sempre dados do mesmo tipo.

Por outro lado na tipagem dinâmica o dado sempre se comportará da mesma forma independente da variável à qual foi associado e na tipagem estática o dado se comportará de formas diferentes de acordo com a variável que o referencia.

Enquanto falamos de valores, pode parecer que a tipagem estática seja superior, mas quando falamos de ponteiros/referências, a tipagem dinâmica passa a levar vantagem.

Isso ocorre porque queremos que um determinado dado se comporte sempre da mesma forma.

No entanto a tipagem dinâmica é mais difícil de ser trabalhada, pois exige atenção redobrada.

Em suma, ambos as tipagens possuem vantagens e desvantagens, cabendo ao programador (veja bem: ao programador, não ao professor do programador, à comunidade, ao livro ou qualquer outro fator externo) decidir qual lhe satisfaz melhor.

  • Tipagem fraca × tipagem forte


Ao contrário da anterior, está uma definição contínua. Há duas direções: tipagem fraca indica menor quantidade de tipos e/ou menor distinção entre os tipos e tipagem forte indica maior quantidade de tipos e/ou maior distinção entre os tipos.

Assim como a definição de nível de abstração, há linguagens de tipagem mais forte e outras de tipagem mais fraca.

Por exemplo, C é uma linguagem de tipagem fraca, pois, apesar de possuir quatro tipos (int, char, float e double) e algumas variações (long, unsigned, struct, union…), os tipos se confundem, ou seja, a distinção entre os tipos não é perfeitamente clara.

Um exemplo de tipagem ainda mais fraca é Perl, que além de possuir apenas três tipos (escalar, vetor e hash), os tipos se confundem.

Vamos agora a linguagens de tipagem mais forte…

C++ possui os mesmos tipos de C, mais as classes (que se comportam de forma semelhante a tipos), e ainda faz uma boa distinção entre os tipos.

Java possui alguns tipos, mais classes (como C++), e tem uma distinção bem forte.

Python possui apenas dois tipos reais: tipo e objeto, no entanto tipo e objeto se comportam da mesma forma e as classes (variantes de tipo e de objeto) se comportam como tipos. Resumindo, Python possui uma tipagem tremendamente forte, pois na prática possui mais de trinta tipos perfeitamente distintos entre si.

Lua é uma linguagem a meio caminho, pois possui sete tipos bem distintos entre si, mas a conversão é facilitada.

Novamente não há uma escolha certa, forte ou fraco… tudo depende de com que o programador se identifica.


Observação séria

Alguns evangelizadores fazem desinformação proposital para convencer as pessoas de suas crenças pessoais, divulgando inverdades.

Algumas inverdades clássicas são:
  • Tipagem dinâmica é ruim, estática é boa.
  • Tipagem fraca é ruim, forte é boa.
  • Tipagem fraca é o mesmo que tipagem dinâmica.
  • Não existe essa de tipagem mais ou menos forte, tipagem é fraca ou forte e pronto.
  • Compilação é melhor que interpretação.
  • Interpretação por máquina virtual não é interpretação, é compilação.
  • Apenas Java usa máquina virtual.
  • C não é portável porque não usa máquina virtual.
  • Toda linguagem interpretada (o que exclui Java) é scripting.


Há outras clássicas, veremos mais a frente. O importante é não acreditar.

Paradigmas de programação


Paradigma de programação é a forma como o programador enxerga a solução do problema. Tem mais a haver com a estruturação.

Em outras palavras, paradigma é a metodologia de solução.

Inicialmente os programadores não se preocupavam com paradigma algum. Então os programas eram simples sequências de procedimentos. Hoje em dia chamamos isso de programação sequencial e exclui automaticamente todos os demais paradigmas.

Mais tarde foi desenvolvido o paradigma procedimental e a programação estruturada.

  • Programação estruturada


Programação estruturada é baseada na estruturação do código.

A idéia é que o programa seja divido em pequenos procedimentos estruturados, chamados subrotinas ou funções. O programa é desenvolvido a partir das funções mais abstratas e terminando pelas mais específicas (desenvolvimento top-down).

Deu origem à modularização e à programação procedimental.

  • Programação procedimental


Erroneamente chamada programação procedural (procedural é procedimental em inglês), programação procedimental é a programação baseada em procedimentos.

O conceito é usado normalmente em oposição a programação funcional e às vezes se confunde com programação estruturada ou com programação imperativa.

  • Programação funcional


O foco deste paradigma está nas funções matemáticas.

Um programa então é uma associação de funções matemáticas.

  • Programação orientada a objetos


Na orientação a objetos o programa não se baseia em procedimentos, mas na relação entre objetos.

Objetos são representações de «coisas» que executam funções (chamadas métodos). Estas «coisas» são quase microuniversos independentes.

Da interação entre os objetos resulta a solução do problema proposto.

Por exemplo, uma porta é um objeto que, através de sua interação com o portal, a tranca e a chave permite que determinadas pessoas entram e saiam enquanto outras não.

Importante: os evangelizadores da desinformação pregam que a orientação a objetos exclui outros paradigmas e que seja o paradigma definitivo, no entanto não é possível usar orientação a objetos sem programação estruturada, ou seja, o código precisa estar estruturado para ser orientado a objetos.

Aliás a programação estruturada é pré-requisito para a maioria dos demais paradigmas.

  • Programação orientada a eventos


A orientação a eventos pressupõe a orientação a objetos, pois implica em criar objetos que reajam a determinados eventos.

Geralmente é criado loop principal que intercepta os eventos, repassando-os para os objetos registrados. Algumas linguagens (ou módulos) oferecem uma implementação pronta do loop principal.

  • Outros paradigmas


Em tese pode haver tantos paradigmas quanto programadores, visto que paradigma é a forma como o programador vê a solução do programa.

Apenas alguns dos mais clássicos são:


Scripting



Há ainda outro conceito, que é a programação scripting, que consiste no desenvolvimento de scripts.

Script é um código interpretado ou interpilado (muitas vezes por máquina virtual) que consiste em agregar componentes pré-compilados.

Pela definição, a grande maioria das linguagens modernas são linguagens de scripting (inclusive Java).

No entanto há pessoas que usam o termo scripting com sentido estritamente pejorativo, sem entender exatamente o significado. Essas pessoas nunca aceitam que sua linguagem seja chamava de linguagem de scripting. Às vezes distorcem a descrição do conceito, às vezes mentem sobre o funcionamento de sua linguagem e muitas vezes apenas negam sistematicamente, sem qualquer argumento real.

Na prática «linguagem de scripting» é só um conceito arbitário usado ou pejorativamente para malfalar alguma linguagem ou para dizer que uma linguagem é muito fácil de ser aprendida.

Conclusão


Esta foi apenas um exposição superficial de alguns conceitos básicos de programação, mas mais importante, é um alerta aos programadores incautos que acabam por crer na evangelização de pessoas que têm por objetivo desinformar e fanatizar.

Estejam sempre atentos e, mais importante, mente sempre aberta. =)

[]'s
Rodrigo Cacilhas (La Batalema Pitonisto)

terça-feira, 13 de março de 2007

Números complexos em Lua

Lua Este artigo foi publicado por mim originalmente em Reflexões de Monte Gasppa e Giulia C.. Esta é uma atualização para Lua 5.1.

Lua é uma poderosa linguagem de programação procedimental, orientada a objetos, de tipagem dinâmica, baseada em tabelas associativas e semântica extensível, projetada e implementada no Tecgraf, Grupo de Computação Gráfica da PUC-Rio, em 1993.

Foi projetada para ser uma linguagem de extensão, para que fosse possível que os usuários reconfigurassem aplicações sem necessidade de recompilação das aplicações.

Atualmente é a linguagem de script mais usada para programação de jogos (em segundo lugar está Python).

Uma curiosidade de Lua é não haver um módulo de suporte a números complexos. Vamos então implementar um.

Metatabelas


Em orientação a objetos, classe é um molde para a criação de objetos similares, chamados instâncias em relação à classe. Lua trabalha com um conceito ligeiramente diferente: metatabelas e metamétodos.

Em Lua tudo são tabelas, cujos elementos são quaisquer objetos de primeira ordem, inclusive funções (chamadas métodos ou metamétodos em classes) e outras tabelas.

Alguns métodos especiais, chamados metamétodos aritméticos, são usados para reagir a operações aritméticas. Há ainda os metamétodos comparativos – que reagem a operações de comparação – e os metamétodos de string.

Os metamétodos aritméticos, comparativos e de string são: __add() (adição), __sub() (subtração), __mul() (multiplicação), __div() (divisão), __pow() (potência), __unm() (inversão de sinal), __tostring() (conversão para string), __concat() (concatenação), __eq() (igualdade), __lt() (menor que) e __le() (menor ou igual).

Alguém pode perguntar «e quanto a ‘maior que’ e ‘maior ou igual’?». A resposta é simples, se a > b então b < a, capicci? A mesma idéia é para diferença (a ~= b é o mesmo que not a == b).

Está confuso até aqui? Vai clarear assim que começarmos a criar nossa metatabela. Vamos então à criação de nossa metatabela: primeiro usaremos o construtor de tabela ({}) para criar a metatabela com alguns valores default e em seguida criaremos o construtor próprio para números complexos:
local cmt = { real = 0, img = 1 }
cmt.__index = cmt
function cmt:new(o)
o = o or {}
return setmetatable(o, self)
end


Números complexos são formados por duas partes, uma real (ℜ) e outra imagem (ℑ), então criamos nossa metatabela assim.

A sintaxe function cmt:new(o) é um açúcar sintático para function cmt.new(self, o) e é usada para métodos.

O comando setmetatable(o, self) define que a metatabela de o será self (que representa mt) e o elemento __index informa de onde a tabela deve retirar os valores padrão (para elementos não definidos), e será a própria metatabela.

No entanto queremos ter alguma flexibilidade ao criar um número complexo:
  • e não for passado argumento, queremos que a função retorne j;
  • Se for passado um número (real), queremos retornar ele mesmo;
  • Se for passado um número complexo, queremos retornar uma cópia dele;
  • Se forem passados dois números (reais), queremos que o primeiro seja a parte real e que o segundo seja a imagem (se a imagem for zero, retorne somente a parte real).


Assim sendo, podemos criar a seguinte função:
function new(...)
if #{...} == 0 then
-- nenhum argumento retorna j
return cmt:new { real = 0, img = 1 }
elseif #{...} == 1 and type(select(1, ...)) == "number" then
-- um argumento: numero real
return select(1, ...)
elseif #{...} == 1 and getmetatable(select(1, ...)) == cmt then
-- um argumento: numero complexo
return cmt:new { real = select(1, ...).real, img = select(1, ...).img }
elseif #{...} == 2 and
type(select(1, ...)) == "number" and type(select(2, ...)) == "number" then
-- dois argumentos reais
if select(2, ...) == 0 then
return select(1, ...)
else
return cmt:new { real = select(1, ...), img = select(2, ...) }
end
else
error "parse error"
end
end


Mostrando nosso número complexo


O primeiro método que definiremos será para exibir nosso número complexo.

Sem este método, o comando abaixo retornaria assim:
lua> print(numero)
table: 0×80725e0


E queremos que, na verdade retorne algo do tipo:
lua> print(numero)
3 + 2j


Para tanto é preciso definir o método __tostring(). Mas não será tão fácil assim!

Imagine só: precisamos definir pelo menos oito casos diferentes:
  1. imagem = 0
  2. real = 0, imagem = 1
  3. real = 0, imagem = -1
  4. real ≠ 0, imagem = 1
  5. real ≠ 0, imagem = -1
  6. real = 0, imagem ≠ 0
  7. real ≠ 0, imagem > 0 e imagem ≠ 1
  8. real ≠ 0, imagem < 0 e imagem ≠ -1


Vamos então!
function cmt:__tostring()
local a, b = self.real, self.img
if b == 0 then
return tostring(a)
elseif b == 1 and a == 0 then
return "j"
elseif b == -1 and a == 0 then
return "-j"
elseif b == 1 and a ~= 0 then
return a .. " + j"
elseif b == -1 and a ~= 0 then
return a .. " - j"
elseif b ~= 0 and a == 0 then
return b .. "j"
elseif b > 0 and a ~= 0 then
return a .. " + " .. b .. "j"
elseif b < 0 and a ~= 0 then
return a .. " - " .. (-b) .. "j"
else
error "unexpected (a + bj) combination"
end
end


Uma funçãozinha útil


Para definir alguns parâmetros importantes precisamos definir o que acontece com o número quando tentamos invertê-lo (1 / (a + bj)).

A operação matemática é multiplicar a fração resultante por uma expressão equivalente a 1, como (a - bj) / (a - bj).

Fazendo esta continha simpática, obtemos real a / (a² + b²) e imagem -b / (a² + b²).

Vamos criar nossa função:
local function inv(v)
if getmetatable(v) ~= cmt then
return v ^ (-1)
else
local a, b, q = v.real, v.img
q = a ^ 2 + b ^ 2
return new(a / q, -b / q)
end
end


Nesta função, a primeira coisa que fizemos foi verificar se o argumento é um número complexo. Se não for, a função retorna um dividido pelo argumento. Se for um número complexo, realiza o cálculo citado.

Repare na linha:
local a, b, q = v.real, v.img


Neste comando, a, b e q são definidos como variáveis locais. a recebe v.real, b recebe v.img e q recebe nil.

Inversão de sinais


Se temos um número complexo b, queremos que -b retorne um número complexo com os sinais do real e da imagem invertidos:
function cmt:__unm()
return new(-self.real, -self.img)
end


Igualdade


Vamos verificar igualdade. Quando Lua verifica a == b, sendo a e b tabelas, na verdade está verificando se a e b são exatamente a mesma tabela, não se seus elementos são iguais. O quer queremos quando comparamos dois números complexos é se representam o mesmo valor, ou seja, se seus reais são iguais e se suas imagens também são.

Precisamos então criar um método para tratar isso:
function cmt:__eq(v)
if getmetatable(v) == cmt then
return self.real == v.real and self.img == v.img
else
return self.img == 0 and v == self.real
end
end


Operações binárias


Agora definiremos as operações binárias, ou seja, que necessitam de dois operandos: adição (+), subtração (-), multiplicação (*), divisão (/), potência (^) e concatenação (..).

Em todos os casos verificaremos se o segundo elemento da operação é também um número complexo ou não.

  • Adição

function cmt:__add(v)
local a1, b1, a2, b2, a3, b3 = self.real, self.img
if getmetatable(v) ~= cmt then
a2, b2 = v, 0
else
a2, b2 = v.real, v.img
end
a3, b3 = a1 + a2, b1 + b2
return new(a3, b3)
end


Na declaração das variáveis locais, a1 recebe self.real e b1 self.img. Todas as demais variáveis recebem nil.

  • Subtração (nada além de adição com sinal invertido)

function cmt:__sub(v)
return self + (-v)
end


  • Multiplicação (muito semelhante à adição)

function cmt:__mut(v)
local a1, b1, a2, b2, a3, b3 = self.real, self.img
if getmetatable(v) ~= cmt then
a2, b2 = v, 0
else
a2, b2 = v.real, v.img
end
a3, b3 = a1 * a2 – b1 * 2, a1 * b2 + a2 * b1
return new(a3, b3)
end


  • Divisão (divisão é a multiplicação onde o segundo termo é invertido)

function cmt:__div(v)
return self * inv(v)
end


  • Potência (aqui trataremos apenas expoentes inteiros, que não passam de multiplicações sucessivas)

function cmt:__pow(v)
if v == 0 then
-- expoente 0 retorna 1
return 1
elseif v == 1 then
-- expoente 1 retorna uma cópia de si mesmo
return new(self)
elseif v < 0 then
-- expoente negativo retorna inversão
return inv(self ^ (-v))
else
local aux, cont = new(self)
for cont = 2, v do
aux = self * aux
end
return aux
end
end


Repare a recursividade na linha:
return inv(self ^ (-v))


A potência chama novamente __pow() para self, mas desta vez com argumento -v.

  • Concatenação (fácil: retorna a contenação das strings!)

function cmt:__concat(v)
return tostring(self) .. tostring(v)
end


Vamos tornar isso tudo útil?


Até agora está tudo muito bonito, tratando números complexos e tudo mais… mas números complexos só são úteis se pudermos fazer duas coisas: ¹converter números reais em complexos quando tentamos extrair a raiz de um número negativo e ²converter números complexos para reais por meio das operações básicas.

Bem, a segunda coisa nosso módulo já faz, falta a primeira! Para tanto, vamos criar uma função de raiz quadrada segura, que retorne um número complexo quando a base for negativa:
function sqrt(v)
if type(v) ~= "number" then
error "value must be a number"
end
if v >= 0 then
return v ^ .5
else
return new(0, (-v) ^ .5)
end
end


Também será útil termos uma função que retorne verdadeiro ou falso para verificar se um valor é um número complexo:
function iscomplex(v)
return getmetatable(v) == cmt
end
j = new()


Finalizando


Para transformar isso tudo num pacote, salve todos os códigos num arquivo (pode ser complex.lua) e coloque na primeira linha do arquivo:
module("complex", package.seeall)


Vamos agora testar! Acesse o diretório onde está o arquivo complex.lua e execute o interpretador lua51. Execute os seguintes comandos e veja se funciona:
lua> require “complex”
lua> for c = -4, 7 do print(c, complex.j ^ c) end
-4 1
-3 j
-2 -1
-1 -j
0 1
1 j
2 -1
3 -j
4 1
5 j
6 -1
7 -j
lua> a = complex.sqrt(-9) + 2
lua> b = complex.new(3, 2)
lua> print(a, b)
2 + 3j 3 + 2j
lua> print(a + b)
5 + 5j
lua> print(a * b)
13j
lua> print(a / 2)
1 + 1.5j
lua> print(b ^ 2)
5 + 12j


Se tudo sair direitinho, parabéns! Acabou de fazer seu primeiro módulo de números complexos.

[]’s

PS: A primeira versão deste artigo foi escrita para Lua 5.0 e publicada aqui. Esta versão foi publicada pela primeira vez no Wordpress.com, no entanto tive problemas com a ferramenta deles.

segunda-feira, 12 de março de 2007

Python com Eggs - Parte II

Construções relevantes do Setuptools

Considero Setuptools um projeto tão importante para a comunidade Python que eu preciso citar mais informações sobre ele antes de entrar realmente no tópico sobre plugins. Para ter uma idéia da quantidade de projetos em Python, pequenos ou grandes, vale a pena visitar o site do Cheese Shop. Ele é um repositório de projetos escritos em Python. A maioria dos projetos já é distribuído usando o formato Egg, principalmente para facilitar a verificação de dependências.

Projetos que ainda não usam os recursos do Setuptools, ainda assim, quando baixados via EasyInstall são transformados em Eggs antes da instalação, automaticamente.

Recursos mais importantes (retirados daqui):

  • Automaticamente encontra/baixa/instala/atualiza dependências em tempo de construção usando a ferramenta EasyInstall, que suporta donwload via HTTP, FTP, Subversion e ainda SourceForge, além de rastrear automaticamente páginas “linkadas” no PyPI para encontrar links de downloads. Como o autor mesmo cita: é o mais próximo que temos do CPAN em Python.
  • Criação de Python Eggs - formato de distribuição importável em um único arquivo.
  • Incluir arquivos de dados em seus diretórios de pacotes.
  • Capaz de automaticamente incluir todos os pacotes da sua árvore-fonte sem a necessidade de declarar individualmente cada pacote no setup.py.
  • Suporta o envio de fontes ou eggs para o PyPI.
  • Instala seu projeto em modo de desenvolvimento. Assim seu projeto fica disponível para importação e você ainda poderá editá-lo e quaisquer modificações são automaticamente visíveis.
  • Facilmente estende o distutils com novos comandos ou argumentos para a função setup() e distribui/reusa suas extensões para cada projeto sem copiar código.
  • Cria aplicações e frameworks extensíveis que automaticamente descobrem extensões usando simplesmente “entry points” declarados no script setup.py do projeto.

Esse último item é o que nos interessa. Ele vem fazendo a mágica em vários projetos, inclusive em favor do próprio Setuptools.

Entry Points

Entry Points é uma lista de objetos públicos numa distribuição. Vejamos um exemplo:

# setup.py

setup(…
entry_points = “”"
[lyricsearch.search]
terra = lyricsearch.terrasearch:LyricsTerra
[console_scripts]
lyse = lyricsearch.lyse:command
“”"
)

Os objetos são ordenados em grupos. No caso do exemplo, lyricsearch.search é um grupo para objetos que fazem busca de letras para a aplicação LyricSearch.

Já existem nomes de grupos convencionalizados:

- [console_scripts] para scripts de linha de comando
- [paste.app_factory] aponta para uma função que constrói uma aplicação WSGI.
- [distutils.command] aponta para um comando do distutils (ex.: setup.py sdist)
- [python.template.plugin] é uma classe que representa uma sistema de template.

Um objeto público possui um nome. Em nosso exemplo, o plugin de busca de letras no site do Terra chama-se ‘terra’. Nomes simplesmente apontam para objetos Python. As duas declarações abaixo são equivalentes:

lyricsearch.terrasearch:LyricsTerra

from lyricsearch.terrasearch import LyricsTerra

Essa aplicação de exemplo realmente existe e sou seu autor. Fiz especialmente para essa matéria. Atualmente o LyricSearch é composto de um simples script de linha de comando para realizar consulta de letras e mais um plugin. Passamos para ele o título da música e o artista. O script procura por plugins e tentará utilizar cada um deles até encontrar um que devolva a letra desejada. Fiz somente um plugin. O plugin consulta o site letras.terra.com.br em busca da página da letra. Ele devolve o texto em HTMl. Todos os plugins do grupo [lyricsearch.search] devem ser uma classe que implemente dois atributos url, description e um método público, find(title, artist), para retornar uma string contendo o texto da letra ou uma string vazia caso não encontre nada.

Fazendo nosso primeiro plugin

Vamos fazer um simples plugin para o LyricSearch na finalidade de mostrar o poder dos Entry Points do Setuptools. Façamos a seguinte estrutura de arquivos:

TestePlugin
+– testeplugin.py
+– setup.py

Agora o código:

#testeplugin.py

class TestePlugin:

url = ‘http://claudiotorcato.wordpress.com’

description = ‘apenas um teste’

def find(self, title, artist):

return artist

#setup.py
from setuptools import setup

setup(

name = ‘TestePlugin’,
version = ‘0.1′,
py_modules = [’testeplugin’],
entry_points = “”"
[lyricsearch.search]
teste = testeplugin:TestePlugin
“”"

)

Nosso plugin não fará nada útil, apenas devolverá o nome do artista.

Antes de continuar, precisamos instalar o setuptools em nossa máquina caso não o tenhamos. Baixe o script ez_setup.py e o execute. Ele baixará e instalará a versão estável mais recente do setuptools. Agora vamos instalar em nossa máquina o LyricSearch. Usuários do Linux que não tenham permissão de root para a instalação há essa alternativa [1].

easy_install LyricSearch

Agora, testemos a aplicação que foi baixada:

lyse “o vencedor” “los hermanos”

Obs.: Usuários do Windows não devem esquecer de colocar o caminho do interpretador Python e dos scripts na variável de ambiente PATH: c:\python24\;c:\python24\scripts.

Felizmente nossa aplicação já vem com pelo menos um plugin de pesquisa. É interessante, ela não usa diretamente o plugin, mas requere para a API Python que trata dos Entry Points o determinado objeto. Desejamos que nosso plugin de teste funcione da mesma forma, ou seja, seja localizado pela aplicação e executado.

O próximo passo é instalar TestePlugin. Na raiz do pacote digite e execute:

python setup.py develop

A opção develop cria um arquivo em site-packages que aponta para nosso diretório de desenvolvimento. Assim nossas modificações nesse ambiente repercutem na biblioteca automaticamte. De modo mais simples: a atualização da biblioteca é instantânea.

O outro modo seria ‘python setup.py install’ que realmente grava nosso pacote na árvore de diretórios do Python. Na verdade, é o modo comum de instalar pacotes.

Se a instalação ocorreu sem problemas, vamos testar agora nosso plugin.

lyse –list

Este comando mostrar os plugins do grupo lyricsearch.lyric. Deveriam ser encontrados dois: terra e teste. Aparecendo, vamos ver se ele realmente devolve o nome do Artista.

lyse -p teste “o vencedor” “los hermanos”

Partindo do mesmo exemplo de consulta, porém forçando o plugin, esperamos que retorne a palavra “los hermanos”!

Tamanha a flexibilidade dos Plugins em Python, cada vez mais desenvolvedores se voltam para esse modo de criar aplicações e ferramentas extensivas de modo mais simples. No próximo material, trataremos de assuntos tais como Paste entre outros.

Parte I

Adicionando usuários ao trac via script

Há um tempo atrás, como todo desenvolvedor que se preze, comecei a usar um controle de versão, no caso, o subversion. Logo depois, descobri o trac, uma ferramenta que agrega ao svn um wiki e um bugtrack. Uma mão na roda pra gerenciamento de projetos!

A ferramenta padrão para administrar o trac é por linha de comando: trac-admin. Sempre que eu criava um novo repositório, precisava adicionar os usuários com permissão de desenvolvedor no trac correspondente a esse repositório. Porque não facilitar as coisas?

Como o trac é feito em python, posso usar a API em um programa. Foi o que fiz. O resultado:

#!/usr/bin/python2.4
# -*- coding: iso-8859-1 -*-
import sys
import os
import trac.scripts.admin as admin
from trac.perm import PermissionSystem as Permission
import pysqlite2

class TracHelper(object):

developers = ("walter","cacilhas","torcato","will")
developersPermissions = ("WIKI_ADMIN","REPORT_ADMIN","TICKET_MODIFY")

def __init__(self,projectPath):
try:
self.projectPath = projectPath
self.env = admin.Environment(self.projectPath)
self.permissao = Permission(self.env)
except:
'Eh necessario especificar um projeto'

def addDeveloperProfile(self):
for permission in self.developersPermissions:
try:
self.permissao.grant_permission('developer',permission)
except pysqlite2.dbapi2.IntegrityError, e:
print('Já existe usuário com essa permissão')
sys.exit(1)

def addDevelopers(self):
for developer in self.developers:
try:
self.permissao.grant_permission(developer,'developer')
except pysqlite2.dbapi2.IntegrityError, e:
print('O usuário ' + developer + ' já existecom essa permissão')
sys.exit(1)

def destroyDeveloperProfile(self):
for permission in self.developersPermissions:
self.permissao.revoke_permission('developer',permission)

if __name__ == "__main__":
try:
helper = TracHelper(sys.argv[1])
except:
print('É necessário informar o caminho do Projeto')
sys.exit(1)

#helper.destroyDeveloperProfile()
helper.addDeveloperProfile()
helper.addDevelopers()

O modo de usar é simples: ./usuariostrac.py /var/trac/repositorio .

Dito isso, eis o que descubro hoje: um plugin para o trac para fazer a administração dele via web. Mas diga que não foi mais interessante o passeio pela API do trac?

Herança múltipla em Lua

Lua Ficou faltando um exemplo de herança múltipla em Lua no artigo de orientação a objetos, né?

Vamos ver algo bem simples...

Você mesmo pode criar um mecanismo para lidar com redundância. No entanto, para manter este artigo o mais simples – e inteligível – possível, vou ignorar deliberadamente problemas desse tipo.


A idéia é que a função na chave __index da metatabela procure a chave em cada uma das classes pai, retornando a primeira ocorrência que encontrar.

Podemos colocar a lista de classes pai em outra chave da metatabela.

Digamos que queremos criar uma classe Button, herdeira de Shape e de EventResponser (só usei os nomes em inglês porque em português ficariam muito grandes). =P
Button = {
super = { Shape, EventResponser }
}

Button.__index = function (t, k)
local class
for _, class in ipairs(Button.super) do
if class[k] then return class[k] end
end
end


Assim que a chave for encontrada em uma das classes (ele deve procurar primeiro em Shape), o valor será encontrado.

Para podermos usar polimorfismo e acrescentar novos métodos a esta classe, teremos de mudar um pouco mais a função para procurar a chave primeiro na própria classe:
Button.__index = function (t, k)
if Button[k] then return Button[k] end
local class
for _, class in ipairs(Button.super) do
if class[k] then return class[k] end
end
end


Valeu a brincadeira?

[]'s
Rodrigo Cacilhas (La Batalema Pitonisto)

sexta-feira, 9 de março de 2007

Saluton!

Kodumaro
Olá gente!

Kodumaro é um trabalho em conjunto de quantro amigos programadores: Cláudio Torcato, Rodrigo Cacilhas, Walter Cruz e William Jammes, num esforço para trazer algumas dicas interessantes sobre programação.

Os temas irão de iniciante a avançado, desde conceitos de programação até códigos em diversas linguagens, com uma redação leve e acessível.

Esperamos que os artigos sejam úteis e elucidativos, e aguardamos retorno de nossos leitores para que Kodumaro se aperfeiçoe dia a dia.

Sem mais delongas, está apresentada nossa nova mídia: Kodumaro!

[]’s
Rodrigo Cacilhas (La Batalema Pitonisto)
[update 2016-03-15]
Após 9 anos, Kodumaro renasce com nova cara: veja!
[/update]