任意对象、类的ruby方法链接

任意对象、类的ruby方法链接,ruby,chain,Ruby,Chain,我经常发现自己编写的ruby代码如下所示: b = f1(a) c = f2(b) d = f3(c) ... 有没有一种方法可以将f1、f2、f3链接在一起,而不考虑a、b和c的类型?例如 a.send_to(&:f1) .sent_to(&:f2) .sent_to(&:f3) 不一定是这样,但我喜欢可以按顺序阅读的代码,如“从a开始,现在应用f1,然后应用f2,…” 我突然想到,这里我真正想要的是在单个对象上使用map,而不是列表。例如,我可以这样做:

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

b = f1(a)
c = f2(b)
d = f3(c)
...
有没有一种方法可以将
f1
f2
f3
链接在一起,而不考虑a、b和c的类型?例如

a.send_to(&:f1)
  .sent_to(&:f2)
  .sent_to(&:f3)
不一定是这样,但我喜欢可以按顺序阅读的代码,如“从
a
开始,现在应用
f1
,然后应用
f2
,…”

我突然想到,这里我真正想要的是在单个对象上使用
map
,而不是列表。例如,我可以这样做:

[a].map(&:f1)
  .map(&:f2)
  .map(&:f3)
  .first
以下(某种程度上)是可行的,尽管猴子补丁
Object
似乎不是一个好主意:

class Object
  def send_to(&block)
    block.call(self)
  end  
end  
我说“(某种程度上)有效”是因为

但是

注意:要求类似的内容,但建议在每个对象的特定类上定义一个方法。

您可以执行以下操作:

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

我认为基本上你想要的是注射和发送的结合。比如:

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

如果您觉得有必要经常这样做,那么您的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
这里,
A
A
所属的类,
B
B
所属的类,依此类推(
A
B
,…不必完全不同。如果要允许任何对象,它们可以是
对象
内核
)。然后,您可以简单地进行链接,如下所示:

a.f1.f2.f3. ...

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

例如:

a = 42

def f1 n; n end

def f2 n; n end

def f3 n; n end

f3 f2 f1 a

# => 42

对于更复杂的函数,可以添加括号

Ruby 2.5的
.yield\u self
就是这样做的!

如果我正确地理解了这个讨论,
。那么
现在是
.yield\u self

你说的“链接”是什么意思?您需要点(
)吗。您是否关心顺序:
a.f1.f2
f2.f1.a
。是其中一个更好还是两者都好?我是不是遗漏了什么?
f3(f2(f1(a))
)有什么问题?@meagar-f3(f2(f1(a))会在紧要关头起作用,但特别是当有更多的fN时,当操作有序时,其他人更容易遵循,因此它可以理解为“从
a
开始,然后应用
f1
,然后应用
f2
,”@Darek Nędza-观点很好;刚刚将问题编辑为(希望如此)澄清所需的属性。@brahn我同意,这就是为什么问题中当前的编写方式已经是最好的方式。下面的经过优化的解决方案都不应该存在于真正的代码库中,它们正在为一系列简单的函数调用添加一个非常不透明的WTF层。@archie当然会。更好的问题是,它确实存在有关系吗?
a.f1.f2.f3. ...
a = 42

def f1 n; n end

def f2 n; n end

def f3 n; n end

f3 f2 f1 a

# => 42