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

uqdfh47h  于 2023-08-04  发布在  Ruby
关注(0)|答案(6)|浏览(103)

我正在经历一个阶段,试图避免临时变量和过度使用条件,我可以使用更流畅的编码风格。我非常喜欢在需要返回值的地方使用#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


显然上面的例子很简单,但这是ruby社区中非常常见的编码风格。我有时也会使用#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已经确定了什么是解决这种情况的好方法。这些例子被大大简化了。

hujrc8aj

hujrc8aj1#

定义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

kyks70gy

kyks70gy2#

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

字符串
神奇的是breaktap中返回另一个值。

Ruby 2.5有yield_self,这正是你想要的。https://stackoverflow.com/a/47890832/683157

13z8s7eq

13z8s7eq3#

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

wwodge7n

wwodge7n4#

我在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

t1qtbnec

t1qtbnec5#

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

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

字符串

gdrx4gfi

gdrx4gfi6#

class Object
  def apply_if(pred)
    if pred
      yield self
    else
      self
    end
  end
end

字符串
典型用法:

def rlrs_usage_by_group(group_id, date_range = nil)
        views = ContentView.joins(user: [:groups])
                           .where(groups: { id: group_id })
                           .where(viewable_type: 'RealStory')
                           .apply_if(date_range) {
                             _1.where(viewed_at: date_range)
                           }
      end


您的案例:

def nice_method
  something_complex(a, b, c)
    .apply_if(a_predicate_check?) { 
      _1.one_more_method_call
    }
end


甚至

something_complex(a, b, c)
     .apply_if(a_predicate_check, &:one_more_method_call)

相关问题