net-imap 0.5.7 → 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 +5 -1
- data/lib/net/imap/response_data.rb +0 -1
- data/lib/net/imap/sequence_set.rb +405 -113
- data/lib/net/imap.rb +46 -16
- data/rakelib/string_prep_tables_generator.rb +4 -2
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9a31378c34762136e5fc341801a0b4073157dc6c35df6aae3254d3f7b90a07b7
|
4
|
+
data.tar.gz: cbf787e39ecfde5a7af0061baba54eae3d7b12077679854ea62b335fc9b48798
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fd0c8a34fa212bb42a55e943bf8184c614256b52da4ac13bdddb48f74c8517f5c7b72addb2153af42d76f2a8bcf42627ceb34e874b7842d8a6dfd542ba577578
|
7
|
+
data.tar.gz: 91dd4d1d35582abb9e4fd0df64c63ee5c9320f3404d548bff0a4023e32dc9a6ddd6b90cd1cc221e637a4719f3cc5699d57cc337ea17a6454b3aa7d7be9ffb423
|
data/Gemfile
CHANGED
@@ -28,7 +28,11 @@ module Net
|
|
28
28
|
end
|
29
29
|
private_class_method :included
|
30
30
|
|
31
|
-
|
31
|
+
if defined?(Ractor.make_shareable)
|
32
|
+
def self.safe(...) Ractor.make_shareable nil.instance_eval(...).freeze end
|
33
|
+
else
|
34
|
+
def self.safe(...) nil.instance_eval(...).freeze end
|
35
|
+
end
|
32
36
|
private_class_method :safe
|
33
37
|
|
34
38
|
Types = Hash.new do |h, type| type => Proc | nil; safe{type} end
|
@@ -6,7 +6,6 @@ module Net
|
|
6
6
|
autoload :FetchData, "#{__dir__}/fetch_data"
|
7
7
|
autoload :UIDFetchData, "#{__dir__}/fetch_data"
|
8
8
|
autoload :SearchResult, "#{__dir__}/search_result"
|
9
|
-
autoload :SequenceSet, "#{__dir__}/sequence_set"
|
10
9
|
autoload :UIDPlusData, "#{__dir__}/uidplus_data"
|
11
10
|
autoload :AppendUIDData, "#{__dir__}/uidplus_data"
|
12
11
|
autoload :CopyUIDData, "#{__dir__}/uidplus_data"
|
@@ -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
|
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
|
53
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 element
|
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
|
@@ -248,6 +324,10 @@ module Net
|
|
248
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
|
#
|
@@ -329,13 +409,12 @@ module Net
|
|
329
409
|
# An empty SequenceSet is invalid and will raise a DataFormatError.
|
330
410
|
#
|
331
411
|
# Use ::new to create a mutable or empty SequenceSet.
|
412
|
+
#
|
413
|
+
# Related: ::new, Net::IMAP::SequenceSet(), ::try_convert
|
332
414
|
def [](first, *rest)
|
333
415
|
if rest.empty?
|
334
|
-
|
335
|
-
|
336
|
-
else
|
337
|
-
new(first).validate.freeze
|
338
|
-
end
|
416
|
+
set = try_convert(first)&.validate
|
417
|
+
set&.frozen? ? set : (set&.dup || new(first).validate).freeze
|
339
418
|
else
|
340
419
|
new(first).merge(*rest).validate.freeze
|
341
420
|
end
|
@@ -350,6 +429,8 @@ module Net
|
|
350
429
|
#
|
351
430
|
# If +obj.to_sequence_set+ doesn't return a SequenceSet, an exception is
|
352
431
|
# raised.
|
432
|
+
#
|
433
|
+
# Related: Net::IMAP::SequenceSet(), ::new, ::[]
|
353
434
|
def try_convert(obj)
|
354
435
|
return obj if obj.is_a?(SequenceSet)
|
355
436
|
return nil unless obj.respond_to?(:to_sequence_set)
|
@@ -368,20 +449,85 @@ module Net
|
|
368
449
|
end
|
369
450
|
|
370
451
|
# Create a new SequenceSet object from +input+, which may be another
|
371
|
-
# SequenceSet, an IMAP formatted +sequence-set+ string, a
|
372
|
-
# range, <tt>:*</tt>,
|
373
|
-
#
|
374
|
-
#
|
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.
|
375
517
|
def initialize(input = nil) input ? replace(input) : clear end
|
376
518
|
|
377
519
|
# Removes all elements and returns self.
|
378
|
-
def clear
|
520
|
+
def clear
|
521
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
522
|
+
@tuples, @string = [], nil
|
523
|
+
self
|
524
|
+
end
|
379
525
|
|
380
526
|
# Replace the contents of the set with the contents of +other+ and returns
|
381
527
|
# +self+.
|
382
528
|
#
|
383
|
-
# +other+ may be another SequenceSet
|
384
|
-
#
|
529
|
+
# +other+ may be another SequenceSet or any other object that would be
|
530
|
+
# accepted by ::new.
|
385
531
|
def replace(other)
|
386
532
|
case other
|
387
533
|
when SequenceSet then initialize_dup(other)
|
@@ -431,11 +577,13 @@ module Net
|
|
431
577
|
if str.nil?
|
432
578
|
clear
|
433
579
|
else
|
580
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
434
581
|
str = String.try_convert(str) or raise ArgumentError, "not a string"
|
435
582
|
tuples = str_to_tuples str
|
436
583
|
@tuples, @string = [], -str
|
437
584
|
tuples_add tuples
|
438
585
|
end
|
586
|
+
str
|
439
587
|
end
|
440
588
|
|
441
589
|
# Returns the \IMAP +sequence-set+ string representation, or an empty
|
@@ -495,8 +643,9 @@ module Net
|
|
495
643
|
|
496
644
|
# :call-seq: self === other -> true | false | nil
|
497
645
|
#
|
498
|
-
# Returns whether +other+ is contained within the set.
|
499
|
-
#
|
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.
|
500
649
|
#
|
501
650
|
# Related: #cover?, #include?, #include_star?
|
502
651
|
def ===(other)
|
@@ -510,12 +659,12 @@ module Net
|
|
510
659
|
# Returns whether +other+ is contained within the set. +other+ may be any
|
511
660
|
# object that would be accepted by ::new.
|
512
661
|
#
|
513
|
-
# Related: #===, #include?, #include_star?
|
662
|
+
# Related: #===, #include?, #include_star?, #intersect?
|
514
663
|
def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
|
515
664
|
|
516
665
|
# Returns +true+ when a given number or range is in +self+, and +false+
|
517
|
-
# otherwise. Returns +
|
518
|
-
# <tt>*</tt
|
666
|
+
# otherwise. Returns +nil+ when +number+ isn't a valid SequenceSet
|
667
|
+
# element (Integer, Range, <tt>*</tt>, +sequence-set+ string).
|
519
668
|
#
|
520
669
|
# set = Net::IMAP::SequenceSet["5:10,100,111:115"]
|
521
670
|
# set.include? 1 #=> false
|
@@ -523,8 +672,8 @@ module Net
|
|
523
672
|
# set.include? 11..20 #=> false
|
524
673
|
# set.include? 100 #=> true
|
525
674
|
# set.include? 6 #=> true, covered by "5:10"
|
526
|
-
# set.include?
|
527
|
-
# set.include? "
|
675
|
+
# set.include? 6..9 #=> true, covered by "5:10"
|
676
|
+
# set.include? "6:9" #=> true, strings are parsed
|
528
677
|
# set.include? 4..9 #=> false, intersection is not sufficient
|
529
678
|
# set.include? "*" #=> false, use #limit to re-interpret "*"
|
530
679
|
# set.include? -1 #=> false, -1 is interpreted as "*"
|
@@ -533,11 +682,14 @@ module Net
|
|
533
682
|
# set.include? :* #=> true
|
534
683
|
# set.include? "*" #=> true
|
535
684
|
# set.include? -1 #=> true
|
536
|
-
# set.include?
|
537
|
-
# set.include?
|
685
|
+
# set.include?(200..) #=> true
|
686
|
+
# set.include?(100..) #=> false
|
538
687
|
#
|
539
|
-
# Related: #include_star?, #cover?,
|
540
|
-
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
|
541
693
|
|
542
694
|
alias member? include?
|
543
695
|
|
@@ -550,7 +702,7 @@ module Net
|
|
550
702
|
# Net::IMAP::SequenceSet["5:10"].intersect? "7,9,11" #=> true
|
551
703
|
# Net::IMAP::SequenceSet["5:10"].intersect? "11:33" #=> false
|
552
704
|
#
|
553
|
-
# Related: #intersection, #disjoint?
|
705
|
+
# Related: #intersection, #disjoint?, #cover?, #include?
|
554
706
|
def intersect?(other)
|
555
707
|
valid? && input_to_tuples(other).any? { intersect_tuple? _1 }
|
556
708
|
end
|
@@ -567,26 +719,53 @@ module Net
|
|
567
719
|
empty? || input_to_tuples(other).none? { intersect_tuple? _1 }
|
568
720
|
end
|
569
721
|
|
570
|
-
# :call-seq:
|
722
|
+
# :call-seq:
|
723
|
+
# max(star: :*) => integer or star or nil
|
724
|
+
# max(count) => SequenceSet
|
571
725
|
#
|
572
726
|
# Returns the maximum value in +self+, +star+ when the set includes
|
573
727
|
# <tt>*</tt>, or +nil+ when the set is empty.
|
574
|
-
|
575
|
-
|
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
|
576
740
|
end
|
577
741
|
|
578
|
-
# :call-seq:
|
742
|
+
# :call-seq:
|
743
|
+
# min(star: :*) => integer or star or nil
|
744
|
+
# min(count) => SequenceSet
|
579
745
|
#
|
580
746
|
# Returns the minimum value in +self+, +star+ when the only value in the
|
581
747
|
# set is <tt>*</tt>, or +nil+ when the set is empty.
|
582
|
-
|
583
|
-
|
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
|
584
760
|
end
|
585
761
|
|
586
|
-
# :call-seq: minmax(star: :*) =>
|
762
|
+
# :call-seq: minmax(star: :*) => [min, max] or nil
|
587
763
|
#
|
588
764
|
# Returns a 2-element array containing the minimum and maximum numbers in
|
589
|
-
# +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
|
590
769
|
def minmax(star: :*); [min(star: star), max(star: star)] unless empty? end
|
591
770
|
|
592
771
|
# Returns false when the set is empty.
|
@@ -606,14 +785,19 @@ module Net
|
|
606
785
|
# Returns a new sequence set that has every number in the +other+ object
|
607
786
|
# added.
|
608
787
|
#
|
609
|
-
# +other+ may be any object that would be accepted by ::new
|
610
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
611
|
-
# another sequence set, or an enumerable containing any of these.
|
788
|
+
# +other+ may be any object that would be accepted by ::new.
|
612
789
|
#
|
613
790
|
# Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99]
|
614
791
|
# #=> Net::IMAP::SequenceSet["1:6,99"]
|
615
792
|
#
|
616
|
-
# 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>
|
617
801
|
def |(other) remain_frozen dup.merge other end
|
618
802
|
alias :+ :|
|
619
803
|
alias union :|
|
@@ -625,14 +809,22 @@ module Net
|
|
625
809
|
# Returns a new sequence set built by duplicating this set and removing
|
626
810
|
# every number that appears in +other+.
|
627
811
|
#
|
628
|
-
# +other+ may be any object that would be accepted by ::new
|
629
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
630
|
-
# another sequence set, or an enumerable containing any of these.
|
812
|
+
# +other+ may be any object that would be accepted by ::new.
|
631
813
|
#
|
632
814
|
# Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6
|
633
815
|
# #=> Net::IMAP::SequenceSet["1,3,5"]
|
634
816
|
#
|
635
|
-
# 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>
|
636
828
|
def -(other) remain_frozen dup.subtract other end
|
637
829
|
alias difference :-
|
638
830
|
|
@@ -643,14 +835,22 @@ module Net
|
|
643
835
|
# Returns a new sequence set containing only the numbers common to this
|
644
836
|
# set and +other+.
|
645
837
|
#
|
646
|
-
# +other+ may be any object that would be accepted by ::new
|
647
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
648
|
-
# another sequence set, or an enumerable containing any of these.
|
838
|
+
# +other+ may be any object that would be accepted by ::new.
|
649
839
|
#
|
650
840
|
# Net::IMAP::SequenceSet[1..5] & [2, 4, 6]
|
651
841
|
# #=> Net::IMAP::SequenceSet["2,4"]
|
652
842
|
#
|
653
|
-
#
|
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>
|
654
854
|
def &(other)
|
655
855
|
remain_frozen dup.subtract SequenceSet.new(other).complement!
|
656
856
|
end
|
@@ -663,16 +863,22 @@ module Net
|
|
663
863
|
# Returns a new sequence set containing numbers that are exclusive between
|
664
864
|
# this set and +other+.
|
665
865
|
#
|
666
|
-
# +other+ may be any object that would be accepted by ::new
|
667
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
668
|
-
# another sequence set, or an enumerable containing any of these.
|
866
|
+
# +other+ may be any object that would be accepted by ::new.
|
669
867
|
#
|
670
868
|
# Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6]
|
671
869
|
# #=> Net::IMAP::SequenceSet["1,3,5:6"]
|
672
870
|
#
|
673
|
-
#
|
674
|
-
#
|
675
|
-
|
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
|
676
882
|
alias xor :^
|
677
883
|
|
678
884
|
# :call-seq:
|
@@ -689,7 +895,12 @@ module Net
|
|
689
895
|
# ~Net::IMAP::SequenceSet["6:99,223:*"]
|
690
896
|
# #=> Net::IMAP::SequenceSet["1:5,100:222"]
|
691
897
|
#
|
692
|
-
# 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
|
693
904
|
def ~; remain_frozen dup.complement! end
|
694
905
|
alias complement :~
|
695
906
|
|
@@ -701,8 +912,12 @@ module Net
|
|
701
912
|
#
|
702
913
|
# #string will be regenerated. Use #merge to add many elements at once.
|
703
914
|
#
|
704
|
-
#
|
915
|
+
# Use #append to append new elements to #string. See
|
916
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
917
|
+
#
|
918
|
+
# Related: #add?, #merge, #union, #append
|
705
919
|
def add(element)
|
920
|
+
modifying! # short-circuit before input_to_tuple
|
706
921
|
tuple_add input_to_tuple element
|
707
922
|
normalize!
|
708
923
|
end
|
@@ -712,8 +927,12 @@ module Net
|
|
712
927
|
#
|
713
928
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
714
929
|
# This may result in a #string which has duplicates or is out-of-order.
|
930
|
+
#
|
931
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
932
|
+
#
|
933
|
+
# Related: #add, #merge, #union
|
715
934
|
def append(entry)
|
716
|
-
modifying!
|
935
|
+
modifying! # short-circuit before input_to_tuple
|
717
936
|
tuple = input_to_tuple entry
|
718
937
|
entry = tuple_to_str tuple
|
719
938
|
string unless empty? # write @string before tuple_add
|
@@ -731,6 +950,7 @@ module Net
|
|
731
950
|
#
|
732
951
|
# Related: #add, #merge, #union, #include?
|
733
952
|
def add?(element)
|
953
|
+
modifying! # short-circuit before include?
|
734
954
|
add element unless include? element
|
735
955
|
end
|
736
956
|
|
@@ -743,6 +963,7 @@ module Net
|
|
743
963
|
#
|
744
964
|
# Related: #delete?, #delete_at, #subtract, #difference
|
745
965
|
def delete(element)
|
966
|
+
modifying! # short-circuit before input_to_tuple
|
746
967
|
tuple_subtract input_to_tuple element
|
747
968
|
normalize!
|
748
969
|
end
|
@@ -780,6 +1001,7 @@ module Net
|
|
780
1001
|
#
|
781
1002
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
782
1003
|
def delete?(element)
|
1004
|
+
modifying! # short-circuit before input_to_tuple
|
783
1005
|
tuple = input_to_tuple element
|
784
1006
|
if tuple.first == tuple.last
|
785
1007
|
return unless include_tuple? tuple
|
@@ -820,6 +1042,7 @@ module Net
|
|
820
1042
|
#
|
821
1043
|
# Related: #slice, #delete_at, #delete, #delete?, #subtract, #difference
|
822
1044
|
def slice!(index, length = nil)
|
1045
|
+
modifying! # short-circuit before slice
|
823
1046
|
deleted = slice(index, length) and subtract deleted
|
824
1047
|
deleted
|
825
1048
|
end
|
@@ -827,14 +1050,13 @@ module Net
|
|
827
1050
|
# Merges all of the elements that appear in any of the +sets+ into the
|
828
1051
|
# set, and returns +self+.
|
829
1052
|
#
|
830
|
-
# The +sets+ may be any objects that would be accepted by ::new
|
831
|
-
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
832
|
-
# strings, other sequence sets, or enumerables containing any of these.
|
1053
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
833
1054
|
#
|
834
1055
|
# #string will be regenerated after all sets have been merged.
|
835
1056
|
#
|
836
1057
|
# Related: #add, #add?, #union
|
837
1058
|
def merge(*sets)
|
1059
|
+
modifying! # short-circuit before input_to_tuples
|
838
1060
|
tuples_add input_to_tuples sets
|
839
1061
|
normalize!
|
840
1062
|
end
|
@@ -842,9 +1064,7 @@ module Net
|
|
842
1064
|
# Removes all of the elements that appear in any of the given +sets+ from
|
843
1065
|
# the set, and returns +self+.
|
844
1066
|
#
|
845
|
-
# The +sets+ may be any objects that would be accepted by ::new
|
846
|
-
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
847
|
-
# strings, other sequence sets, or enumerables containing any of these.
|
1067
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
848
1068
|
#
|
849
1069
|
# Related: #difference
|
850
1070
|
def subtract(*sets)
|
@@ -860,21 +1080,21 @@ module Net
|
|
860
1080
|
# This is useful when the given order is significant, for example in a
|
861
1081
|
# ESEARCH response to IMAP#sort.
|
862
1082
|
#
|
1083
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1084
|
+
#
|
863
1085
|
# Related: #each_entry, #elements
|
864
1086
|
def entries; each_entry.to_a end
|
865
1087
|
|
866
1088
|
# Returns an array of ranges and integers and <tt>:*</tt>.
|
867
1089
|
#
|
868
1090
|
# The returned elements are sorted and coalesced, even when the input
|
869
|
-
# #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.
|
870
1093
|
#
|
871
1094
|
# By itself, <tt>*</tt> translates to <tt>:*</tt>. A range containing
|
872
1095
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
873
1096
|
# cases to a maximum value.
|
874
1097
|
#
|
875
|
-
# The returned elements will be sorted and coalesced, even when the input
|
876
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
877
|
-
#
|
878
1098
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
|
879
1099
|
# #=> [2, 5..9, 11..12, :*]
|
880
1100
|
#
|
@@ -885,15 +1105,13 @@ module Net
|
|
885
1105
|
# Returns an array of ranges
|
886
1106
|
#
|
887
1107
|
# The returned elements are sorted and coalesced, even when the input
|
888
|
-
# #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.
|
889
1110
|
#
|
890
1111
|
# <tt>*</tt> translates to an endless range. By itself, <tt>*</tt>
|
891
1112
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
892
1113
|
# value.
|
893
1114
|
#
|
894
|
-
# The returned ranges will be sorted and coalesced, even when the input
|
895
|
-
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
896
|
-
#
|
897
1115
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
|
898
1116
|
# #=> [2..2, 5..9, 11..12, :*..]
|
899
1117
|
# Net::IMAP::SequenceSet["123,999:*,456:789"].ranges
|
@@ -905,7 +1123,7 @@ module Net
|
|
905
1123
|
# Returns a sorted array of all of the number values in the sequence set.
|
906
1124
|
#
|
907
1125
|
# The returned numbers are sorted and de-duplicated, even when the input
|
908
|
-
# #string is not. See #normalize.
|
1126
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
909
1127
|
#
|
910
1128
|
# Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers
|
911
1129
|
# #=> [2, 5, 6, 7, 8, 9, 11, 12]
|
@@ -937,6 +1155,8 @@ module Net
|
|
937
1155
|
# no sorting, deduplication, or coalescing. When #string is in its
|
938
1156
|
# normalized form, this will yield the same values as #each_element.
|
939
1157
|
#
|
1158
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1159
|
+
#
|
940
1160
|
# Related: #entries, #each_element
|
941
1161
|
def each_entry(&block) # :yields: integer or range or :*
|
942
1162
|
return to_enum(__method__) unless block_given?
|
@@ -947,7 +1167,7 @@ module Net
|
|
947
1167
|
# and returns self. Returns an enumerator when called without a block.
|
948
1168
|
#
|
949
1169
|
# The returned numbers are sorted and de-duplicated, even when the input
|
950
|
-
# #string is not. See #normalize.
|
1170
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
951
1171
|
#
|
952
1172
|
# Related: #elements, #each_entry
|
953
1173
|
def each_element # :yields: integer or range or :*
|
@@ -1241,20 +1461,76 @@ module Net
|
|
1241
1461
|
def slice_range(range)
|
1242
1462
|
first = range.begin || 0
|
1243
1463
|
last = range.end || -1
|
1244
|
-
|
1464
|
+
if range.exclude_end?
|
1465
|
+
return remain_frozen_empty if last.zero?
|
1466
|
+
last -= 1 if range.end && last != STAR_INT
|
1467
|
+
end
|
1245
1468
|
if (first * last).positive? && last < first
|
1246
|
-
|
1469
|
+
remain_frozen_empty
|
1247
1470
|
elsif (min = at(first))
|
1248
1471
|
max = at(last)
|
1472
|
+
max = :* if max.nil?
|
1249
1473
|
if max == :* then self & (min..)
|
1250
1474
|
elsif min <= max then self & (min..max)
|
1251
|
-
else
|
1475
|
+
else remain_frozen_empty
|
1252
1476
|
end
|
1253
1477
|
end
|
1254
1478
|
end
|
1255
1479
|
|
1256
1480
|
public
|
1257
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
|
+
|
1258
1534
|
# Returns a frozen SequenceSet with <tt>*</tt> converted to +max+, numbers
|
1259
1535
|
# and ranges over +max+ removed, and ranges containing +max+ converted to
|
1260
1536
|
# end at +max+.
|
@@ -1272,6 +1548,7 @@ module Net
|
|
1272
1548
|
# Net::IMAP::SequenceSet["500:*"].limit(max: 37)
|
1273
1549
|
# #=> Net::IMAP::SequenceSet["37"]
|
1274
1550
|
#
|
1551
|
+
# Related: #limit!
|
1275
1552
|
def limit(max:)
|
1276
1553
|
max = to_tuple_int(max)
|
1277
1554
|
if empty? then self.class.empty
|
@@ -1286,6 +1563,7 @@ module Net
|
|
1286
1563
|
#
|
1287
1564
|
# Related: #limit
|
1288
1565
|
def limit!(max:)
|
1566
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1289
1567
|
star = include_star?
|
1290
1568
|
max = to_tuple_int(max)
|
1291
1569
|
tuple_subtract [max + 1, STAR_INT]
|
@@ -1300,6 +1578,7 @@ module Net
|
|
1300
1578
|
#
|
1301
1579
|
# Related: #complement
|
1302
1580
|
def complement!
|
1581
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1303
1582
|
return replace(self.class.full) if empty?
|
1304
1583
|
return clear if full?
|
1305
1584
|
flat = @tuples.flat_map { [_1 - 1, _2 + 1] }
|
@@ -1313,6 +1592,7 @@ module Net
|
|
1313
1592
|
#
|
1314
1593
|
# The returned set's #string is sorted and deduplicated. Adjacent or
|
1315
1594
|
# overlapping elements will be merged into a single larger range.
|
1595
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1316
1596
|
#
|
1317
1597
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize
|
1318
1598
|
# #=> Net::IMAP::SequenceSet["1:7,9:11"]
|
@@ -1325,21 +1605,24 @@ module Net
|
|
1325
1605
|
end
|
1326
1606
|
|
1327
1607
|
# Resets #string to be sorted, deduplicated, and coalesced. Returns
|
1328
|
-
# +self+.
|
1608
|
+
# +self+. See SequenceSet@Ordered+and+Normalized+sets.
|
1329
1609
|
#
|
1330
1610
|
# Related: #normalize, #normalized_string
|
1331
1611
|
def normalize!
|
1612
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
1332
1613
|
@string = nil
|
1333
1614
|
self
|
1334
1615
|
end
|
1335
1616
|
|
1336
1617
|
# Returns a normalized +sequence-set+ string representation, sorted
|
1337
1618
|
# and deduplicated. Adjacent or overlapping elements will be merged into
|
1338
|
-
# a single larger range.
|
1619
|
+
# a single larger range. See SequenceSet@Ordered+and+Normalized+sets.
|
1339
1620
|
#
|
1340
1621
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string
|
1341
1622
|
# #=> "1:7,9:11"
|
1342
1623
|
#
|
1624
|
+
# Returns +nil+ when the set is empty.
|
1625
|
+
#
|
1343
1626
|
# Related: #normalize!, #normalize
|
1344
1627
|
def normalized_string
|
1345
1628
|
@tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",")
|
@@ -1355,7 +1638,15 @@ module Net
|
|
1355
1638
|
end
|
1356
1639
|
end
|
1357
1640
|
|
1358
|
-
|
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)
|
1359
1650
|
alias to_sequence_set itself
|
1360
1651
|
|
1361
1652
|
# Unstable API: currently for internal use only (Net::IMAP#validate_data)
|
@@ -1388,6 +1679,7 @@ module Net
|
|
1388
1679
|
private
|
1389
1680
|
|
1390
1681
|
def remain_frozen(set) frozen? ? set.freeze : set end
|
1682
|
+
def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end
|
1391
1683
|
|
1392
1684
|
# frozen clones are shallow copied
|
1393
1685
|
def initialize_clone(other)
|
@@ -1395,6 +1687,7 @@ module Net
|
|
1395
1687
|
end
|
1396
1688
|
|
1397
1689
|
def initialize_dup(other)
|
1690
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
1398
1691
|
@tuples = other.tuples.map(&:dup)
|
1399
1692
|
@string = other.string&.-@
|
1400
1693
|
super
|
@@ -1421,9 +1714,8 @@ module Net
|
|
1421
1714
|
when Array then set.flat_map { input_to_tuples _1 }
|
1422
1715
|
when nil then []
|
1423
1716
|
else
|
1424
|
-
raise DataFormatError,
|
1425
|
-
|
1426
|
-
"got %p" % [set]
|
1717
|
+
raise DataFormatError, "expected nz-number, range, '*', Set, Array; " \
|
1718
|
+
"got %p" % [set]
|
1427
1719
|
end
|
1428
1720
|
end
|
1429
1721
|
|
data/lib/net/imap.rb
CHANGED
@@ -788,7 +788,7 @@ module Net
|
|
788
788
|
# * {IMAP URLAUTH Authorization Mechanism Registry}[https://www.iana.org/assignments/urlauth-authorization-mechanism-registry/urlauth-authorization-mechanism-registry.xhtml]
|
789
789
|
#
|
790
790
|
class IMAP < Protocol
|
791
|
-
VERSION = "0.5.
|
791
|
+
VERSION = "0.5.9"
|
792
792
|
|
793
793
|
# Aliases for supported capabilities, to be used with the #enable command.
|
794
794
|
ENABLE_ALIASES = {
|
@@ -801,6 +801,7 @@ module Net
|
|
801
801
|
autoload :ResponseReader, "#{dir}/response_reader"
|
802
802
|
autoload :SASL, "#{dir}/sasl"
|
803
803
|
autoload :SASLAdapter, "#{dir}/sasl_adapter"
|
804
|
+
autoload :SequenceSet, "#{dir}/sequence_set"
|
804
805
|
autoload :StringPrep, "#{dir}/stringprep"
|
805
806
|
|
806
807
|
include MonitorMixin
|
@@ -809,6 +810,22 @@ module Net
|
|
809
810
|
include SSL
|
810
811
|
end
|
811
812
|
|
813
|
+
# :call-seq:
|
814
|
+
# Net::IMAP::SequenceSet(set = nil) -> SequenceSet
|
815
|
+
#
|
816
|
+
# Coerces +set+ into a SequenceSet, using either SequenceSet.try_convert or
|
817
|
+
# SequenceSet.new.
|
818
|
+
#
|
819
|
+
# * When +set+ is a SequenceSet, that same set is returned.
|
820
|
+
# * When +set+ responds to +to_sequence_set+, +set.to_sequence_set+ is
|
821
|
+
# returned.
|
822
|
+
# * Otherwise, returns the result from calling SequenceSet.new with +set+.
|
823
|
+
#
|
824
|
+
# Related: SequenceSet.try_convert, SequenceSet.new, SequenceSet::[]
|
825
|
+
def self.SequenceSet(set = nil)
|
826
|
+
SequenceSet.try_convert(set) || SequenceSet.new(set)
|
827
|
+
end
|
828
|
+
|
812
829
|
# Returns the global Config object
|
813
830
|
def self.config; Config.global end
|
814
831
|
|
@@ -1114,28 +1131,27 @@ module Net
|
|
1114
1131
|
|
1115
1132
|
# Disconnects from the server.
|
1116
1133
|
#
|
1134
|
+
# Waits for receiver thread to close before returning. Slow or stuck
|
1135
|
+
# response handlers can cause #disconnect to hang until they complete.
|
1136
|
+
#
|
1117
1137
|
# Related: #logout, #logout!
|
1118
1138
|
def disconnect
|
1139
|
+
in_logout_state = try_state_logout?
|
1119
1140
|
return if disconnected?
|
1120
|
-
state_logout!
|
1121
1141
|
begin
|
1122
|
-
|
1123
|
-
# try to call SSL::SSLSocket#io.
|
1124
|
-
@sock.io.shutdown
|
1125
|
-
rescue NoMethodError
|
1126
|
-
# @sock is not an SSL::SSLSocket.
|
1127
|
-
@sock.shutdown
|
1128
|
-
end
|
1142
|
+
@sock.to_io.shutdown
|
1129
1143
|
rescue Errno::ENOTCONN
|
1130
1144
|
# ignore `Errno::ENOTCONN: Socket is not connected' on some platforms.
|
1131
1145
|
rescue Exception => e
|
1132
1146
|
@receiver_thread.raise(e)
|
1133
1147
|
end
|
1148
|
+
@sock.close
|
1134
1149
|
@receiver_thread.join
|
1135
|
-
synchronize do
|
1136
|
-
@sock.close
|
1137
|
-
end
|
1138
1150
|
raise e if e
|
1151
|
+
ensure
|
1152
|
+
# Try again after shutting down the receiver thread. With no reciever
|
1153
|
+
# left to wait for, any remaining locks should be _very_ brief.
|
1154
|
+
state_logout! unless in_logout_state
|
1139
1155
|
end
|
1140
1156
|
|
1141
1157
|
# Returns true if disconnected from the server.
|
@@ -3062,8 +3078,8 @@ module Net
|
|
3062
3078
|
raise @exception || Net::IMAP::Error.new("connection closed")
|
3063
3079
|
end
|
3064
3080
|
ensure
|
3081
|
+
remove_response_handler(response_handler)
|
3065
3082
|
unless @receiver_thread_terminating
|
3066
|
-
remove_response_handler(response_handler)
|
3067
3083
|
put_string("DONE#{CRLF}")
|
3068
3084
|
response = get_tagged_response(tag, "IDLE", idle_response_timeout)
|
3069
3085
|
end
|
@@ -3346,8 +3362,6 @@ module Net
|
|
3346
3362
|
rescue Exception => ex
|
3347
3363
|
@receiver_thread_exception = ex
|
3348
3364
|
# don't exit the thread with an exception
|
3349
|
-
ensure
|
3350
|
-
state_logout!
|
3351
3365
|
end
|
3352
3366
|
end
|
3353
3367
|
|
@@ -3429,6 +3443,8 @@ module Net
|
|
3429
3443
|
@idle_done_cond.signal
|
3430
3444
|
end
|
3431
3445
|
end
|
3446
|
+
ensure
|
3447
|
+
state_logout!
|
3432
3448
|
end
|
3433
3449
|
|
3434
3450
|
def get_tagged_response(tag, cmd, timeout = nil)
|
@@ -3791,15 +3807,29 @@ module Net
|
|
3791
3807
|
end
|
3792
3808
|
|
3793
3809
|
def state_unselected!
|
3794
|
-
|
3810
|
+
synchronize do
|
3811
|
+
state_authenticated! if connection_state.to_sym == :selected
|
3812
|
+
end
|
3795
3813
|
end
|
3796
3814
|
|
3797
3815
|
def state_logout!
|
3816
|
+
return true if connection_state in [:logout, *]
|
3798
3817
|
synchronize do
|
3818
|
+
return true if connection_state in [:logout, *]
|
3799
3819
|
@connection_state = ConnectionState::Logout.new
|
3800
3820
|
end
|
3801
3821
|
end
|
3802
3822
|
|
3823
|
+
# don't wait to aqcuire the lock
|
3824
|
+
def try_state_logout?
|
3825
|
+
return true if connection_state in [:logout, *]
|
3826
|
+
return false unless acquired_lock = mon_try_enter
|
3827
|
+
state_logout!
|
3828
|
+
true
|
3829
|
+
ensure
|
3830
|
+
mon_exit if acquired_lock
|
3831
|
+
end
|
3832
|
+
|
3803
3833
|
def sasl_adapter
|
3804
3834
|
SASLAdapter.new(self, &method(:send_command_with_continuations))
|
3805
3835
|
end
|
@@ -388,9 +388,11 @@ class StringPrepTablesGenerator
|
|
388
388
|
end
|
389
389
|
|
390
390
|
def asgn_mapping(name, replacement = to_map(tables[name]))
|
391
|
+
indent = " " * 2
|
392
|
+
replacement = replacement.inspect.gsub(/" => "/, '"=>"')
|
391
393
|
cname = name.tr(?., ?_).upcase
|
392
|
-
"# Replacements for %s\n%s%s = %
|
393
|
-
"IN_#{name}",
|
394
|
+
"# Replacements for %s\n%s%s = %s.freeze" % [
|
395
|
+
"IN_#{name}", indent, "MAP_#{cname}", replacement,
|
394
396
|
]
|
395
397
|
end
|
396
398
|
|