Is it possible to add a core method to the Module class in Ruby? I want to do something like this (messed around with the idea yesterday, just whipped this together in a second):
是否有可能在Ruby中的模块类中添加一个核心方法?我想做这样的事情(昨天的想法搞得一团糟,一会儿就把它拼凑起来):
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
If I create a module, I can't access that method:
如果我创建一个模块,我不能访问这个方法:
$ module User; end
$ User.base
NoMethodError: undefined method `base' for User:Module
Any ways to do this?
有什么办法吗?
Update
更新
This works! Thanks @Jörg W Mittag. Makes it much easier to read for Rails has_many
and such:
这个工作!由于@Jorg W Mittag。使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
Like this example:
像这样的例子:
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
Cheers!
干杯!
2 个解决方案
#1
6
If you want to add a method to the Module
class, you simply add a method to the Module
class:
如果要向模块类添加方法,只需向模块类添加方法:
class Module
def base
# ...
end
end
In your code, you were using
在您的代码中,您正在使用
def self.base
# ...
end
This syntax (def foo.bar
) is the syntax for adding a singleton method named bar
to the object referenced by foo
, which is actually really just adding a regular instance method to the singleton class of the object referenced by foo
.
这个语法(def . foo.bar)是向foo引用的对象添加名为bar的单例方法的语法,它实际上只是向foo引用的对象的单例类添加一个常规实例方法。
So, in your code you were adding a singleton method named base
to the object referenced by self
, which inside of class_eval
is the class object itself, in this case Module
. The reason why singleton methods are called singleton methods, is because they only exist on a single object. In your case, the method base
exists only on the object Module
, not on any other object, and in particular not on the object User
. In other words: the only way to call the base
method is as Module.base
, because that is the only object that you added it to.
因此,在代码中,您向self引用的对象添加了一个名为base的单例方法,在本例模块中,这个方法在class_eval内部就是类对象本身。单例方法之所以被称为单例方法,是因为它们只存在于一个对象上。在您的示例中,方法库仅存在于对象模块上,而不存在于任何其他对象上,特别是不存在于对象用户上。换句话说:调用基方法的唯一方法是作为模块。基,因为这是唯一添加的对象。
It took me quite a while to wade through your three(!) nested class_eval
s to find out what it is that you are trying to achieve. Which wasn't made easier by the fact that your code doesn't even actually work, even if defined on the correct class, because def
creates a new scope, and so block
is undefined in the innermost class_eval
.
我花了很长时间来遍历您的三个(!)嵌套class_evals,以找出您要实现的目标。因为def创建了一个新范围,所以在最内部的class_eval中没有定义block,所以即使在正确的类上定义了代码,代码实际上也不能工作,这一点也不容易实现。
Apparently, what you are trying to do is this:
显然,你想做的是:
class Module
def base(&block)
define_singleton_method(:included) do |base|
base.class_eval(&block)
end
end
end
#2
1
I believe you add it by defining the method in the module module:
我相信你通过在模块模块中定义方法来添加它:
class Module
def new_method
...
end
end
Be very careful with this, as it effects all code that uses Module.
要非常小心,因为它影响了所有使用模块的代码。
#1
6
If you want to add a method to the Module
class, you simply add a method to the Module
class:
如果要向模块类添加方法,只需向模块类添加方法:
class Module
def base
# ...
end
end
In your code, you were using
在您的代码中,您正在使用
def self.base
# ...
end
This syntax (def foo.bar
) is the syntax for adding a singleton method named bar
to the object referenced by foo
, which is actually really just adding a regular instance method to the singleton class of the object referenced by foo
.
这个语法(def . foo.bar)是向foo引用的对象添加名为bar的单例方法的语法,它实际上只是向foo引用的对象的单例类添加一个常规实例方法。
So, in your code you were adding a singleton method named base
to the object referenced by self
, which inside of class_eval
is the class object itself, in this case Module
. The reason why singleton methods are called singleton methods, is because they only exist on a single object. In your case, the method base
exists only on the object Module
, not on any other object, and in particular not on the object User
. In other words: the only way to call the base
method is as Module.base
, because that is the only object that you added it to.
因此,在代码中,您向self引用的对象添加了一个名为base的单例方法,在本例模块中,这个方法在class_eval内部就是类对象本身。单例方法之所以被称为单例方法,是因为它们只存在于一个对象上。在您的示例中,方法库仅存在于对象模块上,而不存在于任何其他对象上,特别是不存在于对象用户上。换句话说:调用基方法的唯一方法是作为模块。基,因为这是唯一添加的对象。
It took me quite a while to wade through your three(!) nested class_eval
s to find out what it is that you are trying to achieve. Which wasn't made easier by the fact that your code doesn't even actually work, even if defined on the correct class, because def
creates a new scope, and so block
is undefined in the innermost class_eval
.
我花了很长时间来遍历您的三个(!)嵌套class_evals,以找出您要实现的目标。因为def创建了一个新范围,所以在最内部的class_eval中没有定义block,所以即使在正确的类上定义了代码,代码实际上也不能工作,这一点也不容易实现。
Apparently, what you are trying to do is this:
显然,你想做的是:
class Module
def base(&block)
define_singleton_method(:included) do |base|
base.class_eval(&block)
end
end
end
#2
1
I believe you add it by defining the method in the module module:
我相信你通过在模块模块中定义方法来添加它:
class Module
def new_method
...
end
end
Be very careful with this, as it effects all code that uses Module.
要非常小心,因为它影响了所有使用模块的代码。