在Rails中,看到这样的模式很常见(例如在config/environments/development.rb
中):
Rails.application.configure do
config.some_option = some_value
end
由于我最近正在研究如何配置blocks
工作并最终发现this very similar pattern,configure
方法初始化(通常记忆)的一个实例,因此我被这个成语所吸引。配置类(具有配置选项的访问器)并将该实例对象生成块。像这样:
module Clearance
class << self
attr_accessor :configuration
end
def self.configure
self.configuration ||= Configuration.new
yield(configuration)
end
class Configuration
attr_accessor :mailer_sender
def initialize
@mailer_sender = 'donotreply@example.com'
end
end
end
这就是Clearance.configure {|config| config.mailer_sender = 'something'}
工作的原因,因为它将配置类的实例产生为块变量config
。
但是Rails的做法是,没有变量被传递给那个块。没有Rails.application.configure do |config|
,因此该块可以更改配置对象访问器。我认为config
在该区块内未定义,但它不是。
尝试查看rails源代码,我怀疑它与configurable module有关,但我无法100%理解我在那里找到的代码。
答案 0 :(得分:1)
实际的Rails铁路似乎没有使用Configurable
模块。
我没有声称完全了解它的用法,但显然是delegate
方法used in Railtie
class
delegate :config, to: :instance
添加config
属性,指向Rails::Application::Configuration
的实例 - 我们稍后通过Rails.application.config
访问的实例。
答案 1 :(得分:0)
它使用instance_eval
(或基本相同的class_eval
)来评估指定对象上下文中的块。在该块内,该对象成为隐式接收器(即self
)。
例如,使用您的代码:
module Clearance
class << self
attr_accessor :configuration
end
def self.configure(&block)
self.configuration ||= Configuration.new
configuration.instance_eval(&block)
end
class Configuration
attr_accessor :mailer_sender
def initialize
@mailer_sender = 'donotreply@example.com'
end
end
end
Clearance.configure { self.mailer_sender = 'something' }
Clearance.configuration.mailer_sender #=> "something"