我正在阅读一些使用Rails 4中的问题的代码。
如果我们想要包含类方法,我会阅读一些文章
使用模块ClassMethods
,但我使用类似的东西读取代码:
class_methods do
def ****
end
end
答案 0 :(得分:7)
这只是为了方便。 module ClassMethods
是纯Ruby,但为方便起见,class_methods
中定义了ActiveSupport::Concern
。如果您查看源代码,您会发现class_methods
完全相同
# activesupport/lib/concern.rb
def class_methods(&class_methods_module_definition)
mod = const_defined?(:ClassMethods, false) ?
const_get(:ClassMethods) :
const_set(:ClassMethods, Module.new)
mod.module_eval(&class_methods_module_definition)
end
答案 1 :(得分:4)
ActiveSupport::Concern
为模块mixin的常见Ruby模式提供语法糖。
使用modules as mixins时,不能像使用类一样使用self
声明类方法:
module Foo
def self.bar
"Hello World"
end
def instance_method
"Hello World"
end
end
class Baz
extend Foo
end
irb(main):010:0> Baz.bar
NoMethodError: undefined method `bar' for Baz:Class
from (irb):10
irb(main):011:0> Foo.bar
=> "Hello World"
irb(main):012:0>
从示例中可以看到实际上创建了一个模块方法-那是因为self
是模块。您可以改为使用扩展
module Foo
def a_class_method
"Hello World"
end
end
class Bar
extend Foo
end
irb(main):049:0> Bar.a_class_method
=> "Hello World"
但是,这不允许您在模块中声明实例方法。真的没那么有用。
因此解决方案是创建一个名为ClassMethods
的内部模块,并在包含该模块时扩展该类:
module Foo
# this is a method thats called when you include the module in a class.
def self.included(base)
base.extend ClassMethods
end
def an_instance_method
end
# the name ClassMethods is just convention.
module ClassMethods
def a_class_method
"Hello World"
end
end
end
class Bar
include Foo
end
irb(main):071:0> Bar.a_class_method
=> "Hello World"
几乎每个红宝石宝石/图书馆都可以找到这种样板代码。
通过使用ActiveSupport::Concern
扩展模块,您可以将其缩短为:
module Foo
extend ActiveSupport::Concern
class_methods do
def a_class_method
"Hello World"
end
end
end
在内部ActiveSupport::Concern
下创建一个ClassMethods
模块,并在(ClassMethods)模块的上下文中评估该块。如果您对the source的实际用途感到好奇,请继续研究。
答案 2 :(得分:2)
class_methods
用于将类方法添加到关注点使用的模型中。
典型模块如下所示:
module M
def self.included(base)
base.extend ClassMethods
end
module ClassMethods
...
end
end
通过使用ActiveSupport::Concern
,上述模块可以改为:
require 'active_support/concern'
module M
extend ActiveSupport::Concern
class_methods do
...
end
end
作为Oleg Antonyan pointed out,从源代码中我们知道它将在引擎盖下使用ClassMethods
模块。
参考:http://api.rubyonrails.org/classes/ActiveSupport/Concern.html