这是一个外部类,其class
方法被覆盖。
class Foo
def class
"fooo"
end
end
class Boo < Foo
end
class Moo < Foo
end
现在我有一个子类的实例。是否可以找出它属于哪个类?
foo.class # currently returns 'fooo', I want get Boo or Moo.
答案 0 :(得分:8)
您可以使用instance_method
从安全的地方(例如class
)抓取Object
方法作为UnboundMethod
,将该未绑定方法绑定到您的实例,然后叫它。例如:
class_method = Object.instance_method(:class)
# #<UnboundMethod: Object(Kernel)#class>
class_method.bind(Boo.new).call
# Boo
class_method.bind(Moo.new).call
# Moo
class_method.bind(Foo.new).call
# Foo
当然,如果您还替换了Object#class
(或Kernel#class
),那么所有的赌注都消失了,您将面临一个全新的痛苦与困惑世界。
答案 1 :(得分:5)
我更喜欢@Stefan和@muistooshort的解决方案,但这是替代方案。
class Foo
def class
"foo"
end
end
class Boo < Foo
end
class Who < Boo
def class
"who"
end
end
boo = Boo.new
boo.method(:class).super_method.call
#=> Boo
who = Who.new
who.method(:class).super_method.call
#=> "foo"
who.method(:class).super_method.super_method.call
#=> Who
更一般地:
def my_class(obj)
m = obj.method(:class)
until m.owner == Kernel do
m = m.super_method
end
m.call
end
my_class(boo)
#=> Boo
my_class(who)
#=> Who
答案 2 :(得分:5)
对象的类也恰好是其superclass
的singleton_class
:
Boo.new.singleton_class.superclass
#=> Boo
Moo.new.singleton_class.superclass
#=> Moo
Foo.new.singleton_class.superclass
#=> Boo
答案 3 :(得分:3)
此解决方案有点笨拙,但覆盖class
本身也是很笨拙的,因此在罗马时,请像罗马人那样做:
class Foo
def class
'fooo'
end
end
class Boo < Foo
end
boo = Boo.new
=> #<Boo:0x00007fd2361feba8>
boo.class
=> "fooo"
boo.inspect
=> "#<Boo:0x00007fd2361feba8>"
klass = boo.inspect.split(':').reject(&:empty?)[0..-2].join('::').sub('#<', '')
=> "Boo"
boo.is_a?(Kernel.const_get(klass))
=> true
这也适用于模块中的类:
module Bar
class Foo
def class
'fooo'
end
end
class Boo < Foo
end
end
boo = Bar::Boo.new
=> #<Bar::Boo:0x00007fe5a20358b0>
boo.class
=> "fooo"
boo.inspect
=> "#<Bar::Boo:0x00007fe5a20358b0>"
klass = boo.inspect.split(':').reject(&:empty?)[0..-2].join('::').sub('#<', '')
=> "Bar::Boo"
boo.is_a?(Kernel.const_get(klass))
=> true