Ruby:is_a?和instance_of?在BasicObject中

时间:2018-05-28 18:09:51

标签: ruby introspection delegation

怎么办_a?和instance_of?方法使用BasicObject的子类?

class My < BasicObject
  DELEGATE = [:is_a?, :instance_of?]
  def method_missing(name, *args, &blk)
    superclass unless DELEGATE.include? name
    ::Kernel.send(name,*args, &blk) 
  end
end

my = My.new
my.is_a? BasicObject  #=> true
my.is_a? My           #=> false ???
my.instance_of? My    #=> false ???

2 个答案:

答案 0 :(得分:2)

::Kernel.send(name,*args, &blk) calls the method name on the class Kernel with the arguments args and the block &blk.

When you run my.is_a? My name is :is_a?, *args is My, and &blk is nil. You're really running Kernel.is_a? My.

Instead, if you want to reimplement is_a? for BasicObject you can walk your class's ancestors...

  def is_a?(target)
    # I don't know how to get the current class from an instance
    # that isn't an Object, so I'm hard coding the class instead.
    return ::My.ancestors.include?(target)
  end

答案 1 :(得分:1)

您可以从is_a?

中窃取Kernel
class My < BasicObject
  define_method(:is_a?, ::Kernel.method(:is_a?))
end

m = My.new
m.is_a?(My)          #=> true
m.is_a?(BasicObject) #=> true
m.is_a?(Object)      #=> false

如果您要构建自己的对象层次结构,还可以定义自己的Kernel,例如:

module MyKernel
  [:is_a?, :instance_of?, :class].each do |m|
    define_method(m, ::Kernel.method(m))
  end
end

class My < BasicObject
  include ::MyKernel
end