sexta-feira, 30 de maio de 2008

Instalação do TG2: solucionando alguns problemas

Pediram-me para documentar a instalação do TurboGears 2. Vocês podem encontrar os passos para a instalação aqui.

O restante deste post é sobre como solucionar certos problemas. Então, se você seguiu a documentação oficial e não teve problemas não precisa mais ler este post.

É bom salientar que fiz a instalação no Ubuntu Linux.

Installing TurboGears 2 from Source

Nesse ponto, quando vocês forem instalar o tg2 com python setup.py develop, vocês não encontrarão o arquivo setup.py. Ocorre que agora o tg2 usa o paver como instalador. Ou seja, documentação desatualizada. Na raiz de tg2 execute sudo paver develop.

Pode ser que durante o download das dependências do tgdev, não seja encontrado a versão 0.8.7dev do ToscaWidgets. Se este for o caso, é melhor você esperar um tempo para eles disponibilizarem-na e então sincronize a cópia de trabalho com svn update. Depois, execute novamente sudo python setup.py develop.

Concluídas as demandas, você já pode brincar com o TurboGears 2. Comece pelo Wiki em 20 minutos.

Estou querendo instalar o TG2 no Windows, então os problemas que possa encontrar vou colocar como comentário aqui.

Este post foi escrito originalmente no Mosaico Livre.

segunda-feira, 26 de maio de 2008

Ordenando uma lista de objetos em Python

Quer ordenar uma lista de objetos em Python, usando um atributo desses objetos? É fácil! basta user o operator.attrgetter.

import operator

class Language(object):
def __init__(self,year,name):
self.year = year
self.name = name

def __repr__(self):
return ' - '.join(map(str,(self.name,self.year)))


java = Language(1995,'Java')
python = Language(1991,'Python')
ruby = Language(1995,'Ruby')
haskell = Language(1990,'Haskell')
javascript = Language(1995,'Javascript')
self = Language(1986,'Self')
perl = Language(1987,'Perl')

languages = [java,python,ruby,haskell,javascript,self,perl]

#print(languages)
languages.sort(key=operator.attrgetter('year'))
print(languages)
#Apenas Python 2.5 agora!
languages.sort(key=operator.attrgetter('year','name'))
print(languages)


Um pequeno truque que é sempre bom ter guardado na manga ;)

sexta-feira, 23 de maio de 2008

Duck Typing

Um conceito de programação bastante interessante é duck typing (tipagem do pato).

Estamos acostumados a considerar a tipagem quanto a sua rigidez e associação.

Quanto à rigidez, algumas linguagens são mais fortes, outras mais fracas. Quanto mais rígido o sistema de tipos, ou seja, mais tipos, menor flexibilidade de conversão, mais forte é a linguagem. Quanto menos rígido, mais fraca é.

Quanto a associação, o tipo pode estar associado à variável – tipagem estática – ou ao dado – tipagem dinâmica.

No entanto há outro tipo de classificação que não se encaixa bem em nenhum dos sistemas comuns, a duck typing – alguns assumem que duck typing é tipagem dinâmica, mas nem sempre se encaixa bem nessa classificação.

A lógica da duck typing é: «se nada como um pato, anda como um pato e grasna como um pato, deve ser um pato».

Dito de outra forma: se um determinado objeto é capaz de responder corretamente a um grupo específico de mensagens, ele pode ser considerado instância de uma classe hipotética que atenda a tais especificações.

Java se aproxima um pouco de duck typing com o uso de interfaces, porém de forma não tão dinâmica e eficiente quanto duck typing, pois a classe da qual o objeto foi instanciado precisa declarar explicitamente que implementa uma determinada interface.

Em duck typing basta poder responder às mensagens desejadas, não é preciso declarar a implementação da interface. A máquina virtual que executar a linguagem precisa saber – ou ser programada para – determinar em tempo de execução se um objeto atende às especificações de interface.

Geralmente se confunde duck typing com tipagem dinâmica pois é possível fazer duck typing com linguagens de tipagem dinâmica.

Tradicionalmente se usa duck typing em Smalltalk, Python – com o uso de assert –, Boo, Groovy e, mais recentemente, Io, apesar de Steve de Korte preferir o termo elephant typing, mas no fundo a diferença é ínfima.

Para quem quiser saber mais sobre duck typing, recomendo que leia o artigo elephant typing do Mergulhando no Caos, o artigo na Wikipédia, a página no Cunningham & Cunningham, Inc., a página do Boo, o Duck Typing Project para .NET, o artigo no Pythonologia e, claro, fazer a clássica busca no Google. =)

[]'s
Cacilhas, La Batalema

domingo, 11 de maio de 2008

Validação aritmética em shell scripting

Shell
Em shell-scripts, costumamos usar os recursos do Korn Shell, shell desenvolvido por David Korn nos AT&T Bell Labs na década de 1980 como uma extensão do Standard Shell.

Por exemplo, para ciclo de contagem progressiva:
for i in `seq 10`
do
echo $i
done


Outro tipo de contagem:
if [ -z "$FILENAME" ]
then
NULL_FILENAME_COUNT=`expr $NULL_FILENAME_COUNT + 1`
fi


Mas nos esquecemos que em ambiente GNU/Linux usamos o bash, que possui recursos ainda mais poderos que o Korn Shell.

Por exemplo, vamos reescrever a contagem de 1 a 10 usando a validação aritmética:
for ((i=1; i<=10; ++i))
do
echo $i
done


A outra contagem também pode ser escrita usando recursos embutidos do bash, sem precisar levantar um processo test[ e ] são um apelido para test:
if [[ -z "$FILENAME" ]]
then
((++NULL_FILENAME_COUNT))
fi


Em ambiente BSD, o shell usado é o CShell, desenvolvido por Bill Joy – sim! O cara do Java! O CShell tem uma sintaxe propositalmente similar à de C e também é bastante poderoso.

Voltemos a nossos exemplos:
@ i = 0
while ($i < 10)
@ i++
echo $i
end


O ambiente aritmético em CShell é validado por @.
if (!($?filename)) then
@ nullFilenameCount++
else
if (!($%filename)) \
@ nullFilenameCount++
endif


Em ambiente GNU/Linux, você pode evocar o CShell através de tcsh.

Mais dicas nas páginas de manual (manpages) bash e tcsh.

[]'s
Cacilhas, La Batalema

domingo, 4 de maio de 2008

Python 2.4: Decimal

A forma com que números decimais são armazenados na memória do computador faz com que algumas vezes a representação deles psra nós seja inexata. Por exemplo, ao abrir o interpretador python:
>>> 1.1
1.1000000000000001

>>> 1.1+1.1
2.2000000000000002


No caso dos bancos de dados, por exemplo, o armazenamento desses números serial feito com o tipo DECIMAL ao NUMERIC, ao invés do float. Um exemplo de uso seria aplicações financeiras.

No Python 2.4 um novo tipo de dados foi adicionado, o Decimal, que permite a representação desses números de forma exata. Um exemplo!

Python 2.5.1 (r251:54863, Mar  7 2008, 03:39:23)
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.

>>> import decimal
>>> decimal.Decimal("1.1")
Decimal("1.1")

>>> a = decimal.Decimal("1.1")
>>> a+a
Decimal("2.2")
>>> print(a+a)
2.2

>>>

Você pode ler mais sobre isso em http://www.python.org/doc/2.4.3/whatsnew/node9.html.

Magma: persistência de dados no Squeak

Squeak Apesar de eu ter gostado bastante do GNU Smalltalk e sua facilidade em executar scripts, o Squeak é fascinante e tremendamente completo.

A Cincom deveria ficar com vergonha de vender o Visual Works, não porque o Visual Works seja ruim – pelo contrário! É uma senhora ferramenta – mas porque o Squeak dá de dez a zero nele. Aliás até o Eclipse ficaria pra trás do Squeak se não suportasse outras linguagens além de Java.

Você pode encontrar um pouco mais sobre Visual Works na Superfície Reflexiva.

Voltando ao Squeak, que é parte do foco deste artigo, vamos falar agora de persistência de dados.

O Squeak oferece algumas bibliotecas de interface com RDBMS's, como MySQL e PostgreSQL. Mas hoje vamos falar de Magma.

Magma é uma biblioteca de banco de dados multiusuário orientado a objetos. Para instalar Magma, abra o SqueakMap Package Loader e instale os pacotes Magma client e Magma server – a versão que estou usando é 1.0r40.

Magma pode ser usado de duas formas: ¹arquitetura cliente-servidor ou ²em modo monousuário (single-user).

Vamos começar com o modo monousuário, pois é mais simples, depois entender a arquitetura cliente-servidor não vai ser nenhum bicho de sete cabeças – principalmente pra quem já trabalha com RDBMS.

A primeira coisa que precisamos fazer é criar o repositório. Para tanto, crie um diretório em algum lugar, vou criar em /tmp/magmaRepository, depois abra um workspace e digite:
" Create repository "
MagmaRepositoryController
create: '/tmp/magmaRepository'
root: Dictionary new.


Se você estiver usando o Windows e quiser criar o repositório em C:\Magma Repository, pode proceder da mesma forma, basta lembrar de sempre substituir /tmp/magmaRepository pelo path do Windows que você escolheu.

Selecione todo o texto, clique com o botão azul (do meio do mouse) e escolha do it. Quando o Magma terminar de criar o repositório, já podemos fechar o workspace e criar a classe que representará nossa tabela.

Para teste, criei uma classe Person:

No System Browser crie um pacote Kodumaro, nele crie a seguinte classe:
Object subclass: #Person
instanceVariableNames: 'firstname lastname birth'
classVariableNames: ''
poolDictionaries: ''
category: 'Kodumaro'


Crie então os seguintes métodos na classe – não vou entrar em detalhes sobre como fazer isso, é fácil e você pode encontrar no Google:
initialize

firstname := ''.
lastname := ''.
birth := null.


Crie também os métodos acessores:
birth
↑ birth


O sinal você consegue com ^.
birth: aDate
birth := aDate.

firstname
↑ firstname.

firstname: aName
firstname := aName.

lastname
↑ lastname.

lastname: aName
lastname := aName.

fullname
↑ firstname, ' ', lastname.

[update 2008-05-07]Uma coisa legal é que você não precisa criar diretamente os métodos acessores – getters e setters para a galera do Java –, como fizemos acima.

Você pode clicar com o botão azul sobre a lista de categorias ou sobre a lista de métodos, ir em refactor instance variableaccessors e escolher o atributo, então o Squeak cria os métodos acessores pra você![/update]


E os métodos de exibição:
printString
↑ self fullname, ': ', birth printString.

printOn: aStream
self printString printOn: aStream.


Clique com o botão azul (do meio) sobre as yet unclassified e em seguida em categorize automatically, em seguida mova fullname para accessing.

Já temos então nossa classe Person, podemos povoar a base.

Abra um workspace e digite nele:
| coll mySession user1 user2 user3 |
user1 := Person new
firstname: 'Rodrigo';
lastname: 'Cacilhas';
birth: (Date newDay: 20 month: 11 year: 1975).

user2 := Person new
firstname: 'Walter Rodrigo';
lastname: 'Cruz';
birth: (Date newDay: 8 month: 12 year: 1981).

user3 := Person new
firstname: 'Claudio';
lastname: 'Torcato';
birth: (Date newDay: 13 month: 5 year: 1977).

coll := MagmaCollection new.
coll
add: user1;
add: user2;
add: user3.

mySession := MagmaSession openLocal: '/tmp/magmaRepository'.
mySession connectAs: 'cacilhas'.
mySession commit: [
mySession root
at: 'kodumaro'
put: coll
].
mySession disconnect; closeRepository.


Selecione todo o código, clique o botão azul (do meio), selecione do it, depois limpe o workpace para que possamos reaproveitá-lo.

Abra um Transcript e edite o workspace par fazermos uma consulta:
| mySession |

mySession := MagmaSession openLocal: '/tmp/magmaRepository'.
mySession connectAs: 'cacilhas'.

(mySession root at: 'kodumaro') do: [ :col |
Transcript show: col printString; cr
].

mySession disconnect; closeRepository.


Os objetos na base de dados devem ser exibidos no Transcript.

Modelo cliente-servidor


O modelo cliente-servidor é trivial: levantar servidor, conectar com o cliente, fazer as consultas, desconectar. Quando não for mais usar, pare o servidor.

Para levantar o servidor, no workspace execute:
" Start server "
MagmaServerConsole new
open: '/tmp/magmaRepository';
processOn: 51001;
inspect.


Selecione o código, botão azul (do meio) e do it. Isso iniciará o servidor ouvindo na porta 51001/tcp e abrirá uma janela de inspect para o console do servidor – que poderemos usar para pará-lo.

Abra um workspace – ou reaproveite o que está aberto – para podermos fazer uma conexão cliente – abra também o Transcript, se já não estiver aberto:
| mySession |

mySession := MagmaSession
hostAddress: #(127 0 0 1) asByteArray
port: 51001.

mySession connectAs: 'cacilhas'.

(mySession root at: 'kodumaro') do: [ :col |
Transcript show: col printString; cr
].

mySession disconnect.


Selecione o código, botão azul (do meio) e do it.

Para parar no servidor, no inspect do console digite:
self shutdown


Botão azul (do meio) e do it.


Não que alguém vá trocar – por enquanto – um RDBMS pelo Magma, mas já é algum conhecimento para quando os SGBD's orientados a objetos estiverem mais maduros.

[]'s
Cacilhas, La Batalema

PS: Por favor nenhum comentário sobre ZODB estar bem maduro, já sabemos disso. O Magma é que ainda não está.