如果错误地重写了元类方法,那么单例方法属于什么?

时间:2014-03-24 17:55:19

标签: ruby metaprogramming singleton-methods

在“rubymonk”和其他一些ruby资源中,提到当你在一个对象上定义一个单例方法时,Ruby会将这个新方法添加到对象的元类中。对?还有一个访问元类的技巧,就是它:

class Object
  def metaclass
    class << self
      self
    end
  end
end

foo = "I'm a string object"

def foo.shout
  puts self.upcase
end

foo.shout

p foo.metaclass.class
p foo.class.instance_methods.include? :shout
p foo.metaclass.instance_methods.include? :shout

正如我们所料,结果是:

I'M A STRING OBJECT
Class
false
true

一切都好。但是如果我们更改元类方法以返回Hash而不是self呢?

  class Object
      def metaclass
        class << self
          Hash
        end
      end
    end

然后我们检查这些事情:

p foo.class.instance_methods.include? :shout
p foo.metaclass.instance_methods.include? :shout
p String.instance_methods.include? :shout
p Object.instance_methods.include? :shout
p Hash.instance_methods.include? :shout
是的,所有这些都是假的:

false
false
false
false
false

问题是,shout方法现在属于什么?它不是元类。那是什么?!

3 个答案:

答案 0 :(得分:1)

仍然是元类,你刚刚删除了直接访问它的能力......

foo.instance_eval { class << self; self; end.instance_methods.include?(:shout) }
  => true

答案 1 :(得分:1)

shout仍然属于元类,你甚至没有失去访问元类的能力(正如其他答案所暗示的那样)。您刚刚在名为Object的{​​{1}}上创建了一个无用的方法。这并不能阻止你做以下事情:

metaclass

请注意, (class << any_object_here; self; end) 语法是核心Ruby语法,只能通过重新定义方法来“更改”。

答案 2 :(得分:0)

shout方法仍然属于foo的元类,您只是无权访问它,因为您选择始终从方法返回Hashfoo.shout的方法定义不受metaclass方法语义的影响。