Metaprogramação

Entendendo como funcionam class_eval, module_eval e instance_eval

Para quem como eu, vem de linguagens não-dinâmicas, o que mais impressiona (e dificulta no início) é a capacidade de Ruby em se moldar e executar códigos dinamicamente. E seguindo a nossa saga pelos conceitos de metaprogramação, vamos explorar um pouco mais um recurso interessantíssimo de Ruby chamado eval.

Ruby Eval

O nome eval tem origem na palavra inglesa evaluation, que em uma tradução livre significa “avaliar o valor de algo”, no caso de Ruby, o valor de uma expressão ou trecho de código.

No caso de Ruby, a melhor definição seria “interpretar”, devido ao fato que além de avaliar, o código recebido também é executado, como no exemplo abaixo:

eval("puts 'Hello World'") # => Hello World

No post anterior sobre metaprogramação, eu utilizei o método instance_variable_set da classe Object.

Esse método pode ser utilizado para evitar repetições de código. No código abaixo eu mostro como é a implementação desse método e como ele é usado na prática:

Implementação redundante de um construtor de uma classe:

class CalendarEvent
  def initialize(start_time=0, end_time=0, attendees=0)
    @start_time = start_time
    @end_time = end_time
    @attendees = attendees
  end
end

Implementação melhorada com o uso de eval:

#Primeiro, adicionamos o seguinte código à classe Object,
#para torná-lo disponível para as instâncias de quaisquer classe
class Object
  private
  def set_instance_variables(binding, *variables)
    variables.each do |var|
      instance_variable_set("@#{var}", eval(var, binding))
   end
  end
end

#Depois podemos melhorar a nossa classe

class CalendarEvent
  def initialize(start_time=0, end_time=0, attendees=0)
    set_instance_variables(binding, *local_variables)
  end
end

c = CalendarEvent.new(4,5,2)

puts c.instance_eval "@start_time"   # => 4

Read more…

Tudo que você sempre quis saber sobre Metaprogramação mas tinha vergonha de perguntar

A arte de escrever programas que escrevem programas está presente desde o início da ciência da computação, com o objetivo de aumentar a produtividade diminuindo a quantidade de código a ser escrito. O prefixo grego meta está presente na nossa língua, tornando mais fácil o entendimento do conceito por nós brasileiros logo de cara, bastando apenas lembrar das aulas de literatura ou dos livros de Machado de Assis.

Machadão, o rei da Metaliteratura

Machadão, o rei da Metaliteratura

Metaclasses

Lembra daquela frase que dizia que “em Ruby tu é objeto”? Pois é, vamos olhar o seguinte código:

class Zombie
  def self.alive
    puts "i am alive"
  end
end

Zombie.class     # => Class
Zombie.alive      # => "i am alive"
z = Zombie.new
z.class              # => Zombie

Read more…