Skip to content

✨ Add SequenceSet#each_ordered_number #386

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

Merged
merged 1 commit into from
Jan 25, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 26 additions & 7 deletions lib/net/imap/sequence_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ class IMAP
# without deduplicating numbers or coalescing ranges, and returns +self+.
# - #entries: Returns an Array of every number and range in the set,
# unsorted and without deduplicating numbers or coalescing ranges.
# - #each_ordered_number: Yields each number in the ordered entries and
# returns +self+.
#
# === Methods for \Set Operations
# These methods do not modify +self+.
Expand Down Expand Up @@ -990,19 +992,36 @@ def each_range # :yields: range
# Returns an enumerator when called without a block (even if the set
# contains <tt>*</tt>).
#
# Related: #numbers
# Related: #numbers, #each_ordered_number
def each_number(&block) # :yields: integer
return to_enum(__method__) unless block_given?
raise RangeError, '%s contains "*"' % [self.class] if include_star?
each_element do |elem|
case elem
when Range then elem.each(&block)
when Integer then block.(elem)
end
end
@tuples.each do each_number_in_tuple _1, _2, &block end
self
end

# Yields each number in #entries to the block and returns self.
# If the set contains a <tt>*</tt>, RangeError will be raised.
#
# Returns an enumerator when called without a block (even if the set
# contains <tt>*</tt>).
#
# Related: #entries, #each_number
def each_ordered_number(&block)
return to_enum(__method__) unless block_given?
raise RangeError, '%s contains "*"' % [self.class] if include_star?
each_entry_tuple do each_number_in_tuple _1, _2, &block end
end

private def each_number_in_tuple(min, max, &block)
if min == STAR_INT then yield :*
elsif min == max then yield min
elsif max != STAR_INT then (min..max).each(&block)
else
raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
end
end

# Returns a Set with all of the #numbers in the sequence set.
#
# If the set contains a <tt>*</tt>, RangeError will be raised.
Expand Down
18 changes: 18 additions & 0 deletions test/net/imap/test_sequence_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -683,6 +683,7 @@ def test_inspect((expected, input, freeze))
entries: [46, 6..7, 15, 1..3],
ranges: [1..3, 6..7, 15..15, 46..46],
numbers: [1, 2, 3, 6, 7, 15, 46],
ordered: [46, 6, 7, 15, 1, 2, 3],
to_s: "46,7:6,15,3:1",
normalize: "1:3,6:7,15,46",
count: 7,
Expand All @@ -707,6 +708,7 @@ def test_inspect((expected, input, freeze))
entries: [1..5, 3..7, 9..10, 10..11],
ranges: [1..7, 9..11],
numbers: [1, 2, 3, 4, 5, 6, 7, 9, 10, 11],
ordered: [1,2,3,4,5, 3,4,5,6,7, 9,10, 10,11],
to_s: "1:5,3:7,10:9,10:11",
normalize: "1:7,9:11",
count: 10,
Expand All @@ -720,6 +722,7 @@ def test_inspect((expected, input, freeze))
entries: [1..5, 3..4, 9..11, 10],
ranges: [1..5, 9..11],
numbers: [1, 2, 3, 4, 5, 9, 10, 11],
ordered: [1,2,3,4,5, 3,4, 9,10,11, 10],
to_s: "1:5,3:4,9:11,10",
normalize: "1:5,9:11",
count: 8,
Expand Down Expand Up @@ -832,6 +835,21 @@ def assert_seqset_enum(expected, seqset, enum)
end
end

test "#each_ordered_number" do |data|
seqset = SequenceSet.new(data[:input])
expected = data[:ordered] || data[:numbers]
if expected.is_a?(Class) && expected < Exception
assert_raise expected do
seqset.each_ordered_number do fail "shouldn't get here" end
end
enum = seqset.each_ordered_number
assert_raise expected do enum.to_a end
assert_raise expected do enum.each do fail "shouldn't get here" end end
else
assert_seqset_enum expected, seqset, :each_ordered_number
end
end

test "#numbers" do |data|
expected = data[:numbers]
if expected.is_a?(Class) && expected < Exception
Expand Down
Loading