我正在努力理解Ruby中的元编程,并且对于Module.included
是什么感到困惑? 我目前的理解是,每当模块被包含到另一个模块或类中时,Ruby都会调用此回调函数。 除此之外,这些(元)编程构造在哪些方面使用? 有例子吗?
我正在努力理解Ruby中的元编程,并且对于Module.included
是什么感到困惑? 我目前的理解是,每当模块被包含到另一个模块或类中时,Ruby都会调用此回调函数。 除此之外,这些(元)编程构造在哪些方面使用? 有例子吗?
Module#included
允许模块在单个 include 中注入类方法和实例方法,并执行相关代码。
ActiveSupport::Concern 的文档说明了一个典型的用例。它将类方法注入到调用类中,并执行代码。在这种情况下,添加了一个scope。
module M
def self.included(base)
base.extend ClassMethods
base.class_eval do
scope :disabled, -> { where(disabled: true) }
end
end
module ClassMethods
...
end
end
这里是使用ActiveSupport::Concern编写的版本,它执行相同操作,但添加了声明性语法糖。
require 'active_support/concern'
module M
extend ActiveSupport::Concern
included do
scope :disabled, -> { where(disabled: true) }
end
class_methods do
...
end
end
included
是一个类,它将模块包含进去。这使得模块可以成为一个整体:实例方法、类方法和设置代码。
class Thing
# Class and instance methods are injected, and the new scope is added.
include M
end
如果没有included
,一个模块只能注入实例方法。类方法必须单独添加,以及执行任何设置代码。
module M
def some_instance_method
...
end
module ClassMethods
def setup
scope :disabled, -> { where(disabled: true) }
end
end
end
class Thing
# Inject the instance methods
include M
# Inject the class methods
extend M::ClassMethods
# Run any setup code.
setup
end
其他示例可能包括注册类,例如作为可用插件。
module Plugin
def self.included(base)
base.extend ClassMethods
base.class_eval do
register_as_plugin(base)
end
end
module ClassMethods
def register_as_plugin(klass)
...
end
end
end
class Thing
include Plugin
end
或者添加必要的访问器。
module HasLogger
def self.included(base)
base.class_eval do
attr_writer :logger
end
end
def logger
@logger ||= Rails.logger
end
end
class Thing
include HasLogger
end
base.
和base.class_eval
? - TPRincluded
是在模块上调用的,所以包含它的类被传递为base
。在HasLogger
示例中,在self.included
内部,self
是HasLogger
,而base
是Thing
。如果没有base.class_eval
,它会在HasLogger
中添加属性。我们想要将属性添加到Thing
中。base.class_eval
让我们做到了这一点;在base.class_eval
内部,self
是Thing
。我们也可以写成base.attr_writter :logger
。 - Schwern