net-imap 0.5.6 → 0.5.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/net/imap/config/attr_type_coercion.rb +23 -22
- data/lib/net/imap/config.rb +101 -19
- data/lib/net/imap/connection_state.rb +48 -0
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +0 -1
- data/lib/net/imap/response_reader.rb +73 -0
- data/lib/net/imap/sequence_set.rb +471 -165
- data/lib/net/imap.rb +259 -58
- data/rakelib/string_prep_tables_generator.rb +4 -2
- metadata +5 -3
@@ -18,21 +18,9 @@ module Net
|
|
18
18
|
#
|
19
19
|
# == Creating sequence sets
|
20
20
|
#
|
21
|
-
# SequenceSet.new with no arguments creates an empty sequence set. Note
|
22
|
-
# that an empty sequence set is invalid in the \IMAP grammar.
|
23
|
-
#
|
24
|
-
# set = Net::IMAP::SequenceSet.new
|
25
|
-
# set.empty? #=> true
|
26
|
-
# set.valid? #=> false
|
27
|
-
# set.valid_string #!> raises DataFormatError
|
28
|
-
# set << 1..10
|
29
|
-
# set.empty? #=> false
|
30
|
-
# set.valid? #=> true
|
31
|
-
# set.valid_string #=> "1:10"
|
32
|
-
#
|
33
21
|
# SequenceSet.new may receive a single optional argument: a non-zero 32 bit
|
34
22
|
# unsigned integer, a range, a <tt>sequence-set</tt> formatted string,
|
35
|
-
# another
|
23
|
+
# another SequenceSet, a Set (containing only numbers or <tt>*</tt>), or an
|
36
24
|
# Array containing any of these (array inputs may be nested).
|
37
25
|
#
|
38
26
|
# set = Net::IMAP::SequenceSet.new(1)
|
@@ -48,30 +36,114 @@ module Net
|
|
48
36
|
# set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024)
|
49
37
|
# set.valid_string #=> "1:10,55,1024:2048"
|
50
38
|
#
|
51
|
-
#
|
52
|
-
#
|
39
|
+
# SequenceSet.new with no arguments creates an empty sequence set. Note
|
40
|
+
# that an empty sequence set is invalid in the \IMAP grammar.
|
41
|
+
#
|
42
|
+
# set = Net::IMAP::SequenceSet.new
|
43
|
+
# set.empty? #=> true
|
44
|
+
# set.valid? #=> false
|
45
|
+
# set.valid_string #!> raises DataFormatError
|
46
|
+
# set << 1..10
|
47
|
+
# set.empty? #=> false
|
48
|
+
# set.valid? #=> true
|
49
|
+
# set.valid_string #=> "1:10"
|
50
|
+
#
|
51
|
+
# Using SequenceSet.new with another SequenceSet input behaves the same as
|
52
|
+
# calling #dup on the other set. The input's #string will be preserved.
|
53
|
+
#
|
54
|
+
# input = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
|
55
|
+
# copy = Net::IMAP::SequenceSet.new(input)
|
56
|
+
# input.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
57
|
+
# copy.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
58
|
+
# copy2 = input.dup # same as calling new with a SequenceSet input
|
59
|
+
# copy == input #=> true, same set membership
|
60
|
+
# copy.eql? input #=> true, same string value
|
61
|
+
# copy.equal? input #=> false, different objects
|
62
|
+
#
|
63
|
+
# copy.normalize!
|
64
|
+
# copy.valid_string #=> "1:10,1024,2048"
|
65
|
+
# copy == input #=> true, same set membership
|
66
|
+
# copy.eql? input #=> false, different string value
|
53
67
|
#
|
68
|
+
# copy << 999
|
69
|
+
# copy.valid_string #=> "1:10,999,1024,2048"
|
70
|
+
# copy == input #=> false, different set membership
|
71
|
+
# copy.eql? input #=> false, different string value
|
72
|
+
#
|
73
|
+
# Use Net::IMAP::SequenceSet() to coerce a single (optional) input.
|
74
|
+
# A SequenceSet input is returned without duplication, even when frozen.
|
75
|
+
#
|
76
|
+
# set = Net::IMAP::SequenceSet()
|
77
|
+
# set.string #=> nil
|
78
|
+
# set.frozen? #=> false
|
79
|
+
#
|
80
|
+
# # String order is preserved
|
81
|
+
# set = Net::IMAP::SequenceSet("1,2,3:7,5,6:10,2048,1024")
|
82
|
+
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
83
|
+
# set.frozen? #=> false
|
84
|
+
#
|
85
|
+
# # Other inputs are normalized
|
86
|
+
# set = Net::IMAP::SequenceSet([1, 2, [3..7, 5], 6..10, 2048, 1024])
|
87
|
+
# set.valid_string #=> "1:10,55,1024:2048"
|
88
|
+
# set.frozen? #=> false
|
89
|
+
#
|
90
|
+
# unfrozen = set
|
91
|
+
# frozen = set.dup.freeze
|
92
|
+
# unfrozen.equal? Net::IMAP::SequenceSet(unfrozen) #=> true
|
93
|
+
# frozen.equal? Net::IMAP::SequenceSet(frozen) #=> true
|
94
|
+
#
|
95
|
+
# Use ::[] to coerce one or more arguments into a valid frozen SequenceSet.
|
96
|
+
# A valid frozen SequenceSet is returned directly, without allocating a new
|
97
|
+
# object. ::[] will not create an invalid (empty) set.
|
98
|
+
#
|
99
|
+
# Net::IMAP::SequenceSet[] #!> raises ArgumentError
|
100
|
+
# Net::IMAP::SequenceSet[nil] #!> raises DataFormatError
|
101
|
+
# Net::IMAP::SequenceSet[""] #!> raises DataFormatError
|
102
|
+
#
|
103
|
+
# # String order is preserved
|
54
104
|
# set = Net::IMAP::SequenceSet["1,2,3:7,5,6:10,2048,1024"]
|
55
105
|
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
106
|
+
# set.frozen? #=> true
|
107
|
+
#
|
108
|
+
# # Other inputs are normalized
|
56
109
|
# set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
|
57
110
|
# set.valid_string #=> "1:10,55,1024:2048"
|
111
|
+
# set.frozen? #=> true
|
112
|
+
#
|
113
|
+
# frozen = set
|
114
|
+
# unfrozen = set.dup
|
115
|
+
# frozen.equal? Net::IMAP::SequenceSet[frozen] #=> true
|
116
|
+
# unfrozen.equal? Net::IMAP::SequenceSet[unfrozen] #=> false
|
117
|
+
#
|
118
|
+
# Objects which respond to +to_sequence_set+ (such as SearchResult and
|
119
|
+
# ThreadMember) can be coerced to a SequenceSet with ::new, ::try_convert,
|
120
|
+
# ::[], or Net::IMAP::SequenceSet.
|
121
|
+
#
|
122
|
+
# search = imap.uid_search(["SUBJECT", "hello", "NOT", "SEEN"])
|
123
|
+
# seqset = Net::IMAP::SequenceSet(search) - already_fetched
|
124
|
+
# fetch = imap.uid_fetch(seqset, "FAST")
|
58
125
|
#
|
59
126
|
# == Ordered and Normalized sets
|
60
127
|
#
|
61
128
|
# Sometimes the order of the set's members is significant, such as with the
|
62
129
|
# +ESORT+, <tt>CONTEXT=SORT</tt>, and +UIDPLUS+ extensions. So, when a
|
63
|
-
# sequence set is created
|
64
|
-
# #string representation is preserved.
|
130
|
+
# sequence set is created from a single string (such as by the parser), that
|
131
|
+
# #string representation is preserved. Assigning a string with #string= or
|
132
|
+
# #replace will also preserve that string. Use #each_entry, #entries, or
|
133
|
+
# #each_ordered_number to enumerate the entries in their #string order.
|
134
|
+
# Hash equality (using #eql?) is based on the string representation.
|
65
135
|
#
|
66
|
-
# Internally, SequenceSet
|
67
|
-
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
# the set in
|
136
|
+
# Internally, SequenceSet uses a normalized uint32 set representation which
|
137
|
+
# sorts and de-duplicates all numbers and coalesces adjacent or overlapping
|
138
|
+
# entries. Many methods use this sorted set representation for <tt>O(lg
|
139
|
+
# n)</tt> searches. Use #each_element, #elements, #each_range, #ranges,
|
140
|
+
# #each_number, or #numbers to enumerate the set in sorted order. Basic
|
141
|
+
# object equality (using #==) is based on set membership, without regard to
|
142
|
+
# #entry order or #string normalization.
|
71
143
|
#
|
72
|
-
# Most modification methods
|
73
|
-
#
|
74
|
-
#
|
144
|
+
# Most modification methods reset #string to its #normalized form, so that
|
145
|
+
# #entries and #elements are identical. Use #append to preserve #entries
|
146
|
+
# order while modifying a set.
|
75
147
|
#
|
76
148
|
# == Using <tt>*</tt>
|
77
149
|
#
|
@@ -108,11 +180,15 @@ module Net
|
|
108
180
|
# When a set includes <tt>*</tt>, some methods may have surprising behavior.
|
109
181
|
#
|
110
182
|
# For example, #complement treats <tt>*</tt> as its own number. This way,
|
111
|
-
# the #intersection of a set and its #complement will always be empty.
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
183
|
+
# the #intersection of a set and its #complement will always be empty. And
|
184
|
+
# <tt>*</tt> is sorted as greater than any other number in the set. This is
|
185
|
+
# not how an \IMAP server interprets the set: it will convert <tt>*</tt> to
|
186
|
+
# the number of messages in the mailbox, the +UID+ of the last message in
|
187
|
+
# the mailbox, or +UIDNEXT+, as appropriate. Several methods have an
|
188
|
+
# argument for how <tt>*</tt> should be interpreted.
|
189
|
+
#
|
190
|
+
# But, for example, this means that there may be overlap between a set and
|
191
|
+
# its complement after #limit is applied to each:
|
116
192
|
#
|
117
193
|
# ~Net::IMAP::SequenceSet["*"] == Net::IMAP::SequenceSet[1..(2**32-1)]
|
118
194
|
# ~Net::IMAP::SequenceSet[1..5] == Net::IMAP::SequenceSet["6:*"]
|
@@ -149,6 +225,7 @@ module Net
|
|
149
225
|
# * ::new: Creates a new mutable sequence set, which may be empty (invalid).
|
150
226
|
# * ::try_convert: Calls +to_sequence_set+ on an object and verifies that
|
151
227
|
# the result is a SequenceSet.
|
228
|
+
# * Net::IMAP::SequenceSet(): Coerce an input using ::try_convert or ::new.
|
152
229
|
# * ::empty: Returns a frozen empty (invalid) SequenceSet.
|
153
230
|
# * ::full: Returns a frozen SequenceSet containing every possible number.
|
154
231
|
#
|
@@ -174,14 +251,13 @@ module Net
|
|
174
251
|
#
|
175
252
|
# <i>Set membership:</i>
|
176
253
|
# - #include? (aliased as #member?):
|
177
|
-
# Returns whether a given
|
178
|
-
# contained by the set.
|
254
|
+
# Returns whether a given element is contained by the set.
|
179
255
|
# - #include_star?: Returns whether the set contains <tt>*</tt>.
|
180
256
|
#
|
181
257
|
# <i>Minimum and maximum value elements:</i>
|
182
|
-
# - #min: Returns the
|
183
|
-
# - #max: Returns the
|
184
|
-
# - #minmax: Returns the
|
258
|
+
# - #min: Returns one or more of the lowest numbers in the set.
|
259
|
+
# - #max: Returns one or more of the highest numbers in the set.
|
260
|
+
# - #minmax: Returns the lowest and highest numbers in the set.
|
185
261
|
#
|
186
262
|
# <i>Accessing value by offset in sorted set:</i>
|
187
263
|
# - #[] (aliased as #slice): Returns the number or consecutive subset at a
|
@@ -239,15 +315,19 @@ module Net
|
|
239
315
|
# These methods do not modify +self+.
|
240
316
|
#
|
241
317
|
# - #| (aliased as #union and #+): Returns a new set combining all members
|
242
|
-
# from +self+ with all members from the other
|
318
|
+
# from +self+ with all members from the other set.
|
243
319
|
# - #& (aliased as #intersection): Returns a new set containing all members
|
244
|
-
# common to +self+ and the other
|
320
|
+
# common to +self+ and the other set.
|
245
321
|
# - #- (aliased as #difference): Returns a copy of +self+ with all members
|
246
|
-
# in the other
|
322
|
+
# in the other set removed.
|
247
323
|
# - #^ (aliased as #xor): Returns a new set containing all members from
|
248
|
-
# +self+ and the other
|
324
|
+
# +self+ and the other set except those common to both.
|
249
325
|
# - #~ (aliased as #complement): Returns a new set containing all members
|
250
326
|
# that are not in +self+
|
327
|
+
# - #above: Return a copy of +self+ which only contains numbers above a
|
328
|
+
# given number.
|
329
|
+
# - #below: Return a copy of +self+ which only contains numbers below a
|
330
|
+
# given value.
|
251
331
|
# - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
|
252
332
|
# given maximum value and removed all members over that maximum.
|
253
333
|
#
|
@@ -258,17 +338,17 @@ module Net
|
|
258
338
|
#
|
259
339
|
# These methods always update #string to be fully sorted and coalesced.
|
260
340
|
#
|
261
|
-
# - #add (aliased as #<<): Adds a given
|
262
|
-
# - #add?: If the given
|
341
|
+
# - #add (aliased as #<<): Adds a given element to the set; returns +self+.
|
342
|
+
# - #add?: If the given element is not fully included the set, adds it and
|
263
343
|
# returns +self+; otherwise, returns +nil+.
|
264
|
-
# - #merge:
|
344
|
+
# - #merge: Adds all members of the given sets into this set; returns +self+.
|
265
345
|
# - #complement!: Replaces the contents of the set with its own #complement.
|
266
346
|
#
|
267
347
|
# <i>Order preserving:</i>
|
268
348
|
#
|
269
349
|
# These methods _may_ cause #string to not be sorted or coalesced.
|
270
350
|
#
|
271
|
-
# - #append: Adds
|
351
|
+
# - #append: Adds the given entry to the set, appending it to the existing
|
272
352
|
# string, and returns +self+.
|
273
353
|
# - #string=: Assigns a new #string value and replaces #elements to match.
|
274
354
|
# - #replace: Replaces the contents of the set with the contents
|
@@ -279,13 +359,14 @@ module Net
|
|
279
359
|
# sorted and coalesced.
|
280
360
|
#
|
281
361
|
# - #clear: Removes all elements in the set; returns +self+.
|
282
|
-
# - #delete: Removes a given
|
283
|
-
# - #delete?: If the given
|
362
|
+
# - #delete: Removes a given element from the set; returns +self+.
|
363
|
+
# - #delete?: If the given element is included in the set, removes it and
|
284
364
|
# returns it; otherwise, returns +nil+.
|
285
365
|
# - #delete_at: Removes the number at a given offset.
|
286
366
|
# - #slice!: Removes the number or consecutive numbers at a given offset or
|
287
367
|
# range of offsets.
|
288
|
-
# - #subtract: Removes
|
368
|
+
# - #subtract: Removes all members of the given sets from this set; returns
|
369
|
+
# +self+.
|
289
370
|
# - #limit!: Replaces <tt>*</tt> with a given maximum value and removes all
|
290
371
|
# members over that maximum; returns +self+.
|
291
372
|
#
|
@@ -318,20 +399,22 @@ module Net
|
|
318
399
|
class << self
|
319
400
|
|
320
401
|
# :call-seq:
|
321
|
-
# SequenceSet[*
|
402
|
+
# SequenceSet[*inputs] -> valid frozen sequence set
|
403
|
+
#
|
404
|
+
# Returns a frozen SequenceSet, constructed from +inputs+.
|
322
405
|
#
|
323
|
-
#
|
406
|
+
# When only a single valid frozen SequenceSet is given, that same set is
|
407
|
+
# returned.
|
324
408
|
#
|
325
409
|
# An empty SequenceSet is invalid and will raise a DataFormatError.
|
326
410
|
#
|
327
411
|
# Use ::new to create a mutable or empty SequenceSet.
|
412
|
+
#
|
413
|
+
# Related: ::new, Net::IMAP::SequenceSet(), ::try_convert
|
328
414
|
def [](first, *rest)
|
329
415
|
if rest.empty?
|
330
|
-
|
331
|
-
|
332
|
-
else
|
333
|
-
new(first).validate.freeze
|
334
|
-
end
|
416
|
+
set = try_convert(first)&.validate
|
417
|
+
set&.frozen? ? set : (set&.dup || new(first).validate).freeze
|
335
418
|
else
|
336
419
|
new(first).merge(*rest).validate.freeze
|
337
420
|
end
|
@@ -346,6 +429,8 @@ module Net
|
|
346
429
|
#
|
347
430
|
# If +obj.to_sequence_set+ doesn't return a SequenceSet, an exception is
|
348
431
|
# raised.
|
432
|
+
#
|
433
|
+
# Related: Net::IMAP::SequenceSet(), ::new, ::[]
|
349
434
|
def try_convert(obj)
|
350
435
|
return obj if obj.is_a?(SequenceSet)
|
351
436
|
return nil unless obj.respond_to?(:to_sequence_set)
|
@@ -364,20 +449,85 @@ module Net
|
|
364
449
|
end
|
365
450
|
|
366
451
|
# Create a new SequenceSet object from +input+, which may be another
|
367
|
-
# SequenceSet, an IMAP formatted +sequence-set+ string, a
|
368
|
-
# range, <tt>:*</tt>,
|
369
|
-
#
|
370
|
-
#
|
452
|
+
# SequenceSet, an IMAP formatted +sequence-set+ string, a non-zero 32 bit
|
453
|
+
# unsigned integer, a range, <tt>:*</tt>, a Set of numbers or <tt>*</tt>,
|
454
|
+
# an object that responds to +to_sequence_set+ (such as SearchResult) or
|
455
|
+
# an Array of these (array inputs may be nested).
|
456
|
+
#
|
457
|
+
# set = Net::IMAP::SequenceSet.new(1)
|
458
|
+
# set.valid_string #=> "1"
|
459
|
+
# set = Net::IMAP::SequenceSet.new(1..100)
|
460
|
+
# set.valid_string #=> "1:100"
|
461
|
+
# set = Net::IMAP::SequenceSet.new(1...100)
|
462
|
+
# set.valid_string #=> "1:99"
|
463
|
+
# set = Net::IMAP::SequenceSet.new([1, 2, 5..])
|
464
|
+
# set.valid_string #=> "1:2,5:*"
|
465
|
+
# set = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
|
466
|
+
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
467
|
+
# set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024)
|
468
|
+
# set.valid_string #=> "1:10,55,1024:2048"
|
469
|
+
#
|
470
|
+
# With no arguments (or +nil+) creates an empty sequence set. Note that
|
471
|
+
# an empty sequence set is invalid in the \IMAP grammar.
|
472
|
+
#
|
473
|
+
# set = Net::IMAP::SequenceSet.new
|
474
|
+
# set.empty? #=> true
|
475
|
+
# set.valid? #=> false
|
476
|
+
# set.valid_string #!> raises DataFormatError
|
477
|
+
# set << 1..10
|
478
|
+
# set.empty? #=> false
|
479
|
+
# set.valid? #=> true
|
480
|
+
# set.valid_string #=> "1:10"
|
481
|
+
#
|
482
|
+
# When +input+ is a SequenceSet, ::new behaves the same as calling #dup on
|
483
|
+
# that other set. The input's #string will be preserved.
|
484
|
+
#
|
485
|
+
# input = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
|
486
|
+
# copy = Net::IMAP::SequenceSet.new(input)
|
487
|
+
# input.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
488
|
+
# copy.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
489
|
+
# copy2 = input.dup # same as calling new with a SequenceSet input
|
490
|
+
# copy == input #=> true, same set membership
|
491
|
+
# copy.eql? input #=> true, same string value
|
492
|
+
# copy.equal? input #=> false, different objects
|
493
|
+
#
|
494
|
+
# copy.normalize!
|
495
|
+
# copy.valid_string #=> "1:10,1024,2048"
|
496
|
+
# copy == input #=> true, same set membership
|
497
|
+
# copy.eql? input #=> false, different string value
|
498
|
+
#
|
499
|
+
# copy << 999
|
500
|
+
# copy.valid_string #=> "1:10,999,1024,2048"
|
501
|
+
# copy == input #=> false, different set membership
|
502
|
+
# copy.eql? input #=> false, different string value
|
503
|
+
#
|
504
|
+
# === Alternative set creation methods
|
505
|
+
#
|
506
|
+
# * ::[] returns a frozen validated (non-empty) SequenceSet, without
|
507
|
+
# allocating a new object when the input is already a valid frozen
|
508
|
+
# SequenceSet.
|
509
|
+
# * Net::IMAP::SequenceSet() coerces an input to SequenceSet, without
|
510
|
+
# allocating a new object when the input is already a SequenceSet.
|
511
|
+
# * ::try_convert calls +to_sequence_set+ on inputs that support it and
|
512
|
+
# returns +nil+ for inputs that don't.
|
513
|
+
# * ::empty and ::full both return frozen singleton sets which can be
|
514
|
+
# combined with set operations (#|, #&, #^, #-, etc) to make new sets.
|
515
|
+
#
|
516
|
+
# See SequenceSet@Creating+sequence+sets.
|
371
517
|
def initialize(input = nil) input ? replace(input) : clear end
|
372
518
|
|
373
519
|
# Removes all elements and returns self.
|
374
|
-
def clear
|
520
|
+
def clear
|
521
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
522
|
+
@tuples, @string = [], nil
|
523
|
+
self
|
524
|
+
end
|
375
525
|
|
376
526
|
# Replace the contents of the set with the contents of +other+ and returns
|
377
527
|
# +self+.
|
378
528
|
#
|
379
|
-
# +other+ may be another SequenceSet
|
380
|
-
#
|
529
|
+
# +other+ may be another SequenceSet or any other object that would be
|
530
|
+
# accepted by ::new.
|
381
531
|
def replace(other)
|
382
532
|
case other
|
383
533
|
when SequenceSet then initialize_dup(other)
|
@@ -427,11 +577,13 @@ module Net
|
|
427
577
|
if str.nil?
|
428
578
|
clear
|
429
579
|
else
|
580
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
430
581
|
str = String.try_convert(str) or raise ArgumentError, "not a string"
|
431
582
|
tuples = str_to_tuples str
|
432
583
|
@tuples, @string = [], -str
|
433
584
|
tuples_add tuples
|
434
585
|
end
|
586
|
+
str
|
435
587
|
end
|
436
588
|
|
437
589
|
# Returns the \IMAP +sequence-set+ string representation, or an empty
|
@@ -491,8 +643,9 @@ module Net
|
|
491
643
|
|
492
644
|
# :call-seq: self === other -> true | false | nil
|
493
645
|
#
|
494
|
-
# Returns whether +other+ is contained within the set.
|
495
|
-
#
|
646
|
+
# Returns whether +other+ is contained within the set. +other+ may be any
|
647
|
+
# object that would be accepted by ::new. Returns +nil+ if StandardError
|
648
|
+
# is raised while converting +other+ to a comparable type.
|
496
649
|
#
|
497
650
|
# Related: #cover?, #include?, #include_star?
|
498
651
|
def ===(other)
|
@@ -506,12 +659,12 @@ module Net
|
|
506
659
|
# Returns whether +other+ is contained within the set. +other+ may be any
|
507
660
|
# object that would be accepted by ::new.
|
508
661
|
#
|
509
|
-
# Related: #===, #include?, #include_star?
|
662
|
+
# Related: #===, #include?, #include_star?, #intersect?
|
510
663
|
def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
|
511
664
|
|
512
665
|
# Returns +true+ when a given number or range is in +self+, and +false+
|
513
|
-
# otherwise. Returns +
|
514
|
-
# <tt>*</tt
|
666
|
+
# otherwise. Returns +nil+ when +number+ isn't a valid SequenceSet
|
667
|
+
# element (Integer, Range, <tt>*</tt>, +sequence-set+ string).
|
515
668
|
#
|
516
669
|
# set = Net::IMAP::SequenceSet["5:10,100,111:115"]
|
517
670
|
# set.include? 1 #=> false
|
@@ -519,8 +672,8 @@ module Net
|
|
519
672
|
# set.include? 11..20 #=> false
|
520
673
|
# set.include? 100 #=> true
|
521
674
|
# set.include? 6 #=> true, covered by "5:10"
|
522
|
-
# set.include?
|
523
|
-
# set.include? "
|
675
|
+
# set.include? 6..9 #=> true, covered by "5:10"
|
676
|
+
# set.include? "6:9" #=> true, strings are parsed
|
524
677
|
# set.include? 4..9 #=> false, intersection is not sufficient
|
525
678
|
# set.include? "*" #=> false, use #limit to re-interpret "*"
|
526
679
|
# set.include? -1 #=> false, -1 is interpreted as "*"
|
@@ -529,11 +682,14 @@ module Net
|
|
529
682
|
# set.include? :* #=> true
|
530
683
|
# set.include? "*" #=> true
|
531
684
|
# set.include? -1 #=> true
|
532
|
-
# set.include?
|
533
|
-
# set.include?
|
685
|
+
# set.include?(200..) #=> true
|
686
|
+
# set.include?(100..) #=> false
|
534
687
|
#
|
535
|
-
# Related: #include_star?, #cover?,
|
536
|
-
def include?(element)
|
688
|
+
# Related: #include_star?, #cover?, #===, #intersect?
|
689
|
+
def include?(element)
|
690
|
+
tuple = input_to_tuple element rescue nil
|
691
|
+
!!include_tuple?(tuple) if tuple
|
692
|
+
end
|
537
693
|
|
538
694
|
alias member? include?
|
539
695
|
|
@@ -546,7 +702,7 @@ module Net
|
|
546
702
|
# Net::IMAP::SequenceSet["5:10"].intersect? "7,9,11" #=> true
|
547
703
|
# Net::IMAP::SequenceSet["5:10"].intersect? "11:33" #=> false
|
548
704
|
#
|
549
|
-
# Related: #intersection, #disjoint?
|
705
|
+
# Related: #intersection, #disjoint?, #cover?, #include?
|
550
706
|
def intersect?(other)
|
551
707
|
valid? && input_to_tuples(other).any? { intersect_tuple? _1 }
|
552
708
|
end
|
@@ -563,26 +719,53 @@ module Net
|
|
563
719
|
empty? || input_to_tuples(other).none? { intersect_tuple? _1 }
|
564
720
|
end
|
565
721
|
|
566
|
-
# :call-seq:
|
722
|
+
# :call-seq:
|
723
|
+
# max(star: :*) => integer or star or nil
|
724
|
+
# max(count) => SequenceSet
|
567
725
|
#
|
568
726
|
# Returns the maximum value in +self+, +star+ when the set includes
|
569
727
|
# <tt>*</tt>, or +nil+ when the set is empty.
|
570
|
-
|
571
|
-
|
728
|
+
#
|
729
|
+
# When +count+ is given, a new SequenceSet is returned, containing only
|
730
|
+
# the last +count+ numbers. An empty SequenceSet is returned when +self+
|
731
|
+
# is empty. (+star+ is ignored when +count+ is given.)
|
732
|
+
#
|
733
|
+
# Related: #min, #minmax, #slice
|
734
|
+
def max(count = nil, star: :*)
|
735
|
+
if count
|
736
|
+
slice(-[count, size].min..) || remain_frozen_empty
|
737
|
+
elsif (val = @tuples.last&.last)
|
738
|
+
val == STAR_INT ? star : val
|
739
|
+
end
|
572
740
|
end
|
573
741
|
|
574
|
-
# :call-seq:
|
742
|
+
# :call-seq:
|
743
|
+
# min(star: :*) => integer or star or nil
|
744
|
+
# min(count) => SequenceSet
|
575
745
|
#
|
576
746
|
# Returns the minimum value in +self+, +star+ when the only value in the
|
577
747
|
# set is <tt>*</tt>, or +nil+ when the set is empty.
|
578
|
-
|
579
|
-
|
748
|
+
#
|
749
|
+
# When +count+ is given, a new SequenceSet is returned, containing only
|
750
|
+
# the first +count+ numbers. An empty SequenceSet is returned when +self+
|
751
|
+
# is empty. (+star+ is ignored when +count+ is given.)
|
752
|
+
#
|
753
|
+
# Related: #max, #minmax, #slice
|
754
|
+
def min(count = nil, star: :*)
|
755
|
+
if count
|
756
|
+
slice(0...count) || remain_frozen_empty
|
757
|
+
elsif (val = @tuples.first&.first)
|
758
|
+
val != STAR_INT ? val : star
|
759
|
+
end
|
580
760
|
end
|
581
761
|
|
582
|
-
# :call-seq: minmax(star: :*) =>
|
762
|
+
# :call-seq: minmax(star: :*) => [min, max] or nil
|
583
763
|
#
|
584
764
|
# Returns a 2-element array containing the minimum and maximum numbers in
|
585
|
-
# +self+, or +nil+ when the set is empty.
|
765
|
+
# +self+, or +nil+ when the set is empty. +star+ is handled the same way
|
766
|
+
# as by #min and #max.
|
767
|
+
#
|
768
|
+
# Related: #min, #max
|
586
769
|
def minmax(star: :*); [min(star: star), max(star: star)] unless empty? end
|
587
770
|
|
588
771
|
# Returns false when the set is empty.
|
@@ -602,14 +785,19 @@ module Net
|
|
602
785
|
# Returns a new sequence set that has every number in the +other+ object
|
603
786
|
# added.
|
604
787
|
#
|
605
|
-
# +other+ may be any object that would be accepted by ::new
|
606
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
607
|
-
# another sequence set, or an enumerable containing any of these.
|
788
|
+
# +other+ may be any object that would be accepted by ::new.
|
608
789
|
#
|
609
790
|
# Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99]
|
610
791
|
# #=> Net::IMAP::SequenceSet["1:6,99"]
|
611
792
|
#
|
612
|
-
# Related: #add, #merge
|
793
|
+
# Related: #add, #merge, #&, #-, #^, #~
|
794
|
+
#
|
795
|
+
# ==== Set identities
|
796
|
+
#
|
797
|
+
# <tt>lhs | rhs</tt> is equivalent to:
|
798
|
+
# * <tt>rhs | lhs</tt> (commutative)
|
799
|
+
# * <tt>~(~lhs & ~rhs)</tt> (De Morgan's Law)
|
800
|
+
# * <tt>(lhs & rhs) ^ (lhs ^ rhs)</tt>
|
613
801
|
def |(other) remain_frozen dup.merge other end
|
614
802
|
alias :+ :|
|
615
803
|
alias union :|
|
@@ -621,14 +809,22 @@ module Net
|
|
621
809
|
# Returns a new sequence set built by duplicating this set and removing
|
622
810
|
# every number that appears in +other+.
|
623
811
|
#
|
624
|
-
# +other+ may be any object that would be accepted by ::new
|
625
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
626
|
-
# another sequence set, or an enumerable containing any of these.
|
812
|
+
# +other+ may be any object that would be accepted by ::new.
|
627
813
|
#
|
628
814
|
# Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6
|
629
815
|
# #=> Net::IMAP::SequenceSet["1,3,5"]
|
630
816
|
#
|
631
|
-
# Related: #subtract
|
817
|
+
# Related: #subtract, #|, #&, #^, #~
|
818
|
+
#
|
819
|
+
# ==== Set identities
|
820
|
+
#
|
821
|
+
# <tt>lhs - rhs</tt> is equivalent to:
|
822
|
+
# * <tt>~rhs - ~lhs</tt>
|
823
|
+
# * <tt>lhs & ~rhs</tt>
|
824
|
+
# * <tt>~(~lhs | rhs)</tt>
|
825
|
+
# * <tt>lhs & (lhs ^ rhs)</tt>
|
826
|
+
# * <tt>lhs ^ (lhs & rhs)</tt>
|
827
|
+
# * <tt>rhs ^ (lhs | rhs)</tt>
|
632
828
|
def -(other) remain_frozen dup.subtract other end
|
633
829
|
alias difference :-
|
634
830
|
|
@@ -639,14 +835,22 @@ module Net
|
|
639
835
|
# Returns a new sequence set containing only the numbers common to this
|
640
836
|
# set and +other+.
|
641
837
|
#
|
642
|
-
# +other+ may be any object that would be accepted by ::new
|
643
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
644
|
-
# another sequence set, or an enumerable containing any of these.
|
838
|
+
# +other+ may be any object that would be accepted by ::new.
|
645
839
|
#
|
646
840
|
# Net::IMAP::SequenceSet[1..5] & [2, 4, 6]
|
647
841
|
# #=> Net::IMAP::SequenceSet["2,4"]
|
648
842
|
#
|
649
|
-
#
|
843
|
+
# Related: #intersect?, #|, #-, #^, #~
|
844
|
+
#
|
845
|
+
# ==== Set identities
|
846
|
+
#
|
847
|
+
# <tt>lhs & rhs</tt> is equivalent to:
|
848
|
+
# * <tt>rhs & lhs</tt> (commutative)
|
849
|
+
# * <tt>~(~lhs | ~rhs)</tt> (De Morgan's Law)
|
850
|
+
# * <tt>lhs - ~rhs</tt>
|
851
|
+
# * <tt>lhs - (lhs - rhs)</tt>
|
852
|
+
# * <tt>lhs - (lhs ^ rhs)</tt>
|
853
|
+
# * <tt>lhs ^ (lhs - rhs)</tt>
|
650
854
|
def &(other)
|
651
855
|
remain_frozen dup.subtract SequenceSet.new(other).complement!
|
652
856
|
end
|
@@ -659,16 +863,22 @@ module Net
|
|
659
863
|
# Returns a new sequence set containing numbers that are exclusive between
|
660
864
|
# this set and +other+.
|
661
865
|
#
|
662
|
-
# +other+ may be any object that would be accepted by ::new
|
663
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
664
|
-
# another sequence set, or an enumerable containing any of these.
|
866
|
+
# +other+ may be any object that would be accepted by ::new.
|
665
867
|
#
|
666
868
|
# Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6]
|
667
869
|
# #=> Net::IMAP::SequenceSet["1,3,5:6"]
|
668
870
|
#
|
669
|
-
#
|
670
|
-
#
|
671
|
-
|
871
|
+
# Related: #|, #&, #-, #~
|
872
|
+
#
|
873
|
+
# ==== Set identities
|
874
|
+
#
|
875
|
+
# <tt>lhs ^ rhs</tt> is equivalent to:
|
876
|
+
# * <tt>rhs ^ lhs</tt> (commutative)
|
877
|
+
# * <tt>~lhs ^ ~rhs</tt>
|
878
|
+
# * <tt>(lhs | rhs) - (lhs & rhs)</tt>
|
879
|
+
# * <tt>(lhs - rhs) | (rhs - lhs)</tt>
|
880
|
+
# * <tt>(lhs ^ other) ^ (other ^ rhs)</tt>
|
881
|
+
def ^(other) remain_frozen (dup | other).subtract(self & other) end
|
672
882
|
alias xor :^
|
673
883
|
|
674
884
|
# :call-seq:
|
@@ -685,21 +895,30 @@ module Net
|
|
685
895
|
# ~Net::IMAP::SequenceSet["6:99,223:*"]
|
686
896
|
# #=> Net::IMAP::SequenceSet["1:5,100:222"]
|
687
897
|
#
|
688
|
-
# Related: #complement
|
898
|
+
# Related: #complement!, #|, #&, #-, #^
|
899
|
+
#
|
900
|
+
# ==== Set identities
|
901
|
+
#
|
902
|
+
# <tt>~set</tt> is equivalent to:
|
903
|
+
# * <tt>full - set</tt>, where "full" is Net::IMAP::SequenceSet.full
|
689
904
|
def ~; remain_frozen dup.complement! end
|
690
905
|
alias complement :~
|
691
906
|
|
692
907
|
# :call-seq:
|
693
|
-
# add(
|
908
|
+
# add(element) -> self
|
694
909
|
# self << other -> self
|
695
910
|
#
|
696
911
|
# Adds a range or number to the set and returns +self+.
|
697
912
|
#
|
698
913
|
# #string will be regenerated. Use #merge to add many elements at once.
|
699
914
|
#
|
700
|
-
#
|
701
|
-
|
702
|
-
|
915
|
+
# Use #append to append new elements to #string. See
|
916
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
917
|
+
#
|
918
|
+
# Related: #add?, #merge, #union, #append
|
919
|
+
def add(element)
|
920
|
+
modifying! # short-circuit before input_to_tuple
|
921
|
+
tuple_add input_to_tuple element
|
703
922
|
normalize!
|
704
923
|
end
|
705
924
|
alias << add
|
@@ -708,9 +927,13 @@ module Net
|
|
708
927
|
#
|
709
928
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
710
929
|
# This may result in a #string which has duplicates or is out-of-order.
|
711
|
-
|
712
|
-
|
713
|
-
|
930
|
+
#
|
931
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
932
|
+
#
|
933
|
+
# Related: #add, #merge, #union
|
934
|
+
def append(entry)
|
935
|
+
modifying! # short-circuit before input_to_tuple
|
936
|
+
tuple = input_to_tuple entry
|
714
937
|
entry = tuple_to_str tuple
|
715
938
|
string unless empty? # write @string before tuple_add
|
716
939
|
tuple_add tuple
|
@@ -718,19 +941,20 @@ module Net
|
|
718
941
|
self
|
719
942
|
end
|
720
943
|
|
721
|
-
# :call-seq: add?(
|
944
|
+
# :call-seq: add?(element) -> self or nil
|
722
945
|
#
|
723
946
|
# Adds a range or number to the set and returns +self+. Returns +nil+
|
724
|
-
# when the
|
947
|
+
# when the element is already included in the set.
|
725
948
|
#
|
726
949
|
# #string will be regenerated. Use #merge to add many elements at once.
|
727
950
|
#
|
728
951
|
# Related: #add, #merge, #union, #include?
|
729
|
-
def add?(
|
730
|
-
|
952
|
+
def add?(element)
|
953
|
+
modifying! # short-circuit before include?
|
954
|
+
add element unless include? element
|
731
955
|
end
|
732
956
|
|
733
|
-
# :call-seq: delete(
|
957
|
+
# :call-seq: delete(element) -> self
|
734
958
|
#
|
735
959
|
# Deletes the given range or number from the set and returns +self+.
|
736
960
|
#
|
@@ -738,8 +962,9 @@ module Net
|
|
738
962
|
# many elements at once.
|
739
963
|
#
|
740
964
|
# Related: #delete?, #delete_at, #subtract, #difference
|
741
|
-
def delete(
|
742
|
-
|
965
|
+
def delete(element)
|
966
|
+
modifying! # short-circuit before input_to_tuple
|
967
|
+
tuple_subtract input_to_tuple element
|
743
968
|
normalize!
|
744
969
|
end
|
745
970
|
|
@@ -775,8 +1000,9 @@ module Net
|
|
775
1000
|
# #string will be regenerated after deletion.
|
776
1001
|
#
|
777
1002
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
778
|
-
def delete?(
|
779
|
-
|
1003
|
+
def delete?(element)
|
1004
|
+
modifying! # short-circuit before input_to_tuple
|
1005
|
+
tuple = input_to_tuple element
|
780
1006
|
if tuple.first == tuple.last
|
781
1007
|
return unless include_tuple? tuple
|
782
1008
|
tuple_subtract tuple
|
@@ -816,37 +1042,33 @@ module Net
|
|
816
1042
|
#
|
817
1043
|
# Related: #slice, #delete_at, #delete, #delete?, #subtract, #difference
|
818
1044
|
def slice!(index, length = nil)
|
1045
|
+
modifying! # short-circuit before slice
|
819
1046
|
deleted = slice(index, length) and subtract deleted
|
820
1047
|
deleted
|
821
1048
|
end
|
822
1049
|
|
823
|
-
# Merges all of the elements that appear in any of the +
|
1050
|
+
# Merges all of the elements that appear in any of the +sets+ into the
|
824
1051
|
# set, and returns +self+.
|
825
1052
|
#
|
826
|
-
# The +
|
827
|
-
# non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
|
828
|
-
# formatted strings, other sequence sets, or enumerables containing any of
|
829
|
-
# these.
|
1053
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
830
1054
|
#
|
831
|
-
# #string will be regenerated after all
|
1055
|
+
# #string will be regenerated after all sets have been merged.
|
832
1056
|
#
|
833
1057
|
# Related: #add, #add?, #union
|
834
|
-
def merge(*
|
835
|
-
|
1058
|
+
def merge(*sets)
|
1059
|
+
modifying! # short-circuit before input_to_tuples
|
1060
|
+
tuples_add input_to_tuples sets
|
836
1061
|
normalize!
|
837
1062
|
end
|
838
1063
|
|
839
|
-
# Removes all of the elements that appear in any of the given +
|
840
|
-
#
|
1064
|
+
# Removes all of the elements that appear in any of the given +sets+ from
|
1065
|
+
# the set, and returns +self+.
|
841
1066
|
#
|
842
|
-
# The +
|
843
|
-
# non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
|
844
|
-
# formatted strings, other sequence sets, or enumerables containing any of
|
845
|
-
# these.
|
1067
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
846
1068
|
#
|
847
1069
|
# Related: #difference
|
848
|
-
def subtract(*
|
849
|
-
tuples_subtract input_to_tuples
|
1070
|
+
def subtract(*sets)
|
1071
|
+
tuples_subtract input_to_tuples sets
|
850
1072
|
normalize!
|
851
1073
|
end
|
852
1074
|
|
@@ -858,21 +1080,21 @@ module Net
|
|
858
1080
|
# This is useful when the given order is significant, for example in a
|
859
1081
|
# ESEARCH response to IMAP#sort.
|
860
1082
|
#
|
1083
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1084
|
+
#
|
861
1085
|
# Related: #each_entry, #elements
|
862
1086
|
def entries; each_entry.to_a end
|
863
1087
|
|
864
1088
|
# Returns an array of ranges and integers and <tt>:*</tt>.
|
865
1089
|
#
|
866
1090
|
# The returned elements are sorted and coalesced, even when the input
|
867
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize
|
1091
|
+
# #string is not. <tt>*</tt> will sort last. See #normalize,
|
1092
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
868
1093
|
#
|
869
1094
|
# By itself, <tt>*</tt> translates to <tt>:*</tt>. A range containing
|
870
1095
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
871
1096
|
# cases to a maximum value.
|
872
1097
|
#
|
873
|
-
# The returned elements will be sorted and coalesced, even when the input
|
874
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
875
|
-
#
|
876
1098
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
|
877
1099
|
# #=> [2, 5..9, 11..12, :*]
|
878
1100
|
#
|
@@ -883,15 +1105,13 @@ module Net
|
|
883
1105
|
# Returns an array of ranges
|
884
1106
|
#
|
885
1107
|
# The returned elements are sorted and coalesced, even when the input
|
886
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize
|
1108
|
+
# #string is not. <tt>*</tt> will sort last. See #normalize,
|
1109
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
887
1110
|
#
|
888
1111
|
# <tt>*</tt> translates to an endless range. By itself, <tt>*</tt>
|
889
1112
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
890
1113
|
# value.
|
891
1114
|
#
|
892
|
-
# The returned ranges will be sorted and coalesced, even when the input
|
893
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
894
|
-
#
|
895
1115
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
|
896
1116
|
# #=> [2..2, 5..9, 11..12, :*..]
|
897
1117
|
# Net::IMAP::SequenceSet["123,999:*,456:789"].ranges
|
@@ -903,7 +1123,7 @@ module Net
|
|
903
1123
|
# Returns a sorted array of all of the number values in the sequence set.
|
904
1124
|
#
|
905
1125
|
# The returned numbers are sorted and de-duplicated, even when the input
|
906
|
-
# #string is not. See #normalize.
|
1126
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
907
1127
|
#
|
908
1128
|
# Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers
|
909
1129
|
# #=> [2, 5, 6, 7, 8, 9, 11, 12]
|
@@ -935,6 +1155,8 @@ module Net
|
|
935
1155
|
# no sorting, deduplication, or coalescing. When #string is in its
|
936
1156
|
# normalized form, this will yield the same values as #each_element.
|
937
1157
|
#
|
1158
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1159
|
+
#
|
938
1160
|
# Related: #entries, #each_element
|
939
1161
|
def each_entry(&block) # :yields: integer or range or :*
|
940
1162
|
return to_enum(__method__) unless block_given?
|
@@ -945,7 +1167,7 @@ module Net
|
|
945
1167
|
# and returns self. Returns an enumerator when called without a block.
|
946
1168
|
#
|
947
1169
|
# The returned numbers are sorted and de-duplicated, even when the input
|
948
|
-
# #string is not. See #normalize.
|
1170
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
949
1171
|
#
|
950
1172
|
# Related: #elements, #each_entry
|
951
1173
|
def each_element # :yields: integer or range or :*
|
@@ -1239,20 +1461,76 @@ module Net
|
|
1239
1461
|
def slice_range(range)
|
1240
1462
|
first = range.begin || 0
|
1241
1463
|
last = range.end || -1
|
1242
|
-
|
1464
|
+
if range.exclude_end?
|
1465
|
+
return remain_frozen_empty if last.zero?
|
1466
|
+
last -= 1 if range.end && last != STAR_INT
|
1467
|
+
end
|
1243
1468
|
if (first * last).positive? && last < first
|
1244
|
-
|
1469
|
+
remain_frozen_empty
|
1245
1470
|
elsif (min = at(first))
|
1246
1471
|
max = at(last)
|
1472
|
+
max = :* if max.nil?
|
1247
1473
|
if max == :* then self & (min..)
|
1248
1474
|
elsif min <= max then self & (min..max)
|
1249
|
-
else
|
1475
|
+
else remain_frozen_empty
|
1250
1476
|
end
|
1251
1477
|
end
|
1252
1478
|
end
|
1253
1479
|
|
1254
1480
|
public
|
1255
1481
|
|
1482
|
+
# Returns a copy of +self+ which only contains the numbers above +num+.
|
1483
|
+
#
|
1484
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].above(10) # to_s => "11:22,50"
|
1485
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].above(20) # to_s => "21:22,50
|
1486
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].above(30) # to_s => "50"
|
1487
|
+
#
|
1488
|
+
# This returns the same result as #intersection with <tt>((num+1)..)</tt>
|
1489
|
+
# or #difference with <tt>(..num)</tt>.
|
1490
|
+
#
|
1491
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] & (11..) # to_s => "11:22,50"
|
1492
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] - (..10) # to_s => "11:22,50"
|
1493
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] & (21..) # to_s => "21:22,50"
|
1494
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] - (..20) # to_s => "21:22,50"
|
1495
|
+
#
|
1496
|
+
# Related: #above, #-, #&
|
1497
|
+
def above(num)
|
1498
|
+
NumValidator.valid_nz_number?(num) or
|
1499
|
+
raise ArgumentError, "not a valid sequence set number"
|
1500
|
+
difference(..num)
|
1501
|
+
end
|
1502
|
+
|
1503
|
+
# Returns a copy of +self+ which only contains numbers below +num+.
|
1504
|
+
#
|
1505
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].below(10) # to_s => "5"
|
1506
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].below(20) # to_s => "5,10:19"
|
1507
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
|
1508
|
+
#
|
1509
|
+
# This returns the same result as #intersection with <tt>(..(num-1))</tt>
|
1510
|
+
# or #difference with <tt>(num..)</tt>.
|
1511
|
+
#
|
1512
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] & (..9) # to_s => "5"
|
1513
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] - (10..) # to_s => "5"
|
1514
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] & (..19) # to_s => "5,10:19"
|
1515
|
+
# Net::IMAP::SequenceSet["5,10:22,50"] - (20..) # to_s => "5,10:19"
|
1516
|
+
#
|
1517
|
+
# When the set does not contain <tt>*</tt>, #below is identical to #limit
|
1518
|
+
# with <tt>max: num - 1</tt>. When the set does contain <tt>*</tt>,
|
1519
|
+
# #below always drops it from the result. Use #limit when the IMAP
|
1520
|
+
# semantics for <tt>*</tt> must be enforced.
|
1521
|
+
#
|
1522
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
|
1523
|
+
# Net::IMAP::SequenceSet["5,10:22,50"].limit(max: 29) # to_s => "5,10:22"
|
1524
|
+
# Net::IMAP::SequenceSet["5,10:22,*"].below(30) # to_s => "5,10:22"
|
1525
|
+
# Net::IMAP::SequenceSet["5,10:22,*"].limit(max: 29) # to_s => "5,10:22,29"
|
1526
|
+
#
|
1527
|
+
# Related: #above, #-, #&, #limit
|
1528
|
+
def below(num)
|
1529
|
+
NumValidator.valid_nz_number?(num) or
|
1530
|
+
raise ArgumentError, "not a valid sequence set number"
|
1531
|
+
difference(num..)
|
1532
|
+
end
|
1533
|
+
|
1256
1534
|
# Returns a frozen SequenceSet with <tt>*</tt> converted to +max+, numbers
|
1257
1535
|
# and ranges over +max+ removed, and ranges containing +max+ converted to
|
1258
1536
|
# end at +max+.
|
@@ -1270,6 +1548,7 @@ module Net
|
|
1270
1548
|
# Net::IMAP::SequenceSet["500:*"].limit(max: 37)
|
1271
1549
|
# #=> Net::IMAP::SequenceSet["37"]
|
1272
1550
|
#
|
1551
|
+
# Related: #limit!
|
1273
1552
|
def limit(max:)
|
1274
1553
|
max = to_tuple_int(max)
|
1275
1554
|
if empty? then self.class.empty
|
@@ -1284,6 +1563,7 @@ module Net
|
|
1284
1563
|
#
|
1285
1564
|
# Related: #limit
|
1286
1565
|
def limit!(max:)
|
1566
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1287
1567
|
star = include_star?
|
1288
1568
|
max = to_tuple_int(max)
|
1289
1569
|
tuple_subtract [max + 1, STAR_INT]
|
@@ -1298,6 +1578,7 @@ module Net
|
|
1298
1578
|
#
|
1299
1579
|
# Related: #complement
|
1300
1580
|
def complement!
|
1581
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1301
1582
|
return replace(self.class.full) if empty?
|
1302
1583
|
return clear if full?
|
1303
1584
|
flat = @tuples.flat_map { [_1 - 1, _2 + 1] }
|
@@ -1311,6 +1592,7 @@ module Net
|
|
1311
1592
|
#
|
1312
1593
|
# The returned set's #string is sorted and deduplicated. Adjacent or
|
1313
1594
|
# overlapping elements will be merged into a single larger range.
|
1595
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1314
1596
|
#
|
1315
1597
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize
|
1316
1598
|
# #=> Net::IMAP::SequenceSet["1:7,9:11"]
|
@@ -1323,21 +1605,24 @@ module Net
|
|
1323
1605
|
end
|
1324
1606
|
|
1325
1607
|
# Resets #string to be sorted, deduplicated, and coalesced. Returns
|
1326
|
-
# +self+.
|
1608
|
+
# +self+. See SequenceSet@Ordered+and+Normalized+sets.
|
1327
1609
|
#
|
1328
1610
|
# Related: #normalize, #normalized_string
|
1329
1611
|
def normalize!
|
1612
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
1330
1613
|
@string = nil
|
1331
1614
|
self
|
1332
1615
|
end
|
1333
1616
|
|
1334
1617
|
# Returns a normalized +sequence-set+ string representation, sorted
|
1335
1618
|
# and deduplicated. Adjacent or overlapping elements will be merged into
|
1336
|
-
# a single larger range.
|
1619
|
+
# a single larger range. See SequenceSet@Ordered+and+Normalized+sets.
|
1337
1620
|
#
|
1338
1621
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string
|
1339
1622
|
# #=> "1:7,9:11"
|
1340
1623
|
#
|
1624
|
+
# Returns +nil+ when the set is empty.
|
1625
|
+
#
|
1341
1626
|
# Related: #normalize!, #normalize
|
1342
1627
|
def normalized_string
|
1343
1628
|
@tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",")
|
@@ -1353,7 +1638,15 @@ module Net
|
|
1353
1638
|
end
|
1354
1639
|
end
|
1355
1640
|
|
1356
|
-
|
1641
|
+
##
|
1642
|
+
# :method: to_sequence_set
|
1643
|
+
# :call-seq: to_sequence_set -> self
|
1644
|
+
#
|
1645
|
+
# Returns +self+
|
1646
|
+
#
|
1647
|
+
# Related: ::try_convert
|
1648
|
+
|
1649
|
+
# :nodoc: (work around rdoc bug)
|
1357
1650
|
alias to_sequence_set itself
|
1358
1651
|
|
1359
1652
|
# Unstable API: currently for internal use only (Net::IMAP#validate_data)
|
@@ -1367,6 +1660,18 @@ module Net
|
|
1367
1660
|
imap.__send__(:put_string, valid_string)
|
1368
1661
|
end
|
1369
1662
|
|
1663
|
+
# For YAML serialization
|
1664
|
+
def encode_with(coder) # :nodoc:
|
1665
|
+
# we can perfectly reconstruct from the string
|
1666
|
+
coder['string'] = to_s
|
1667
|
+
end
|
1668
|
+
|
1669
|
+
# For YAML deserialization
|
1670
|
+
def init_with(coder) # :nodoc:
|
1671
|
+
@tuples = []
|
1672
|
+
self.string = coder['string']
|
1673
|
+
end
|
1674
|
+
|
1370
1675
|
protected
|
1371
1676
|
|
1372
1677
|
attr_reader :tuples # :nodoc:
|
@@ -1374,6 +1679,7 @@ module Net
|
|
1374
1679
|
private
|
1375
1680
|
|
1376
1681
|
def remain_frozen(set) frozen? ? set.freeze : set end
|
1682
|
+
def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end
|
1377
1683
|
|
1378
1684
|
# frozen clones are shallow copied
|
1379
1685
|
def initialize_clone(other)
|
@@ -1381,35 +1687,35 @@ module Net
|
|
1381
1687
|
end
|
1382
1688
|
|
1383
1689
|
def initialize_dup(other)
|
1690
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
1384
1691
|
@tuples = other.tuples.map(&:dup)
|
1385
1692
|
@string = other.string&.-@
|
1386
1693
|
super
|
1387
1694
|
end
|
1388
1695
|
|
1389
|
-
def input_to_tuple(
|
1390
|
-
|
1391
|
-
case
|
1392
|
-
when *STARS, Integer then [int = to_tuple_int(
|
1393
|
-
when Range then range_to_tuple(
|
1394
|
-
when String then str_to_tuple(
|
1696
|
+
def input_to_tuple(entry)
|
1697
|
+
entry = input_try_convert entry
|
1698
|
+
case entry
|
1699
|
+
when *STARS, Integer then [int = to_tuple_int(entry), int]
|
1700
|
+
when Range then range_to_tuple(entry)
|
1701
|
+
when String then str_to_tuple(entry)
|
1395
1702
|
else
|
1396
|
-
raise DataFormatError, "expected number or range, got %p" % [
|
1703
|
+
raise DataFormatError, "expected number or range, got %p" % [entry]
|
1397
1704
|
end
|
1398
1705
|
end
|
1399
1706
|
|
1400
|
-
def input_to_tuples(
|
1401
|
-
|
1402
|
-
case
|
1403
|
-
when *STARS, Integer, Range then [input_to_tuple(
|
1404
|
-
when String then str_to_tuples
|
1405
|
-
when SequenceSet then
|
1406
|
-
when Set then
|
1407
|
-
when Array then
|
1707
|
+
def input_to_tuples(set)
|
1708
|
+
set = input_try_convert set
|
1709
|
+
case set
|
1710
|
+
when *STARS, Integer, Range then [input_to_tuple(set)]
|
1711
|
+
when String then str_to_tuples set
|
1712
|
+
when SequenceSet then set.tuples
|
1713
|
+
when Set then set.map { [to_tuple_int(_1)] * 2 }
|
1714
|
+
when Array then set.flat_map { input_to_tuples _1 }
|
1408
1715
|
when nil then []
|
1409
1716
|
else
|
1410
|
-
raise DataFormatError,
|
1411
|
-
|
1412
|
-
"got %p" % [obj]
|
1717
|
+
raise DataFormatError, "expected nz-number, range, '*', Set, Array; " \
|
1718
|
+
"got %p" % [set]
|
1413
1719
|
end
|
1414
1720
|
end
|
1415
1721
|
|