This is the inverse of the question "Given an instance of a Ruby object, how do I get its metaclass?"
You can see a representation of the object to which a metaclass or singleton class is attached in the default to_s
output:
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>"
Is it possible to implement a method Class.attached
that returns this object (or nil if the receiver is a regular class)?
s_meta.attached # => s
c_meta.attached # => C
C.attached # => nil
There's an ugly (yet working) hack, using ObjectSpace. Like, something that you should never use except for playing and perhaps debugging. You just want its first (and only) instance, so:
ObjectSpace.each_object(self).first
To determine whether it's a singleton class, you can use the weird property that ancestors
will not include its receiver if it's a singleton class (or eigenclass, or magical class):
ObjectSpace.each_object(self).first unless ancestors.include? self
If you care about edgecases, there are three objects whose classes are also their singleton classes.
[true, false, nil].each do |o|
o.class.send(:define_method, :attached) { o }
end
I don't know about MRI.
In JRuby, the following returns what you want:
require 'java'
class A
def self.meta
class << self; self; end
end
end
A.meta.to_java.attached
You can get it from inspect
(in MRI implementation):
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
For the relationship between object id and inspect
, see this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With