Last active
December 12, 2015 10:19
-
-
Save fcofdez/4758093 to your computer and use it in GitHub Desktop.
Metaprogramming Ruby talk
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 | |
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