class_methods关注的是什么?

Ada*_*Lee 15 ruby ruby-on-rails ruby-on-rails-4

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

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

class_methods do
  def **** 
  end
end
Run Code Online (Sandbox Code Playgroud)

max*_*max 10

ActiveSupport::Concern 为模块混合模块的常见Ruby模式提供语法糖。

当您使用模块作为mixins时,不能self像在类中那样声明类方法:

module Foo
  def self.bar
    "Hello World"
  end

  def instance_method
    "Hello World"
  end
end

class Baz
  include Foo
end
Run Code Online (Sandbox Code Playgroud)
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> 
Run Code Online (Sandbox Code Playgroud)

从示例中可以看到,实际上创建了一个模块方法-那是因为self是模块。您可以改用extend:

module Foo
  def a_class_method
    "Hello World"
  end
end

class Bar
  extend Foo
end
Run Code Online (Sandbox Code Playgroud)
irb(main):049:0> Bar.a_class_method
=> "Hello World"
Run Code Online (Sandbox Code Playgroud)

但这不允许您在模块中声明实例方法。真的没有那么有用。

因此解决方案是创建一个名为的内部模块,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
Run Code Online (Sandbox Code Playgroud)
irb(main):071:0> Bar.a_class_method
=> "Hello World"
Run Code Online (Sandbox Code Playgroud)

几乎每个红宝石宝石/图书馆都可以找到这种样板代码。

通过扩展模块,ActiveSupport::Concern您可以将其缩短为:

module Foo
  extend ActiveSupport::Concern
  class_methods do
    def a_class_method
      "Hello World"
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

在后台ActiveSupport::Concern创建一个ClassMethods模块,并在(ClassMethods)模块的上下文中评估该块。如果您对它实际上是如何执行的感到好奇,请挖掘源代码

  • 令我惊讶的是,自从有人在这里发表评论以感谢您对这个问题的出色回答以来,已经过去了 3 年。最后,有人从头到尾真正回答了我们真正想知道的问题,并一路提供提示和点击。您无疑是一位好老师。谢谢。需要大量的理解才能意识到你到底需要向他人传授什么。你明白了,伙计。 (2认同)
  • 这是一个很好的答案。 (2认同)

Ole*_*yan 8

这只是为了方便.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
Run Code Online (Sandbox Code Playgroud)

  • 我不认为模块ClassMethods完全是“纯红宝石”-红宝石语言中的任何东西都不会自动对子类ClassMethods做一些特殊的事情,而子模块也来自ActiveActive :: Concern。 (2认同)
  • 当然可以。但是,如果您将子模块命名为“ClassMethods”,AS::Concern 会为您完成此操作,并且您不需要自己使用“extend”实现“def self.included”。就此而言,这都是“普通的红宝石”,但我同意,您正确地实现了 AS::Concern 使用 `ClassMethods` 所做的事情,只需要一行相当简单的代码。虽然实现 AS::Concern 使用 `class_methods do` 所做的事情需要四到五行,更令人困惑,但这是事实。但最终这一切都只是“纯红宝石”,包括 AS::Concern 正在做的事情。 (2认同)