def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end
如果attr_name
变量等于,比方说,"params"
。这实际上会变成这样:
def params=(attr_name)
@params = attr_name
@params_history = [nil] if @params_history.nil?
@params_history << attr_name
end
为什么会这样?因为所谓的字符串插值。如果您#{something}
在字符串中写入,something
将在该字符串中进行评估和替换。
为什么上面的代码即使不在字符串中也能工作?
答案是,因为它是!
Ruby 为您提供了不同的处理方式,并且对于某些文字有另一种语法,就像这样:只要您使用相同或相应的结束符,%w{one two three}
哪里可以是任何分隔符。{}
所以它可能是%w\one two three\
or %w[one two three]
,它们都会起作用。
那个,%w
用于数组,%Q
用于双引号字符串。如果你想看到所有这些,我建议你看看这个:http ://www.ruby-doc.org/docs/ProgrammingRuby/html/language.html
现在,在那个代码中
class Class
def attr_accessor_with_history(attr_name)
attr_name = attr_name.to_s # make sure it's a string
attr_reader attr_name # create the attribute's getter
attr_reader attr_name+"_history" # create bar_history getter
class_eval %Q{ <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # STRING BEGINS
def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end
} <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< # STRING ENDS
end
end
我们可以看到带有字符串插值的整个部分都在一个%Q{ }
. 这意味着整个块是一个大的双引号字符串。这就是为什么字符串插值会在将字符串发送到 eval 之前成功完成它的工作。