I have a script that iterates using ObjectSpace#each_object
with no args. Then it prints how many instances exist for each class.
I realized that some
The following solution refers to the superclass of the eigenclass. As a consequence, it has the side effect of allocating the eigenclass (detectable by ObjectSpace.count_objects[:T_CLASS]
in MRI). But since BasicObject#class
is only invoked on blank slate objects (i.e. objects that are not kind-of Object
, i.e. that are not Object
s) the side effect also applies just for blank slate objects. For Object
s,
the standard Kernel#class
is invoked.
class BasicObject
def class
(class << self; self end).superclass
end
end
# tests:
puts RUBY_VERSION # 1.9.2
class B < BasicObject; end
class X; end
p BasicObject.new.class # BasicObject
p B .new.class # B
p X .new.class # X
p 6.class # Fixnum
p B.instance_method(:class).owner # BasicObject
p X.instance_method(:class).owner # Kernel
p 6.method(:class).owner # Kernel
Edit - Note:
Indeed, there is an issue with ActiveSupport::Duration
. This class uses interception (method_missing
) for redirecting messages to the :value
attribute. As a consequence, it provides false introspection for its instances. To preserve this falsity, it is necessary to use another name for the class map, e.g. the proposed __realclass__
. Thus, the modified solution might look like this:
class BasicObject
def __realclass__; (class << self; self end).superclass end
end
class Object; alias __realclass__ class end
Another way of not invoking class << self
on Object
s is via Module#===
, as suggested by Kelvin on this page.