Skip to content

Commit a2cc018

Browse files
committed
✨ Add SequenceSet#each_ordered_number
Yields each number in the ordered entries and returns +self+.
1 parent c26dc51 commit a2cc018

File tree

2 files changed

+44
-7
lines changed

2 files changed

+44
-7
lines changed

lib/net/imap/sequence_set.rb

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,8 @@ class IMAP
227227
# without deduplicating numbers or coalescing ranges, and returns +self+.
228228
# - #entries: Returns an Array of every number and range in the set,
229229
# unsorted and without deduplicating numbers or coalescing ranges.
230+
# - #each_ordered_number: Yields each number in the ordered entries and
231+
# returns +self+.
230232
#
231233
# === Methods for \Set Operations
232234
# These methods do not modify +self+.
@@ -990,19 +992,36 @@ def each_range # :yields: range
990992
# Returns an enumerator when called without a block (even if the set
991993
# contains <tt>*</tt>).
992994
#
993-
# Related: #numbers
995+
# Related: #numbers, #each_ordered_number
994996
def each_number(&block) # :yields: integer
995997
return to_enum(__method__) unless block_given?
996998
raise RangeError, '%s contains "*"' % [self.class] if include_star?
997-
each_element do |elem|
998-
case elem
999-
when Range then elem.each(&block)
1000-
when Integer then block.(elem)
1001-
end
1002-
end
999+
@tuples.each do each_number_in_tuple _1, _2, &block end
10031000
self
10041001
end
10051002

1003+
# Yields each number in #entries to the block and returns self.
1004+
# If the set contains a <tt>*</tt>, RangeError will be raised.
1005+
#
1006+
# Returns an enumerator when called without a block (even if the set
1007+
# contains <tt>*</tt>).
1008+
#
1009+
# Related: #entries, #each_number
1010+
def each_ordered_number(&block)
1011+
return to_enum(__method__) unless block_given?
1012+
raise RangeError, '%s contains "*"' % [self.class] if include_star?
1013+
each_entry_tuple do each_number_in_tuple _1, _2, &block end
1014+
end
1015+
1016+
private def each_number_in_tuple(min, max, &block)
1017+
if min == STAR_INT then yield :*
1018+
elsif min == max then yield min
1019+
elsif max != STAR_INT then (min..max).each(&block)
1020+
else
1021+
raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
1022+
end
1023+
end
1024+
10061025
# Returns a Set with all of the #numbers in the sequence set.
10071026
#
10081027
# If the set contains a <tt>*</tt>, RangeError will be raised.

test/net/imap/test_sequence_set.rb

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -683,6 +683,7 @@ def test_inspect((expected, input, freeze))
683683
entries: [46, 6..7, 15, 1..3],
684684
ranges: [1..3, 6..7, 15..15, 46..46],
685685
numbers: [1, 2, 3, 6, 7, 15, 46],
686+
ordered: [46, 6, 7, 15, 1, 2, 3],
686687
to_s: "46,7:6,15,3:1",
687688
normalize: "1:3,6:7,15,46",
688689
count: 7,
@@ -707,6 +708,7 @@ def test_inspect((expected, input, freeze))
707708
entries: [1..5, 3..7, 9..10, 10..11],
708709
ranges: [1..7, 9..11],
709710
numbers: [1, 2, 3, 4, 5, 6, 7, 9, 10, 11],
711+
ordered: [1,2,3,4,5, 3,4,5,6,7, 9,10, 10,11],
710712
to_s: "1:5,3:7,10:9,10:11",
711713
normalize: "1:7,9:11",
712714
count: 10,
@@ -720,6 +722,7 @@ def test_inspect((expected, input, freeze))
720722
entries: [1..5, 3..4, 9..11, 10],
721723
ranges: [1..5, 9..11],
722724
numbers: [1, 2, 3, 4, 5, 9, 10, 11],
725+
ordered: [1,2,3,4,5, 3,4, 9,10,11, 10],
723726
to_s: "1:5,3:4,9:11,10",
724727
normalize: "1:5,9:11",
725728
count: 8,
@@ -832,6 +835,21 @@ def assert_seqset_enum(expected, seqset, enum)
832835
end
833836
end
834837

838+
test "#each_ordered_number" do |data|
839+
seqset = SequenceSet.new(data[:input])
840+
expected = data[:ordered] || data[:numbers]
841+
if expected.is_a?(Class) && expected < Exception
842+
assert_raise expected do
843+
seqset.each_ordered_number do fail "shouldn't get here" end
844+
end
845+
enum = seqset.each_ordered_number
846+
assert_raise expected do enum.to_a end
847+
assert_raise expected do enum.each do fail "shouldn't get here" end end
848+
else
849+
assert_seqset_enum expected, seqset, :each_ordered_number
850+
end
851+
end
852+
835853
test "#numbers" do |data|
836854
expected = data[:numbers]
837855
if expected.is_a?(Class) && expected < Exception

0 commit comments

Comments
 (0)