net-imap 0.5.8 → 0.5.10
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 +2 -0
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +0 -1
- data/lib/net/imap/sequence_set.rb +327 -111
- data/lib/net/imap.rb +46 -16
- data/rakelib/string_prep_tables_generator.rb +4 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 261794e07175481d35e146b718183fc057a3a54e2fd9958b25918c6bd4178ec4
|
4
|
+
data.tar.gz: 2568eb1d284b3f1662d1cf0c1bc79eb65722fa3ba8dc03072b52fbd3716c9294
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 357279f77c69c27b78924847216afad6c806abb7bfee5f0c95aab6c397cb10298440a59cb32b9f75a4174e6965d6bfe48a5e847e20d9098845033e8453f73302
|
7
|
+
data.tar.gz: e3c29888d787de23a843bfb9ff9194d1fa136763e9d9bcf36800953362f7611c489da1f9150ee2a23baa571125f4f2af2cebe4ee4666447783e355bd9995eb3a
|
data/Gemfile
CHANGED
@@ -14,7 +14,9 @@ gem "rdoc"
|
|
14
14
|
gem "test-unit"
|
15
15
|
gem "test-unit-ruby-core", git: "https://github.com/ruby/test-unit-ruby-core"
|
16
16
|
|
17
|
+
gem "benchmark", require: false
|
17
18
|
gem "benchmark-driver", require: false
|
19
|
+
gem "vernier", require: false, platform: :mri
|
18
20
|
|
19
21
|
group :test do
|
20
22
|
gem "simplecov", require: false
|
data/lib/net/imap/flags.rb
CHANGED
@@ -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.
|
53
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,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
|
-
# set.valid_string #=> "1:10,
|
110
|
+
# set.valid_string #=> "1:10,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
|
#
|
@@ -153,6 +225,7 @@ module Net
|
|
153
225
|
# * ::new: Creates a new mutable sequence set, which may be empty (invalid).
|
154
226
|
# * ::try_convert: Calls +to_sequence_set+ on an object and verifies that
|
155
227
|
# the result is a SequenceSet.
|
228
|
+
# * Net::IMAP::SequenceSet(): Coerce an input using ::try_convert or ::new.
|
156
229
|
# * ::empty: Returns a frozen empty (invalid) SequenceSet.
|
157
230
|
# * ::full: Returns a frozen SequenceSet containing every possible number.
|
158
231
|
#
|
@@ -178,8 +251,7 @@ module Net
|
|
178
251
|
#
|
179
252
|
# <i>Set membership:</i>
|
180
253
|
# - #include? (aliased as #member?):
|
181
|
-
# Returns whether a given element
|
182
|
-
# contained by the set.
|
254
|
+
# Returns whether a given element is contained by the set.
|
183
255
|
# - #include_star?: Returns whether the set contains <tt>*</tt>.
|
184
256
|
#
|
185
257
|
# <i>Minimum and maximum value elements:</i>
|
@@ -324,6 +396,23 @@ module Net
|
|
324
396
|
STARS = [:*, ?*, -1].freeze
|
325
397
|
private_constant :STARS
|
326
398
|
|
399
|
+
INSPECT_MAX_LEN = 512
|
400
|
+
INSPECT_TRUNCATE_LEN = 16
|
401
|
+
private_constant :INSPECT_MAX_LEN, :INSPECT_TRUNCATE_LEN
|
402
|
+
|
403
|
+
# /(,\d+){100}\z/ is shockingly slow on huge strings.
|
404
|
+
# /(,\d{0,10}){100}\z/ is ok, but ironically, Regexp.linear_time? is false.
|
405
|
+
#
|
406
|
+
# This unrolls all nested quantifiers. It's much harder to read, but it's
|
407
|
+
# also the fastest out of all the versions I tested.
|
408
|
+
nz_uint32 = /[1-9](?:\d(?:\d(?:\d(?:\d(?:\d(?:\d(?:\d(?:\d(?:\d)?)?)?)?)?)?)?)?)?/
|
409
|
+
num_or_star = /#{nz_uint32}|\*/
|
410
|
+
entry = /#{num_or_star}(?::#{num_or_star})?/
|
411
|
+
entries = ([entry] * INSPECT_TRUNCATE_LEN).join(",")
|
412
|
+
INSPECT_ABRIDGED_HEAD_RE = /\A#{entries},/
|
413
|
+
INSPECT_ABRIDGED_TAIL_RE = /,#{entries}\z/
|
414
|
+
private_constant :INSPECT_ABRIDGED_HEAD_RE, :INSPECT_ABRIDGED_TAIL_RE
|
415
|
+
|
327
416
|
class << self
|
328
417
|
|
329
418
|
# :call-seq:
|
@@ -337,13 +426,12 @@ module Net
|
|
337
426
|
# An empty SequenceSet is invalid and will raise a DataFormatError.
|
338
427
|
#
|
339
428
|
# Use ::new to create a mutable or empty SequenceSet.
|
429
|
+
#
|
430
|
+
# Related: ::new, Net::IMAP::SequenceSet(), ::try_convert
|
340
431
|
def [](first, *rest)
|
341
432
|
if rest.empty?
|
342
|
-
|
343
|
-
|
344
|
-
else
|
345
|
-
new(first).validate.freeze
|
346
|
-
end
|
433
|
+
set = try_convert(first)&.validate
|
434
|
+
set&.frozen? ? set : (set&.dup || new(first).validate).freeze
|
347
435
|
else
|
348
436
|
new(first).merge(*rest).validate.freeze
|
349
437
|
end
|
@@ -358,6 +446,8 @@ module Net
|
|
358
446
|
#
|
359
447
|
# If +obj.to_sequence_set+ doesn't return a SequenceSet, an exception is
|
360
448
|
# raised.
|
449
|
+
#
|
450
|
+
# Related: Net::IMAP::SequenceSet(), ::new, ::[]
|
361
451
|
def try_convert(obj)
|
362
452
|
return obj if obj.is_a?(SequenceSet)
|
363
453
|
return nil unless obj.respond_to?(:to_sequence_set)
|
@@ -376,23 +466,91 @@ module Net
|
|
376
466
|
end
|
377
467
|
|
378
468
|
# Create a new SequenceSet object from +input+, which may be another
|
379
|
-
# SequenceSet, an IMAP formatted +sequence-set+ string, a
|
380
|
-
# range, <tt>:*</tt>,
|
381
|
-
#
|
382
|
-
#
|
469
|
+
# SequenceSet, an IMAP formatted +sequence-set+ string, a non-zero 32 bit
|
470
|
+
# unsigned integer, a range, <tt>:*</tt>, a Set of numbers or <tt>*</tt>,
|
471
|
+
# an object that responds to +to_sequence_set+ (such as SearchResult) or
|
472
|
+
# an Array of these (array inputs may be nested).
|
473
|
+
#
|
474
|
+
# set = Net::IMAP::SequenceSet.new(1)
|
475
|
+
# set.valid_string #=> "1"
|
476
|
+
# set = Net::IMAP::SequenceSet.new(1..100)
|
477
|
+
# set.valid_string #=> "1:100"
|
478
|
+
# set = Net::IMAP::SequenceSet.new(1...100)
|
479
|
+
# set.valid_string #=> "1:99"
|
480
|
+
# set = Net::IMAP::SequenceSet.new([1, 2, 5..])
|
481
|
+
# set.valid_string #=> "1:2,5:*"
|
482
|
+
# set = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
|
483
|
+
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
484
|
+
# set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024)
|
485
|
+
# set.valid_string #=> "1:10,1024,2048"
|
486
|
+
#
|
487
|
+
# With no arguments (or +nil+) creates an empty sequence set. Note that
|
488
|
+
# an empty sequence set is invalid in the \IMAP grammar.
|
489
|
+
#
|
490
|
+
# set = Net::IMAP::SequenceSet.new
|
491
|
+
# set.empty? #=> true
|
492
|
+
# set.valid? #=> false
|
493
|
+
# set.valid_string #!> raises DataFormatError
|
494
|
+
# set << 1..10
|
495
|
+
# set.empty? #=> false
|
496
|
+
# set.valid? #=> true
|
497
|
+
# set.valid_string #=> "1:10"
|
498
|
+
#
|
499
|
+
# When +input+ is a SequenceSet, ::new behaves the same as calling #dup on
|
500
|
+
# that other set. The input's #string will be preserved.
|
501
|
+
#
|
502
|
+
# input = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
|
503
|
+
# copy = Net::IMAP::SequenceSet.new(input)
|
504
|
+
# input.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
505
|
+
# copy.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
|
506
|
+
# copy2 = input.dup # same as calling new with a SequenceSet input
|
507
|
+
# copy == input #=> true, same set membership
|
508
|
+
# copy.eql? input #=> true, same string value
|
509
|
+
# copy.equal? input #=> false, different objects
|
510
|
+
#
|
511
|
+
# copy.normalize!
|
512
|
+
# copy.valid_string #=> "1:10,1024,2048"
|
513
|
+
# copy == input #=> true, same set membership
|
514
|
+
# copy.eql? input #=> false, different string value
|
515
|
+
#
|
516
|
+
# copy << 999
|
517
|
+
# copy.valid_string #=> "1:10,999,1024,2048"
|
518
|
+
# copy == input #=> false, different set membership
|
519
|
+
# copy.eql? input #=> false, different string value
|
520
|
+
#
|
521
|
+
# === Alternative set creation methods
|
522
|
+
#
|
523
|
+
# * ::[] returns a frozen validated (non-empty) SequenceSet, without
|
524
|
+
# allocating a new object when the input is already a valid frozen
|
525
|
+
# SequenceSet.
|
526
|
+
# * Net::IMAP::SequenceSet() coerces an input to SequenceSet, without
|
527
|
+
# allocating a new object when the input is already a SequenceSet.
|
528
|
+
# * ::try_convert calls +to_sequence_set+ on inputs that support it and
|
529
|
+
# returns +nil+ for inputs that don't.
|
530
|
+
# * ::empty and ::full both return frozen singleton sets which can be
|
531
|
+
# combined with set operations (#|, #&, #^, #-, etc) to make new sets.
|
532
|
+
#
|
533
|
+
# See SequenceSet@Creating+sequence+sets.
|
383
534
|
def initialize(input = nil) input ? replace(input) : clear end
|
384
535
|
|
385
536
|
# Removes all elements and returns self.
|
386
|
-
def clear
|
537
|
+
def clear
|
538
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
539
|
+
@tuples, @string = [], nil
|
540
|
+
self
|
541
|
+
end
|
387
542
|
|
388
543
|
# Replace the contents of the set with the contents of +other+ and returns
|
389
544
|
# +self+.
|
390
545
|
#
|
391
|
-
# +other+ may be another SequenceSet
|
392
|
-
#
|
546
|
+
# +other+ may be another SequenceSet or any other object that would be
|
547
|
+
# accepted by ::new.
|
393
548
|
def replace(other)
|
394
549
|
case other
|
395
|
-
when SequenceSet then
|
550
|
+
when SequenceSet then
|
551
|
+
modifying! # short circuit before doing any work
|
552
|
+
@tuples = other.deep_copy_tuples
|
553
|
+
@string = other.instance_variable_get(:@string)
|
396
554
|
when String then self.string = other
|
397
555
|
else clear; merge other
|
398
556
|
end
|
@@ -421,36 +579,40 @@ module Net
|
|
421
579
|
# If the set was created from a single string, it is not normalized. If
|
422
580
|
# the set is updated the string will be normalized.
|
423
581
|
#
|
424
|
-
# Related: #valid_string, #normalized_string, #to_s
|
582
|
+
# Related: #valid_string, #normalized_string, #to_s, #inspect
|
425
583
|
def string; @string ||= normalized_string if valid? end
|
426
584
|
|
427
585
|
# Returns an array with #normalized_string when valid and an empty array
|
428
586
|
# otherwise.
|
429
587
|
def deconstruct; valid? ? [normalized_string] : [] end
|
430
588
|
|
431
|
-
# Assigns a new string to #string and resets #elements to match.
|
432
|
-
#
|
433
|
-
#
|
589
|
+
# Assigns a new string to #string and resets #elements to match.
|
590
|
+
# Assigning +nil+ or an empty string are equivalent to calling #clear.
|
591
|
+
#
|
592
|
+
# Non-empty strings are validated but not normalized.
|
434
593
|
#
|
435
|
-
# Use #add or #
|
594
|
+
# Use #add, #merge, or #append to add a string to an existing set.
|
436
595
|
#
|
437
596
|
# Related: #replace, #clear
|
438
|
-
def string=(
|
439
|
-
if
|
597
|
+
def string=(input)
|
598
|
+
if input.nil?
|
440
599
|
clear
|
441
|
-
|
442
|
-
|
600
|
+
elsif (str = String.try_convert(input))
|
601
|
+
modifying! # short-circuit before parsing the string
|
443
602
|
tuples = str_to_tuples str
|
444
603
|
@tuples, @string = [], -str
|
445
604
|
tuples_add tuples
|
605
|
+
else
|
606
|
+
raise ArgumentError, "expected a string or nil, got #{input.class}"
|
446
607
|
end
|
608
|
+
str
|
447
609
|
end
|
448
610
|
|
449
611
|
# Returns the \IMAP +sequence-set+ string representation, or an empty
|
450
612
|
# string when the set is empty. Note that an empty set is invalid in the
|
451
613
|
# \IMAP syntax.
|
452
614
|
#
|
453
|
-
# Related: #valid_string, #normalized_string, #
|
615
|
+
# Related: #string, #valid_string, #normalized_string, #inspect
|
454
616
|
def to_s; string || "" end
|
455
617
|
|
456
618
|
# Freezes and returns the set. A frozen SequenceSet is Ractor-safe.
|
@@ -503,8 +665,9 @@ module Net
|
|
503
665
|
|
504
666
|
# :call-seq: self === other -> true | false | nil
|
505
667
|
#
|
506
|
-
# Returns whether +other+ is contained within the set.
|
507
|
-
#
|
668
|
+
# Returns whether +other+ is contained within the set. +other+ may be any
|
669
|
+
# object that would be accepted by ::new. Returns +nil+ if StandardError
|
670
|
+
# is raised while converting +other+ to a comparable type.
|
508
671
|
#
|
509
672
|
# Related: #cover?, #include?, #include_star?
|
510
673
|
def ===(other)
|
@@ -518,12 +681,12 @@ module Net
|
|
518
681
|
# Returns whether +other+ is contained within the set. +other+ may be any
|
519
682
|
# object that would be accepted by ::new.
|
520
683
|
#
|
521
|
-
# Related: #===, #include?, #include_star?
|
684
|
+
# Related: #===, #include?, #include_star?, #intersect?
|
522
685
|
def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
|
523
686
|
|
524
687
|
# Returns +true+ when a given number or range is in +self+, and +false+
|
525
|
-
# otherwise. Returns +
|
526
|
-
# <tt>*</tt
|
688
|
+
# otherwise. Returns +nil+ when +number+ isn't a valid SequenceSet
|
689
|
+
# element (Integer, Range, <tt>*</tt>, +sequence-set+ string).
|
527
690
|
#
|
528
691
|
# set = Net::IMAP::SequenceSet["5:10,100,111:115"]
|
529
692
|
# set.include? 1 #=> false
|
@@ -531,8 +694,8 @@ module Net
|
|
531
694
|
# set.include? 11..20 #=> false
|
532
695
|
# set.include? 100 #=> true
|
533
696
|
# set.include? 6 #=> true, covered by "5:10"
|
534
|
-
# set.include?
|
535
|
-
# set.include? "
|
697
|
+
# set.include? 6..9 #=> true, covered by "5:10"
|
698
|
+
# set.include? "6:9" #=> true, strings are parsed
|
536
699
|
# set.include? 4..9 #=> false, intersection is not sufficient
|
537
700
|
# set.include? "*" #=> false, use #limit to re-interpret "*"
|
538
701
|
# set.include? -1 #=> false, -1 is interpreted as "*"
|
@@ -541,11 +704,14 @@ module Net
|
|
541
704
|
# set.include? :* #=> true
|
542
705
|
# set.include? "*" #=> true
|
543
706
|
# set.include? -1 #=> true
|
544
|
-
# set.include?
|
545
|
-
# set.include?
|
707
|
+
# set.include?(200..) #=> true
|
708
|
+
# set.include?(100..) #=> false
|
546
709
|
#
|
547
|
-
# Related: #include_star?, #cover?,
|
548
|
-
def include?(element)
|
710
|
+
# Related: #include_star?, #cover?, #===, #intersect?
|
711
|
+
def include?(element)
|
712
|
+
tuple = input_to_tuple element rescue nil
|
713
|
+
!!include_tuple?(tuple) if tuple
|
714
|
+
end
|
549
715
|
|
550
716
|
alias member? include?
|
551
717
|
|
@@ -558,7 +724,7 @@ module Net
|
|
558
724
|
# Net::IMAP::SequenceSet["5:10"].intersect? "7,9,11" #=> true
|
559
725
|
# Net::IMAP::SequenceSet["5:10"].intersect? "11:33" #=> false
|
560
726
|
#
|
561
|
-
# Related: #intersection, #disjoint?
|
727
|
+
# Related: #intersection, #disjoint?, #cover?, #include?
|
562
728
|
def intersect?(other)
|
563
729
|
valid? && input_to_tuples(other).any? { intersect_tuple? _1 }
|
564
730
|
end
|
@@ -577,7 +743,7 @@ module Net
|
|
577
743
|
|
578
744
|
# :call-seq:
|
579
745
|
# max(star: :*) => integer or star or nil
|
580
|
-
# max(count
|
746
|
+
# max(count) => SequenceSet
|
581
747
|
#
|
582
748
|
# Returns the maximum value in +self+, +star+ when the set includes
|
583
749
|
# <tt>*</tt>, or +nil+ when the set is empty.
|
@@ -597,7 +763,7 @@ module Net
|
|
597
763
|
|
598
764
|
# :call-seq:
|
599
765
|
# min(star: :*) => integer or star or nil
|
600
|
-
# min(count
|
766
|
+
# min(count) => SequenceSet
|
601
767
|
#
|
602
768
|
# Returns the minimum value in +self+, +star+ when the only value in the
|
603
769
|
# set is <tt>*</tt>, or +nil+ when the set is empty.
|
@@ -615,10 +781,11 @@ module Net
|
|
615
781
|
end
|
616
782
|
end
|
617
783
|
|
618
|
-
# :call-seq: minmax(star: :*) =>
|
784
|
+
# :call-seq: minmax(star: :*) => [min, max] or nil
|
619
785
|
#
|
620
786
|
# Returns a 2-element array containing the minimum and maximum numbers in
|
621
|
-
# +self+, or +nil+ when the set is empty.
|
787
|
+
# +self+, or +nil+ when the set is empty. +star+ is handled the same way
|
788
|
+
# as by #min and #max.
|
622
789
|
#
|
623
790
|
# Related: #min, #max
|
624
791
|
def minmax(star: :*); [min(star: star), max(star: star)] unless empty? end
|
@@ -640,9 +807,7 @@ module Net
|
|
640
807
|
# Returns a new sequence set that has every number in the +other+ object
|
641
808
|
# added.
|
642
809
|
#
|
643
|
-
# +other+ may be any object that would be accepted by ::new
|
644
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
645
|
-
# another sequence set, or an enumerable containing any of these.
|
810
|
+
# +other+ may be any object that would be accepted by ::new.
|
646
811
|
#
|
647
812
|
# Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99]
|
648
813
|
# #=> Net::IMAP::SequenceSet["1:6,99"]
|
@@ -666,9 +831,7 @@ module Net
|
|
666
831
|
# Returns a new sequence set built by duplicating this set and removing
|
667
832
|
# every number that appears in +other+.
|
668
833
|
#
|
669
|
-
# +other+ may be any object that would be accepted by ::new
|
670
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
671
|
-
# another sequence set, or an enumerable containing any of these.
|
834
|
+
# +other+ may be any object that would be accepted by ::new.
|
672
835
|
#
|
673
836
|
# Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6
|
674
837
|
# #=> Net::IMAP::SequenceSet["1,3,5"]
|
@@ -678,7 +841,7 @@ module Net
|
|
678
841
|
# ==== Set identities
|
679
842
|
#
|
680
843
|
# <tt>lhs - rhs</tt> is equivalent to:
|
681
|
-
# * <tt>~
|
844
|
+
# * <tt>~rhs - ~lhs</tt>
|
682
845
|
# * <tt>lhs & ~rhs</tt>
|
683
846
|
# * <tt>~(~lhs | rhs)</tt>
|
684
847
|
# * <tt>lhs & (lhs ^ rhs)</tt>
|
@@ -694,9 +857,7 @@ module Net
|
|
694
857
|
# Returns a new sequence set containing only the numbers common to this
|
695
858
|
# set and +other+.
|
696
859
|
#
|
697
|
-
# +other+ may be any object that would be accepted by ::new
|
698
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
699
|
-
# another sequence set, or an enumerable containing any of these.
|
860
|
+
# +other+ may be any object that would be accepted by ::new.
|
700
861
|
#
|
701
862
|
# Net::IMAP::SequenceSet[1..5] & [2, 4, 6]
|
702
863
|
# #=> Net::IMAP::SequenceSet["2,4"]
|
@@ -724,9 +885,7 @@ module Net
|
|
724
885
|
# Returns a new sequence set containing numbers that are exclusive between
|
725
886
|
# this set and +other+.
|
726
887
|
#
|
727
|
-
# +other+ may be any object that would be accepted by ::new
|
728
|
-
# bit unsigned integer, range, <tt>sequence-set</tt> formatted string,
|
729
|
-
# another sequence set, or an enumerable containing any of these.
|
888
|
+
# +other+ may be any object that would be accepted by ::new.
|
730
889
|
#
|
731
890
|
# Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6]
|
732
891
|
# #=> Net::IMAP::SequenceSet["1,3,5:6"]
|
@@ -776,10 +935,11 @@ module Net
|
|
776
935
|
# #string will be regenerated. Use #merge to add many elements at once.
|
777
936
|
#
|
778
937
|
# Use #append to append new elements to #string. See
|
779
|
-
#
|
938
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
780
939
|
#
|
781
940
|
# Related: #add?, #merge, #union, #append
|
782
941
|
def add(element)
|
942
|
+
modifying! # short-circuit before input_to_tuple
|
783
943
|
tuple_add input_to_tuple element
|
784
944
|
normalize!
|
785
945
|
end
|
@@ -790,11 +950,11 @@ module Net
|
|
790
950
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
791
951
|
# This may result in a #string which has duplicates or is out-of-order.
|
792
952
|
#
|
793
|
-
# See
|
953
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
794
954
|
#
|
795
955
|
# Related: #add, #merge, #union
|
796
956
|
def append(entry)
|
797
|
-
modifying!
|
957
|
+
modifying! # short-circuit before input_to_tuple
|
798
958
|
tuple = input_to_tuple entry
|
799
959
|
entry = tuple_to_str tuple
|
800
960
|
string unless empty? # write @string before tuple_add
|
@@ -812,6 +972,7 @@ module Net
|
|
812
972
|
#
|
813
973
|
# Related: #add, #merge, #union, #include?
|
814
974
|
def add?(element)
|
975
|
+
modifying! # short-circuit before include?
|
815
976
|
add element unless include? element
|
816
977
|
end
|
817
978
|
|
@@ -824,6 +985,7 @@ module Net
|
|
824
985
|
#
|
825
986
|
# Related: #delete?, #delete_at, #subtract, #difference
|
826
987
|
def delete(element)
|
988
|
+
modifying! # short-circuit before input_to_tuple
|
827
989
|
tuple_subtract input_to_tuple element
|
828
990
|
normalize!
|
829
991
|
end
|
@@ -861,6 +1023,7 @@ module Net
|
|
861
1023
|
#
|
862
1024
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
863
1025
|
def delete?(element)
|
1026
|
+
modifying! # short-circuit before input_to_tuple
|
864
1027
|
tuple = input_to_tuple element
|
865
1028
|
if tuple.first == tuple.last
|
866
1029
|
return unless include_tuple? tuple
|
@@ -901,6 +1064,7 @@ module Net
|
|
901
1064
|
#
|
902
1065
|
# Related: #slice, #delete_at, #delete, #delete?, #subtract, #difference
|
903
1066
|
def slice!(index, length = nil)
|
1067
|
+
modifying! # short-circuit before slice
|
904
1068
|
deleted = slice(index, length) and subtract deleted
|
905
1069
|
deleted
|
906
1070
|
end
|
@@ -908,14 +1072,13 @@ module Net
|
|
908
1072
|
# Merges all of the elements that appear in any of the +sets+ into the
|
909
1073
|
# set, and returns +self+.
|
910
1074
|
#
|
911
|
-
# The +sets+ may be any objects that would be accepted by ::new
|
912
|
-
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
913
|
-
# strings, other sequence sets, or enumerables containing any of these.
|
1075
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
914
1076
|
#
|
915
1077
|
# #string will be regenerated after all sets have been merged.
|
916
1078
|
#
|
917
1079
|
# Related: #add, #add?, #union
|
918
1080
|
def merge(*sets)
|
1081
|
+
modifying! # short-circuit before input_to_tuples
|
919
1082
|
tuples_add input_to_tuples sets
|
920
1083
|
normalize!
|
921
1084
|
end
|
@@ -923,9 +1086,7 @@ module Net
|
|
923
1086
|
# Removes all of the elements that appear in any of the given +sets+ from
|
924
1087
|
# the set, and returns +self+.
|
925
1088
|
#
|
926
|
-
# The +sets+ may be any objects that would be accepted by ::new
|
927
|
-
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
928
|
-
# strings, other sequence sets, or enumerables containing any of these.
|
1089
|
+
# The +sets+ may be any objects that would be accepted by ::new.
|
929
1090
|
#
|
930
1091
|
# Related: #difference
|
931
1092
|
def subtract(*sets)
|
@@ -941,7 +1102,7 @@ module Net
|
|
941
1102
|
# This is useful when the given order is significant, for example in a
|
942
1103
|
# ESEARCH response to IMAP#sort.
|
943
1104
|
#
|
944
|
-
# See
|
1105
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
945
1106
|
#
|
946
1107
|
# Related: #each_entry, #elements
|
947
1108
|
def entries; each_entry.to_a end
|
@@ -950,7 +1111,7 @@ module Net
|
|
950
1111
|
#
|
951
1112
|
# The returned elements are sorted and coalesced, even when the input
|
952
1113
|
# #string is not. <tt>*</tt> will sort last. See #normalize,
|
953
|
-
#
|
1114
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
954
1115
|
#
|
955
1116
|
# By itself, <tt>*</tt> translates to <tt>:*</tt>. A range containing
|
956
1117
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
@@ -967,7 +1128,7 @@ module Net
|
|
967
1128
|
#
|
968
1129
|
# The returned elements are sorted and coalesced, even when the input
|
969
1130
|
# #string is not. <tt>*</tt> will sort last. See #normalize,
|
970
|
-
#
|
1131
|
+
# SequenceSet@Ordered+and+Normalized+sets.
|
971
1132
|
#
|
972
1133
|
# <tt>*</tt> translates to an endless range. By itself, <tt>*</tt>
|
973
1134
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
@@ -984,7 +1145,7 @@ module Net
|
|
984
1145
|
# Returns a sorted array of all of the number values in the sequence set.
|
985
1146
|
#
|
986
1147
|
# The returned numbers are sorted and de-duplicated, even when the input
|
987
|
-
# #string is not. See #normalize,
|
1148
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
988
1149
|
#
|
989
1150
|
# Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers
|
990
1151
|
# #=> [2, 5, 6, 7, 8, 9, 11, 12]
|
@@ -1016,7 +1177,7 @@ module Net
|
|
1016
1177
|
# no sorting, deduplication, or coalescing. When #string is in its
|
1017
1178
|
# normalized form, this will yield the same values as #each_element.
|
1018
1179
|
#
|
1019
|
-
# See
|
1180
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1020
1181
|
#
|
1021
1182
|
# Related: #entries, #each_element
|
1022
1183
|
def each_entry(&block) # :yields: integer or range or :*
|
@@ -1028,7 +1189,7 @@ module Net
|
|
1028
1189
|
# and returns self. Returns an enumerator when called without a block.
|
1029
1190
|
#
|
1030
1191
|
# The returned numbers are sorted and de-duplicated, even when the input
|
1031
|
-
# #string is not. See #normalize,
|
1192
|
+
# #string is not. See #normalize, SequenceSet@Ordered+and+Normalized+sets.
|
1032
1193
|
#
|
1033
1194
|
# Related: #elements, #each_entry
|
1034
1195
|
def each_element # :yields: integer or range or :*
|
@@ -1424,6 +1585,7 @@ module Net
|
|
1424
1585
|
#
|
1425
1586
|
# Related: #limit
|
1426
1587
|
def limit!(max:)
|
1588
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1427
1589
|
star = include_star?
|
1428
1590
|
max = to_tuple_int(max)
|
1429
1591
|
tuple_subtract [max + 1, STAR_INT]
|
@@ -1438,6 +1600,7 @@ module Net
|
|
1438
1600
|
#
|
1439
1601
|
# Related: #complement
|
1440
1602
|
def complement!
|
1603
|
+
modifying! # short-circuit, and normalize the error message for JRuby
|
1441
1604
|
return replace(self.class.full) if empty?
|
1442
1605
|
return clear if full?
|
1443
1606
|
flat = @tuples.flat_map { [_1 - 1, _2 + 1] }
|
@@ -1451,7 +1614,7 @@ module Net
|
|
1451
1614
|
#
|
1452
1615
|
# The returned set's #string is sorted and deduplicated. Adjacent or
|
1453
1616
|
# overlapping elements will be merged into a single larger range.
|
1454
|
-
# See
|
1617
|
+
# See SequenceSet@Ordered+and+Normalized+sets.
|
1455
1618
|
#
|
1456
1619
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize
|
1457
1620
|
# #=> Net::IMAP::SequenceSet["1:7,9:11"]
|
@@ -1464,39 +1627,87 @@ module Net
|
|
1464
1627
|
end
|
1465
1628
|
|
1466
1629
|
# Resets #string to be sorted, deduplicated, and coalesced. Returns
|
1467
|
-
# +self+. See
|
1630
|
+
# +self+. See SequenceSet@Ordered+and+Normalized+sets.
|
1468
1631
|
#
|
1469
1632
|
# Related: #normalize, #normalized_string
|
1470
1633
|
def normalize!
|
1634
|
+
modifying! # redundant check, to normalize the error message for JRuby
|
1471
1635
|
@string = nil
|
1472
1636
|
self
|
1473
1637
|
end
|
1474
1638
|
|
1475
1639
|
# Returns a normalized +sequence-set+ string representation, sorted
|
1476
1640
|
# and deduplicated. Adjacent or overlapping elements will be merged into
|
1477
|
-
# a single larger range. See
|
1641
|
+
# a single larger range. See SequenceSet@Ordered+and+Normalized+sets.
|
1478
1642
|
#
|
1479
1643
|
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string
|
1480
1644
|
# #=> "1:7,9:11"
|
1481
1645
|
#
|
1482
1646
|
# Returns +nil+ when the set is empty.
|
1483
1647
|
#
|
1484
|
-
# Related: #normalize!, #normalize
|
1648
|
+
# Related: #normalize!, #normalize, #string, #to_s
|
1485
1649
|
def normalized_string
|
1486
1650
|
@tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",")
|
1487
1651
|
end
|
1488
1652
|
|
1653
|
+
# Returns an inspection string for the SequenceSet.
|
1654
|
+
#
|
1655
|
+
# Net::IMAP::SequenceSet.new.inspect
|
1656
|
+
# #=> "Net::IMAP::SequenceSet()"
|
1657
|
+
#
|
1658
|
+
# Net::IMAP::SequenceSet(1..5, 1024, 15, 2000).inspect
|
1659
|
+
# #=> 'Net::IMAP::SequenceSet("1:5,15,1024,2000")'
|
1660
|
+
#
|
1661
|
+
# Frozen sets have slightly different output:
|
1662
|
+
#
|
1663
|
+
# Net::IMAP::SequenceSet.empty.inspect
|
1664
|
+
# #=> "Net::IMAP::SequenceSet.empty"
|
1665
|
+
#
|
1666
|
+
# Net::IMAP::SequenceSet[1..5, 1024, 15, 2000].inspect
|
1667
|
+
# #=> 'Net::IMAP::SequenceSet["1:5,15,1024,2000"]'
|
1668
|
+
#
|
1669
|
+
# Large sets (by number of #entries) have abridged output, with only the
|
1670
|
+
# first and last entries:
|
1671
|
+
#
|
1672
|
+
# Net::IMAP::SequenceSet(((1..5000) % 2).to_a).inspect
|
1673
|
+
# #=> #<Net::IMAP::SequenceSet 2500 entries "1,3,5,7,9,11,13,15,17,19,21,23,25,27,29,31,...(2468 entries omitted)...,4969,4971,4973,4975,4977,4979,4981,4983,4985,4987,4989,4991,4993,4995,4997,4999">
|
1674
|
+
#
|
1675
|
+
# Related: #to_s, #string
|
1489
1676
|
def inspect
|
1490
|
-
|
1491
|
-
|
1492
|
-
|
1493
|
-
|
1677
|
+
case (count = count_entries)
|
1678
|
+
when 0
|
1679
|
+
(frozen? ? "%s.empty" : "%s()") % [self.class]
|
1680
|
+
when ..INSPECT_MAX_LEN
|
1681
|
+
(frozen? ? "%s[%p]" : "%s(%p)") % [self.class, to_s]
|
1494
1682
|
else
|
1495
|
-
|
1683
|
+
if @string
|
1684
|
+
head = @string[INSPECT_ABRIDGED_HEAD_RE]
|
1685
|
+
tail = @string[INSPECT_ABRIDGED_TAIL_RE]
|
1686
|
+
else
|
1687
|
+
head = export_string_entries(@tuples.first(INSPECT_TRUNCATE_LEN)) + ","
|
1688
|
+
tail = "," + export_string_entries(@tuples.last(INSPECT_TRUNCATE_LEN))
|
1689
|
+
end
|
1690
|
+
'#<%s %d entries "%s...(%d entries omitted)...%s"%s>' % [
|
1691
|
+
self.class, count,
|
1692
|
+
head, count - INSPECT_TRUNCATE_LEN * 2, tail,
|
1693
|
+
frozen? ? " (frozen)" : "",
|
1694
|
+
]
|
1496
1695
|
end
|
1497
1696
|
end
|
1498
1697
|
|
1499
|
-
|
1698
|
+
private def count_entries
|
1699
|
+
@string ? @string.count(",") + 1 : @tuples.count
|
1700
|
+
end
|
1701
|
+
|
1702
|
+
##
|
1703
|
+
# :method: to_sequence_set
|
1704
|
+
# :call-seq: to_sequence_set -> self
|
1705
|
+
#
|
1706
|
+
# Returns +self+
|
1707
|
+
#
|
1708
|
+
# Related: ::try_convert
|
1709
|
+
|
1710
|
+
# :nodoc: (work around rdoc bug)
|
1500
1711
|
alias to_sequence_set itself
|
1501
1712
|
|
1502
1713
|
# Unstable API: currently for internal use only (Net::IMAP#validate_data)
|
@@ -1526,6 +1737,8 @@ module Net
|
|
1526
1737
|
|
1527
1738
|
attr_reader :tuples # :nodoc:
|
1528
1739
|
|
1740
|
+
def deep_copy_tuples; @tuples.map { _1.dup } end # :nodoc:
|
1741
|
+
|
1529
1742
|
private
|
1530
1743
|
|
1531
1744
|
def remain_frozen(set) frozen? ? set.freeze : set end
|
@@ -1533,12 +1746,12 @@ module Net
|
|
1533
1746
|
|
1534
1747
|
# frozen clones are shallow copied
|
1535
1748
|
def initialize_clone(other)
|
1536
|
-
other.
|
1749
|
+
@tuples = other.deep_copy_tuples unless other.frozen?
|
1750
|
+
super
|
1537
1751
|
end
|
1538
1752
|
|
1539
1753
|
def initialize_dup(other)
|
1540
|
-
@tuples = other.
|
1541
|
-
@string = other.string&.-@
|
1754
|
+
@tuples = other.deep_copy_tuples
|
1542
1755
|
super
|
1543
1756
|
end
|
1544
1757
|
|
@@ -1563,9 +1776,8 @@ module Net
|
|
1563
1776
|
when Array then set.flat_map { input_to_tuples _1 }
|
1564
1777
|
when nil then []
|
1565
1778
|
else
|
1566
|
-
raise DataFormatError,
|
1567
|
-
|
1568
|
-
"got %p" % [set]
|
1779
|
+
raise DataFormatError, "expected nz-number, range, '*', Set, Array; " \
|
1780
|
+
"got %p" % [set]
|
1569
1781
|
end
|
1570
1782
|
end
|
1571
1783
|
|
@@ -1591,6 +1803,10 @@ module Net
|
|
1591
1803
|
def to_tuple_int(obj) STARS.include?(obj) ? STAR_INT : nz_number(obj) end
|
1592
1804
|
def from_tuple_int(num) num == STAR_INT ? :* : num end
|
1593
1805
|
|
1806
|
+
def export_string_entries(entries)
|
1807
|
+
-entries.map { tuple_to_str _1 }.join(",")
|
1808
|
+
end
|
1809
|
+
|
1594
1810
|
def tuple_to_str(tuple) tuple.uniq.map{ from_tuple_int _1 }.join(":") end
|
1595
1811
|
def str_to_tuples(str) str.split(",", -1).map! { str_to_tuple _1 } end
|
1596
1812
|
def str_to_tuple(str)
|
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.10"
|
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
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-imap
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.10
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shugo Maeda
|
@@ -129,7 +129,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
131
|
requirements: []
|
132
|
-
rubygems_version: 3.6.
|
132
|
+
rubygems_version: 3.6.9
|
133
133
|
specification_version: 4
|
134
134
|
summary: Ruby client api for Internet Message Access Protocol
|
135
135
|
test_files: []
|