Metaprogramação Ruby

Post on 10-May-2015

2.867 views 0 download

description

Formas de como aplicar metaprogramação com Ruby e principalmente os cuidados para quando se aplicar.

Transcript of Metaprogramação Ruby

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 vai �ser criado

block é o que esse �novo método vai fazer

#define_method

def create_method(name, &block)

self.class.send(:define_method, name, block)

end Podemos criar qualquer método �em qualquer lugar em qualquer �momento!

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 chama �o 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 nos �módulos

Ruby method lookup

Procura no �

objeto Procura na �

classe

Procura nas �

superclasses

Procura nos �mó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