我对ruby很新,我只是花时间研究github中现有ruby项目的模式。现在,我登陆了twitter's ruby project并在配置中发现了这些行:
client = Twitter::REST::Client.new do |config|
config.consumer_key = "YOUR_CONSUMER_KEY"
config.consumer_secret = "YOUR_CONSUMER_SECRET"
config.access_token = "YOUR_ACCESS_TOKEN"
config.access_token_secret = "YOUR_ACCESS_SECRET"
end
在此方法调用的declaration中,我也注意到了这一点:
module Twitter
class Client
include Twitter::Utils
attr_accessor :access_token, :access_token_secret, :consumer_key, :consumer_secret, :proxy
def initialize(options = {})
options.each do |key, value|
instance_variable_set("@#{key}", value)
end
yield(self) if block_given?
end
...
现在,当我练习时,我复制了相同的逻辑,但观察了"初始化"的内容。方法。
module Main
class Sample
attr_accessor :hello, :foo
def initialize(options={})
yield(self) if block_given?
end
def test
@hello
end
end
end
并称之为(与上面的推特代码相同)
sample = Main::Sample.new do |config|
config.hello = "world"
config.foo = "bar"
end
puts "#{sample.hello} #{sample.foo}" # outputs => world bar
puts sample.test # outputs => world
现在,我的问题是,即使我的代码中没有这些行(请参阅上面的twitter中的代码块),我的"初始化"方法,
options.each do |key, value|
instance_variable_set("@#{key}", value)
end
代码
puts "#{sample.hello} #{sample.foo}"
和puts sample.test
仍然正常。为什么会这样?实例变量是如何在这里设置的?
答案 0 :(得分:1)
这是因为您使用config.hello=
和config.foo=
之类的内容手动调用它们。
如果没有这一大块代码,那将无法工作的是:
Main::Sample.new(hello: 'world')
您需要该部分来选择并应用它们。
Twitter版本相当松懈。通常,您希望测试具有该名称的属性,而不是仅仅随机分配实例变量。通常,这是通过某种白名单来完成的:
ATTRIBUTES = %i[ hello world ]
attr_accessor *ATTRIBUTES
def initialize(options = nil)
options and options.each do |attr, value|
if (ATTRIBUTES.include?(attr))
send("#{attr}=", value)
else
raise "Unknown attribute #{attr.inspect}"
end
end
yield self if (block_given?)
end
如果使用无效选项调用,则会引发异常。