我正在研究 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
当我在这里尝试做的是用 IdAndNameRedefine
模块动态插入的方法覆盖类 Model 中的类方法 id_and_name
。当包含该模块时,它会创建一个“静态”方法(实际上,据我所知,是 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
但在这种特殊情况下,我们只是告诉 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
(我只是想展示 class_eval
是如何工作的,因为你似乎对那部分最感兴趣。)
关于ruby - 包含一个模块来定义动态类方法,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1011142/