I want to put a method in a Ruby module such that it can be called from a class method or an instance method, using simple syntax:
我想把一个方法放在Ruby模块中,这样就可以使用简单的语法从类方法或实例方法调用它:
module MyMod
def fmt *args
args.map { | a | "You said #{a}" }
end
end
class MyClass
include MyMod
def inst
puts fmt 1,2,3
end
def self.cls
puts fmt 4,5,6
end
end
The above doesn't work because the class method (cls
) can't see the instance method fmt. If I change the definition to self.fmt
, then the instance method has to invoke it as MyMod.fmt
.
上面的方法不起作用,因为类方法(cls)不能看到实例方法fmt。如果我把定义改成self。然后实例方法必须调用它作为MyMod.fmt。
I'd like to be able to just invoke fmt (some stuff)
from both types of method. Is there a "ruby-ish" way of doing this? I can define the module as
我希望能够从这两种方法中调用fmt(一些东西)。有没有一种“像红宝石一样”的方式来做这件事?我可以将模块定义为
module MyMod
def self.fmt *args
args.map { | a | "You said #{a}" }
end
def fmt *args
MyMod.fmt args
end
end
but that's not very DRY, is it? Is there a simpler way?
但那不是很干燥,是吗?有更简单的方法吗?
2 个解决方案
#1
5
You can use advantage of Module#included
method to do it like that:
您可以利用模块#include方法来实现:
module MyMod
# here base is a class the module is included into
def self.included(base)
# extend includes all methods of the module as class methods
# into the target class
base.extend self
end
def fmt(*args)
args.map { |a| "You said #{a}" }
end
end
class MyClass
# regular include provides us with instance methods
# and defined above MyMod#included hook - with class methods
include MyMod
def inst
puts fmt(1, 2, 3)
end
def self.cls
puts fmt(4, 5, 6)
end
end
puts MyClass.cls
puts MyClass.new.inst
And here's the output:
这是输出:
You said 4
You said 5
You said 6
You said 1
You said 2
You said 3
For more detailed explanation have a look at this article.
有关更详细的解释,请参阅本文。
#2
1
Both include
and extend
the MyMod
module in MyClass
, so that the fmt
method gets added both as an instance and a class method to MyClass
.
在MyClass中包含和扩展MyMod模块,以便将fmt方法作为实例和类方法添加到MyClass中。
What Object#extend
does is add the methods of a module to a single instance. In this case, that instance is the class itself, which is why the methods will be available as class methods.
对象#extend做的是将模块的方法添加到单个实例。在本例中,该实例是类本身,这就是为什么这些方法可以作为类方法使用。
#1
5
You can use advantage of Module#included
method to do it like that:
您可以利用模块#include方法来实现:
module MyMod
# here base is a class the module is included into
def self.included(base)
# extend includes all methods of the module as class methods
# into the target class
base.extend self
end
def fmt(*args)
args.map { |a| "You said #{a}" }
end
end
class MyClass
# regular include provides us with instance methods
# and defined above MyMod#included hook - with class methods
include MyMod
def inst
puts fmt(1, 2, 3)
end
def self.cls
puts fmt(4, 5, 6)
end
end
puts MyClass.cls
puts MyClass.new.inst
And here's the output:
这是输出:
You said 4
You said 5
You said 6
You said 1
You said 2
You said 3
For more detailed explanation have a look at this article.
有关更详细的解释,请参阅本文。
#2
1
Both include
and extend
the MyMod
module in MyClass
, so that the fmt
method gets added both as an instance and a class method to MyClass
.
在MyClass中包含和扩展MyMod模块,以便将fmt方法作为实例和类方法添加到MyClass中。
What Object#extend
does is add the methods of a module to a single instance. In this case, that instance is the class itself, which is why the methods will be available as class methods.
对象#extend做的是将模块的方法添加到单个实例。在本例中,该实例是类本身,这就是为什么这些方法可以作为类方法使用。