Chr*_*ris 2 ruby delegates design-patterns ruby-on-rails ruby-1.9.2
给出以下代码:
class ArrayProxy < BasicObject
def initialize
@array = []
end
def foo
puts 'foo'
end
def method_missing(*args, &block)
@array = @array.send(*args, &block)
end
def self.method_missing(*args, &block)
new.send(*args, &block)
end
end
Run Code Online (Sandbox Code Playgroud)
为什么将'foo'的调用委托给数组?
ruby-1.9.2-p290 :018 > ArrayProxy.new << 1
=> [1]
ruby-1.9.2-p290 :019 > ArrayProxy << 1
=> [1]
ruby-1.9.2-p290 :020 > ArrayProxy.new.foo
foo
=> nil
ruby-1.9.2-p290 :021 > ArrayProxy.foo
NoMethodError: undefined method `foo' for []:Array
Run Code Online (Sandbox Code Playgroud)
正如注释中注释的Linux_iOS.rb.cpp.c.lisp.m.sh,__send__
在这种情况下你应该使用方法,因为BasicObject
没有定义实例方法send
:
Object.instance_methods.grep /send/
# => [:send, :public_send, :__send__]
BasicObject.instance_methods.grep /send/
# => [:__send__]
Run Code Online (Sandbox Code Playgroud)
这也可以通过文档证明BasicObject
.
类中缺少send
实例方法会BasicObect
产生以下调用链:
# initial call
ArrayProxy.foo
# there's no class method 'foo', so we go to class 'method_missing' method
ArrayProxy.method_missing :foo
# inside class 'method_missing' we delegate call to new instance using 'send'
ArrayProxy.new.send :foo
# there is no instance method 'send' in ArrayProxy class (and its parent class
# BasicObject) so instance 'method_missing' is called
ArrayProxy.new.method_missing :send, :foo
# instance 'method_missing' delegates call of 'send' method to @array
@array.send :send, :foo
# that is unfolded into regular call of 'send' on @array object
@array.send :foo
# and finally 'foo' is called for @array object
@array.foo
# => NoMethodError: undefined method `foo' for []:Array
Run Code Online (Sandbox Code Playgroud)