Ruby中是否有类似于object.in(array)的方法?

4

标准的写法似乎是array.include?(object),但我发现与object.in(array)相比,这种方式阅读和理解起来更加困难。Ruby中是否有类似的方法?

我刚刚遇到的例子是(user_role是一个字符串,allowed_user_roles是一个字符串数组):

allowed_user_roles.include?(user_role)

我知道这可能是个人偏好,但我发现这样更容易阅读和理解。

user_role.in(allowed_user_roles)

2
一个集合包含对其所持有对象的引用,反之不成立。一个对象通常不知道它被包含在哪里。因此,你说 ary.index(obj) 而不是 obj.index_within(ary)。或者说 'ruby'.start_with?('ru') 而不是 'ru'.prefix_of?('ruby')。在你的例子中,数组可能包含另一个具有相同字符的字符串,即不是同一个对象。所以你在问这个字符串:“嘿,字符串,这个数组里有没有另一个看起来和你一模一样的字符串?”而不是“嘿,数组,你是否包含一个等于这个的字符串?”对我来说,前者似乎有点奇怪。 - Stefan
2
有点奇怪,但是很好理解:if str.in? names then... :) - mrzasa
我觉得使用 object.in?(array) 更易读,更像英语。特别是在 if 语句中,我发现 if object.in?(array) 比 if array.include?(object) 更容易理解。这只是个人偏好。当然,这也取决于上下文。 - Andrew
@mrzasa,或者if str.in? name then... - Cary Swoveland
1
@Andrew,看起来很不错。但是对我而言,像needle.in?(haystack)这样的语法暗示着needle知道它是否在haystack中。它只需要回答“是”或“否”,也就是说,我期望得到一个即时响应。而haystack.include?(needle)听起来就像一项繁琐的任务。 如果没有接收器,则情况会有所不同。如果in?是一个运算符,那么obj in? collection(没有点号,不指向obj)将成为一个更普遍的问题,并且可以作为collection.include?(obj)的语法糖。如你所说,这可能只是个人偏好。 - Stefan
我找不到它,但我认为Rails有这个实现。最近我也在思考同样的问题,并考虑为Ruby编写一个功能请求。然而,定义适当的结果并不是一件简单的事情([1,2].in?([1,3,4])应该返回什么?),我理解@Stefan的想法。 - Felix
2个回答

6

这个功能不是 Ruby 核心的一部分,但是它被添加到了 ActiveSupport 核心扩展 中。如果你使用 Rails,你可以使用这个功能:

1.in?([1,2])        # => true
"lo".in?("hello")   # => true
25.in?(30..50)      # => false
1.in?(1)            # => ArgumentError

如果要在Rails之外使用它,您需要安装active_support gem,然后需要引入 active_support/core_ext/object/inclusion

# Gemfile
gem 'active_support'

# code
require 'active_support/core_ext/object/inclusion'

1
太棒了,谢谢!我正在使用Rails,所以这正是我想要的。我想我甚至在过去的几年中也使用过这个“in?”方法,但去年停止使用Rails一年后,我忘记了这个方法。 - Andrew
如果这有帮助的话,请考虑点赞并接受回答 :) - mrzasa
值得阅读 ActiveSupport 以了解 Ruby on Rails 在精炼/扩展哪些 Ruby 代码。Rails 对核心 Ruby 代码进行了如此多的改进,以至于很难区分两者。 - Matthew
这是我在stackoverflow上的第一个问题之一。 :) - Sergio Tulentsev
1
@Matthew,有一个测验可以展示区分纯 Ruby 和 Rails-flavored Ruby 有多难:https://railshurts.com/quiz/。 - mrzasa
@mrzasa 很棒 :) - Matthew

2
作为一个实验,你也可以自己创建这个(虽然猴子补丁通常不被赞同)。最初的回答。
class Object
  def in?(collection)
    raise ArgumentError unless collection.respond_to?(:include?)
    collection.include?(self)
  end
end

那么任何继承自Object的东西(几乎所有东西)都将拥有一个#in?方法。

5.in?(0..10)
=> true

'carrot'.in?(['potato', 'carrot', 'lettuce'])
=> true

“Refining”对象通常更安全且更受认可(Rails在ActiveSupport中使用了refinements)。尽管如此,这仍然是技术上的monkeypatching。 - Matthew

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接