self.included - 包括Ruby中模块的类方法

时间:2017-07-14 17:34:34

标签: ruby-on-rails ruby

我读过这篇文章:Ruby modules - included do end block - 但是当您在模块中使用self.included do ... end块时仍然无法获得。

帖子说当你包含模块时,块中的代码会被运行,但是如果要包含模块的唯一目的,那么它的重点是什么?这个代码不需要运行吗?该块不需要存在就可以运行该代码,对吗?

以下两者之间有什么区别:

module M
  def self.included(base)
    base.extend ClassMethods
    base.class_eval do
      scope :disabled, -> { where(disabled: true) }
    end
  end

  module ClassMethods
    ...
  end
end

VS

module M
  def self.some_class_method
     ...
  end

  scope :disabled, -> { where(disabled: true) }
end

2 个答案:

答案 0 :(得分:3)

这两个例子的区别是什么?

第一个代码块将ClassMethods中的类方法添加到包含类,并在其上调用scope方法。第二个不执行这些操作,并且将导致NoMethodError,因为模块没有scope类方法。一旦包含该模块,self.some_class_method将无法在包含类中使用。

关于模块包含如何在Ruby中工作的完整故事,请在此处阅读我的答案:
Inheriting class methods from modules / mixins in Ruby

如果要包含模块的唯一目的,self.included的重点是什么?

包含不是模块的唯一目的。它们还可用于其他内容,例如命名空间,或者只是存储可在模块本身上调用的各种类方法。

为什么Ruby不自动包含类方法?

理论上,Ruby 可以自动将模块中定义的所有类方法添加到包含类中,但实际上这不是一个坏主意,因为将无法再选择是否要包含类方法 - 每次都包含所有类方法,无论它们是否包含在内。考虑这个例子:

module M
  def self.class_method
    "foo"
  end

  def self.configure_module
    # add configuration for this module
  end
end

class C
  include M
end

这里,configure_module方法显然 不应该添加到C,因为它的目的是设置模块对象的配置。然而,如果我们有类方法的自动包含,你将无法阻止它被包括在内。

但是所有实例方法都已包含在内!那怎么样?

模块中的实例方法只有才真正有用如果它们包含在类中,因为模块不能有实例,只有类可以。因此,在一个模块中,每个实例方法都应该包含在某个地方。

A" class"模块上的方法是不同的,因为它可以在模块本身上调用,因此无论它是否也添加到包含类,它都可以使用。这就是为什么你在那里做出选择会更好。

答案 1 :(得分:1)

module M
  # self.included is the hook which automatically runs when this module is included
  def self.included(base)
    puts 'this will be printed when this module will be included inside a class'
    base.extend ClassMethods
    base.class_eval do
      scope :disabled, -> { where(disabled: true) }
    end
  end

  def print_object_class
    self.class.name # here self will be the object of class which includes this module
  end

  module ClassMethods
    def print_class_name
      self.name # Here self would be the class which is including this module
    end
  end
end

我尝试修改上面的module,以帮助您了解模块(关注点)如何在代码可重用性方面发挥作用

self.included是一个钩子,当模块包含在类中时会自动运行。

module ClassMethods中声明的任何方法都将成为包含此模块的类的类方法

module ClassMethods之外声明的任何方法都将成为包含此模块的类的实例方法

对于Ex,假设有一个Product类,并且您已将模块包含在其中

class Product < ActiveRecord::Base
  include M
  puts 'after including M'
end

如果您在rails控制台中尝试此示例,您会注意到模块M包含在class Product包含的模块运行挂钩中并且

this will be printed when this module will be included inside a class这是打印在控制台上的

之后after including M这将打印在控制台上。

您也可以尝试以下命令

Product.disabled # a scope with name 'disabled' is avaialble because of including the module M
Product.print_class_name # Outputs => 'Product' This method is available to class with the help of module M
Product.new.print_object_class #Outputs => 'Product'

它还提供可重用性,在任何类中包含此模块M,并且该类可以访问模块中描述的所有这些方法。

而你的第二个例子仅仅是基本模块的例子

module N
  def self.abc
    puts 'basic module'
  end
end

现在abc模块中的方法定义只能使用此模块

进行访问

N.abc # outputs 'basic module'

class Product < ActiveRecord::Base
  include  N
end

Product.abc #raises exception,在类Product上找不到方法 Product.new.abc #raises exception,在类Product

的对象上找不到方法

我希望这可以帮助您更好地理解模块的概念。 如果您还有任何疑问,请告诉我。