У меня есть script, который выполняет итерацию с помощью ObjectSpace#each_object
без аргументов. Затем он печатает, сколько экземпляров существует для каждого класса.
Я понял, что некоторые классы переопределяют метод экземпляра #class
, поэтому мне пришлось найти другой способ получить фактический класс; Скажем, он хранится в переменной "klass"
, а klass === object
- true.
В Ruby 1.8 я мог сделать это, предполагая, что Object
не был обезврежен обеими:
Object.instance_method(:class).bind(object).call
Это сработало для экземпляров ActiveSupport::Duration
:
# 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
Но в Ruby 1.9 это больше не работает:
# 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>'
Оказывается, ActiveSupport::Duration
подклассы ActiveSupport::BasicObject
. Последнее делается для подкласса ::BasicObject
в Ruby 1.9, поэтому Object
исключается из цепочки наследования. Это не так и не может произойти в Ruby 1.8, поэтому ActiveSupport::BasicObject
является подклассом Object
.
Я не нашел способа определить фактический класс объекта Ruby 1.9, который не является экземпляром Object
. BasicObject
в 1.9 действительно голые кости:
BasicObject.instance_methods
=> [:==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__]
Идеи?
UPDATE:
Так как ruby 1.9 достиг конца жизни, я меняю свой прием на @indirect-ответ. Упоминания о рубине 1.9 выше приведены только для исторических целей, чтобы показать, что изменение от 1,8 до 1,9 было исходной причиной моей проблемы.