我读过这篇文章: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
答案 0 :(得分:3)
第一个代码块将ClassMethods
中的类方法添加到包含类,并在其上调用scope
方法。第二个不执行这些操作,并且将导致NoMethodError
,因为模块没有scope
类方法。一旦包含该模块,self.some_class_method
将无法在包含类中使用。
关于模块包含如何在Ruby中工作的完整故事,请在此处阅读我的答案:
Inheriting class methods from modules / mixins in Ruby
self.included
的重点是什么?包含不是模块的唯一目的。它们还可用于其他内容,例如命名空间,或者只是存储可在模块本身上调用的各种类方法。
理论上,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
的对象上找不到方法我希望这可以帮助您更好地理解模块的概念。 如果您还有任何疑问,请告诉我。