32

我正在经历一个尝试避免临时变量和过度使用条件的阶段,我可以使用更流畅的编码风格。我非常喜欢#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通过一系列过滤器来传递一个对象:

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

我可以在这里遵循哪些其他模式。我意识到这对某些人来说只是无意义的糖,我应该转向更有趣的问题,但我正在努力学习以更实用的风格写作,所以我只是好奇长期的 ruby​​ist 已经确定了什么成为解决此类情况的好方法。这些例子被大大简化了。

4

5 回答 5

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
于 2011-10-24T16:54:59.207 回答
12
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

于 2017-11-01T02:29:26.360 回答
6

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

于 2018-09-06T21:26:45.497 回答
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
于 2013-01-17T01:59:04.390 回答
1

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

[something_complicated].tap { |s| s[0] = new_cool_thing)}.first
于 2015-11-05T00:17:30.323 回答