如何在 Ruby 中的模块中定义类级宏?



在Ruby编程语言中,我正在创建一个具有类级宏的类,如下所示:

class Timer 
def self.add_time
def time
STDERR.puts Time.now.strftime("%H:%M:%S")      
end 
end 
end 

类方法add_time在执行时将生成一个time方法。 现在,我可以在另一个类Example中执行该类级宏,如下所示:

class Example < Timer 
add_time 
end 

当我现在在类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未在类Example上定义:NameError: undefined local variable or method ‘add_time’ for Example:Class。因此,我尝试使用extend,如下所示:

class Example 
extend Timer
add_time
end

但它给了我一个类似的错误。

所以问题是:我怎样才能获得与我的原始示例中相同的效果,其中Timer被定义为一个类,但使用模块?

正如@CarySwoveland所指出的,module Timerdef self.add_time的方法在类中包含或扩展时被忽略。只有模块的实例方法作为类的实例方法(在包含的情况下)或作为类的类方法(在扩展的情况下)添加到类中。

module Timer 
def add_time # INSTANCE METHOD !
def time
STDERR.puts Time.now.strftime("%H:%M:%S")      
end 
end 
end 

因此,解决方案的第一步是将方法def add_time声明为模块的实例方法。接下来,我们使用该模块扩展类Example,以便将模块的实例方法作为类方法添加到类Example中,并调用add_time方法:

class Example 
extend Timer # EXTEND INSTEAD OF INCLUDE
add_time
end

但是,这还没有完全按照预期工作,因为time方法现在已经生成为类方法:Example.time打印当前时间01:30:37,但类Example的实例ex不理解该方法time

因此,解决方案是将方法def time生成为实例方法而不是类方法。这可以使用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

最新更新