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

发布于 2024-12-12 04:48:19 字数 1274 浏览 0 评论 0原文

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

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

I'm going through a phase of trying to avoid temporary variables and over-use of conditional where I can use a more fluid style of coding. I've taken a great liking to using #tap in places where I want to get the value I need to return, but do something with it before I return it.

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

Vs. the procedural:

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

Obviously the above examples are simple, but this is a pretty common coding style in the ruby community nonetheless. I'll sometimes use #inject to pass an object through a series of filters too:

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

Vs. the procedural:

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

Now I'm facing repeated use of a condition like the following, and looking for a more fluid approach to handling it:

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

The (slightly) cleaner solution is to avoid the temporary variable at the cost of duplication:

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

I can't help but feeling the desire to use something almost like #tap here though.

What other patterns might I follow here. I realise this is all just nonsensical sugar to some people and that I should just move onto more interesting problems, but I'm trying to learn to write in a more functional style, so I'm just curious what long-term rubyists have determined to be good ways to tackle situations like this. These examples are hugely simplified.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

在梵高的星空下 2024-12-19 04:48:19

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

Define Object#as:

class Object
  def as
    yield self
  end
end

And now you can write:

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
温柔女人霸气范 2024-12-19 04:48:19
def best_nice_method
  something_complex(a, b, c).tap |obj|
    break obj.one_more_method_call if a_predicate_check?
  end
end

神奇之处在于 tap 中的 break 返回另一个值。

new

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

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

The magic is break in tap returns another value.

new

ruby 2.5 has yield_self which exactly you want.
https://stackoverflow.com/a/47890832/683157

微暖i 2024-12-19 04:48:19

instance_eval 可能会被滥用于此目的

"this".instance_eval { |test|测试+“有效”}

从 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

instance_eval can be misused for this purpose

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

since 2.5 it is possible to use yield_self

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

Read more:

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

诗酒趁年少 2024-12-19 04:48:19

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

I found a method in the Facets gem that might be what you were looking for: Kernel#ergo

So your original method:

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

might end up looking something like this:

require 'facets/kernel/ergo'

def nice_method
  something_complex(a, b, c).ergo do |_| 
    a_predicate_check? ? _.one_more_method_call : _
  end
end
独享拥抱 2024-12-19 04:48:19

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

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

I needed to do something like this and I like tokland's answer, but I didn't want to pollute Object for the small script I was writing. Instead, I made use of tap on an array:

[something_complicated].tap { |s| s[0] = new_cool_thing)}.first
清引 2024-12-19 04:48:19
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)
class Object
  def apply_if(pred)
    if pred
      yield self
    else
      self
    end
  end
end

Typical usage:

      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

Your case:

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

or even

  something_complex(a, b, c)
     .apply_if(a_predicate_check, &:one_more_method_call)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文