我有一个类A
,我想匿名扩展并向子类添加一个类方法。 E.g:
class A
end
Class.new A do
def self.new_class_method
puts 'I am a class method'
end
end.new_class_method
=> I am a class method
上述示例效果很好,除非您想要访问def self.new_class_method
块之外的某些变量。 E,G,
greeting = 'hello'
Class.new A do
def self.new_class_method
puts greeting + ' I am a class method'
end
end.new_class_method
=> NameError: undefined local variable or method `greeting'
我正在使用Ruby 1.8.7,这很难过,因为我相信Ruby 1.9+包含一个类似define_method
的模拟,它增加了一个类方法。有没有人有1.8.7的解决方法?
答案 0 :(得分:4)
我在 Ruby 1.8.7 中测试了以下内容: -
greeting = 'hello'
class A
end
Class.new A do
meta_klass = class << self; self ;end
meta_klass.send(:define_method, :new_class_method) do
puts greeting + ' I am a class method'
end
end.new_class_method
# >> hello I am a class method
由于Ruby 1.8.7不支持Object#singleton_class
,我使用了meta_klass = class << self; self ;end
。我认为这个方法可用于 1.9.2 。
答案 1 :(得分:2)
您也可以使用extend()来打开对象的单例类。调用extend(模块)将模块中的方法添加到调用对象(即接收者)的单例类中。因此,如果你在self = A时调用extend(module),即在类A中调用,那么模块的方法将被插入到A的单例类中,而A的单例类中的方法也被称为A的类方法:
class A
end
greeting = "hello"
Class.new(A) do
extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
)
end.greet
--output:--
hello
你可以像这样重写(虽然那时并不那么棘手):
class A
end
greeting = "hello"
Class.new(A) do
m = Module.new do
define_method(:greet) do
puts greeting
end
end
extend(m)
end.greet
......与...没什么不同。
class A
end
greeting = "hello"
m = Module.new do
define_method(:greet) do
puts greeting
end
end
Class.new(A) do
extend(m)
end.greet
...它将闭包移出了类,并且看起来并不是很棘手,因为它只打开了两个范围门而不是三个。
另请注意,extend()是一个公共方法,所以它不需要私有方法的技巧,即你不能指定一个显式接收器,所以你必须创建一个自我是要调用私有方法的对象。换句话说,您可以为extend()指定显式接收器。 Class.new(A)返回的类怎么样?
class A
end
greeting = "hello"
Class.new(A).extend(
Module.new do
define_method(:greet) do
puts greeting
end
end
).greet
--output:--
hello
嘿,加上“.greet”就行了!哦,哦,有一个衬垫的材料:
class A
end
greeting = "hello"
Class.new(A).extend(Module.new {define_method(:greet) {puts greeting} }).greet
--output:--
hello
Yeech!
答案 2 :(得分:1)
更一般地说,
class A
end
class Object
def meta_def name, &blk
(class << self; self; end).instance_eval { define_method name, &blk }
end
end
greeting = 'hello'
Class.new A do
meta_def :new_class_method do
puts greeting + ' I am a class method'
end
end.new_class_method
#=> hello I am a class method
如果您觉得这很有用,请不要感谢我,谢谢lucky stiff {我在Jay Fields看到的那些内容)。
答案 3 :(得分:0)
不确定这是否可以解决您的问题,但将Greeting更改为大写(使其成为常量)将有效......
class A
end
Greeting = 'hello'
Class.new A do
def self.new_class_method
puts Greeting + ' I am a class method'
end
end.new_class_method