繁体   English   中英

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

[英]self.included – including class methods from a module in Ruby

我读过这篇文章: Ruby模块 - 包括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

module M
  def self.some_class_method
     ...
  end

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

这两个例子有什么区别?

第一个代码块将ClassMethods的类方法ClassMethods到包含类,并在其上调用scope方法。 第二个没有做这些事情并且会导致NoMethodError因为模块没有scope类方法。 包含模块后, self.some_class_method将不会在包含类中提供。

有关模块包含如何在Ruby中工作的完整故事,请在此处阅读我的答案:
从Ruby中的modules / mixins继承类方法

什么是点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 ,因为它的目的是设置模块对象的配置。 然而,如果我们有类方法的自动包含,你将无法阻止它被包括在内。

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

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

模块上的“类”方法是不同的,因为它可以在模块本身上调用,因此无论它是否也添加到包含类,它都可以正常使用。 这就是为什么你有一个选择更好的原因。

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都将成为包含此模块的类的类方法

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打印在控制台上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异常,没有在类Product.new.abc #raises异常上找到的方法,没有找到类对象的方法

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM