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 classes redefine the #class
instance method, so I had to find another way to get the actual class; Let's say it's stored in variable "klass"
, and klass === object
is true.
In Ruby 1.8 I could do this, assuming Object
wasn't monkeypatched:
Object.instance_method(:class).bind(object).call
This worked for ActiveSupport::Duration
instances:
# Ruby 1.8
# (tries to trick us)
20.seconds.class
=> Fixnum
# don't try to trick us, we can tell
Object.instance_method(:class).bind(20.seconds).call
=> ActiveSupport::Duration
But, in Ruby 1.9 this no longer works:
# Ruby 1.9
# we are not smart...
Object.instance_method(:class).bind(20.seconds).call
TypeError: bind argument must be an instance of Object
from (irb):53:in `bind'
from (irb):53
from /Users/user/.rvm/rubies/ruby-1.9.2-p0/bin/irb:17:in `<main>'
It turns out that ActiveSupport::Duration
subclasses ActiveSupport::BasicObject
. The latter is made to subclass ::BasicObject
in Ruby 1.9, so Object
is excluded from the inheritance chain. This doesn't, and can't, happen in Ruby 1.8, so ActiveSupport::BasicObject
is a subclass of Object
.
I haven't found any way to detect the actual class of a Ruby 1.9 object that isn't an instance of Object
. BasicObject
in 1.9 is really bare-bones:
BasicObject.instance_methods
=> [:==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__]
Ideas?
UPDATE:
Since ruby 1.9 reached end-of-life, I'm changing my accept to @indirect's answer. The mentions of ruby 1.9 above are merely for historical purposes, to show that the change from 1.8 to 1.9 was the original cause of my problem.
If you can upgrade to Ruby 2.0, you don't need to implement anything at all:
>> Kernel.instance_method(:class).bind(BasicObject.new).call
=> BasicObject