Ruby: definir el método vs def
Como un ejercicio de programación, he escrito un fragmento de Ruby que crea una clase, crea instancias de dos objetos de esa clase, monkeypatches un objeto, y se basa en method_missing para monkeypatch el otro.
Este es el trato. Esto funciona según lo previsto:
class Monkey
def chatter
puts "I am a chattering monkey!"
end
def method_missing(m)
puts "No #{m}, so I'll make one..."
def screech
puts "This is the new screech."
end
end
end
m1 = Monkey.new
m2 = Monkey.new
m1.chatter
m2.chatter
def m1.screech
puts "Aaaaaargh!"
end
m1.screech
m2.screech
m2.screech
m1.screech
m2.screech
Te darás cuenta de que tengo un parámetro para method_missing. Hice esto porque esperaba usar define_method para crear dinámicamente métodos faltantes con el nombre apropiado. Sin embargo, no funciona. En realidad, incluso usando define_method con un nombre estático como este:
def method_missing(m)
puts "No #{m}, so I'll make one..."
define_method(:screech) do
puts "This is the new screech."
end
end
Termina con el siguiente resultado:
ArgumentError: wrong number of arguments (2 for 1)
method method_missing in untitled document at line 9
method method_missing in untitled document at line 9
at top level in untitled document at line 26
Program exited.
Lo que hace que el mensaje de error sea más desconcertante es que solo tengo un argumento para method_missing
...
3 answers
define_method
es un método (privado) de la clase object . Lo estás llamando desde una instancia . No hay ningún método de instancia llamado define_method
, por lo que reproduce a su method_missing
, esta vez con :define_method
(el nombre del método que falta), y :screech
(el único argumento que se pasa a define_method
).
Pruebe esto en su lugar (para definir el nuevo método en todos los objetos Monkey):
def method_missing(m)
puts "No #{m}, so I'll make one..."
self.class.send(:define_method, :screech) do
puts "This is the new screech."
end
end
O esto (para definirlo solo en el objeto sobre el que se invoca, utilizando el "clase propia"):
def method_missing(m)
puts "No #{m}, so I'll make one..."
class << self
define_method(:screech) do
puts "This is the new screech."
end
end
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-01-05 05:15:43
Auto.clase.define_method (: screech) no funciona, porque define_method es un método privado puedes hacer eso
class << self
public :define_method
end
def method_missing(m)
puts "No #{m}, so I'll make one..."
Monkey.define_method(:screech) do
puts "This is the new screech."
end
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-03-27 18:44:58
def method_missing(m)
self.class.class_exec do
define_method(:screech) {puts "This is the new screech."}
end
end
El método Screech estará disponible para todos los objetos Monkey.
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-08-02 01:29:36