我正在经历一个试图避免临时变量和过度使用条件的阶段,我可以使用更流畅的编码风格。我非常喜欢在我想要获得我需要返回的值的地方使用#tap
,但在我返回它之前先做一些事情。
def fluid_method
something_complicated(a, b, c).tap do |obj|
obj.update(:x => y)
end
end
Vs以上。程序:
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
显然上面的例子很简单,但这仍然是红宝石社区中非常常见的编码风格。我有时会使用#inject
通过一系列过滤器传递对象:
things.inject(whatever) do |obj, thing|
thing.filter(obj)
end
Vs以上。程序:
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
这样的几乎的愿望。
我可以在此处遵循其他模式。我意识到这对于某些人来说只是荒谬的糖,我应该转移到更有趣的问题,但我正在努力学习写一个更具功能性的风格,所以我只是好奇长期的rubyists确定了什么要成为解决这种情况的好方法。这些例子非常简单。
答案 0 :(得分:15)
定义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
答案 1 :(得分:7)
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
答案 2 :(得分:3)
我在Facets gem中找到了一个可能正是您所寻找的方法:Kernel#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
答案 3 :(得分:1)
我需要做这样的事情,我喜欢tokland的回答,但是我并不想为我正在编写的小脚本污染Object。相反,我在数组上使用了tap
:
[something_complicated].tap { |s| s[0] = new_cool_thing)}.first
答案 4 :(得分:0)
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