【问题标题】:Ruby modules - included do end blockRuby 模块 - 包括 do 结束块
【发布时间】:2015-01-18 12:40:57
【问题描述】:

有一个模块MyModule:

module MyModule

  extend ActiveSupport::Concern

  def first_method
  end

  def second_method
  end

  included do
    second_class_method
  end

  module ClassMethods
    def first_class_method
    end

    def second_class_method
    end
  end
end

当某个类includes 这个模块时,它将有2个方法暴露为实例方法(first_methodsecond_method)和2个类方法(first_class_methodsecond_class_method) - 很清楚。

据说

included 块将在类的上下文中执行 包括模块。

具体是什么意思?意思是,这个方法(second_class_method)到底什么时候执行?

【问题讨论】:

    标签: ruby


    【解决方案1】:

    这是一个实际的例子。

    class MyClass
      include MyModule
    end
    

    当您将模块包含在一个类中时,included 挂钩将被调用。所以second_class_method会在Class的范围内被调用。

    这里发生的是

    1. first_methodsecond_method 包含在 MyClass. 的实例方法中

      instance = MyClass.new
      instance.first_method
      # => whatever returned value of first_method is
      
    2. ClassMethods 的方法自动混合为MyClass 的类方法。这是ActiveSupport::Concern 封装的常见Ruby 模式。非 Rails Ruby 代码是

      module MyModule
        def self.included(base)
          base.extend ClassMethods
        end
      
        module ClassMethods
          def this_is_a_class_method
          end
        end
      end
      

      结果

      MyClass.this_is_a_class_method
      

      或者在你的情况下

      MyClass.first_class_method
      
    3. included 是一个对以下代码有效的钩子

      # non-Rails version
      module MyModule
        def self.included(base)
          base.class_eval do
            # somecode
          end
        end
      end
      
      # Rails version with ActiveSupport::Concerns
      module MyModule
        included do
          # somecode
        end
      end
      

      它主要是常见模式的“语法糖”。在实践中发生的情况是,当您混合模块时,该代码会在混合器类的上下文中执行。

    【讨论】:

    • 一切听起来都合乎逻辑,但仍然......让我们看一个例子。如果second_class_method 实现为raise "When am I raised?" 会怎样,什么时候会提升?
    • 只要包含器包含您的模块,它就会立即被提升。这实际上会导致 ruby​​ 代码解析过程并导致解释器立即崩溃。你可以自己试试。
    【解决方案2】:

    included 在你包含module 到一个类时被调用,它用于定义关系、范围、验证,... 它甚至在您从该类创建对象之前就被调用。

    例子

    module M
    ...
      included do
        validates :attr, presence: true
        has_many :groups
      end
     ...
    end
    

    【讨论】:

    • 所以验证会限制模块可以包含的位置?
    • 如果您在 include do 块之外设置范围,为什么它不起作用?它仍然会在包含该模块的类的上下文中设置,对吧?
    • 它不会“在包含模块的类的上下文中设置”。 validates 是一种方法。您在模块主体内运行的任何方法都会在“加载时”在该模块的上下文中运行。你会得到“NoMethodError”,因为对于一个模块,validates 没有多大意义
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-24
    • 2021-05-26
    相关资源
    最近更新 更多