Ruby:如何将多个方法调用与"send"链接在一起

Zan*_*ndo 30 ruby metaprogramming

必须有一种内置的方式来做到这一点,对吧?

class Object
  def send_chain(arr)
    o=self
    arr.each{|a| o=o.send(a) }
    return o
  end
end
Run Code Online (Sandbox Code Playgroud)

小智 59

我只是跑过这个,它真的乞求注入:

def send_chain(arr)
  arr.inject(self) {|o, a| o.send(a) }
end
Run Code Online (Sandbox Code Playgroud)

  • 更短:`arr.inject(self,:send)` (29认同)
  • 更安全:`arr.inject(self,:try)`:) (15认同)
  • 当其中一个发送方法接受参数时,如何做到这一点? (5认同)

edg*_*ner 6

不,没有内置的方法来做到这一点.你所做的简单而简洁,更不用说危险了.使用时要小心.

另一方面,这可以扩展为接受参数:

class Object
  def send_chain(*args)
    o=self
    args.each do |arg|
      case arg
      when Symbol, String
        o = o.send arg # send single symbol or string without arguments
      when Array
        o = o.send *arg # smash the inner array into method name + arguments
      else
        raise ArgumentError
      end
    end
    return o
  end
end
Run Code Online (Sandbox Code Playgroud)

这将允许您在数组中传递方法名称及其参数,例如;

test = MyObject.new
test.send_chain :a_method, [:a_method_with_args, an_argument, another_argument], :another_method
Run Code Online (Sandbox Code Playgroud)

  • 只是在这里挑剔,但与Ruby成语保持一致,这真的应该是鸭子型. (2认同)

dgi*_*rez 5

基于先前的答案,如果您需要将参数传递给每个方法,则可以使用以下方法:

def send_chain(arr)
  Array(arr).inject(self) { |o, a| o.send(*a) }
end
Run Code Online (Sandbox Code Playgroud)

然后,您可以使用如下方法:

arr = [:to_i, [:+, 4], :to_s, [:*, 3]]
'1'.send_chain(arr) # => "555"
Run Code Online (Sandbox Code Playgroud)

此方法也接受单个参数。