我正在玩Ruby,我编写了以下代码:
module IdAndNameRedefine
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def use_id_and_name_from_module(use_attribute)
class_eval <<CODE
def id_and_name
"\#{id}-\#{#{use_attribute}.downcase}"
end
CODE
end
end
end
class Model
include IdAndNameRedefine
attr_reader :id, :name1, :name2
def initialize(id, name1, name2)
@id = id
@name1 = name1
@name2 = name2
end
def id_and_name
"#{id}-#{name1}"
end
use_id_and_name_from_module :name2
end
model = Model.new(1, "TesT", "Test number TWO")
puts model.id_and_name
Run Code Online (Sandbox Code Playgroud)
当我在这里尝试时,是id_and_name使用IdAndNameRedefine-module 动态插入的方法覆盖类Model中的类方法.当包含该模块时,它会创建一个"静态"方法(实际上,我理解它是Model.class的类方法),并且在use_id_and_name_from_module调用它时,它在Model中创建一个类方法,重新定义id_and_name使用模型的任何属性要求.
我的问题是.. 有没有更好的方法来做到这一点,或者这是"正确"的做法?我不确定我是否喜欢class_eval带有一个字符串,我需要转义值等来使这个工作.
您不必传递字符串class_eval.它可能需要一个块.事实上,我想不出一个我必须传递字符串的场合class_eval.所以我们可以像这样重写ClassMethods模块:
module ClassMethods
def use_id_and_name_from_module(use_attribute)
class_eval do
define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
end
end
end
Run Code Online (Sandbox Code Playgroud)
但是,在这种特殊情况下,我们只是告诉self来class_eval,这意味着我们已经在这个类的上下文.所以它实际上可以缩短为:
module ClassMethods
def use_id_and_name_from_module(use_attribute)
define_method(:id_and_name) {"#{id}-#{send(use_attribute).downcase}"}
end
end
Run Code Online (Sandbox Code Playgroud)
(我只是想表明它是如何class_eval运作的,因为你似乎对那部分最感兴趣.)