2014-12-02 65 views
4

我正在學習一些元編程,並且我試圖找到一種方法。比方說,我有下面的類:在頂層定義的方法在哪裏存在?

class MyClass 
    def self.my_method 
    end 
    def your_method 
    end 
end 

用下面的代碼我可以搜索的對象空間的每個方法:

type = Class 
name = /^my_method$/ 
result = ObjectSpace.each_object(type).select do |o| 
    o.instance_methods(false).grep(name).size > 0 || o.methods.grep(name).size > 0 
end 
p result 

而且它發現它顯示下面的輸出:

[MyClass] 

由於搜索程序代碼還搜索實例方法,它在查找your_method時顯示相同的輸出。

即使有,如果我加一個單方法的對象:

mc = MyClass.new 
def mc.our_method 
end 

只是改變了搜索這樣的:

type = Object 
name = /^our_method$/ 
result = ObjectSpace.each_object(type).select do |o| 
    o.methods.grep(name).size > 0 
end 
p result 

它還發現它:

[#<MyClass:0x8f86760>] 

的問題是,我如何找到頂層對象中定義的方法?此方法:

def hidden 
end 

此外,當定義類似這樣的方法時,哪個類是當前類?

回答

5

當定義這樣的方法時,哪個類是當前類?

我們可以很容易地找出對象,我們在這個頂級的範圍檢查self是在:

self  #=> main 
self.class #=> Object 

所以我們不是在類,但它被稱爲對象的實例「主要」。


我如何找到頂層對象定義的方法?

這是它變得有趣的地方。在Ruby中的頂級範圍對象的行爲特別,但它是比較容易發現其中的方法在這裏定義的生活:

def foo; :bar; end 
method(:foo).owner  #=> Object 
Object.new.foo   #=> NoMethodError: private method `foo' called 
Object.new.send(:foo) #=> :bar 

因此,在頂層定義的方法是由對象(私有*)實例方法。您的「搜索者」不能發現這是因爲這些方法都是私人的原因,既不methods也不instance_methods包括私有方法,而不是你需要private_methodsprivate_instance_methods

Object.instance_methods.include?(:foo)   #=> false 
Object.private_instance_methods.include?(:foo) #=> true 

*注意撬(至少v0.10.1 )改變了這一點,使其在REPL public中在頂層定義方法。

+0

注意,以饗讀者(我敢肯定安德魯知道這一點):可以改爲使用'puts Object.send:private_instance_methods,false#=> foo'。一個類似的語句(用'false')表示在'Object'中沒有創建新的實例方法。 – 2014-12-02 06:41:29

0

如果你有這樣的:

def my_method() end 

class A 
    def self.my_method() end 
end 

class B < A 
    def my_method() end 
end 

class C 
    def my_method() end 
end 

,想去找一個你已經創建'my_method'方法,你可以這樣做:

ObjectSpace.each_object(Class).select do |o| 
    o.instance_methods(false).include?(:my_method) 
end 
    #=> [C, B] 

ObjectSpace.each_object(Class).select do |o| 
    o.methods(false).include?(:my_method) 
end 
    #=> [A] 

ObjectSpace.each_object(Class).select do |o| 
    o.private_instance_methods(false).include?(:my_method) 
end 
    #=> [Object]