Trabalhando com a versão de desenvolvimento do Django

Quando você começa a desenvolver mais seriamente com o Django (em vez de ficar apenas lendo os tutoriais para criar coragem) você nota que a versão de desenvolvimento do framework, aquela que os criadores aprimoram a cada dia no repositório Subversion, está bastante diferente da atual, distribuída no site como um tarball (atualmente na versão 0.96.1).

Estes são os passos que segui para usar sempre a versão mais recente do Django no meu computador (em ambiente Linux):

Instale o Subversion:

sudo apt-get install subversion # Apenas para Debian/Ubuntu

Escolha onde quer armazenar o código-fonte do Django. Neste exemplo utilizo o diretório /opt. Entre nesse diretório e execute o comando:

svn co http://code.djangoproject.com/svn/django/trunk/ django

Você terá agora o diretório /opt/django disponível. Precisamos agora que o seu ambiente Linux inclua no caminho do sistema e no caminho do Python as bibliotecas do Django.

Abra seu arquivo ~/.bashrc (ou ~/.bash_profile, dependendo de sua distribuição Linux) e adicione as seguintes linhas a ele:

export PATH=$PATH:/opt/django/django/bin
export PYTHONPATH=$PYTHONPATH:/opt/django

Salve o arquivo e feche-o.

Recarregue as configurações recém-editadas (ou feche seu console e o abra novamente):

source ~/.bashrc

Vamos testar se tudo correu bem. Digite o comando django-admin.py no console e tecle Enter. Se você vir a mensagem:

Type 'django-admin.py help' for usage.

então a primeira parte funcionou.

Agora abra o shell interativo do Python (digite python no console). Dentro do console digite import django. Se o shell não acusar nenhum erro então está tudo certo. Você pode verificar que versão do Django você tem instalada digitando, em seguida, python.VERSION. A listagem abaixo mostra a minha sessão no shell interativo do Python executando os comandos mencionados.

caio@superjesus:$ python
Python 2.5.1 (r251:54863, Oct  5 2007, 13:36:32) 
[GCC 4.1.3 20070929 (prerelease) (Ubuntu 4.1.2-16ubuntu2)] on linux2
Type "help", "copyright", "credits" or "license" for more information.
>>> import django
>>> django.VERSION
(0, 97, 'pre')
>>> exit()

Sempre que você quiser sincronizar o código-fonte do Django presente no seu computador com a versão de desenvolvimento, vá até o diretório /opt/django e digite:

svn up

Note que a configuração definida neste tutorial é muito boa quando você está querendo realizar o deploy de sua aplicação Django, digamos, em um serviço de hospedagem que possua máquinas compartilhadas entre usuários. Como você não quer depender da boa vontade dos administradores do seu servidor para ter sempre a última versão do código do Django, você realiza essa configuração na conta do seu usuário. Caso queira saber mais sobre isso leia este ótimo tutorial do Jeff Croft (o exemplo possui partes específicas da DreamHost, mas é possível aproveitar bastante coisa mesmo se você utiliza outro serviço).


Índice TIOBE declara Python linguagem de 2007

O índice TIOBE declarou o Python linguagem de programação do ano de 2007. No ranking geral a linguagem se encontra agora na 6ª posição, tendo pulado da 8ª posição, onde se encontrava há exatamente 1 ano (passando na frente de Perl e C#, que caíram uma posição cada).

Outras mudanças interessantes no top 20:

  • PHP subiu 1 posição (ultrapassando C++), estando agora em 4º (atrás apenas de Java, C e Basic)
  • Delphi subiu 3 posições, estando agora em 9º
  • Ruby caiu 1 posição, estando agora em 10º
  • Lua subiu 30 posições, da 46ª para a 16ª posição
  • Logo entrou no top 20 na 20ª posição, tendo subido 7 posições

A diferença de percentual entre Python (6º) e C++ (5º), ainda é grande, mas se mantiver a mesma saúde o Python pode passar o C++ dentro de 12 meses. A linguagem criada por Bjarne Stroustrup caiu 2 posições em 1 ano, então é possível que continue ladeira abaixo durante 2008. Vamos ver.


Byte of Python

Eu acabei de ler o livro online Byte of Python, de Swaroop C H, um programador indiano que trabalha na Adobe. Comecei lendo o capítulo sobre orientação a objetos, pois queria ver qual era a abordagem do Python para essa questão fundamental. Como muitas coisas em Python, a abordagem OO é simples e direta, com uma sintaxe muito legal.

Como esse capítulo era muito bem escrito acabei me empolgando e li o restante do livro, dessa vez seguindo a ordem de capítulos proposta pelo autor. Posso lhe garantir que valhe a pena, se você está chegando ao mundo onde a indentação é obrigatória e as declarações “não terminam”.

Se você ainda não se convenceu a ler o livro talvez se interesse pela minha listagem dos “melhores momentos” de Byte of Python (ela acabou ficando um pouco extensa, pois foi escrita como uma forma de eu mesmo estudar aquilo que estava lendo no livro). Ela é feita do meu ponto de vista e do meu background principal (PHP e Ruby).

A indentação do código é obrigatória

Certas expressões Python impõe restrições sobre as expressões seguintes. Por exemplo, uma expressão que termina com : (dois pontos), impõe que a expressão seguinte seja um bloco de expressões (e blocos de expressões devem ser, obrigatoriamente, indentados 1 nível a mais que a expressão anterior/externa).

Exemplo:

if len('caio') == 4:
    print 'OK'

Saída:

OK

Agora se você não indentar a segunda linha teremos um erro de sintaxe:

  File "<stdin>", line 2
    print 'OK'
        ^
IndentationError: expected an indented block

Quando o bloco de expressões possuir apenas um comando, esse comando pode parecer na mesma linha que inicia o bloco, por exemplo:

if len('caio') == 4: print 'OK'

O autor do livro não recomenda esse tipo de uso (mas não justifica essa opinião).

A quebra de linha termina blocos de expressões

Você não verá isto em Python:

class Dog:
    def __init__(self, name):
        self.name = name
    end
    def bark(self, times=1):
        print 'au' * times
    end
end

snoopy = Dog('Snoopy')
snoopy.bark()

Mas isso (note a ausência de todos os end):

class Dog:
    def __init__(self, name):
        self.name = name
    def bark(self, times=1):
        print 'au' * times

snoopy = Dog('Snoopy')
snoopy.bark()

No início eu achava essa sintaxe muito alienígena. Mas quando se trata de escrever menos e obter o mesmo resultado, por que não?

Isso traz algumas conseqüências interessantes. Por exemplo, como declarar a mesma classe Dog, agora sem nenhum daqueles dois métodos? Tente desta forma:

class Dog:

O interpretador Python vai reclamar dessa declaração. Ele vai lhe dizer que esperava um “bloco indentado”, e você deu a ele apenas uma quebra de linha. Ou seja, uma declaração de classe (class Dog:) possui o caracter : (dois pontos), e isso indica ao interpretador que em seguida você vai declarar um conjunto de expressões (ou bloco indentado).

O que você pode fazer, portanto, para dizer ao interpretador que você não vai declarar um bloco indentado é utilizar a declaração pass no lugar do conjunto de blocos. Ou seja, a definição mínima para a classe Dog é a seguinte:

class Dog:
    pass

Não há blocos switch

Python adota a seguinte filosofia: “There should be one — and preferably only one — obvious way to do it” (”Deve haver uma - e de preferência apenas uma - maneira de se fazer alguma coisa”). Como a construção switch pode ser traduzida em um bloco if-else, a linguagem não o suporta.

Suporta herança múltipla

Python suporta a herança múltipla diretamente (ao contrário de Ruby, por exemplo, que a suporta por meio de mixins). A seguinte listagem de código Python declara Dog como herdeiro de duas classes, Animal e Mammal.

class Animal:
    pass

class Mammal:
    pass

class Dog(Animal, Mammal):
    pass

Variáveis globais

Variáveis globais podem ser acessadas dentro de uma função diretamente (apenas pelo nome da variável) ou utilizando a palavra-chave global. Há uma diferença entre utilizar uma variável no escopo da função após a declaração dela como global e sem sua declaração como global, como apontado pelo Luciano Ramalho nos comentários deste post:

a declaração global não é sempre opcional […]. Ela é opcional apenas para se acessar a variável global. Porém, se a intenção do programador é atribuir um novo valor ao uma variável global x, ele é obrigado a declarar global x no escopo local, do contrário uma atribuição como x=1 vai apenas criar uma nova variável local, e não alterar o valor da variável global.

Exemplo:

my_global_var = 5

def some_function():
    global my_global_var
    my_global_var = 1

print my_global_var
some_function()
print my_global_var

A saída desse programa será:

5
1

Strings suportam o método *

Exemplo:

`'python' * 2

Saída:

'pythonpython'

Em Ruby isso também é possível, em PHP não (na verdade é, e o resultado é zero, hehe).

Argumentos nomeados são suportados nativamente

Python suporta o conceito de argumentos nomeados (keyword arguments). Isso é útil quando não queremos nos preocupar com a ordem na qual os parâmetros são passados para uma função.

Exemplo:

def my_func(a = 1, b = 5):
    print 'a =', a
    print 'b =', b 

my_func()
my_func(b = 30, a = 100)

Saída:

a = 1
b = 5
a = 100
b = 30

O “nada” é representado por None

Uma função que não retorna valores explicitamente (com o uso da palavra-chave return) retorna, implicitamente, None, que em Python corresponde a nada, ou vazio. Exemplo:

def my_func():
    pass

print my_func()

A saída do programa será:

None

Para retornar valores de uma função use return

Em Ruby, se uma função não retorna um valor explicitamente, então o último valor avaliado é retornado. Com Python, assim como em PHP, você deve retornar valores explicitamente com return.

Tipos boolean são True e False

Python conta com duas instâncias do tipo boolean: True e False. Expressões lógicas retornam um desses dois valores. Exemplos:

print type(True)
print type(False)
print 1 == 1
print 1 == 0

Saída:

<type 'bool'>
<type 'bool'>
True
False

Funções são objetos de primeira classe

Diferentemente de PHP, em Python este código é possível:

def my_func():
    print 'hey'

a = my_func
a()

a, neste caso, passou a ser um objeto do tipo function. Como qualquer outra variável, ela poderá ser passada como argumento de outras funções. Se você não percebe o benefício desse recurso pesquise o assunto first class functions no Google.

DocStrings são documentação e código ao mesmo tempo

O seguinte código:

def my_documented_function():
    '''This is a one-liner description of the function.

    This is a long description of the function.'''
    pass

print my_documented_function()
print my_documented_function.__doc__
help(my_documented_function)

Irá gerar a seguinte saída:

None
This function doesn't do much (this is the docstring header)

    But its documentation takes a few lines

O Python trata, como podemos ver, a documentação como uma propriedade/atributo da função my_documented_function (a linguagem associa a documentação automaticamente a __doc__). Note, ainda, que para acessar o atributo de uma função não a invocamos, pois não estamos utilizando os parênteses após seu nome.

O outro ponto interessante é que help é um atalho que podemos utilizar para acessar a propriedade __doc__ da função.

Ainda é possível associar docstrings também a classes e módulos.

Listas, Tuplas e Dicionários

Listas são coleções de objetos mutáveis.

Exemplos de manipulação de listas:

a = [1,2,3,4]
print type(a)
a.append(5)
print (a)
del a[0]
print a

Saída:

<type 'list'>
[1, 2, 3, 4, 5]
[2, 3, 4, 5]

Tuplas são coleções de objetos imutáveis. Tuplas têm a mesma sintaxe de criação das listas, mas troca-se o [] por (), como em:

a = ('caio', 'moritz')

Dicionários correspondem aos arrays associativos de PHP ou Hashes de Ruby. Sua sintaxe é bem simples:

lang_creators = {
    'Ruby':   'Yukihiro Matsumoto',
    'Python': 'Guido van Rossum',
    'PHP':    'Rasmus Lerdorf'
}

for lang, creator in lang_creators.items():
    print '%s was created by %s' % (lang, creator)

print 'Who created Java?'

if lang_creators.has_key('Java'):
    print lang_creators['Java']
else:
    print 'I have no idea.'

Saída:

Python was created by Guido van Rossum
PHP was created by Rasmus Lerdorf
Ruby was created by Yukihiro Matsumoto
Who created Java?
I have no idea.

Pontos importantes:

  • No loop for, utilize o método items() do dicionário para acessar seus itens
  • Dicionários não guardam a ordem em que seus elementos foram declarados

Interpolação de strings

Em PHP interpolamos strings assim:

echo "My favourite programming language is {$lang}";

Em Ruby assim:

puts "My favourite programming language is #{lang}";

Em Python não temos algo diferente, que atinge o mesmo objetivo:

print "My favourite programming language is %s" % lang

Referências

Uma variável referencia um objeto, e não um valor, conforme o código abaixo:

lang_creators = ['matz', 'guido', 'rasmus']
lc = lang_creators
lc == lang_creators
del(lang_creators[0])
print lc
print lang_creators

Saída:

['guido', 'rasmus']
['guido', 'rasmus']

A segunda linha da listagem faz com que lc e lang_creators passem a apontar para o mesmo objeto (no caso uma lista). Por conseqüência, quando a lista é alterada através da referência lc a mudança também é sentida pela referência lang_creators.

String.Join ou Array.Join?

Em Ruby utiliza-se Array#join para unir todos os elementos de um array, separando-os por um determinado caracter passado como parâmetro.

Exemplo:

arr = ['this', 'is', 'going', 'to', 'be', 'a', 'string']
arr.join(' ')

Saída:

"this is going to be a string"

Com Python o método join está em String, funcionando de forma “inversa” (é a String que une o Array, e não o Array que une seus elementos a partir de uma String):

lst = ['this', 'is', 'going', 'to', 'be', 'a', 'string']
' '.join(lst)

Saída:

'this is going to be a string'

Entrada e saída

Não vou me alongar muito neste tópico: entrada e saída em Python é muito simples, como em PHP e Ruby. Nada me supreendeu nem pro bem e nem pro mal.

Destaque para a iteração sobre todas as linhas de um arquivo, em 2 linhas de código:

for line in file('some_file.txt'):
    print line[:-1]

[:-1] evita que se imprima a quebra de linha original.

Namespaces

Python suporta namespaces de um forma muito legal. Um arquivo externo importado para dentro de um programa Python tem todo o seu código (variáveis, funções etc.) carregado dentro de um namespace próprio, igual ao nome do arquivo importado.

Orientação a Objetos

A orientação a objetos, ao menos até onde o livro explica, é bastante simples. Não compreendi bem como fica a questão do encapsulamento, por exemplo. Gostei da possibilidade da herança múltipla (isso sempre me fez falta no Java), só não gostei de todos os métodos de uma classe precisarem declarar self como o primeiro parâmetro. Sei o que self representa, mas porquê a linguagem não pode tomar conta de torná-lo presente no código interno da classe?

Miscelânea

  • Strings são imutáveis
  • Strings não são Unicode por padrão (confira os comentários do Luciano Ramalho neste post para entender como utilizar strings normais e strings Unicode)

Tópicos importantes não abordados no meu resumo

Tópicos importantes que não abordei no resumo mas que são tratados mais ou menos profundamente no livro:

  • Tratamento de exceções
  • Compreensão de listas (list comprehensions)
  • Métodos especiais (como __str__ e __init__)
  • Expressões Lambda

E agora?

Você continuar aprendendo Python lendo o livro do Swaroop ou seguindo sua recomendação de leituras.


Ganhando agilidade com Python e Vim

Eu confesso que gosto muito de aprender novas linguagens, mas trocar o Vim por outro editor de textos é algo que nunca passou pela minha cabeça desde que o conheci (e olha que já troquei até de gerenciador de janelas).

E se para aprender Python é preciso de um editor de textos, que seja o Vim. E quando se trata de editar código Python a questão é um pouco mais delicada, pois essa linguagem leva a indentação muito a sério: ou você indenta corretamente ou seu código não roda. Mas para indentar o código no Vim não basta sair apertando Tab: o mais interessante é configurar o editor de modo que, quando você apertar Tab, a tabulação seja substituída por 4 espaços em branco.

Outra funcionalidade que o Vim nos dá é a auto-indentação. Com ela, a cada nova linha o Vim calcula onde deve estar o cursor baseado na linha de cima. O código abaixo, por exemplo:

class Person:

Vai forçar a próxima linha desse código a ter 4 espaços de indentação.

Caso o Vim erre em algum momento, ou após refatorar o código a indentação tenha ficado estranha, você pode apertar Backspace em uma linha indentada e 4 espaços em branco serão apagados de uma vez (ou seja, você apaga 1 nível inteiro de indentação, que é na maioria das vezes o que você deseja).

O comportamento descrito acima é possível no Vim mas não está configurado por padrão. Para que as coisas funcionem dessa forma edite seu vimrc e adicione as seguintes linhas:

set smartindent
set shiftwidth=4
set tabstop=4
set expandtab
set smarttab

Para obter mais informações sobre os comandos acima digite, dentro do Vim:

:help nome-do-comando

Autocompletar dentro do Vim7

Em: 04/01/2008 Tags: Vim Comentários (1) Referencie do seu blog (Trackback)

Os usuários de IDEs famosas como Eclipse sabem que o auto-completar do código-fonte é uma funcionalidade que pode aumentar bastante a produtividade do programador. Como alcançar isso para a sua linguagem de programação favorita dentro do Vim?

Se você está no Vim7, então você não precisa configurar nada: ele já tem essa capacidade, por padrão. Este exemplo utiliza o Python como linguagem. Abra o arquivo a.py dentro do Vim e digite o seguinte:

str = 'lala'
str.

Com o cursor após o último caracter (o ponto), e no modo de inserção, basta digitar Ctrl^x, seguido de Ctrl^O e você deve ver o seguinte:

Autocompletar dentro do Vim7: preview

O que aconteceu? Em primeiro lugar o Vim abriu uma janela pop up com todos as funções/propriedades dos objetos String. Mais que isso, sua tela foi quebrada horizontalmente em duas, e na parte superior o Vim abriu um arquivo que tem a documentação da função sobre o qual o seu cursor repousa (replace(), na imagem).

O que não gostei nessa solução do Vim é que aquela janelinha superior que foi aberta automaticamente não é fechada quando seleciono a função que quero (veja imagem abaixo).

Autocompletar dentro do Vim7: após seleção do item

Não que eu não saiba fechá-la, mas dá muito trabalho (Esc, seguido de Ctrl^w, seguido de k, seguido de :q). Se você também é preguiçoso, talvez queira dizer ao Vim que ele não deve abrir essa janela superior com a descrição do método, e apenas mostrar o menu pop up. Para isso adicione a seguinte linha ao seu .vimrc:

set completeopt=menu 

Essa opção aceita os seguintes valores:

  • menu
  • menuone
  • longest
  • preview

Você pode combinar esses valores, se separá-los por vírgula. Exemplo:

set completeopt=menu,menuone,longest,preview

A combinação default é:

set completeopt=menu,preview

Consulte a documentação do Vim referente a esse comando para saber o que as outras opções significam (digite dentro do Vim, em modo de edição):

:help completeopt

Só testando todos esses valores para a opção completeopt você poderá saber as vantagens e desvantagens de cada um, e qual é o mais adequado pra você. Como descobri tudo isso há poucos minutos ainda não fiz a minha escolha.

Para finalizar: de acordo com a documentação (:help new-omni-completion), as seguintes linguagens são suportadas:

  • C
  • (X)HTML com CSS
  • PHP
  • Python
  • Ruby
  • SQL
  • XML
  • Qualquer linguagem com coloração de sintaxe

PHP Day Curitiba

Em: 04/01/2008 Tags: PHP Comentários (0) Referencie do seu blog (Trackback)

Essa é para quem vai estar perto de Curitiba no próximo dia 12: a lista de usuários PHP de Curitiba está promovendo o PHP Day. No momento parece que há apenas 2 palestras sobre PHP confirmadas (uma sobre Smarty e outra sobre Symfony).


Novos feeds para o blog

Em: 04/01/2008 Tags: Meta Comentários (0) Referencie do seu blog (Trackback)

Agora o blog conta com um feed para os comentários. Para os que já assinam o feed dos artigos, um comunicado: o feed de artigos está mudando de endereço. O feed antigo continuará funcionando até 31 de janeiro. Peço que os leitores troquem, até lá, para o novo feed de artigos (disponível neste link) e removam a assinatura do feed antigo. Essa será a primeira e última vez que o feed muda de endereço, não se preocupem.

Estou providenciando também um serviço para envio das novidades do blog por email.

Fiquem ligados!


Meu blog agora é caiomoritz ponto com

Em: 03/01/2008 Tags: Meta Comentários (1) Referencie do seu blog (Trackback)

Aviso aos leitores: agora o blog mudou de endereço: é caiomoritz.com. O novo endereço ainda está sendo propagado pela internet, então é possível que ele não responda bem nos próximos 2 dias (o site pode aparecer como “Não encontrado” em algumas tentativas).

Espero não provocar maiores transtornos com a mudança. É possível que o feed sofra algum tipo de colapso (posts anteriores apareçam como não-lidos), e já peço desculpas agora. Esse colapso pode acontecer pois precisarei redirecionar o endereço antigo do feed da minha conta no FeedBurner para este novo endereço.

Para quem está com tempo, continue lendo este post (nada sobre tecnologia, apenas o histórico do blog e porquê da mudança de endereço).

No ano passado eu, minha namorada Thânia e mais 2 amigos (Daniel e Rodrigo), usuários de Ruby nas horas vagas, decidimos fundar o Grupo de Usuários Ruby de Florianópolis, SC (e deixamos o nome em inglês mesmo, Florianópolis Ruby User Group, o FRUG). A idéia era difundir na nossa cidade a utilização do Ruby como uma linguagem do mundo real, para as mais diversas finalidades. Resumo da ópera: não conseguimos parar para criar um bom site, mas ao menos temos uma lista de discussão. Quem sabe neste ano a gente não faça a coisa acontecer?

De qualquer modo acabamos criando blogs (com exceção do Rodrigo) e, posso falar por mim, tem sido muito legal mantê-lo. O feedback das pessoas também tem sido ótimo (continuem lendo e comentando, faço o possível pra responder a todos rapidamente), e, como o blog tem dado muito certo, decidi abrir a mão e comprar um domínio pra mim, que é o assunto deste post.


Simples deploy de aplicações Rails - quando isso será possível?

O recente rant de Zed Shaw, o criador do Mongrel, está repercutindo muito pela comunidade Rails e Ruby. Zed conta como foi ignorado pelo Core Team do Rails e como foi desrespeitado por algumas empresas de software nos EUA e no Canadá. Ele também detona uma das principais consultorias Rails do mercado, a ThoughtWorks.

Um dos locais onde esse rant repercutiu foi no Ruby Inside. Em geral as pessoas têm dito que já viveram situações semelhantes àquelas que o Zed afirma ter vivido, mas dizem que isso não é nada de novo e que com outras comunidades (de outras linguagens e frameworks) isso não é diferente. Toda comunidade tem suas maçãs podres e devemos tentar nos afastar. Eu poderia destacar diversas passagens desse post, mas fico com uma que me pareceu a mais preocupante:

[…] Notice how it took me a few seconds to reply. This one single statement basically means that we all got duped. The main Rails application that DHH created required restarting ~400 times/day. That’s a production application that can’t stay up for more than 4 minutes on average.

Preciso dizer mais alguma coisa? Alguma coisa está muito errada. O DHH disse que sua aplicação não ficava mais de 4 minutos de pé em 2007.

Apenas para registrar, não concordo com a postura do Zed. Ele poderia ter dito tudo o que disse de outra forma, sem ser tão baixo com essas pessoas como ele afirma que elas o trataram.

Mas o que me levou a escrever este post foi o comentário, nesse mesmo post do Ruby Inside, de Peter Cooper, com o qual eu (sendo um programador PHP há alguns anos) concordo em gênero, número e grau. Ele diz:

One thing Zed’s rant also highlights is something I have mega issues over, and the reason I still use a lot of PHP code (such as WordPress) even though I can’t code PHP myself. It’s an absolute nightmare deploying Rails apps.

Alguém discorda? Aliás, alguém tem coragem de discordar? Isso não é uma opinião, é simplesmente um fato. Se você não tem a conta de root do servidor onde o deploy será feito é bem provável que você terá sérios problemas ao fazer deploy de sua aplicação Rails - e se você tiver a senha, então poderá encontrar diversos problemas relacionados a distribuição Linux desse servidor, pois nem todos rodam uma baseada em Debian (que, ao menos para mim, é a melhor opção hoje em dia para instalação e configuração de qualquer coisa relacionada a Ruby e Rails).

Mas o Paul Cooper continua:

I don’t get why some really clever so-and-so hasn’t come up with a mod_ruby that works in a somewhat similar fashion to mod_php. PHP as a language is no more “stable” than Ruby, but people perceive PHP as being more mature simply because you can upload a .php file and bam, it works. Not so with Ruby. You gotta know about daemons, proxying stuff around.. like.. WTF? If I didn’t have crap for brains, I’d probably start such a project, but I’m totally blown away that no-one is making moves in this direction already?

Preciso dizer mais alguma coisa? Todos falam mal do mod_ruby e parece que ninguém quer fazer nada a respeito, talvez porquê aproximaria o Ruby, ó perfeito Ruby, do tão odiado PHP. No fim das contas temos o mod_python, que até onde sei não tem grandes problemas, e o mod_php, que é simplesmente tão difundido entre os servidores Apache mundo afora que os programadores PHP, de fato, nunca precisaram pra pensar que o deploy de uma aplicação web poderia ser problemático.

Ao contrário do Paul Cooper, eu programo em PHP, e continuarei com ele enquanto o deploy de Ruby não for adequado. Mas eu sou otimista a esse respeito. Acho que o Ruby vai continuar crescendo, não apenas por conta do Rails, mas por todas as discussões que ele tem colocado na mesa (closures, bdd, dsl’s, metaprogramação etc.).