在Ruby的对象中重写`not`的定义

时间:2016-01-01 21:42:47

标签: ruby metaprogramming

真的很困惑这个RubyMonk示例的作用。 class Not应该返回一个能够将调用反转为Object#not的对象。

class Object
  def not
    Not.new(self)
  end

  class Not
    def initialize(original)
      @original = original
    end

    def method_missing(sym, *args, &blk)
      !@original.send(sym, *args, &blk)
    end
  end
end

class Person
  def initialize(name)
    @name = name
  end

  def smith?
    @name == "Smith"
  end
end

这就是测试的方式

puts Person.new("Smith").not.smith?
puts Person.new("Ziggy").not.smith?

我不明白的是

  1. 这会以何种方式更改方法not的内置定义?
  2. 将参数传递给not时,它是如何"旅行"?它转到not方法,之后创建了class Not的新实例并将其传递给该实例?
  3. method_missing需要什么?在这种情况下可能会缺少什么方法?当有方法丢失时它会怎么做?只是告诉他们不要将论据发送到@original那就是它了吗?

2 个答案:

答案 0 :(得分:3)

回答你的问题#1:

  

这会以什么方式改变方法not的内置定义?

a)它没有,因为b)not不是一个方法,它是一个关键字,因此它的定义被烘焙到语言规范中。

更准确地说:not关键字转换为方法!的调用,就像!运算符一样,因此以下所有三个都是等效的:

not foo
!foo
foo.!

答案 1 :(得分:2)

method_missing课程中的

Not是真正的魔力。这是场景:

Person.new("Smith")   # you create new person
Person.new("Smith").not # calls method #not on the person object instance
# the method #not will create new instance of the class Not and passing self as argument
# passing the person on which you have called the method 
# then the initialize method of the Not class gets called
# because you want to create new object of the Not class and 
# @original is the person on which you have called the method #not
Person.new("Smith").not.smith?  # will call method #smith? on the Not object instance

到目前为止发生的事情

person = Person.new("Smith")
not_class_object = person.not
not_class_object.smith? # there is no method named #smith? in the Not class

如果不存在任何方法,则检查所有层次结构,并查看继承链中的任何内容是否已实现smith?方法。如果没有实现smith?方法,则Ruby将以相同的方式调用method_missing,并且您已更改method_missingNot的行为。

现在它将获得@original person对象并调用person对象上的方法,此Person实例对象已实现该方法,当结果出现时,我们将取消结果。因此,如果smith?方法为调用not.smith?的人返回true将返回false,因为smith?方法返回true我们否定该值并获取false,如果它返回false,则当我们否定时你明白了。

编辑:

PersonObject的扩展名,但NotPerson之间没有关联,Person未延伸Not和{ {1}}未展开Not

PersonNot内的类,它没有名为Object的方法,smith?的实例对象获得了Person方法。这就是为什么它没有在smith?实例对象上找到smith?方法,然后从继承链调用Not,并且为{{method_missing实现了method_missing 1}}类,它使用Notnot方法调用的对象,并从Object类创建实例对象,参数为Not实例对象。< / p>

EDIT2:

Person

EDIT3:

还查看一些参考class NotPerson ... # some code ... end p1 = Person.new("Smith") p2 = Person.new("Ziggy") p3 = NotPerson.new("something") p1.smith? # -> true p2.smith? # -> false p3.smith? # Error there is no method named #smith? in NotPerson class not_p1 = p1.not not_p2 = p2.not not_p3 = p3.not not_p1.smith? # -> false # Because there is no method #smith? on #not class, and #method_missing is called not_p1.smith? # is eqivavlent to !(p1.smith?) not_p2.smith? # -> true not_p3.smith? # Error there is no method #smith? definedin NotPerson class 如何工作

method_missing

second_example