Lan*_*ard 2 ruby metaprogramming
是否可以在Ruby中向Module类添加核心方法?我想做这样的事情(昨天弄乱了这个想法,只是在一瞬间鞭打了这个):
module MyModule
base do
has_many :something
end
end
# implementation, doesn't work though... reason for the question
Module.class_eval do
def self.base(&block)
class_eval do
def self.included(base)
base.class_eval(&block)
end
end
end
end
Run Code Online (Sandbox Code Playgroud)
如果我创建一个模块,我无法访问该方法:
$ module User; end
$ User.base
NoMethodError: undefined method `base' for User:Module
Run Code Online (Sandbox Code Playgroud)
有什么办法吗?
更新
这有效!谢谢@JörgWMittag.使Rails has_many等更容易阅读:
class Module
def base(&block)
metaclass = class << self; self; end
# add the method using define_method instead of def x.say so we can use a closure
metaclass.send :define_method, :included do |base|
base.class_eval(&block) unless block.nil?
base.class_eval <<-EOF
extend #{name}::ClassMethods
include #{name}::InstanceMethods
EOF
end
block
end
end
Run Code Online (Sandbox Code Playgroud)
像这个例子:
module UserRoleBehavior
base do
has_many :user_roles
has_many :roles, :through => :user_roles
end
module ClassMethods
# ...
end
module InstanceMethods
# ...
end
end
class User < ActiveRecord::Base
include UserRoleBehavior
end
Run Code Online (Sandbox Code Playgroud)
干杯!
如果要向Module该类添加方法,只需向Module该类添加一个方法:
class Module
def base
# ...
end
end
Run Code Online (Sandbox Code Playgroud)
在您的代码中,您正在使用
def self.base
# ...
end
Run Code Online (Sandbox Code Playgroud)
这个语法(def foo.bar)是添加一个名为bar引用对象的单例方法的语法,foo实际上它实际上只是将常规实例方法添加到引用的对象的单例类中foo.
因此,在您的代码中,您添加了一个以base引用的对象命名的单例方法,在这种情况下self,其内部class_eval是类对象本身Module.单例方法被称为单例方法的原因是因为它们只存在于单个对象上.在您的情况下,该方法base仅存在于对象上Module,而不存在于任何其他对象上,特别是不存在于对象上User.换句话说:调用方法的唯一base方法是Module.base,因为这是您添加它的唯一对象.
我花了很长时间来浏览你的三个(!)嵌套class_evals,以找出你想要实现的目标.这是不是事实,你的代码甚至不实际的工作变得更加容易,甚至如果在正确的类中定义,因为def创建一个新的范围,所以block在最里面的不确定class_eval.
显然,你要做的是:
class Module
def base(&block)
define_singleton_method(:included) do |base|
base.class_eval(&block)
end
end
end
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
544 次 |
| 最近记录: |