Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add single shortcut for reducing single element enumerables #39549

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion activerecord/test/models/book.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ class Book < ActiveRecord::Base

enum status: [:proposed, :written, :published]
enum last_read: { unread: 0, reading: 2, read: 3, forgotten: nil }
enum nullable_status: [:single, :married]
enum nullable_status: [:single, :married], _prefix: :true
enum language: [:english, :spanish, :french], _prefix: :in
enum author_visibility: [:visible, :invisible], _prefix: true
enum illustrator_visibility: [:visible, :invisible], _prefix: true
Expand Down
5 changes: 5 additions & 0 deletions activesupport/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
* Add `Enumerable#single` to return the only element contained in an Enumerable.
Will raise RangeError if the Enumerable is empty or contins multiple elements.

*Ryan O'Neill*

* `require_dependency` has been documented to be _obsolete_ in `:zeitwerk`
mode. The method is not deprecated as such (yet), but applications are
encouraged to not use it.
Expand Down
12 changes: 12 additions & 0 deletions activesupport/lib/active_support/core_ext/enumerable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,18 @@ def index_with(default = INDEX_WITH_DEFAULT)
end
end

# Returns the only element of the enumerable and raises if there is not exactly
# 1 element in the enumerable
#
# [1].single # => 1
# [].single # => RangeError: Empty enumerable
# [1, 2].single # => RangeError: Multiple elements in enumerable
def single
raise RangeError, "Empty enumerable" if count == 0
raise RangeError, "Multiple elements in enumerable" if count > 1
first
end

# Returns +true+ if the enumerable has more than 1 element. Functionally
# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
Expand Down
9 changes: 9 additions & 0 deletions activesupport/test/core_ext/enumerable_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -194,6 +194,15 @@ def test_index_with
assert_equal({ Payment.new(5) => 5, Payment.new(15) => 15, Payment.new(10) => 10 }, payments.index_with.each(&:price))
end

def test_single
assert_equal 1, [1].single

expected_raise = RangeError

assert_raise(expected_raise) { [].single }
assert_raise(expected_raise) { [ 1, 2 ].single }
end

def test_many
assert_equal false, GenericEnumerable.new([]).many?
assert_equal false, GenericEnumerable.new([ 1 ]).many?
Expand Down