Considérese la siguiente extensión (el patrón popularizado por varios rieles plugins lo largo de los años):¿Cómo extiendes un módulo Ruby con métodos de metaprogramación tipo macro?
module Extension
def self.included(recipient)
recipient.extend ClassMethods
recipient.send :include, InstanceMethods
end
module ClassMethods
def macro_method
puts "Called macro_method within #{self.name}"
end
end
module InstanceMethods
def instance_method
puts "Called instance_method within #{self.object_id}"
end
end
end
Si usted deseaba exponer esto a cada clase, puede hacer lo siguiente:
Object.send :include, Extension
Ahora se puede definir cualquier clase y utilizar el método de macro:
class FooClass
macro_method
end
#=> Called macro_method within FooClass
e instancias pueden utilizar los métodos de instancia:
FooClass.new.instance_method
#=> Called instance_method within 2148182320
Pero aunque Module.is_a?(Object)
, no puede usar el método macro en un módulo.
module FooModule
macro_method
end
#=> undefined local variable or method `macro_method' for FooModule:Module (NameError)
Esto es cierto incluso si se incluye explícitamente el original Extension
en Module
con Module.send(:include, Extension)
.
Para los módulos individuales se pueden incluir las extensiones de la mano y obtener el mismo efecto:
module FooModule
include Extension
macro_method
end
#=> Called macro_method within FooModule
Pero, ¿Cómo se puede añadir macro-como métodos a todos los módulos de Ruby?
* Hay * esa publicación en el blog. Sabía que lo había visto en algún lugar recientemente. Siento curiosidad por saber por qué la otra estrategia no funciona, y no creo que sea un serio antipatrón sino una falla menor, pero estoy de acuerdo en que "no tiene sentido anular incluir comportarse como extender cuando Ruby proporciona ambas cosas ". –
+1 para "carga-culted." –
¿Existe alguna manera de definir "macro_method" como lo hizo, pero puede elegir qué clases tienen acceso a él? –