我的代码在#
部分中有一个class_eval
符号。这对我来说很陌生,这是什么意思?
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{
def #{attr_name}=(attr_name)
@#{attr_name} = attr_name
@#{attr_name}_history = [nil] if @#{attr_name}_history.nil?
@#{attr_name}_history << attr_name
end
}
end
end
答案 0 :(得分:4)
此功能称为字符串插值。它实际上做的是用#{attr_name}
替换attr_name
实际值。您发布的代码显示了一个用例 - 当您想在运行时使用具有通用名称的变量时。
然后更常使用的用例如下:
您可以这样使用字符串:"Hello, #{name}!"
和#{name}
将自动替换 - 这是非常方便的功能。语法糖。
但请注意代码中的%Q
- 这会将以下代码转换为字符串,然后传递给class_eval
并在那里执行。详细了解here。没有它,它当然不会起作用。
答案 1 :(得分:2)
为什么下一个代码在class_eval中有#?
这是字符串插值。
一个例子:
x = 12
puts %Q{ the numer is #{x} }
# >> the numer is 12
%Q Here
当你在字符串中有更多的引号字符时,这是双引号字符串的替代方法。而不是在它们前面加上反斜杠。
答案 2 :(得分:2)
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
为什么会这样?因为称为String插值的东西。如果在String中写#{something}
,则会在该String中评估并替换something
。
为什么上述代码即使不在字符串中也能正常工作?
答案是,因为它!
Ruby为您提供了不同的处理方式,并且对于某些文字有一种替代语法,如下所示:%w{one two three}
其中{}
可以是任何分隔符,只要您使用相同的分隔符或相应的结束。所以它可能是%w\one two three\
或%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{ }
内。这意味着整个块是一个大的双引号字符串。这就是为什么在将String发送到eval之前,String插值将成功完成它的工作。