Dá para criar classes abstratas em Ruby?

Ok, aqui vamos nós para mais estudos de como fazer coisas bizarras em Ruby… outro dia, estava olhando para um livro, “Design Patterns in Ruby”, que falava de classes abstratas (tipo Java) e a inexistência delas em Ruby, aonde “Duck Typing” resolve. Mas aí pensei: será que não dá para simular o comportamento de classes abstratas tipo Java, em Ruby?

Para os que não conhecem Java: se você, em Java, declarar uma classe como abstrata, e definir, digamos, dois métodos abstratos, quando esta classe for herdada, você é obrigado a definir estes dois métodos, senão o código sequer compila. Bom, parece então simples, em Ruby: basta criar uma classe, informar, de alguma que ela é abstrata, e então quando ela for herdada, se a classe herdada não definir todos os métodos, lançar uma exceção (digamos, um NoMethodError). Ok, Ruby permite traçar quando uma classe foi herdada com o método “callback” inherited, portanto é relativamente simples saber se a classe foi herdada e se ela implementa os métodos da abstrata, certo?

Bom, na prática… não.
(more…)

Traçando a Execução em Bibliotecas de Terceiros (em Ruby)

Ontem, acredito que esbarrei feio num bug do Ruby 1.8 (não sei se outras versões estão com o mesmo problema). Para encurtar a longa história, estava mexendo num código usando TheRubyRacer semelhante ao seguinte (nota: se você não entender o código a seguir, vale a pena dar uma olhada em meu post anterior):

class UmaClasse
  def method_missing(method, *args, &b)
    puts "Método #{method} chamado!"
    ...
  end
end

require 'v8'
context = V8::Context.new
context['classe'] = UmaClasse.new
p context.eval('classe.um_metodo')
p context.eval('classe.um_metodo = 10')

O que eu esperava, é que na linha 11, fosse impressa a mensagem “Método um_metodo chamado!”, porém o que aconteceu não foi bem isso. Quando olhei para a documentação da biblioteca, descobri que ela expõe apenas os métodos públicos por padrão, agora COMO ela fazia isso… isso já é outro problema. Então, num primeiro momento, resolvi remover todos os métodos da classe UmaClasse, e ver o que acontecia:
(more…)

Conectando Javascript e Ruby

Bom, a algum tempo vi uma biblioteca chamada Harmony, para Ruby, que tenta fazer esse processo. Porém, eu achei alguns problemas na biblioteca que meio que me impediam de usá-la do jeito que eu queria, então acabei encontrando uma outra alternativa: The Ruby Racer.

Esta biblioteca usa o interpretador V8, o mesmo usado no Google Chrome, para interpretar Javascript. Possui uma API bem simples, e consegue incorporar objetos Ruby no Javascript de uma forma bem transparente. Como exemplo, digamos que queremos expor uma classe Ruby para o Javascript. Basta usar o código a seguir:

require 'v8'

class UmaClasse
  def initialize(nome)
    @nome = nome
  end

  def imprimir_nome
    puts @nome
  end
end

js = V8::Context.new
js['uma_classe'] = UmaClasse.new
js.eval('uma_classe.imprimir_nome()')

Este código conectará, no Javascript, um objeto chamado uma_classe. Para instalar a biblioteca, um simples “gem install therubyracer” basta, na maioria das vezes. Quando isso não funciona (que nem o meu caso)…
(more…)

Dá para fazer tipagem estática em Ruby?

Bom, resolvi começar uma série – coisas que você NUNCA quis fazer com Ruby, e tinha medo de perguntar. Basicamente, pensei em montar códigos absurdos de coisas que são completamente contra a filosofia da linguagem, ou que pelo menos são muito esquisitas, e publicar aqui os resultados. As regras são simples: os resultados devem ser testáveis (com RSpec, de preferência) e devem ser escritas puramente em Ruby, de preferência sem nenhuma biblioteca auxiliar (e, se for necessário usar, é obrigatório que a biblioteca tenha sido escrita puramente em Ruby também).

Como primeiro da série, vamos simular uma tipagem estática em Ruby. Como é impossível sobrescrever o operador “=” em Ruby, resolvi usar uma função – static – para simular o mesmo comportamento. Para simplificar, vamos meio que definir uma “variável global” com “static.”, e definir que esta terá tipagem estática. Começamos definindo uma função chamada “static”

def static
  Static.instance
end

(more…)

Porque o Rubinius é importante.

Muita gente já falou sobre o assunto, e eu percebi, até agora, que não dei minha opinião então…

Para as pessoas que estão interadas, Rubinius é uma implementação de Ruby sobre Ruby. Parece estranho, e é um pouco mesmo, então vale a pena mostrar mais como isso funciona. Nos outros interpretadores, uma boa parte das classes padrão da linguagem são implementadas em C (ou Java, no caso do JRuby). Em Rubinius, estas classes são implementadas em Ruby sempre que possível, e a máquina virtual (VM, atualmente estão usando o LLVM) é extremamente simples e otimizada. Com isso, além de Ruby ficar muito mais flexível (mais? sim, é sempre possível) ainda se ganham alguns conceitos interessantes. Para fazer esta “mágica”, é necessário um compilador que traduz código Ruby para bytecodes que serão executados na LLVM – e Rubinius escreveu este compilador totalmente em Ruby. Pode parecer um conceito absurdo, mas não é – o próprio compilador C da Gnu, o GCC, é escrito em C.
(more…)

A importância do código-fonte

Talvez o nome deste post seja estranho, em um blog tão focado à programação. Porém, vale um pouco de história.

De duas semanas para cá, estou escrevendo um artigo para tentar apresentar no Workshop Brasileiro de Métodos Ágeis. Inclusive, eu recomendo a todos que trabalham a um certo tempo com uma linguagem, tecnologia, etc, que escrevam um artigo sobre o assunto, mesmo que não seja em formato científico, só para organizar as idéias. Ajuda bastante a focalizar seus próximos passos. Porém, esse não é o assunto. O assunto é bem simples, na verdade:

Design de Software.

Tentei traçar as origens da tal “metodologia em cascata”, e não consegui. O artigo mais antigo que eu cheguei foi de Winston Royce, em 1970 (sim, 1970 – é difícil de acreditar que a maioria das metodologias de desenvolvimento de software de hoje se baseiam numa idéia que surgiu a 40 anos atrás), e Royce sequer nomeia a metodologia. Na verdade, ele apresenta o desenho típico de uma metodologia em cascata e comenta: “a implementação acima é arriscada e convida à falhas”. Seria possível que, na informática, alguém em 1970 apresenta o modelo que mais tarde seria chamado de “cascata”, diz para as pessoas não usarem, e as pessoas começam a usá-lo? Bom, sendo informática, eu não duvido de nada (nem de doutores em engenharia de software citando que até uma metodologia em cascata é melhor do que as metodologias ágeis – sim, eu ouvi isso). Enfim…

Mas, voltando ao tópico – a metodologia que Royce propôe enfatiza a documentação. Mais tarde, essa documentação seria unificada pela UML, e uma série de estudiosos iriam “contribuir” para a tal UML, criando mais e mais diagramas… além daquelas coisas obsoletas, tipo fluxograma, “teste de mesa”, etc etc. Aqui, vale a pena citar Jack Reeves, que pergunta em seu artigo (de 1992): “O que é design de software?”. O artigo é extenso, mas transcrevo umas partes aqui:

O objetivo final de qualquer atividade de engenharia é algum tipo de documentação. Quando um trabalho de design foi completado, a documentação é entregue à manufatura. Eles são um grupo completamente diferente, com habilidades completamente diferentes do time do design. Se a documentação realmente representa um design completo, o time da manufatura pode proceder para construir o produto. De fato, eles podem proceder para construir uma grande parte do produto, sem qualquer intervenção dos designers. Depois de revisar o ciclo de desenvolvimento de software, da forma que eu entendo, eu concluo que a única documentação de um software que, na verdade, satisfaz o critério de uma documentação de design é o código-fonte.
(more…)

Smalltalk, e a noção de objetos

Em outro artigo meu, citei como uma linguagem como Java pode ser usada para programação procedural, mesmo sendo “orientada a objeto”. Esses dias, brincando um pouco com Smalltalk, acabei achando um e-mail do Alan Kay sobre o que ele considera “programação orientada a objeto”, e o que isso difere do que conhecemos.

Primeiro ponto: na programação orientada a objetos que a maioria de nós conhecemos, a abstração é mais ou menos assim: um objeto é uma “coisa”, e essa coisa possui métodos. Na hora em que você roda o programa, a “classe” é definida, um ou mais objetos são instanciados, e a partir daí você pode chamar os métodos dos objetos.

Em Smalltalk, as coisas são um pouco diferentes
(more…)

A saga da busca em bancos de dados

Num mundo perfeito, todos os sistemas de armazenamento se conversariam, a nível do servidor e não do cliente, e jamais precisaríamos manualmente definir por “joins”, ou seja lá qual a forma que seu banco de dados faz.

Claro, o mundo não é perfeito.

Nesse caso, precisamos no mínimo padronizar uma forma de buscar dados. A maioria dos sistemas relacionais entende SQL, embora isso também não seja padronizado. Pior ainda, se for necessário buscar uma informação que está em uma tabela da base de dados X, e uní-la (join) com uma da base de dados Y, temos que fazer a busca manualmente.

Entra, aí, uma idéia.
(more…)

Curiosidades sobre Procs em Ruby

Esses dias, estava montando um código para Ruby usando Procs (blocos de código), salvando esses procs em variáveis e depois rodando-os sobre “bindings” diferentes. Talvez tenha ficado um pouco complicado de entender, mas na prática é algo mais ou menos assim:

class UmaClasse
  def self.callback_qualquer
    ...#alguns códigos aqui....
    @@bloco = proc do
      break if condicao_qualquer
      ...#códigos do meu callback
    end
    ...#mais algumas coisas
  end

  def salvar
    instance_eval(&@@bloco)
    puts "Rodei"
  end
end

Ou seja, eu posso criar um bloco definindo um callbackqualquer, e depois rodar esse bloco no contexto da “instância”, não da classe (o código que eu fiz, na verdade, é bem mais complexo). Mas, surpreeendentemente, esse código não funciona – ele lança um LocalJumpError se a condição do Proc for satisfeita. Por quê?

(more…)

Lazy Evaluation

Existe um conceito, muito utilizado por programadores de linguagens funcionais e pouco utilizado em outras linguagens, chamado Lazy Evaluation. Para não extender muito a definição, basta dizer que no caso do Lazy Evaluation, um resultado só é computado quando ele é necessário ao programa. Exemplos explicam melhor o conceito, então segue um:

100.times do |iterador| #Equivalente ao "for" de outras linguagens
  n = fatorial(iterador)  #Calcula o fatorial
  if(iterador.even?)       #Se for um número PAR
    print "Resultado da operação: #{n}" #Imprime o resultado do fatorial
  end
end

Lembrando que Ruby não trabalha com Lazy Evaluation, portanto o código acima não seria adequado. Mas, digamos que a linguagem acima suporte Lazy Evaluation: o resultado de n só seria calculado se o iterador for par. Ou seja, embora estejamos sempre definindo que n = fatorial(iterador), o programa não calcula o resultado do fatorial até que precisemos dele – neste caso, até que ele seja impresso na tela. Ou seja, em linguagens como Haskell, que suportam Lazy Evaluation por padrão, o código acima seria perfeitamente válido e não seria ineficiente. Normalmente, quando você usa Lazy Evaluation o código que só rodará depois é chamado de “promisse”, pois ele é uma promessa que o valor será calculado.

Mas porque isso é tão interessante?

(more…)