Получить имя класса Ruby без метода класса - PullRequest
5 голосов
/ 03 апреля 2012

Как я могу получить имя класса экземпляра BasicObject в Ruby?Например, скажем, у меня есть это:

class MyObjectSystem < BasicObject
end
puts MyObjectSystem.new.class

Как мне сделать этот код успешным?

РЕДАКТИРОВАТЬ: Я обнаружил, что метод экземпляра объекта class определен как return rb_class_real(CLASS_OF(obj));,Есть ли способ использовать это из Ruby?

Ответы [ 3 ]

8 голосов
/ 03 апреля 2012

Я провел некоторое время, играя с irb, и придумал следующее:

class BasicObject
  def class
    klass = class << self; self; end # get the object's singleton class
    klass.superclass # the superclass of an object's singleton class is that object's class
  end
end

Это даст любому объекту, унаследованному от BasicObject, #class метод, который вы можете вызвать.

Редактировать

Дополнительные пояснения в соответствии с просьбой в комментариях:

Скажем, у вас есть объект obj, который является экземпляром класса Foo. obj получает методы своего экземпляра от тех, которые определены в классе Foo, в дополнение к методам, определенным в родительском классе Foo, и так далее в цепочке наследования. Ruby позволяет вам определять методы непосредственно для объекта, которые доступны только этому конкретному объекту, как этот

obj = Foo.new
def obj.hello
  puts "hello"
end

obj.hello  #=> hello

other_obj = Foo.new
other_obj.hello  #=> Method missing error

Причина, по которой вы можете это сделать, заключается в том, что у каждого объекта есть нечто, называемое одноэлементным классом (или иногда называемым собственным классом), для которого вы фактически определяете метод. Этот одноэлементный класс фактически существует в цепочке наследования объекта непосредственно под фактическим классом объекта. Это делает фактический класс объекта, Foo в этом примере, суперклассом синглтон-класса объекта.

Строка class << self, которую вы видите в ответе, является специальным синтаксисом для ввода области видимости одноэлементного класса объекта. Таким образом, в приведенном выше примере вы также можете определить метод в одноэлементном классе объекта, например:

class << obj
  def goodbye
    puts "goodbye"
  end
end

obj.goodbye  #=> goodbye

Таким образом, строка class << self; self; end открывает одноэлементный класс объекта (независимо от того, какой объект в настоящее время self) и затем возвращает self (self теперь стал одноэлементным классом), который затем может быть назначен переменной делать то, что вы хотите с

Я бы порекомендовал прочитать Metaprogramming Ruby , если вы хотите получить лучшее объяснение всего этого. Это определенно дает вам лучшее понимание объектной модели Ruby в целом.

1 голос
/ 03 апреля 2012

Мне нужно уйти через несколько минут, чтобы я сам не смог протестировать его, но кажется, что вы могли бы создать отдельный модуль, который использует ffi для вызова rb_class_real из libruby.Если бы у меня было больше времени, я бы сначала проверил его, но никто еще не ответил, и я не хочу, чтобы вы полностью оставляли вас в дураках.

0 голосов
/ 04 мая 2016

Основываясь на ответе Джеффа Смита , вы можете сделать это без изменения BasicObject:

class << object; self; end.superclass

, где object - это экземпляр объекта, класс которого вы хотите, т.е.,

irb(main):001:0> object = BasicObject.new
(Object doesn't support #inspect)
=> 
irb(main):002:0> class << object; self; end.superclass
=> BasicObject
...