Podemos usar define_method
dentro de missing_method
para crear
el método fantasma. define_method
define un método de instancia en el objeto receptor.
La sintáxis es:
define_method(symbol, method) => new_method define_method(symbol) { block } => proc
El parámetro method
puede ser un Proc
o un Method
.
Si se usa un bloque como parámetro, es usado como cuerpo del método.
El bloque es evaluado utilizando instance_eval.
Puesto que define_method
es privado y de clase, no podemos llamarlo
directamente dentro de method_missing
. Al ser privado no podemos llamarlo
explicitamente en la clase. Dentro de method_missing
la variable self
refiere al objeto, y define_method
no es un método de instancia.
Una solución es llamarlo via Kernel.send
.
MacBook-Air-de-casiano:rubytesting casiano$ cat -n chamcham3.rb 1 class A 2 def method_missing(n, *a) 3 super unless %{aa bb cc dd}.include? n.to_s 4 5 m = Kernel.send :define_method, n do 6 puts "Inside #{n}" 7 end 8 m[] 9 puts "Inside method_missing, building #{n}" 10 end 11 end 12 13 a = A.new() 14 a.aa() 15 a.aa() 16 a.aa() 17 a.ee()
MacBook-Air-de-casiano:rubytesting casiano$ ruby chamcham3.rb Inside aa Inside method_missing, building aa Inside aa Inside aa chamcham3.rb:3:in `method_missing': undefined method `ee' for #<A:0x10513dcf0> (NoMethodError) from chamcham3.rb:17
Otra forma de hacerlo es usar class_eval:
MacBook-Air-de-casiano:rubytesting casiano$ cat -n chamcham5.rb 1 class A 2 3 def method_missing(n, *a) 4 super unless %{aa bb cc dd}.include? n.to_s 5 A.class_eval { 6 m = define_method(n) do 7 puts "Inside #{n} #{self.class.ancestors.inspect}" 8 end 9 m[] 10 } 11 puts "Inside method_missing, building #{n}" 12 end 13 end 14 15 a = A.new() 16 a.aa() 17 a.aa() 18 a.aa()
MacBook-Air-de-casiano:rubytesting casiano$ ruby chamcham5.rb Inside aa [Class, Module, Object, Kernel] Inside method_missing, building aa Inside aa [A, Object, Kernel] Inside aa [A, Object, Kernel]
O bien
llamar a un método de clase desde el cual se llame
a defined_method
:
MacBook-Air-de-casiano:rubytesting casiano$ cat -n chamcham4.rb 1 class A 2 def self.build_method(n) 3 m = define_method(n) do 4 puts "Inside #{n} #{self.class.ancestors.inspect}" 5 end 6 m[] 7 end 8 9 def method_missing(n, *a) 10 super unless %{aa bb cc dd}.include? n.to_s 11 self.class.build_method(n) 12 puts "Inside method_missing, building #{n}" 13 end 14 end 15 16 a = A.new() 17 a.aa() 18 a.aa() 19 a.aa()
MacBook-Air-de-casiano:rubytesting casiano$ ruby chamcham4.rb Inside aa [Class, Module, Object, Kernel] Inside method_missing, building aa Inside aa [A, Object, Kernel] Inside aa [A, Object, Kernel]
Casiano Rodriguez León 2015-01-07