META
PROGRAM
AÇÃO
RUBY
Marcos Brizeno
Cientista da Computação
Consultor ThoughtWorks
Cearense!
@marcosbrizeno
brizeno.wordpress.com
Avisos
Conteúdo não indicado
para menores de 18 anos
Exemplos de código não
foram testados
<jabá>
</jabá>
ü Discutir o que é
metaprogramação
ü Diferenciar reflexão e
metaprogramação
ü Como a
metaprogramação pode
nos ajudar
ü Como a
metaprogramação pode
nos atrapalhar
ü Se divertir :D
⊠ Ruby
⊠ Orientação a Objetos
O que é
Metaprogramação?
WAT???
§ Código que escreve código
§ Programa que escreve
programas
§ Altera código em tempo
de execução
§ Alterar o comportamento
do programa com o
programa
§ Lógica escondidada
dentro de si mesma
Reflexão
§ Inspecionar o
próprio objeto
§ respond_to?
§ methods
§ class_variable
_get/set
Metaprogramação
§ Programa que
escreve programa
§ define_method
§ method_missing
§ class_eval
O que é
Metaprogramação?
WAT???
Metaprogramação
§ Código genérico
§ Remove
duplicações
§ É muito foda =)
Metaprogramação
§ Código difícil de ler
§ Complexo
§ É muito foda =(
Exemplo Simples:
§ Ruby accessors:
§ attr_accessor
§ attr_reader
§ attr_writer
class AttrExamples
attr_accessor :accessor
attr_reader :reader
attr_writer :writer
end
class AttrExamples
attr_accessor :accessor
attr_reader :reader
attr_writer :writer
end
Modificadores de
visibiliade/acesso
class AttrExamples
attr_accessor :accessor
attr_reader :reader
attr_writer :writer
end
Modificadores de
visibiliade/acesso
Attributos da
classe/instancias
class AttrExamples
attr_accessor :accessor
attr_reader :reader
attr_writer :writer
end
Modificadores de
visibiliade/acesso
Attributos da
classe/instancias
class AttrExamples
attr_accessor :accessor
attr_reader :reader
attr_writer :writer
end
Modificadores de
visibiliade/acesso
Attributos da
classe/instancias
Rails Models
class Product < ActiveRecord::Base
end
Rails Models
class Product < ActiveRecord::Base
end
Cadê os
atributos?
Cadê o
construtor?
Métodos que definem
métodos
§ Definidos na class Module
Exemplo: attr_accessor
@attr = nil
def attr()
@attr
end
def attr=(attr)
@attr = attr
end
Exemplo: attr_accessor
@attr = nil
def attr()
@attr
end
def attr=(attr)
@attr = attr
end
Método para
ler o valor
Método para
escrever um
valor
Como o ruby sabe qual o nome da
minha variável?
Vamos pensar um pouco…
#define_method
symbol é o nome
do método que vaiser criado
block é o que essenovo método vai fazer
#define_method
def create_method(name, &block)
self.class.send(:define_method,
name, block)
end Podemos criar qualquer métodoem qualquer lugar em qualquermomento!
Ruby tem classes “abertas”
§ Podemos adicionar ou
sobrescrever métodos em
uma classe em qualquer
momento
§ Podemos adicionar ou
sobrescrever métodos em
uma instância em
qualquer momento
Classes ou
Instâncias???
Nota sobre mapa do objeto
Classes são Objetos
§ CONSTANTES são escritas
com letras maiúsculas
§ Uma classe é só uma
Constante apontando para
um objeto do tipo Class
Exemplo real
#showmethecode
Um exemplo mais “interessante”
Um sistema de
vendas de revistas
Eventos:
•  Nova venda
•  Nova promoção
•  Revista em falta
Interessados:
•  Clientes (email)
•  Gerentes (ActiveMQ)
•  Outros apps (WS)
Fontes:
•  Controllers
•  Workers
•  Models
Resolvendo com programação
Controller
Model
Worker
Notifier
-sell()
notify_client
notify_manager
notify_app1
-out_of_stock()
EmailHandler
ActiveMQHandler
RestHandler
Resolvendo com programação
Controller
Model
Worker
Notifier
-sell()
notify_client
notify_manager
notify_app1
-out_of_stock()
EmailHandler
ActiveMQHandler
RestHandler
Notifier tem muitas
responsabilidades
Notifier quebra
muito fácil
Notifier está
sobrecarregado
Resolvendo com programação
Controller
Model
Worker
Notifier
-sell()
ClientNotifier.notify_sell()
ManagerNotifier.notify_sell()
App1Notifier.notify_sell()
-out_of_stock()
EmailHandler
ActiveMQHandler
RestHandler
ClientNotifier
ManagerNotifier
App1Notifier
Resolvendo com programação
Controller
Model
Worker
Notifier
-sell()
ClientNotifier.notify_sell()
ManagerNotifier.notify_sell()
App1Notifier.notify_sell()
-out_of_stock()
EmailHandler
ActiveMQHandler
RestHandler
ClientNotifier
ManagerNotifier
App1Notifier
Classes
especializadas
Ainda existe código
duplicado
Melhorando com metaprogramação
Controller
Model
Worker
Notifier
EVENTOS = [:sell, …]
NOTIFIERS = [ClientNotifier, …]
EmailHandler
ActiveMQHandler
RestHandler
ClientNotifier
ManagerNotifier
App1Notifier
Podemos varrer a lista de
notifiers e eventos para chamar
as devidas notificações
Melhorando com metaprogramação
Analisando a solução
§ Define vários
métodos em tempo
de execução
§ Código genérico
§ Remove
duplicações
§ É muito foda =)
Analisando a solução
§ O método nunca
ser utilizado
§ Código difícil de ler
§ Complexo
§ É muito foda =(
#method_missing
se o ruby não sabe
o que fazer ele chamao method_missing
Outra solução com metaprogramação
#method_missing
§ Executado quando um
método não é encontrado
§ Última tentativa antes de
lançar NoMethodError
§ Só é executado após
percorrer todo o mapa do
objeto
Ruby method lookup
Procura no
objeto
Ruby method lookup
Procura no
objeto
 Procura na
classe
Ruby method lookup
Procura no
objeto
 Procura na
classe
Procura nas
superclasses
Ruby method lookup
Procura no
objeto
 Procura na
classe
Procura nas
superclasses
Procura nosmódulos
Ruby method lookup
Procura no
objeto
 Procura na
classe
Procura nas
superclasses
Procura nosmódulos
Procura na
classe da
classe
Analisando a solução
§ Só executa quando
o método é
chamado
§ Código genérico
§ Remove
duplicações
§ É muito foda =)
Analisando a solução
§ Percorre todo o
mapa de objetos
§ Código difícil de ler
§ Complexo
§ É muito foda =(
Outra solução com metaprogramação
Analisando a solução
§ Só executa quando o
método é chamado
§ Cria o método pra
evitar outra busca
§ Código genérico
§ Remove duplicações
§ É muito foda =)
Analisando a solução
§ Código difícil de ler
§ Complexo
§ É muito foda =(
Outra possível solução
§ class_eval / instance_eval
§ String -> Código
“def #{event}” +
“ #chama notifiers” +
“end”
§ PERIGO!!!
Aprecie com moderação
§ Lógica de negócio NÃO
DEVE ser metaprogramada
§ Muita mágica aumenta o
tempo de aprendizado de
novos devs
§ Debugar o código fica difícil
§ Modificações em uma única
parte são difíceis
Quais os próximos passos
§ Entender Modelo de Objetos do Ruby
§ Singleton class/Eigenclass
§ Lambdas e Procs
§ Soluções alternativas para
metaprogramação
OBRIGADO!
@marcosbrizeno
Geek Night Recife

Metaprogramação Ruby