2011-08-13 12 views
6

यह सवाल "Given an instance of a Ruby object, how do I get its metaclass?"रूबी मेटाक्लास को देखते हुए, मैं उस उदाहरण को कैसे प्राप्त करूं जिसमें यह संलग्न है?

आप वस्तु जो करने के लिए एक metaclass या सिंगलटन वर्ग डिफ़ॉल्ट में जुड़ा हुआ है का प्रतिनिधित्व देख सकते हैं का उल्टा होता है to_s उत्पादन:

s = "hello" 
s_meta = class << s; self; end 
s_meta.to_s # => "#<Class:#<String:0x15004dd>>" 

class C; end 
c_meta = class << C; self; end 
c_meta.to_s # => "#<Class:C>" 

को क्या यह संभव है एक विधि Class.attached लागू करें जो इस ऑब्जेक्ट को लौटाता है (या शून्य अगर रिसीवर नियमित कक्षा है)?

s_meta.attached # => s 
c_meta.attached # => C 
C.attached # => nil 

उत्तर

8

वहाँ एक बदसूरत (अभी तक काम कर रहे) हैक, का उपयोग कर ObjectSpace है। जैसे, कुछ ऐसा जो आपको कभी भी खेलना और शायद डिबगिंग के अलावा उपयोग नहीं करना चाहिए। तुम सिर्फ अपनी पहली (और केवल) उदाहरण चाहते हैं, इसलिए:

ObjectSpace.each_object(self).first 

कि क्या यह एक सिंगलटन वर्ग है निर्धारित करने के लिए, अगर यह एक सिंगलटन वर्ग (या eigenclass तुम अजीब संपत्ति है कि ancestors अपने रिसीवर शामिल नहीं होगा उपयोग कर सकते हैं, या जादुई वर्ग):

ObjectSpace.each_object(self).first unless ancestors.include? self 

यदि आप किनारे के बारे में परवाह करते हैं, तो तीन वस्तुएं हैं जिनके वर्ग भी उनके सिंगलटन वर्ग हैं।

[true, false, nil].each do |o| 
    o.class.send(:define_method, :attached) { o } 
end 
3

मुझे एमआरआई के बारे में पता नहीं है।

JRuby में, निम्न रिटर्न आप क्या चाहते हैं:

require 'java' 
class A 
    def self.meta 
    class << self; self; end 
    end 
end 

A.meta.to_java.attached 
1

आप संलग्न वस्तु स्टोर करने के लिए metaclass परिभाषित कर सकते हैं।

class Class 
    attr_accessor :attached 
end 

class Object 
    def metaclass 
    meta = class << self; self; end 
    meta.attached = self 
    meta 
    end 
end 

class A; end 

a = A.new 
a_meta = a.metaclass 
p a      #=> #<A:0xb74ed768> 
p a_meta    #=> #<Class:#<A:0xb74ed768>> 

obj = a_meta.attached 
p obj     #=> #<A:0xb74ed768> 

puts obj == a   #=> true 
p A.attached   #=> nil 
1

आप inspect से (एमआरआई कार्यान्वयन में) प्राप्त कर सकते हैं:

class Class 
    def attached 
    # first, match the object reference from inspect 
    o_ref = inspect.match /0x([0-9a-f]+)>>$/ 

    # if not found, it's not a metaclass 
    return nil unless o_ref 

    # calculate the object id from the object reference  
    o_id = (o_ref[1].to_i(16) >> 1) - 0x80000000 

    # get the object from its id 
    ObjectSpace._id2ref o_id 
    end 
end 

# testing... 
class A; end 

a = A.new 
a_meta = class << a; self; end 

p a      #=> #<A:0xb7507b00> 
p a_meta     #=> #<Class:#<A:0xb7507b00>> 
p a_meta.attached   #=> #<A:0xb7507b00> 
p a == a_meta.attached  #=> true 
p A.attached    #=> nil 

वस्तु आईडी और inspect के बीच के रिश्ते के लिए, this answer देखते हैं।

संबंधित मुद्दे

 संबंधित मुद्दे