Ruby 从特征类确定类

Ruby 从特征类确定类,ruby,class,metaprogramming,eigenclass,Ruby,Class,Metaprogramming,Eigenclass,在Ruby中,获取类Foo的特征类非常简单 eigenclass = class << Foo; self; end #=> #<Class:Foo> eigenclass = Foo.singleton_class #2.1.0 #=> #<Class:Foo> 我不确定这是否可能,因为特征类是Class的匿名子类,所以Foo在其继承层次结构中不存在。检查特征类的方法列表也不令人鼓舞eigenclass.name返回nil。唯一能给我带来希望的

在Ruby中,获取类
Foo
的特征类非常简单

eigenclass = class << Foo; self; end
#=> #<Class:Foo>
eigenclass = Foo.singleton_class #2.1.0
#=> #<Class:Foo>
我不确定这是否可能,因为特征类是
Class
的匿名子类,所以
Foo
在其继承层次结构中不存在。检查特征类的方法列表也不令人鼓舞
eigenclass.name
返回
nil
。唯一能给我带来希望的是:

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

使用
ObjectSpace

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

ObjectSpace.each_object(e).first    #=> 'foo'
e=class'foo'
要从特征类内部获取对象,请执行以下操作:

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

#=> 'foo'  
class'foo'

以ruby实现不可知的方式精炼@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
A类;结束
B级A
在处理子类树中的分支时,这也是可靠的,这也是@Andrew Marshall优雅的答案不起作用的唯一原因。

使用传递singleton类来查找与给定singleton类匹配的所有类:

Klass = Class.new
ObjectSpace.each_object(Klass.singleton_class).to_a  #=> [Klass]
但是,由于类的singleton类继承自其超类的singleton类,因此如果要查找的类具有子类,则会得到多个结果:

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]
幸运的是,根据它们在继承树中的位置(相同的顺序)。因为我们知道所有结果都必须是同一继承树的一部分,所以我们可以采取以下步骤来获得正确的类:

candidates.sort.last  #=> A
ObjectSpace.each_object(B.singleton_class).max  #=> B

更简洁地说:考虑到
“foo.singleton\u class
,我们如何回到
“foo”
?这很聪明,但不是100%可靠:
A类;结束;B级B
我很确定这是因为大多数实现在需要之前都会避免实例化特征类,所以如果
A
在其定义中没有调用自己的特征类,那么在子类化
B
时会首先调用它。您使用的是哪个ruby版本,我仍然在运行上面的代码。我在MRI 2.1.0-p0 ATM上。如果继承树中有分支,这似乎不起作用:
class A;结束;B级
ObjectSpace.each_对象(A.singleton_类)。to_A#=>[C,B,A]
ObjectSpace.each_对象(A.singleton_类)。排序#=>参数错误:类与类的比较失败
@ChrisKeele-Hmm,有趣。不幸的是,我认为在这个问题上没有什么优雅的解决方法。当然,它失败了,因为它不知道是将
B
放在
C
之前,还是将
B
放在
C
之前。考虑到这一点,我认为你自己的答案可能是最可靠的,而且不会被过度设计。直到模块是可排序的,这在其他元编程环境中是非常好的。我想知道这个比较函数实际上是如何实现的?我的意思是这只是一个偏序,所以基于比较的排序直觉上是行不通的。但是
Enumerable#sort
是基于比较的,对吗?它必须是一种粗糙的颜色子树和字典比较元组的颜色。有点奇怪。安德鲁,有些人更喜欢
max
而不是
sort.last
:-)
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]
candidates.sort.last  #=> A
ObjectSpace.each_object(B.singleton_class).max  #=> B