ruby方法链接任意对象,类

时间:2014-04-23 16:55:52

标签: ruby chain

我经常发现自己编写的ruby代码如下:

b = f1(a)
c = f2(b)
d = f3(c)
...

有没有办法将f1f2f3链接在一起,无论a,b和c的类型如何?例如

之类的例子
a.send_to(&:f1)
  .sent_to(&:f2)
  .sent_to(&:f3)

它不一定是那个,但我喜欢可以按顺序阅读的代码,“从a开始,现在应用f1,然后应用{{1} },...“

在我看来,我真正要求的是在单个对象而不是列表上使用f2的方法。例如。我能做到这一点:

map

以下(有点)工作,虽然猴子修补[a].map(&:f1) .map(&:f2) .map(&:f3) .first 似乎是一个坏主意:

Object

我说“(有点)有效”因为

class Object
  def send_to(&block)
    block.call(self)
  end  
end  

1.send_to{|x| x+1}
#=> 2

注意:This question提出类似的问题,但建议是在每个对象的特定类上定义一个方法。

5 个答案:

答案 0 :(得分:5)

你可以这样做:

d = [:f1, :f2, :f3].inject(a) { |res,f| send(f, res) }

答案 1 :(得分:4)

我认为你想要的基本上是注入和发送的组合。类似的东西:

d = [:f1, :f2, :f3].inject(a) {|memo, fun| send(fun, memo) }

答案 2 :(得分:3)

如果您觉得有必要经常这样做,那么您的API设计作为Ruby代码是错误的。而不是在函数风格中定义方法:

b = f1(a)
c = f2(b)
d = f3(c)
...

以OOP样式定义它们:

class A
  def f1; ... end # => b instance
end
class B
  def f2; ... end # => c instance
end
class C
  def f3; ... end # => d instance
end

此处,Aa所属的类,Bb所属的类,依此类推(A,{ {1}},...不必完全不同。如果您想允许任何对象,它们可以是BObject。然后,您可以简单地进行链接:

Kernel

答案 3 :(得分:1)

Ruby 2.5的.yield_self正是这样做的! https://zverok.github.io/blog/2018-01-24-yield_self.html

如果我正确地遵循了这一讨论,那么.then现在就是.yield_self的别名 https://www.reddit.com/r/ruby/comments/8nfqmt/kernelthen_is_now_an_alias_for_kernelyield_self/

答案 4 :(得分:0)

如果您从f3功能开始,则无需更改任何内容 其次,省略括号的能力很强。

例如:

a = 42

def f1 n; n end

def f2 n; n end

def f3 n; n end

f3 f2 f1 a

# => 42

使用更复杂的功能,您可以添加括号。