9

在 Ruby 中,获取类的 eigenclassFoo很简单

eigenclass = class << Foo; self; end
#=> #<Class:Foo>
eigenclass = Foo.singleton_class #2.1.0
#=> #<Class:Foo>

我对逆运算感兴趣:从 eigenclass 本身获取 eigenclass 的所有者:

klass = eigenclass.owner
#=> Foo

我不确定这是否可能,因为 eigenclass 是 的匿名子类Class,因此Foo在其继承层次结构中没有出现。检查 eigenclass 的方法列表也不令人鼓舞。eigenclass.name返回nil。唯一让我希望这是可能的:

Class.new # normal anon class
#=> #<Class:0x007fbdc499a050>
Foo.singleton_class
#=> #<Class:Foo>

显然,本征类的to_s方法对所有者有所了解,即使在本征类被实例化时该信息是硬编码的。因此,我知道的唯一方法是一些 hacky 之Object.const_getting类的

Object.const_get eigenclass.to_s[/^#\<Class\:(?<owner>.+)\>$/, :owner]
#=> Foo
4

3 回答 3

6

使用ObjectSpace.each_object将单例类传递给它来查找与给定单例类匹配的所有类:

Klass = Class.new
ObjectSpace.each_object(Klass.singleton_class).to_a  #=> [Klass]

但是,由于一个类的单例类继承自其超类的单例类,如果您要查找的类具有子类,您将获得多个结果:

A = Class.new
B = Class.new(A)
B.singleton_class.ancestors.include?(A.singleton_class)  #=> true

candidates = ObjectSpace.each_object(A.singleton_class)
candidates.to_a  #=> [A, B]

幸运的是,类/模块可以按它们在继承树中的位置进行排序(ancestors给出相同的顺序)。由于我们知道所有结果必须是同一继承树的一部分,因此我们可以max获取正确的类:

candidates.sort.last  #=> A
ObjectSpace.each_object(B.singleton_class).max  #=> B
于 2014-02-01T22:18:03.033 回答
2

以与红宝石实现无关的方式完善@BroiSatse 的答案,

class A; end
class B < A; end
class C < A; end
eigenclass = A.singleton_class
ObjectSpace.each_object(eigenclass).find do |klass|
  klass.singleton_class == eigenclass
end
#=> A

这在处理子类树中的分支时也是可靠的,这是@Andrew Marshall 的优雅答案不起作用的唯一原因。

于 2014-02-01T22:17:51.540 回答
1

使用ObjectSpace

e = class << 'foo'; self; end

ObjectSpace.each_object(e).first    #=> 'foo'

要从 eigenclass 内部获取对象:

class << 'foo'
  puts ObjectSpace.each_object(self).first
end

#=> 'foo'  
于 2014-02-01T21:51:15.653 回答