Skip to content

Instantly share code, notes, and snippets.

@fcofdez
Last active December 12, 2015 10:19
Show Gist options
  • Save fcofdez/4758093 to your computer and use it in GitHub Desktop.
Save fcofdez/4758093 to your computer and use it in GitHub Desktop.
Metaprogramming Ruby talk
Qué?
Metaprogramming is code that writes code
Metafora lenguaje compilado - dinámico
Ruby es un lenguaje dinámico y orientado a objetos
Todo son mensajes que se pasan
Manejo de esos mensajes
Dónde manejamos esos mensajes?
Ruby object model
Open Classes
Monkey Patchs
Código que se ejecuta dentro de class
no tiene distinción con respecto a código de fuera
lo único que cambia es el ámbito de self
class keyword más bien como cambio de contexto que como definición de clase (Expresar mejor)
clases no son mas que objetos
por ejemplo
"test".class
2.0.0-rc2 :005 > "test".class
=> String
2.0.0-rc2 :006 > String.class
=> Class
2.0.0dev :006 > String.superclass
=> Object
2.0.0dev :004 > Object.superclass
=> BasicObject
2.0.0dev :005 > BasicObject.superclass
=> nil
2.0.0dev :007 > Array.superclass
=> Object
Todas las clases heredan de Object que a su vez heredan de BasicObject y éste es el nodo raiz de la jerarquía de clases de Ruby.
2.0.0dev :008 > Class.superclass
=> Module
Existen pocas diferencias entre una clase y un módulo salvando los métodos como allocate y new que por supuesto son imprescindibles. Podemos tratar ambos como ciudadanos de primera clase.
Referencia a figura 1.2
Referencias!!
la única diferencia entre una instancia de una clase y una clase es que la primera es una variable que referencia a otra instancia que en su caso es una Constante.
Como bien sabéis en Ruby las referencias que empiezan en mayúscula son constantes.
What’s an object? It’s just a bunch of instance variables, plus a link to
a class.
The object’s methods don’t live in the object—they live in the
object’s class, where they’re called the instance methods of the class.
What’s a class? It’s just an object (an instance of Class), plus a list of
instance methods and a link to a superclass. Class is a subclass of
Module, so a class is also a module.
Like any object, a class has its own methods, such as new( ). These are
instance methods of the Class class. Also like any object, classes must
be accessed through references. You already have a constant reference
to each class: the class’s name.
Method lookup
receiver es el objeto que recibe el mensaje (la llamada al método)
ancestor chain el orden y dónde busca Ruby el método
Ruby sigue el siguiente camino
Primero comprueba si el método está en la clase de receiver, si no lo encuentra
va subiendo a través de sus ancestros hasta encontrarlo
2.0.0dev :012 > String.ancestors
=> [String, Comparable, Object, Kernel, BasicObject]
2.0.0dev :013 >
WTF? Kernel no es un módulo? Comparable también!
Ruby hace un pequeño "truco" introduce en la jerarquía clases anónimas que contienen los métodos
definidos en el módulo (eigenclass?) include classes (or sometimes proxy
classes).
Hablar sobre el módulo Kernel?
lo incluye object por eso sus métodos, como print, están disponibles en todos sitios
pareciendo una palabra reservada de ruby.
por ejemplo module
2.0.0dev :018 > module Kernel
2.0.0dev :019?> def my_cool_monkey_patch
2.0.0dev :020?> puts "yehaa"
2.0.0dev :021?> end
2.0.0dev :022?> end
=> nil
2.0.0dev :023 > String.my_cool_monkey_patch
yehaa
=> nil
2.0.0dev :024 > self
=> main
2.0.0dev :025 > my_cool_monkey_patch
yehaa
=> nil
Hablar sobre self!
Every line of Ruby code is executed inside an object—the so–called cur-
rent object. The current object is also known as self, because you can
access it with the self keyword.
Only one object can take the role of self at a given time, but no object
holds that role for a long time. In particular, when you call a method,
the receiver becomes self.
module Printable
def print
# ...
end
def prepare_cover
# ...
end
end
module Document
def print_to_screen
prepare_cover
format_for_screen
print
end
def format_for_screen
# ...
end
def print
# ...
end
end
class Book
include Document
include Printable
# ...
end
Book.ancestors
Dynamic Dispatch
Usar send ya que cuando llamas a un método lo que haces es enviar un mensaje
class MyClass
def my_method(my_arg)
my_arg * 2
end
end
obj = MyClass.new
obj.my_method(3) # => 6
Bill demonstrates how you can also call MyClass#my_method( ) using
Object#send( ) in place of the dot notation:
obj.send(:my_method, 3)
The Test::Unit Example
method_names = public_instance_methods(true)
tests = method_names.delete_if {|method_name| method_name !~ /^test./}
se puede romper la restricción private con send
Definición de métodos
https://gist.github.com/fcofdez/4955358
Tenemos un código duplicado por todas partes, eso puede conllevar a un mayor riesgo de fallos replicados.
Si se añade algún tipo de componente se deben crear nuevos métodos.
Ruby nos da la posibilidad de generar métodos (y todo lo que queramos) de manera dinámica.
Vamos a abordar este problema desde tres enfoques.
Dynamic dispatch
Define method
class Car
def self.define_part name
define_method name do
"dumb #{name}"
end
end
end
Car.define_part wheel
car = Car.new.wheel
"dumb wheel"
Por qué?
Cómo?
Cuando?
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment