如何在Ruby的模块中定义class级的宏?
How to define a class-level macro in a module in Ruby?
在Ruby编程语言中,我正在创建一个带有class级宏的class,如下:
class Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
class方法add_time
,执行时会生成time
方法。
现在,我可以在另一个 class Example
中执行那个 class 级别的宏,如下所示:
class Example < Timer
add_time
end
当我现在在 class Example
的一个实例上调用 time
时,time
方法出现在那里,正如我预期的那样:
ex = Example.new
ex.time
并打印当前时间:23:18:38
.
但是现在我想把add_time
宏放在一个模块里,整体效果还是一样的。我试过这样的 include
:
module Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
class Example
include Timer
add_time
end
ex = Example.new
ex.time
但随后我收到一条错误消息,指出方法 add_time
未在 class Example
上定义:NameError: undefined local variable or method ‘add_time’ for Example:Class
。所以然后我尝试使用 extend
而不是像这样:
class Example
extend Timer
add_time
end
但它给了我一个类似的错误。
所以问题是:我如何才能获得与原始示例相同的效果,其中 Timer
被定义为 class,但使用模块代替?
正如@CarySwoveland 指出的那样,module Timer
中的方法 def self.add_time
在 class 中包含或扩展时被忽略。只有模块的实例方法被添加到 class 作为 class 的实例方法(在包含的情况下)或作为 class 的 class 方法(在扩展的情况下) ).
module Timer
def add_time # INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
所以解决方案的第一步是将方法def add_time
声明为模块的实例方法。接下来,我们使用该模块扩展 class Example
,以便模块的实例方法作为 class 方法添加到 class Example
中,我们调用 add_time
方法:
class Example
extend Timer # EXTEND INSTEAD OF INCLUDE
add_time
end
但是,由于 time
方法现在已生成为 class 方法,所以这还不能完全按预期工作:Example.time
打印当前时间 01:30:37
,但是 class Example
的实例 ex
不理解方法 time
.
因此,解决方案是将方法 def time
生成为实例方法而不是 class 方法。这可以使用 class_eval
来完成,这使我们得到以下可行的解决方案:
module Timer
def add_time # INSTANCE METHOD !
self.class_eval do # USE class_eval TO DEFINE AN INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
end
class Example
extend Timer # USE EXTEND TO ADD add_time AS A CLASS METHOD
add_time
end
ex = Example.new
ex.time
在Ruby编程语言中,我正在创建一个带有class级宏的class,如下:
class Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
class方法add_time
,执行时会生成time
方法。
现在,我可以在另一个 class Example
中执行那个 class 级别的宏,如下所示:
class Example < Timer
add_time
end
当我现在在 class Example
的一个实例上调用 time
时,time
方法出现在那里,正如我预期的那样:
ex = Example.new
ex.time
并打印当前时间:23:18:38
.
但是现在我想把add_time
宏放在一个模块里,整体效果还是一样的。我试过这样的 include
:
module Timer
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
class Example
include Timer
add_time
end
ex = Example.new
ex.time
但随后我收到一条错误消息,指出方法 add_time
未在 class Example
上定义:NameError: undefined local variable or method ‘add_time’ for Example:Class
。所以然后我尝试使用 extend
而不是像这样:
class Example
extend Timer
add_time
end
但它给了我一个类似的错误。
所以问题是:我如何才能获得与原始示例相同的效果,其中 Timer
被定义为 class,但使用模块代替?
正如@CarySwoveland 指出的那样,module Timer
中的方法 def self.add_time
在 class 中包含或扩展时被忽略。只有模块的实例方法被添加到 class 作为 class 的实例方法(在包含的情况下)或作为 class 的 class 方法(在扩展的情况下) ).
module Timer
def add_time # INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
所以解决方案的第一步是将方法def add_time
声明为模块的实例方法。接下来,我们使用该模块扩展 class Example
,以便模块的实例方法作为 class 方法添加到 class Example
中,我们调用 add_time
方法:
class Example
extend Timer # EXTEND INSTEAD OF INCLUDE
add_time
end
但是,由于 time
方法现在已生成为 class 方法,所以这还不能完全按预期工作:Example.time
打印当前时间 01:30:37
,但是 class Example
的实例 ex
不理解方法 time
.
因此,解决方案是将方法 def time
生成为实例方法而不是 class 方法。这可以使用 class_eval
来完成,这使我们得到以下可行的解决方案:
module Timer
def add_time # INSTANCE METHOD !
self.class_eval do # USE class_eval TO DEFINE AN INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")
end
end
end
end
class Example
extend Timer # USE EXTEND TO ADD add_time AS A CLASS METHOD
add_time
end
ex = Example.new
ex.time