像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_self
。 https://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