2014-05-16 27 views
1

我有一個類A,我想匿名擴展並向子類添加類方法。例如: -在定義類方法時規避Ruby的範圍門

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,因爲我相信紅寶石1.9+包含模擬define_method它增加了一類方法,它是可悲的。有沒有人有1.8.7的工作?

回答

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,我想。

0

不知道這是否會解決您的問題,但改變問候大寫(使其成爲一個常數)會工作......

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 
+1

我不認爲這是馬克思的問題。他用一個字符串作爲示例,但他想要做的是將變量或方法的值合併到當前作用域中的方法中。 –

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提到)。

2

你也可以使用extend()來撬開對象的單例類。調用extend(module)將模塊中的方法添加到調用對象(即接收者)的單例類中。所以如果你在self = A的時候調用extend(module),也就是在A類的內部,那麼模塊的方法會被插入到A的singleton類中,而A的singleton類中的方法也被稱爲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 

...其移動關閉了cla ss,而且看起來並不複雜,因爲它只打開了兩個示波器門,而不是三個。另外請注意,extend()是一個公共方法,所以它不需要私有方法的詭計,也就是說你不能指定顯式接收方,所以你必須創建一個上下文,其中self您要調用私有方法的對象。換句話說,你可以爲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!