像tap这样的组合方法,但能够返回不同的值吗?

我正在经历一个试图避免临时变量和过度使用条件的阶段,我可以使用更流畅的编码风格。 我非常喜欢在我想要获得我需要返回的值的地方使用#tap ,但在返回它之前先做一些事情。

 def fluid_method something_complicated(a, b, c).tap do |obj| obj.update(:x => y) end end 

比。 程序:

 def non_fluid_method obj = something_complicated(a, b, c) obj.update(:x => y) obj # <= I don't like this, if it's avoidable end 

显然上面的例子很简单,但这仍然是ruby社区中非常常见的编码风格。 我有时会使用#inject通过一系列filter传递一个对象:

 things.inject(whatever) do |obj, thing| thing.filter(obj) end 

比。 程序:

 obj = whatever things.each do |thing| obj = thing.filter(obj) end obj 

现在我正面临着如下条件的重复使用,并寻找一种更流畅的方法来处理它:

 def not_nice_method obj = something_complex(a, b, c) if a_predicate_check? obj.one_more_method_call else obj end end 

(稍微)更清洁的解决方案是以复制为代价避免临时变量:

 def not_nice_method if a_predicate_check? something_complex(a, b, c).one_more_method_call else something_complex(a, b, c) end end 

我不禁感到渴望在这里使用类似#tap东西。

我可以在这里遵循哪些其他模式。 我意识到这对于某些人来说只是荒谬的糖,我应该转向更有趣的问题,但我正在努力学习写一个更具function性的风格,所以我只是好奇长期的ruby家族已经确定了什么要成为解决这种情况的好方法。 这些例子非常简单。

Object#as定义Object#as

 class Object def as yield self end end 

现在你可以写:

 def not_sure_this_is_nice_enough_method1 something_complex(a, b, c).as do |obj| a_predicate_check? ? obj.one_more_method_call : obj end end 
 def best_nice_method something_complex(a, b, c).tap |obj| break obj.one_more_method_call if a_predicate_check? end end 

神奇的是break tap返回另一个值。

ruby 2.5有你想要的yield_selfhttps://stackoverflow.com/a/47890832/683157

我在Facets gem中找到了一个可能是你正在寻找的方法: 内核#ergo

所以你原来的方法:

 def not_nice_method obj = something_complex(a, b, c) if a_predicate_check? obj.one_more_method_call else obj end end 

可能最终看起来像这样:

 require 'facets/kernel/ergo' def nice_method something_complex(a, b, c).ergo do |_| a_predicate_check? ? _.one_more_method_call : _ end end 

我需要做这样的事情,我喜欢tokland的回答,但我不想为我写的小脚本污染Object。 相反,我在数组上使用了tap

 [something_complicated].tap { |s| s[0] = new_cool_thing)}.first 

instance_eval可能被滥用于此目的

"this".instance_eval { |test| test + " works" }

从2.5开始就可以使用yield_self

"easy".yield_self{ |a| a + " peasy" }

阅读更多:

https://ruby-doc.org/core-1.9.3/BasicObject.html#method-i-instance_eval

https://ruby-doc.org/core-2.5.0/Object.html#method-i-yield_self