Ian*_*ell 6 ruby module metaprogramming
考虑以下扩展(多年来由多个Rails插件推广的模式):
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
Run Code Online (Sandbox Code Playgroud)
如果您希望将其公开给每个班级,您可以执行以下操作:
Object.send :include, Extension
Run Code Online (Sandbox Code Playgroud)
现在您可以定义任何类并使用宏方法:
class FooClass
macro_method
end
#=> Called macro_method within FooClass
Run Code Online (Sandbox Code Playgroud)
实例可以使用实例方法:
FooClass.new.instance_method
#=> Called instance_method within 2148182320
Run Code Online (Sandbox Code Playgroud)
但即使如此Module.is_a?(Object),您也无法在模块中使用宏方法.
module FooModule
macro_method
end
#=> undefined local variable or method `macro_method' for FooModule:Module (NameError)
Run Code Online (Sandbox Code Playgroud)
这是真实的,即使你明确地包括原Extension成Module与Module.send(:include, Extension).
对于单个模块,您可以手动包含扩展并获得相同的效果:
module FooModule
include Extension
macro_method
end
#=> Called macro_method within FooModule
Run Code Online (Sandbox Code Playgroud)
但是,如何为所有Ruby模块添加类似宏的方法呢?
Jör*_*tag 22
考虑以下扩展(多年来由多个Rails插件推广的模式)
这不是一种模式,并没有"普及".这是一个反模式,由不知道Ruby的1337 PHP h4X0rZ 进行了货物测试.值得庆幸的是,由于Yehuda Katz,Carl Lerche和其他人的硬话,Rails 3已经消除了许多(所有?)这种反模式的实例.Yehuda甚至在他最近关于清理Rails代码库的讨论中使用了与你发布的完全相同的代码,并且他写了一篇关于这个反模式的完整博客文章.
如果您希望将其公开给每个班级,您可以执行以下操作:
Run Code Online (Sandbox Code Playgroud)Object.send :include, Extension
如果你想将它添加到Object 任何地方,那么为什么不这样做呢:
class Object
def instance_method
puts "Called instance_method within #{inspect}"
end
end
Run Code Online (Sandbox Code Playgroud)
但是,如何为所有Ruby模块添加类似宏的方法呢?
简单:将它们添加到Module:
class Module
def macro_method
puts "Called macro_method within #{inspect}"
end
end
Run Code Online (Sandbox Code Playgroud)
一切正常:
class FooClass
macro_method
end
#=> Called macro_method within FooClass
FooClass.new.instance_method
#=> Called instance_method within #<FooClass:0x192abe0>
module FooModule
macro_method
end
#=> Called macro_method within FooModule
Run Code Online (Sandbox Code Playgroud)
它只有10行代码而不是你的16行,而这10行中恰好有0行是元编程或钩子或任何甚至远程复杂的东西.
代码与我的代码之间的唯一区别在于,在代码中,mixins显示在继承层次结构中,因此调试起来更容易,因为您实际上看到了添加的内容Object.但这很容易解决:
module ObjectExtensions
def instance_method
puts "Called instance_method within #{inspect}"
end
end
class Object
include ObjectExtensions
end
module ModuleExtensions
def macro_method
puts "Called macro_method within #{inspect}"
end
end
class Module
include ModuleExtensions
end
Run Code Online (Sandbox Code Playgroud)
现在我用你的代码绑定了16行,但我认为我的代码比你的简单,特别是考虑到你的代码不起作用,你和我以及几乎190000 StackOverflow用户都无法弄清楚原因.