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

rewriting definition of `not` in Ruby's Object

对这个 RubyMonk 示例的作用感到非常困惑。 class Not 应该是 return 一个能够反转对 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 传递参数时,它是如何 "travel" 的?它转到 not 方法,之后创建 class Not 的新实例并将其传递给该实例?
  3. method_missing 需要什么?在这种情况下可能缺少什么方法?当缺少方法时它会做什么?它只是被告知不要将参数发送给 @original 就这样吗?

method_missingNot class 中才是真正的魔法。这些是场景:

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? 方法。如果 none 实现了 smith? 方法,那么 Ruby 将以相同的方式调用 method_missing,并且您已经为 [=14] 更改了 method_missing 的行为=] class.

现在它会得到@original也就是person对象并调用person对象的方法,这个Person实例对象已经实现了这个方法,等结果出来了我们就否定结果。因此,如果调用 not.smith? 的人的 smith? 方法 return 为真,则 return 为假,因为 smith? 方法 return 为真,我们否定value 并得到 false,如果它 returns false,当我们取反时你得到 true。

编辑:

PersonObject的扩展,但是NotPerson没有联系,Person不是扩展Not Not 没有扩展 Person.

NotObject 里面的 class 并且它没有名为 smith? 的方法,Person 的实例对象得到了 smith? 方法。这就是为什么它没有在 Not 实例对象上找到 smith? 方法,然后它从继承链中调用 method_missing,而你已经为 [=] 实现了 method_missing 14=] class 它采用您调用 Object class 的 not 方法并从 Not class 创建实例对象的对象参数为 Person 实例对象。

编辑2:

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

编辑 3:

另请查看一些参考文献 method_missing 的工作原理

method_missing

second_example

回答您的问题 #1:

in what ways does this change the built-in definition of method not?

a) 不是,因为 b) not 不是方法,它是关键字,因此它的定义已融入语言规范。

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

not foo
!foo
foo.!