Skip to content

Commit 714e51f

Browse files
committed
✨ Add SequenceSet#above and SequenceSet#below
These are just sugar over `set - (..num)` and `set - (num..)`. They are included because they can sometimes make the code much easier to read than doing set algebra with `-` or `&`.
1 parent cf54642 commit 714e51f

File tree

2 files changed

+90
-0
lines changed

2 files changed

+90
-0
lines changed

lib/net/imap/sequence_set.rb

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,10 @@ class IMAP
248248
# +self+ and the other set except those common to both.
249249
# - #~ (aliased as #complement): Returns a new set containing all members
250250
# that are not in +self+
251+
# - #above: Return a copy of +self+ which only contains numbers above a
252+
# given number.
253+
# - #below: Return a copy of +self+ which only contains numbers below a
254+
# given value.
251255
# - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
252256
# given maximum value and removed all members over that maximum.
253257
#
@@ -1285,6 +1289,58 @@ def slice_range(range)
12851289

12861290
public
12871291

1292+
# Returns a copy of +self+ which only contains the numbers above +num+.
1293+
#
1294+
# Net::IMAP::SequenceSet["5,10:22,50"].above(10) # to_s => "11:22,50"
1295+
# Net::IMAP::SequenceSet["5,10:22,50"].above(20) # to_s => "21:22,50
1296+
# Net::IMAP::SequenceSet["5,10:22,50"].above(30) # to_s => "50"
1297+
#
1298+
# This returns the same result as #intersection with <tt>((num+1)..)</tt>
1299+
# or #difference with <tt>(..num)</tt>.
1300+
#
1301+
# Net::IMAP::SequenceSet["5,10:22,50"] & (11..) # to_s => "11:22,50"
1302+
# Net::IMAP::SequenceSet["5,10:22,50"] - (..10) # to_s => "11:22,50"
1303+
# Net::IMAP::SequenceSet["5,10:22,50"] & (21..) # to_s => "21:22,50"
1304+
# Net::IMAP::SequenceSet["5,10:22,50"] - (..20) # to_s => "21:22,50"
1305+
#
1306+
# Related: #above, #-, #&
1307+
def above(num)
1308+
NumValidator.valid_nz_number?(num) or
1309+
raise ArgumentError, "not a valid sequence set number"
1310+
difference(..num)
1311+
end
1312+
1313+
# Returns a copy of +self+ which only contains numbers below +num+.
1314+
#
1315+
# Net::IMAP::SequenceSet["5,10:22,50"].below(10) # to_s => "5"
1316+
# Net::IMAP::SequenceSet["5,10:22,50"].below(20) # to_s => "5,10:19"
1317+
# Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
1318+
#
1319+
# This returns the same result as #intersection with <tt>(..(num-1))</tt>
1320+
# or #difference with <tt>(num..)</tt>.
1321+
#
1322+
# Net::IMAP::SequenceSet["5,10:22,50"] & (..9) # to_s => "5"
1323+
# Net::IMAP::SequenceSet["5,10:22,50"] - (10..) # to_s => "5"
1324+
# Net::IMAP::SequenceSet["5,10:22,50"] & (..19) # to_s => "5,10:19"
1325+
# Net::IMAP::SequenceSet["5,10:22,50"] - (20..) # to_s => "5,10:19"
1326+
#
1327+
# When the set does not contain <tt>*</tt>, #below is identical to #limit
1328+
# with <tt>max: num - 1</tt>. When the set does contain <tt>*</tt>,
1329+
# #below always drops it from the result. Use #limit when the IMAP
1330+
# semantics for <tt>*</tt> must be enforced.
1331+
#
1332+
# Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
1333+
# Net::IMAP::SequenceSet["5,10:22,50"].limit(max: 29) # to_s => "5,10:22"
1334+
# Net::IMAP::SequenceSet["5,10:22,*"].below(30) # to_s => "5,10:22"
1335+
# Net::IMAP::SequenceSet["5,10:22,*"].limit(max: 29) # to_s => "5,10:22,29"
1336+
#
1337+
# Related: #above, #-, #&, #limit
1338+
def below(num)
1339+
NumValidator.valid_nz_number?(num) or
1340+
raise ArgumentError, "not a valid sequence set number"
1341+
difference(num..)
1342+
end
1343+
12881344
# Returns a frozen SequenceSet with <tt>*</tt> converted to +max+, numbers
12891345
# and ranges over +max+ removed, and ranges containing +max+ converted to
12901346
# end at +max+.

test/net/imap/test_sequence_set.rb

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ def compare_to_reference_set(nums, set, seqset)
9494
data "#xor", {transform: ->{ _1 ^ (1..100) }, }
9595
data "#complement", {transform: ->{ ~_1 }, }
9696
data "#normalize", {transform: ->{ _1.normalize }, }
97+
data "#above", {transform: ->{ _1.above(22) }, }
98+
data "#below", {transform: ->{ _1.below(22) }, }
9799
data "#limit", {transform: ->{ _1.limit(max: 22) }, freeze: :always }
98100
data "#limit => empty", {transform: ->{ _1.limit(max: 1) }, freeze: :always }
99101
test "transforms keep frozen status" do |data|
@@ -387,6 +389,38 @@ def obj.to_sequence_set; 192_168.001_255 end
387389
assert_equal 0, SequenceSet["*,1"].find_ordered_index(-1)
388390
end
389391

392+
test "#above" do
393+
set = SequenceSet["5,10:22,50"]
394+
assert_equal SequenceSet.empty, set.above(2**32 - 1)
395+
assert_equal SequenceSet.empty, set.above(99)
396+
assert_equal SequenceSet.empty, set.above(50)
397+
assert_equal SequenceSet["50"], set.above(40)
398+
assert_equal SequenceSet["50"], set.above(30)
399+
assert_equal SequenceSet["21:22,50"], set.above(20)
400+
assert_equal SequenceSet["11:22,50"], set.above(10)
401+
assert_equal SequenceSet["5,10:22,50"], set.above(1)
402+
assert_raise ArgumentError do set.above(2**32) end
403+
assert_raise ArgumentError do set.above(0) end
404+
assert_raise ArgumentError do set.above(-1) end
405+
assert_raise ArgumentError do set.above(:*) end
406+
end
407+
408+
test "#below" do
409+
set = SequenceSet["5,10:22,50"]
410+
assert_equal SequenceSet["5,10:22,50"], set.below(99)
411+
assert_equal SequenceSet["5,10:22"], set.below(50)
412+
assert_equal SequenceSet["5,10:22"], set.below(40)
413+
assert_equal SequenceSet["5,10:22"], set.below(30)
414+
assert_equal SequenceSet["5,10:19"], set.below(20)
415+
assert_equal SequenceSet["5"], set.below(10)
416+
assert_equal SequenceSet.empty, set.below(1)
417+
assert_equal SequenceSet.empty, set.below(1)
418+
assert_raise ArgumentError do set.below(2**32) end
419+
assert_raise ArgumentError do set.below(0) end
420+
assert_raise ArgumentError do set.below(-1) end
421+
assert_raise ArgumentError do set.below(:*) end
422+
end
423+
390424
test "#limit" do
391425
set = SequenceSet["1:100,500"]
392426
assert_equal [1..99], set.limit(max: 99).ranges

0 commit comments

Comments
 (0)