![Page 1: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/1.jpg)
MetaprogramaciónProgramas que escriben programas
(en Ruby)
Sergio Gil
![Page 2: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/2.jpg)
Sólo para vagos
![Page 3: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/3.jpg)
“Para qué voy a hacer [tarea X] si puedo escribir un programa que lo
haga por mí”Cualquier programador, en cualquier momento,
ante cualquier situación
![Page 4: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/4.jpg)
Programar no es una excepción
![Page 5: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/5.jpg)
Automatización
![Page 6: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/6.jpg)
Acercar el lenguaje al problema(para resolverlo mejor)
![Page 7: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/7.jpg)
Qué es la metaprogramación y de dónde ha salido semejante cosa
![Page 8: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/8.jpg)
puts "puts 'hola'"
$ ruby -e "`ruby hola.rb`"
![Page 9: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/9.jpg)
Programas que escriben otros programas
Programas que modifican su propio comportamiento
(es decir, se escriben a sí mismos)
![Page 10: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/10.jpg)
“In Lisp, you don’t just write your program down toward the language,
you also build the language up toward your program.”
Paul Graham
![Page 11: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/11.jpg)
Tipos de metaprogramación
![Page 12: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/12.jpg)
Estática / Interna
![Page 13: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/13.jpg)
Dinámica / Interna
![Page 14: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/14.jpg)
Metaprogramación en Rails
![Page 15: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/15.jpg)
Metaprogramación en Rails
• Generadores
![Page 16: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/16.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
![Page 17: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/17.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
![Page 18: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/18.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
• const_missing
![Page 19: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/19.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
• const_missing
• Definiciones dinámicas
![Page 20: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/20.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
• const_missing
• Definiciones dinámicas
$ grep -r method_missing vendor/rails/ | wc -l72
![Page 21: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/21.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
• const_missing
• Definiciones dinámicas
$ grep -r method_missing vendor/rails/ | wc -l72$ grep -r const_missing vendor/rails/ | wc -l41
![Page 22: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/22.jpg)
Metaprogramación en Rails
• Generadores
• Métodos mágicos
• method_missing
• const_missing
• Definiciones dinámicas
$ grep -r method_missing vendor/rails/ | wc -l72$ grep -r const_missing vendor/rails/ | wc -l41$ grep -r define_method vendor/rails/ | wc -l67
![Page 23: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/23.jpg)
Técnicas en Ruby/Rails
![Page 24: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/24.jpg)
Generadores
![Page 25: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/25.jpg)
Generadores
class ModelGenerator < Rails::Generator::NamedBase def manifest record do |m| m.directory File.join('app/models', class_path) m.directory File.join('test/unit', class_path) m.directory File.join('test/fixtures', class_path) m.template 'model.rb', File.join('app/models', class_path, "#{file_name}.rb") m.template 'unit_test.rb', File.join('test/unit', class_path, "#{file_name}_test.rb") m.template 'fixtures.yml', File.join('test/fixtures', "#{table_name}.yml") m.migration_template 'migration.rb', 'db/migrate', :assigns => { :migration_name => "Create#{class_name.pluralize.gsub(/::/, '')}" }, :migration_file_name => "create_#{file_path.gsub(/\//, '_').pluralize}" end endend
![Page 26: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/26.jpg)
method_missing
![Page 27: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/27.jpg)
class Array def method_missing(meth, *args, &blk) if meth.to_s =~ /^map_(.+)$/ map {|i| i.send($1)} else super end endend(1..5).to_a.map_to_s
method_missing
![Page 28: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/28.jpg)
class Array def method_missing(meth, *args, &blk) if meth.to_s =~ /^map_(.+)$/ map {|i| i.send($1)} else super end endend(1..5).to_a.map_to_s
method_missing
>> ["1", "2", "3", "4", "5"]
![Page 29: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/29.jpg)
const_missing
![Page 30: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/30.jpg)
class Module alias :normal_const_missing :const_missing
def const_missing(cname) return normal_const_missing(cname) rescue nil unless table_name = SchemaLookup.models[cname] raise NameError.new("uninitialized constant #{cname}") end klass = Class.new(ActiveRecord::Base) const_set cname, klass klass.set_table_name table_name klass end end
const_missing
![Page 31: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/31.jpg)
alias
![Page 32: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/32.jpg)
alias
class String alias :largo :lengthend
puts "hola".largoputs "hola".length
![Page 33: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/33.jpg)
alias
class String alias :largo :lengthend
puts "hola".largoputs "hola".length
44
![Page 34: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/34.jpg)
alias
class String alias :largo :lengthend
puts "hola".largoputs "hola".length
class String alias :old_length :length def length old_length + 2 endend
puts "hola".length
44
![Page 35: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/35.jpg)
alias
class String alias :largo :lengthend
puts "hola".largoputs "hola".length
class String alias :old_length :length def length old_length + 2 endend
puts "hola".length
44
6
![Page 36: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/36.jpg)
alias_method_chain(el estándar de Rails para añadir funcionalidad a un método preexistente)
![Page 37: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/37.jpg)
alias_method_chain(el estándar de Rails para añadir funcionalidad a un método preexistente)
class String def length_with_message puts "Calculando longitud de #{self}" length_without_message end alias_method_chain :length, :messageendputs "hola".length
![Page 38: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/38.jpg)
alias_method_chain(el estándar de Rails para añadir funcionalidad a un método preexistente)
class String def length_with_message puts "Calculando longitud de #{self}" length_without_message end alias_method_chain :length, :messageendputs "hola".length
Calculando longitud de hola4
![Page 39: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/39.jpg)
send y define_methodla metaprogramación pata negra
![Page 40: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/40.jpg)
send
![Page 41: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/41.jpg)
str = "Metaprogramaciongue"
puts str.upcaseputs str.send(:upcase)
send
![Page 42: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/42.jpg)
str = "Metaprogramaciongue"
puts str.upcaseputs str.send(:upcase)
METAPROGRAMACIONGUEMETAPROGRAMACIONGUE
send
![Page 43: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/43.jpg)
str = "Metaprogramaciongue"
puts str.upcaseputs str.send(:upcase)
METAPROGRAMACIONGUEMETAPROGRAMACIONGUE
[ :upcase, :downcase, :reverse ].each do |m| puts str.send(m)end
send
![Page 44: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/44.jpg)
str = "Metaprogramaciongue"
puts str.upcaseputs str.send(:upcase)
METAPROGRAMACIONGUEMETAPROGRAMACIONGUE
[ :upcase, :downcase, :reverse ].each do |m| puts str.send(m)end
METAPROGRAMACIONGUEmetaprogramaciongueeugnoicamargorpateM
send
![Page 45: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/45.jpg)
define_method y def
![Page 46: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/46.jpg)
define_method y def
class Prueba def foo "foo" end define_method(:bar) do "bar" endend
p = Prueba.newputs p.fooputs p.bar
![Page 47: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/47.jpg)
define_method y def
class Prueba def foo "foo" end define_method(:bar) do "bar" endend
p = Prueba.newputs p.fooputs p.bar
foobar
![Page 48: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/48.jpg)
¿¿Y entonces??
![Page 49: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/49.jpg)
class Prueba [ :foo, :bar, :jander, :klander ].each do |m| define_method(m) do m.to_s end endend
p = Prueba.newputs p.fooputs p.barputs p.janderputs p.klander
¿¿Y entonces??
![Page 50: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/50.jpg)
class Prueba [ :foo, :bar, :jander, :klander ].each do |m| define_method(m) do m.to_s end endend
p = Prueba.newputs p.fooputs p.barputs p.janderputs p.klander
foobarjanderklander
¿¿Y entonces??
![Page 51: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/51.jpg)
foobarjanderklander
Versión para realmente vagos
M = [ :foo, :bar, :jander, :klander ]
class Prueba M.each do |m| define_method(m) do m.to_s end endend
p = Prueba.newM.each do |m| puts p.send(m)end
![Page 52: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/52.jpg)
Un ejemplo pequeño (pero real) de algunas de estas cosas juntas
![Page 53: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/53.jpg)
VALIDATION_METHODS = [:presence, :numericality, :format, :length, :acceptance, :confirmation]VALIDATION_METHODS.each do |type| define_method "validates_#{type}_of_with_live_validations".to_sym do |*attr_names| send "validates_#{type}_of_without_live_validations".to_sym, *attr_names define_validations(type, attr_names) end alias_method_chain "validates_#{type}_of".to_sym, :live_validationsend
![Page 54: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/54.jpg)
Un consejito
![Page 55: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/55.jpg)
Usa módulos (mixins) para extender clases
![Page 56: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/56.jpg)
class String def italianize self.gsub(/[aeiou]/, 'i') endend
Usa módulos (mixins) para extender clases
![Page 57: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/57.jpg)
class String def italianize self.gsub(/[aeiou]/, 'i') endend
module Italianization def italianize self.gsub(/[aeiou]/, 'i') end endString.send(:include, Italianization)
Usa módulos (mixins) para extender clases
![Page 58: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/58.jpg)
¿Y por qué?
![Page 59: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/59.jpg)
¿Y por qué?
1. Gracias al const_missing de Rails, no importa el orden en que carguen las definiciones
![Page 60: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/60.jpg)
¿Y por qué?
1. Gracias al const_missing de Rails, no importa el orden en que carguen las definiciones
2. Más fácil de depurar
![Page 61: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/61.jpg)
¿Y por qué?
1. Gracias al const_missing de Rails, no importa el orden en que carguen las definiciones
2. Más fácil de depurar
String.ancestors
![Page 62: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/62.jpg)
¿Y por qué?
1. Gracias al const_missing de Rails, no importa el orden en que carguen las definiciones
2. Más fácil de depurar
String.ancestors>> [ String, Enumerable, Comparable, Object, Kernel ]
![Page 63: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/63.jpg)
¿Y por qué?
1. Gracias al const_missing de Rails, no importa el orden en que carguen las definiciones
2. Más fácil de depurar
String.ancestors>> [ String, Enumerable, Comparable, Object, Kernel ]>> [ String, Italianization, Enumerable, Comparable, Object, Kernel ]
![Page 64: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/64.jpg)
Recapitulando
![Page 65: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/65.jpg)
![Page 66: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/66.jpg)
1. Sé vago
![Page 67: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/67.jpg)
1. Sé vago2. Pero no te pases de listo
![Page 68: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/68.jpg)
1. Sé vago2. Pero no te pases de listo3. Y testea
![Page 69: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/69.jpg)
![Page 70: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/70.jpg)
¿Preguntas, dudas?
![Page 71: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/71.jpg)
¿Preguntas, dudas?
¿Opiniones?
![Page 72: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/72.jpg)
Referencias
"Metaprogramming Ruby: Domain-Specific Languages for Programmers", Glenn Vanderburg [www.vanderburg.org/Speaking/Stu!/oscon05.pdf]"The art of metaprogramming", Jonhathan Bartlett [http://www-128.ibm.com/developerworks/linux/library/l-metaprog1.html]C2.com Wiki [http://c2.com/cgi/wiki?MetaProgramming]http://api.rubyonrails.org/Ola Bini [http://ola-bini.blogspot.com/]Jay Fields [http://blog.jayfields.com/]Nic Williams [http://drnicwilliams.com/]Lambda the Ultimate [http://lambda-the-ultimate.org/]LiveValidation Plugin [http://livevalidation.rubyforge.org]Sofá Naranja [http://sofanaranja.com/2007/09/19/elogio-de-la-vagancia/]
![Page 73: Metaprogramación (en Ruby): programas que escriben programas](https://reader033.vdocuments.net/reader033/viewer/2022042607/559a93591a28abf46e8b459f/html5/thumbnails/73.jpg)
Muchas graciassergio.gil@the‐cocktail.com
lacoctelera.com/porras
the‐cocktail.com