元编程:如何发现对象的真实类?

问题描述

| 我在跟Ruby中的元编程开玩笑,我做了这段代码
class Class
  def ===(other)
    other.kind_of?(self)
  end
end
class FakeClass
  def initialize(object)
    methods.each {|m| eval \"undef #{m}\" if m.to_sym != :methods }
    define = proc do |m|
      eval(<<-END)
        def #{m}(*a,&b)
          @object.#{m}(*a,&b)
        rescue Object
          raise $!.class,$!.message.gsub(\"FakeClass\",@object.class.to_s),$!.backtrace-[$!.backtrace[-caller.size-1]]
        end
      END
    end
    object.methods.each {|m| define[m] }
    def method_missing(name,*a,&b)
      if @object.methods.include?(name.to_s)
        define[name]
        eval \"@object.#{name}(*a,&b)\"
      elsif @object.methods.include?(\"method_missing\")
        eval \"@object.#{name}(*a,&b)\"
      else
        super
      end
    rescue Object
      raise $!.class,$!.backtrace-[$!.backtrace[-caller.size-1]]
    end
    @object = object
  end
end
这将创建一个模仿对象的伪类。看:
a = FakeClass.new(1)  # => 1
a.class               # => Fixnum
a.methods             # => Return all Fixnum methods
a + 1                 # => 2 (is not a FakeClass)
Fixnum === a          # => true
a.something           # => NoMethodError:
                      #    undefined method `something\' for 1:Fixnum
class Fixnum
  def foo
    true
  end
end

a.foo                 # => true
问题是,现在我不知道如何知道一个对象是真实的还是假的。换句话说,如果
#class
返回对象的真实类。存在一些纯粹的红宝石方式来区分吗? 想一想我不知道FakeClass存在或者我不知道FakeClass的名字的情况。这意味着我无法编辑FakeClass来添加like3之类的方法。 PS:我知道
a.instance_eval {self}
返回对象(不是伪造的)。但是,检查5英镑是否是假的无济于事。     

解决方法

        这是另一个答案:
a = FakeClass.new(1)
b = 1
da = Marshal.dump(a)
db = Marshal.dump(b)
puts da == db            #=> false
    ,        一个有趣的答案:更改Fixnum,看看它是否粘住。我猜它是特定于这种代理方法的,但是它将完成工作。
class Fixnum
  def foo
    return true
  end
end

a.foo # NoMethodError
我应该把它变成一个不错的函数,但是很懒:)     ,        您可以让FakeClass实现#class并返回
FakeClass
如:
class FakeClass
  #code
  def class
    FakeClass
  end
end
要查看您要代理的对象是什么类,只需调用
a.object.class #=> Fixnum
    ,        对于那个FakeClass,我了解@object,然后尝试:
a = FakeClass.new(5)

class << a
  def fake?
    self.instance_variable_defined? :@object
  end
end

a.fake?  #=> true
关于未知的FakeClass,我将比较实例变量的数量:
fake = (a.instance_variables.length > 1.instance_variables.length)
    ,        您可以在FakeClass中定义所需的任何方法,并使用response_to检查它?
a = FakeClass.new(1)

a.respond_to?( \'is_fake_class?\' )
例如。     ,        我想知道同样的事情。并且,如果您认为这只是在玩弄,请尝试深入研究Rails ActiveRecord关联(特别是:AssociationProxy),然后您会发现这种魔术(令人恐惧的一种!)正在发生。 这是我至少检测到这种情况的一种方法:
a = FakeClass.new(5)
Fixnum.instance_method(:class).bind(a)
抛出:
TypeError: bind argument must be an instance of Fixnum
我觉得虽然有更好的办法。