class_methods关注的是什么?

时间:2015-10-25 04:39:51

标签: ruby-on-rails ruby ruby-on-rails-4

我正在阅读一些使用Rails 4中的问题的代码。

如果我们想要包含类方法,我会阅读一些文章 使用模块ClassMethods,但我使用类似的东西读取代码:

class_methods do
  def **** 
  end
end

3 个答案:

答案 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