How do I get the class of a BasicObject instance?

后端 未结 8 2038
小鲜肉
小鲜肉 2020-12-08 03:03

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

8条回答
  •  北海茫月
    2020-12-08 03:28

    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 Objects) the side effect also applies just for blank slate objects. For Objects, 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 Objects is via Module#===, as suggested by Kelvin on this page.

提交回复
热议问题