net-imap 0.4.9.1 → 0.5.6
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/BSDL +22 -0
- data/COPYING +56 -0
- data/Gemfile +12 -1
- data/LICENSE.txt +3 -22
- data/README.md +10 -4
- data/docs/styles.css +75 -14
- data/lib/net/imap/authenticators.rb +2 -2
- data/lib/net/imap/command_data.rb +61 -48
- data/lib/net/imap/config/attr_accessors.rb +75 -0
- data/lib/net/imap/config/attr_inheritance.rb +90 -0
- data/lib/net/imap/config/attr_type_coercion.rb +61 -0
- data/lib/net/imap/config.rb +470 -0
- data/lib/net/imap/data_encoding.rb +4 -4
- data/lib/net/imap/data_lite.rb +226 -0
- data/lib/net/imap/deprecated_client_options.rb +9 -6
- data/lib/net/imap/errors.rb +7 -1
- data/lib/net/imap/esearch_result.rb +180 -0
- data/lib/net/imap/fetch_data.rb +126 -47
- data/lib/net/imap/flags.rb +1 -1
- data/lib/net/imap/response_data.rb +126 -239
- data/lib/net/imap/response_parser/parser_utils.rb +11 -6
- data/lib/net/imap/response_parser.rb +188 -34
- data/lib/net/imap/sasl/anonymous_authenticator.rb +3 -3
- data/lib/net/imap/sasl/authentication_exchange.rb +52 -20
- data/lib/net/imap/sasl/authenticators.rb +8 -4
- data/lib/net/imap/sasl/client_adapter.rb +77 -26
- data/lib/net/imap/sasl/cram_md5_authenticator.rb +4 -4
- data/lib/net/imap/sasl/digest_md5_authenticator.rb +218 -56
- data/lib/net/imap/sasl/external_authenticator.rb +3 -3
- data/lib/net/imap/sasl/gs2_header.rb +7 -7
- data/lib/net/imap/sasl/login_authenticator.rb +4 -3
- data/lib/net/imap/sasl/oauthbearer_authenticator.rb +6 -6
- data/lib/net/imap/sasl/plain_authenticator.rb +7 -7
- data/lib/net/imap/sasl/protocol_adapters.rb +60 -4
- data/lib/net/imap/sasl/scram_authenticator.rb +8 -8
- data/lib/net/imap/sasl.rb +8 -5
- data/lib/net/imap/sasl_adapter.rb +0 -1
- data/lib/net/imap/search_result.rb +4 -8
- data/lib/net/imap/sequence_set.rb +239 -88
- data/lib/net/imap/stringprep/nameprep.rb +1 -1
- data/lib/net/imap/stringprep/trace.rb +4 -4
- data/lib/net/imap/uidplus_data.rb +244 -0
- data/lib/net/imap/vanished_data.rb +56 -0
- data/lib/net/imap.rb +1012 -322
- data/net-imap.gemspec +4 -7
- data/rakelib/benchmarks.rake +1 -1
- data/rakelib/rfcs.rake +2 -0
- data/rakelib/string_prep_tables_generator.rb +2 -0
- data/sample/net-imap.rb +167 -0
- metadata +16 -40
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/pages.yml +0 -46
- data/.github/workflows/test.yml +0 -31
- data/.gitignore +0 -12
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require "set" unless defined?(::Set)
|
4
|
+
|
3
5
|
module Net
|
4
6
|
class IMAP
|
5
7
|
|
@@ -14,13 +16,6 @@ module Net
|
|
14
16
|
# receive a SequenceSet as an argument, for example IMAP#search, IMAP#fetch,
|
15
17
|
# and IMAP#store.
|
16
18
|
#
|
17
|
-
# == EXPERIMENTAL API
|
18
|
-
#
|
19
|
-
# SequenceSet is currently experimental. Only two methods, ::[] and
|
20
|
-
# #valid_string, are considered stable. Although the API isn't expected to
|
21
|
-
# change much, any other methods may be removed or changed without
|
22
|
-
# deprecation.
|
23
|
-
#
|
24
19
|
# == Creating sequence sets
|
25
20
|
#
|
26
21
|
# SequenceSet.new with no arguments creates an empty sequence set. Note
|
@@ -37,7 +32,8 @@ module Net
|
|
37
32
|
#
|
38
33
|
# SequenceSet.new may receive a single optional argument: a non-zero 32 bit
|
39
34
|
# unsigned integer, a range, a <tt>sequence-set</tt> formatted string,
|
40
|
-
# another sequence set,
|
35
|
+
# another sequence set, a Set (containing only numbers or <tt>*</tt>), or an
|
36
|
+
# Array containing any of these (array inputs may be nested).
|
41
37
|
#
|
42
38
|
# set = Net::IMAP::SequenceSet.new(1)
|
43
39
|
# set.valid_string #=> "1"
|
@@ -60,18 +56,20 @@ module Net
|
|
60
56
|
# set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
|
61
57
|
# set.valid_string #=> "1:10,55,1024:2048"
|
62
58
|
#
|
63
|
-
# == Normalized
|
59
|
+
# == Ordered and Normalized sets
|
64
60
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
69
|
-
# methods use this normalized representation. Most modification methods
|
70
|
-
# will convert #string to its normalized form.
|
61
|
+
# Sometimes the order of the set's members is significant, such as with the
|
62
|
+
# +ESORT+, <tt>CONTEXT=SORT</tt>, and +UIDPLUS+ extensions. So, when a
|
63
|
+
# sequence set is created by the parser or with a single string value, that
|
64
|
+
# #string representation is preserved.
|
71
65
|
#
|
72
|
-
#
|
73
|
-
#
|
74
|
-
#
|
66
|
+
# Internally, SequenceSet stores a normalized representation which sorts all
|
67
|
+
# entries, de-duplicates numbers, and coalesces adjacent or overlapping
|
68
|
+
# ranges. Most methods use this normalized representation to achieve
|
69
|
+
# <tt>O(lg n)</tt> porformance. Use #entries or #each_entry to enumerate
|
70
|
+
# the set in its original order.
|
71
|
+
#
|
72
|
+
# Most modification methods convert #string to its normalized form. To
|
75
73
|
# preserve #string order while modifying a set, use #append, #string=, or
|
76
74
|
# #replace.
|
77
75
|
#
|
@@ -164,7 +162,7 @@ module Net
|
|
164
162
|
# - #===:
|
165
163
|
# Returns whether a given object is fully contained within +self+, or
|
166
164
|
# +nil+ if the object cannot be converted to a compatible type.
|
167
|
-
# - #cover
|
165
|
+
# - #cover?:
|
168
166
|
# Returns whether a given object is fully contained within +self+.
|
169
167
|
# - #intersect? (aliased as #overlap?):
|
170
168
|
# Returns whether +self+ and a given object have any common elements.
|
@@ -185,30 +183,41 @@ module Net
|
|
185
183
|
# - #max: Returns the maximum number in the set.
|
186
184
|
# - #minmax: Returns the minimum and maximum numbers in the set.
|
187
185
|
#
|
188
|
-
# <i>Accessing value by offset:</i>
|
186
|
+
# <i>Accessing value by offset in sorted set:</i>
|
189
187
|
# - #[] (aliased as #slice): Returns the number or consecutive subset at a
|
190
|
-
# given offset or range of offsets.
|
191
|
-
# - #at: Returns the number at a given offset.
|
192
|
-
# - #find_index: Returns the given number's offset in the set
|
188
|
+
# given offset or range of offsets in the sorted set.
|
189
|
+
# - #at: Returns the number at a given offset in the sorted set.
|
190
|
+
# - #find_index: Returns the given number's offset in the sorted set.
|
191
|
+
#
|
192
|
+
# <i>Accessing value by offset in ordered entries</i>
|
193
|
+
# - #ordered_at: Returns the number at a given offset in the ordered entries.
|
194
|
+
# - #find_ordered_index: Returns the index of the given number's first
|
195
|
+
# occurrence in entries.
|
193
196
|
#
|
194
197
|
# <i>Set cardinality:</i>
|
195
198
|
# - #count (aliased as #size): Returns the count of numbers in the set.
|
199
|
+
# Duplicated numbers are not counted.
|
196
200
|
# - #empty?: Returns whether the set has no members. \IMAP syntax does not
|
197
201
|
# allow empty sequence sets.
|
198
202
|
# - #valid?: Returns whether the set has any members.
|
199
203
|
# - #full?: Returns whether the set contains every possible value, including
|
200
204
|
# <tt>*</tt>.
|
201
205
|
#
|
206
|
+
# <i>Denormalized properties:</i>
|
207
|
+
# - #has_duplicates?: Returns whether the ordered entries repeat any
|
208
|
+
# numbers.
|
209
|
+
# - #count_duplicates: Returns the count of repeated numbers in the ordered
|
210
|
+
# entries.
|
211
|
+
# - #count_with_duplicates: Returns the count of numbers in the ordered
|
212
|
+
# entries, including any repeated numbers.
|
213
|
+
#
|
202
214
|
# === Methods for Iterating
|
203
215
|
#
|
216
|
+
# <i>Normalized (sorted and coalesced):</i>
|
204
217
|
# - #each_element: Yields each number and range in the set, sorted and
|
205
218
|
# coalesced, and returns +self+.
|
206
219
|
# - #elements (aliased as #to_a): Returns an Array of every number and range
|
207
220
|
# in the set, sorted and coalesced.
|
208
|
-
# - #each_entry: Yields each number and range in the set, unsorted and
|
209
|
-
# without deduplicating numbers or coalescing ranges, and returns +self+.
|
210
|
-
# - #entries: Returns an Array of every number and range in the set,
|
211
|
-
# unsorted and without deduplicating numbers or coalescing ranges.
|
212
221
|
# - #each_range:
|
213
222
|
# Yields each element in the set as a Range and returns +self+.
|
214
223
|
# - #ranges: Returns an Array of every element in the set, converting
|
@@ -218,6 +227,14 @@ module Net
|
|
218
227
|
# ranges into all of their contained numbers.
|
219
228
|
# - #to_set: Returns a Set containing all of the #numbers in the set.
|
220
229
|
#
|
230
|
+
# <i>Order preserving:</i>
|
231
|
+
# - #each_entry: Yields each number and range in the set, unsorted and
|
232
|
+
# without deduplicating numbers or coalescing ranges, and returns +self+.
|
233
|
+
# - #entries: Returns an Array of every number and range in the set,
|
234
|
+
# unsorted and without deduplicating numbers or coalescing ranges.
|
235
|
+
# - #each_ordered_number: Yields each number in the ordered entries and
|
236
|
+
# returns +self+.
|
237
|
+
#
|
221
238
|
# === Methods for \Set Operations
|
222
239
|
# These methods do not modify +self+.
|
223
240
|
#
|
@@ -237,19 +254,29 @@ module Net
|
|
237
254
|
# === Methods for Assigning
|
238
255
|
# These methods add or replace elements in +self+.
|
239
256
|
#
|
257
|
+
# <i>Normalized (sorted and coalesced):</i>
|
258
|
+
#
|
259
|
+
# These methods always update #string to be fully sorted and coalesced.
|
260
|
+
#
|
240
261
|
# - #add (aliased as #<<): Adds a given object to the set; returns +self+.
|
241
262
|
# - #add?: If the given object is not an element in the set, adds it and
|
242
263
|
# returns +self+; otherwise, returns +nil+.
|
243
264
|
# - #merge: Merges multiple elements into the set; returns +self+.
|
265
|
+
# - #complement!: Replaces the contents of the set with its own #complement.
|
266
|
+
#
|
267
|
+
# <i>Order preserving:</i>
|
268
|
+
#
|
269
|
+
# These methods _may_ cause #string to not be sorted or coalesced.
|
270
|
+
#
|
244
271
|
# - #append: Adds a given object to the set, appending it to the existing
|
245
272
|
# string, and returns +self+.
|
246
273
|
# - #string=: Assigns a new #string value and replaces #elements to match.
|
247
274
|
# - #replace: Replaces the contents of the set with the contents
|
248
275
|
# of a given object.
|
249
|
-
# - #complement!: Replaces the contents of the set with its own #complement.
|
250
276
|
#
|
251
277
|
# === Methods for Deleting
|
252
|
-
# These methods remove elements from +self
|
278
|
+
# These methods remove elements from +self+, and update #string to be fully
|
279
|
+
# sorted and coalesced.
|
253
280
|
#
|
254
281
|
# - #clear: Removes all elements in the set; returns +self+.
|
255
282
|
# - #delete: Removes a given object from the set; returns +self+.
|
@@ -286,11 +313,7 @@ module Net
|
|
286
313
|
|
287
314
|
# valid inputs for "*"
|
288
315
|
STARS = [:*, ?*, -1].freeze
|
289
|
-
private_constant :
|
290
|
-
|
291
|
-
COERCIBLE = ->{ _1.respond_to? :to_sequence_set }
|
292
|
-
ENUMABLE = ->{ _1.respond_to?(:each) && _1.respond_to?(:empty?) }
|
293
|
-
private_constant :COERCIBLE, :ENUMABLE
|
316
|
+
private_constant :STARS
|
294
317
|
|
295
318
|
class << self
|
296
319
|
|
@@ -304,7 +327,7 @@ module Net
|
|
304
327
|
# Use ::new to create a mutable or empty SequenceSet.
|
305
328
|
def [](first, *rest)
|
306
329
|
if rest.empty?
|
307
|
-
if first.is_a?(SequenceSet) &&
|
330
|
+
if first.is_a?(SequenceSet) && first.frozen? && first.valid?
|
308
331
|
first
|
309
332
|
else
|
310
333
|
new(first).validate.freeze
|
@@ -325,7 +348,7 @@ module Net
|
|
325
348
|
# raised.
|
326
349
|
def try_convert(obj)
|
327
350
|
return obj if obj.is_a?(SequenceSet)
|
328
|
-
return nil unless respond_to?(:to_sequence_set)
|
351
|
+
return nil unless obj.respond_to?(:to_sequence_set)
|
329
352
|
obj = obj.to_sequence_set
|
330
353
|
return obj if obj.is_a?(SequenceSet)
|
331
354
|
raise DataFormatError, "invalid object returned from to_sequence_set"
|
@@ -389,6 +412,10 @@ module Net
|
|
389
412
|
# Related: #valid_string, #normalized_string, #to_s
|
390
413
|
def string; @string ||= normalized_string if valid? end
|
391
414
|
|
415
|
+
# Returns an array with #normalized_string when valid and an empty array
|
416
|
+
# otherwise.
|
417
|
+
def deconstruct; valid? ? [normalized_string] : [] end
|
418
|
+
|
392
419
|
# Assigns a new string to #string and resets #elements to match. It
|
393
420
|
# cannot be set to an empty string—assign +nil+ or use #clear instead.
|
394
421
|
# The string is validated but not normalized.
|
@@ -682,10 +709,12 @@ module Net
|
|
682
709
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
683
710
|
# This may result in a #string which has duplicates or is out-of-order.
|
684
711
|
def append(object)
|
712
|
+
modifying!
|
685
713
|
tuple = input_to_tuple object
|
686
714
|
entry = tuple_to_str tuple
|
715
|
+
string unless empty? # write @string before tuple_add
|
687
716
|
tuple_add tuple
|
688
|
-
@string = -(string ? "#{@string},#{entry}" : entry)
|
717
|
+
@string = -(@string ? "#{@string},#{entry}" : entry)
|
689
718
|
self
|
690
719
|
end
|
691
720
|
|
@@ -841,8 +870,8 @@ module Net
|
|
841
870
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
842
871
|
# cases to a maximum value.
|
843
872
|
#
|
844
|
-
#
|
845
|
-
#
|
873
|
+
# The returned elements will be sorted and coalesced, even when the input
|
874
|
+
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
846
875
|
#
|
847
876
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
|
848
877
|
# #=> [2, 5..9, 11..12, :*]
|
@@ -860,7 +889,7 @@ module Net
|
|
860
889
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
861
890
|
# value.
|
862
891
|
#
|
863
|
-
# The returned ranges will be
|
892
|
+
# The returned ranges will be sorted and coalesced, even when the input
|
864
893
|
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
865
894
|
#
|
866
895
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
|
@@ -902,16 +931,14 @@ module Net
|
|
902
931
|
# Yields each number or range in #string to the block and returns +self+.
|
903
932
|
# Returns an enumerator when called without a block.
|
904
933
|
#
|
905
|
-
# The entries are yielded in the same order they appear in #
|
906
|
-
# sorting, deduplication, or coalescing. When #string is in its
|
934
|
+
# The entries are yielded in the same order they appear in #string, with
|
935
|
+
# no sorting, deduplication, or coalescing. When #string is in its
|
907
936
|
# normalized form, this will yield the same values as #each_element.
|
908
937
|
#
|
909
938
|
# Related: #entries, #each_element
|
910
|
-
def each_entry(&block)
|
939
|
+
def each_entry(&block) # :yields: integer or range or :*
|
911
940
|
return to_enum(__method__) unless block_given?
|
912
|
-
|
913
|
-
@string.split(",").each do yield tuple_to_entry str_to_tuple _1 end
|
914
|
-
self
|
941
|
+
each_entry_tuple do yield tuple_to_entry _1 end
|
915
942
|
end
|
916
943
|
|
917
944
|
# Yields each number or range (or <tt>:*</tt>) in #elements to the block
|
@@ -927,7 +954,19 @@ module Net
|
|
927
954
|
self
|
928
955
|
end
|
929
956
|
|
930
|
-
private
|
957
|
+
private
|
958
|
+
|
959
|
+
def each_entry_tuple(&block)
|
960
|
+
return to_enum(__method__) unless block_given?
|
961
|
+
if @string
|
962
|
+
@string.split(",") do block.call str_to_tuple _1 end
|
963
|
+
else
|
964
|
+
@tuples.each(&block)
|
965
|
+
end
|
966
|
+
self
|
967
|
+
end
|
968
|
+
|
969
|
+
def tuple_to_entry((min, max))
|
931
970
|
if min == STAR_INT then :*
|
932
971
|
elsif max == STAR_INT then min..
|
933
972
|
elsif min == max then min
|
@@ -935,6 +974,8 @@ module Net
|
|
935
974
|
end
|
936
975
|
end
|
937
976
|
|
977
|
+
public
|
978
|
+
|
938
979
|
# Yields each range in #ranges to the block and returns self.
|
939
980
|
# Returns an enumerator when called without a block.
|
940
981
|
#
|
@@ -956,19 +997,36 @@ module Net
|
|
956
997
|
# Returns an enumerator when called without a block (even if the set
|
957
998
|
# contains <tt>*</tt>).
|
958
999
|
#
|
959
|
-
# Related: #numbers
|
1000
|
+
# Related: #numbers, #each_ordered_number
|
960
1001
|
def each_number(&block) # :yields: integer
|
961
1002
|
return to_enum(__method__) unless block_given?
|
962
1003
|
raise RangeError, '%s contains "*"' % [self.class] if include_star?
|
963
|
-
|
964
|
-
case elem
|
965
|
-
when Range then elem.each(&block)
|
966
|
-
when Integer then block.(elem)
|
967
|
-
end
|
968
|
-
end
|
1004
|
+
@tuples.each do each_number_in_tuple _1, _2, &block end
|
969
1005
|
self
|
970
1006
|
end
|
971
1007
|
|
1008
|
+
# Yields each number in #entries to the block and returns self.
|
1009
|
+
# If the set contains a <tt>*</tt>, RangeError will be raised.
|
1010
|
+
#
|
1011
|
+
# Returns an enumerator when called without a block (even if the set
|
1012
|
+
# contains <tt>*</tt>).
|
1013
|
+
#
|
1014
|
+
# Related: #entries, #each_number
|
1015
|
+
def each_ordered_number(&block)
|
1016
|
+
return to_enum(__method__) unless block_given?
|
1017
|
+
raise RangeError, '%s contains "*"' % [self.class] if include_star?
|
1018
|
+
each_entry_tuple do each_number_in_tuple _1, _2, &block end
|
1019
|
+
end
|
1020
|
+
|
1021
|
+
private def each_number_in_tuple(min, max, &block)
|
1022
|
+
if min == STAR_INT then yield :*
|
1023
|
+
elsif min == max then yield min
|
1024
|
+
elsif max != STAR_INT then (min..max).each(&block)
|
1025
|
+
else
|
1026
|
+
raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
|
1027
|
+
end
|
1028
|
+
end
|
1029
|
+
|
972
1030
|
# Returns a Set with all of the #numbers in the sequence set.
|
973
1031
|
#
|
974
1032
|
# If the set contains a <tt>*</tt>, RangeError will be raised.
|
@@ -980,8 +1038,10 @@ module Net
|
|
980
1038
|
|
981
1039
|
# Returns the count of #numbers in the set.
|
982
1040
|
#
|
983
|
-
#
|
984
|
-
# integer value)
|
1041
|
+
# <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
|
1042
|
+
# unsigned integer value).
|
1043
|
+
#
|
1044
|
+
# Related: #count_with_duplicates
|
985
1045
|
def count
|
986
1046
|
@tuples.sum(@tuples.count) { _2 - _1 } +
|
987
1047
|
(include_star? && include?(UINT32_MAX) ? -1 : 0)
|
@@ -989,51 +1049,129 @@ module Net
|
|
989
1049
|
|
990
1050
|
alias size count
|
991
1051
|
|
992
|
-
# Returns the
|
993
|
-
#
|
1052
|
+
# Returns the count of numbers in the ordered #entries, including any
|
1053
|
+
# repeated numbers.
|
1054
|
+
#
|
1055
|
+
# <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
|
1056
|
+
# unsigned integer value).
|
1057
|
+
#
|
1058
|
+
# When #string is normalized, this behaves the same as #count.
|
1059
|
+
#
|
1060
|
+
# Related: #entries, #count_duplicates, #has_duplicates?
|
1061
|
+
def count_with_duplicates
|
1062
|
+
return count unless @string
|
1063
|
+
each_entry_tuple.sum {|min, max|
|
1064
|
+
max - min + ((max == STAR_INT && min != STAR_INT) ? 0 : 1)
|
1065
|
+
}
|
1066
|
+
end
|
1067
|
+
|
1068
|
+
# Returns the count of repeated numbers in the ordered #entries, the
|
1069
|
+
# difference between #count_with_duplicates and #count.
|
1070
|
+
#
|
1071
|
+
# When #string is normalized, this is zero.
|
994
1072
|
#
|
995
|
-
# Related: #
|
1073
|
+
# Related: #entries, #count_with_duplicates, #has_duplicates?
|
1074
|
+
def count_duplicates
|
1075
|
+
return 0 unless @string
|
1076
|
+
count_with_duplicates - count
|
1077
|
+
end
|
1078
|
+
|
1079
|
+
# :call-seq: has_duplicates? -> true | false
|
1080
|
+
#
|
1081
|
+
# Returns whether or not the ordered #entries repeat any numbers.
|
1082
|
+
#
|
1083
|
+
# Always returns +false+ when #string is normalized.
|
1084
|
+
#
|
1085
|
+
# Related: #entries, #count_with_duplicates, #count_duplicates?
|
1086
|
+
def has_duplicates?
|
1087
|
+
return false unless @string
|
1088
|
+
count_with_duplicates != count
|
1089
|
+
end
|
1090
|
+
|
1091
|
+
# Returns the (sorted and deduplicated) index of +number+ in the set, or
|
1092
|
+
# +nil+ if +number+ isn't in the set.
|
1093
|
+
#
|
1094
|
+
# Related: #[], #at, #find_ordered_index
|
996
1095
|
def find_index(number)
|
997
1096
|
number = to_tuple_int number
|
998
|
-
each_tuple_with_index do |min, max, idx_min|
|
1097
|
+
each_tuple_with_index(@tuples) do |min, max, idx_min|
|
999
1098
|
number < min and return nil
|
1000
1099
|
number <= max and return from_tuple_int(idx_min + (number - min))
|
1001
1100
|
end
|
1002
1101
|
nil
|
1003
1102
|
end
|
1004
1103
|
|
1005
|
-
|
1104
|
+
# Returns the first index of +number+ in the ordered #entries, or
|
1105
|
+
# +nil+ if +number+ isn't in the set.
|
1106
|
+
#
|
1107
|
+
# Related: #find_index
|
1108
|
+
def find_ordered_index(number)
|
1109
|
+
number = to_tuple_int number
|
1110
|
+
each_tuple_with_index(each_entry_tuple) do |min, max, idx_min|
|
1111
|
+
if min <= number && number <= max
|
1112
|
+
return from_tuple_int(idx_min + (number - min))
|
1113
|
+
end
|
1114
|
+
end
|
1115
|
+
nil
|
1116
|
+
end
|
1117
|
+
|
1118
|
+
private
|
1119
|
+
|
1120
|
+
def each_tuple_with_index(tuples)
|
1006
1121
|
idx_min = 0
|
1007
|
-
|
1008
|
-
|
1122
|
+
tuples.each do |min, max|
|
1123
|
+
idx_max = idx_min + (max - min)
|
1124
|
+
yield min, max, idx_min, idx_max
|
1009
1125
|
idx_min = idx_max + 1
|
1010
1126
|
end
|
1011
1127
|
idx_min
|
1012
1128
|
end
|
1013
1129
|
|
1014
|
-
|
1130
|
+
def reverse_each_tuple_with_index(tuples)
|
1015
1131
|
idx_max = -1
|
1016
|
-
|
1132
|
+
tuples.reverse_each do |min, max|
|
1017
1133
|
yield min, max, (idx_min = idx_max - (max - min)), idx_max
|
1018
1134
|
idx_max = idx_min - 1
|
1019
1135
|
end
|
1020
1136
|
idx_max
|
1021
1137
|
end
|
1022
1138
|
|
1139
|
+
public
|
1140
|
+
|
1023
1141
|
# :call-seq: at(index) -> integer or nil
|
1024
1142
|
#
|
1025
|
-
# Returns
|
1026
|
-
#
|
1143
|
+
# Returns the number at the given +index+ in the sorted set, without
|
1144
|
+
# modifying the set.
|
1145
|
+
#
|
1146
|
+
# +index+ is interpreted the same as in #[], except that #at only allows a
|
1147
|
+
# single integer argument.
|
1027
1148
|
#
|
1028
|
-
# Related: #[], #slice
|
1149
|
+
# Related: #[], #slice, #ordered_at
|
1029
1150
|
def at(index)
|
1151
|
+
lookup_number_by_tuple_index(tuples, index)
|
1152
|
+
end
|
1153
|
+
|
1154
|
+
# :call-seq: ordered_at(index) -> integer or nil
|
1155
|
+
#
|
1156
|
+
# Returns the number at the given +index+ in the ordered #entries, without
|
1157
|
+
# modifying the set.
|
1158
|
+
#
|
1159
|
+
# +index+ is interpreted the same as in #at (and #[]), except that
|
1160
|
+
# #ordered_at applies to the ordered #entries, not the sorted set.
|
1161
|
+
#
|
1162
|
+
# Related: #[], #slice, #ordered_at
|
1163
|
+
def ordered_at(index)
|
1164
|
+
lookup_number_by_tuple_index(each_entry_tuple, index)
|
1165
|
+
end
|
1166
|
+
|
1167
|
+
private def lookup_number_by_tuple_index(tuples, index)
|
1030
1168
|
index = Integer(index.to_int)
|
1031
1169
|
if index.negative?
|
1032
|
-
reverse_each_tuple_with_index do |min, max, idx_min, idx_max|
|
1170
|
+
reverse_each_tuple_with_index(tuples) do |min, max, idx_min, idx_max|
|
1033
1171
|
idx_min <= index and return from_tuple_int(min + (index - idx_min))
|
1034
1172
|
end
|
1035
1173
|
else
|
1036
|
-
each_tuple_with_index do |min, _, idx_min, idx_max|
|
1174
|
+
each_tuple_with_index(tuples) do |min, _, idx_min, idx_max|
|
1037
1175
|
index <= idx_max and return from_tuple_int(min + (index - idx_min))
|
1038
1176
|
end
|
1039
1177
|
end
|
@@ -1048,17 +1186,18 @@ module Net
|
|
1048
1186
|
# seqset[range] -> sequence set or nil
|
1049
1187
|
# slice(range) -> sequence set or nil
|
1050
1188
|
#
|
1051
|
-
# Returns a number or a subset from
|
1189
|
+
# Returns a number or a subset from the _sorted_ set, without modifying
|
1190
|
+
# the set.
|
1052
1191
|
#
|
1053
1192
|
# When an Integer argument +index+ is given, the number at offset +index+
|
1054
|
-
# is returned:
|
1193
|
+
# in the sorted set is returned:
|
1055
1194
|
#
|
1056
1195
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1057
1196
|
# set[0] #=> 10
|
1058
1197
|
# set[5] #=> 15
|
1059
1198
|
# set[10] #=> 26
|
1060
1199
|
#
|
1061
|
-
# If +index+ is negative, it counts relative to the end of
|
1200
|
+
# If +index+ is negative, it counts relative to the end of the sorted set:
|
1062
1201
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1063
1202
|
# set[-1] #=> 26
|
1064
1203
|
# set[-3] #=> 22
|
@@ -1070,13 +1209,14 @@ module Net
|
|
1070
1209
|
# set[11] #=> nil
|
1071
1210
|
# set[-12] #=> nil
|
1072
1211
|
#
|
1073
|
-
# The result is based on the
|
1074
|
-
#
|
1212
|
+
# The result is based on the sorted and de-duplicated set, not on the
|
1213
|
+
# ordered #entries in #string.
|
1075
1214
|
#
|
1076
1215
|
# set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
|
1077
1216
|
# set[0] #=> 11
|
1078
1217
|
# set[-1] #=> 23
|
1079
1218
|
#
|
1219
|
+
# Related: #at
|
1080
1220
|
def [](index, length = nil)
|
1081
1221
|
if length then slice_length(index, length)
|
1082
1222
|
elsif index.is_a?(Range) then slice_range(index)
|
@@ -1086,7 +1226,9 @@ module Net
|
|
1086
1226
|
|
1087
1227
|
alias slice :[]
|
1088
1228
|
|
1089
|
-
private
|
1229
|
+
private
|
1230
|
+
|
1231
|
+
def slice_length(start, length)
|
1090
1232
|
start = Integer(start.to_int)
|
1091
1233
|
length = Integer(length.to_int)
|
1092
1234
|
raise ArgumentError, "length must be positive" unless length.positive?
|
@@ -1094,7 +1236,7 @@ module Net
|
|
1094
1236
|
slice_range(start..last)
|
1095
1237
|
end
|
1096
1238
|
|
1097
|
-
|
1239
|
+
def slice_range(range)
|
1098
1240
|
first = range.begin || 0
|
1099
1241
|
last = range.end || -1
|
1100
1242
|
last -= 1 if range.exclude_end? && range.end && last != STAR_INT
|
@@ -1109,6 +1251,8 @@ module Net
|
|
1109
1251
|
end
|
1110
1252
|
end
|
1111
1253
|
|
1254
|
+
public
|
1255
|
+
|
1112
1256
|
# Returns a frozen SequenceSet with <tt>*</tt> converted to +max+, numbers
|
1113
1257
|
# and ranges over +max+ removed, and ranges containing +max+ converted to
|
1114
1258
|
# end at +max+.
|
@@ -1259,7 +1403,8 @@ module Net
|
|
1259
1403
|
when *STARS, Integer, Range then [input_to_tuple(obj)]
|
1260
1404
|
when String then str_to_tuples obj
|
1261
1405
|
when SequenceSet then obj.tuples
|
1262
|
-
when
|
1406
|
+
when Set then obj.map { [to_tuple_int(_1)] * 2 }
|
1407
|
+
when Array then obj.flat_map { input_to_tuples _1 }
|
1263
1408
|
when nil then []
|
1264
1409
|
else
|
1265
1410
|
raise DataFormatError,
|
@@ -1272,8 +1417,7 @@ module Net
|
|
1272
1417
|
# String, Set, Array, or... any type of object.
|
1273
1418
|
def input_try_convert(input)
|
1274
1419
|
SequenceSet.try_convert(input) ||
|
1275
|
-
|
1276
|
-
input.respond_to?(:to_int) && Integer(input.to_int) ||
|
1420
|
+
Integer.try_convert(input) ||
|
1277
1421
|
String.try_convert(input) ||
|
1278
1422
|
input
|
1279
1423
|
end
|
@@ -1305,6 +1449,12 @@ module Net
|
|
1305
1449
|
range.include?(min) || range.include?(max) || (min..max).cover?(range)
|
1306
1450
|
end
|
1307
1451
|
|
1452
|
+
def modifying!
|
1453
|
+
if frozen?
|
1454
|
+
raise FrozenError, "can't modify frozen #{self.class}: %p" % [self]
|
1455
|
+
end
|
1456
|
+
end
|
1457
|
+
|
1308
1458
|
def tuples_add(tuples) tuples.each do tuple_add _1 end; self end
|
1309
1459
|
def tuples_subtract(tuples) tuples.each do tuple_subtract _1 end; self end
|
1310
1460
|
|
@@ -1319,10 +1469,11 @@ module Net
|
|
1319
1469
|
# ---------??===lower==|--|==|----|===upper===|-- join until upper
|
1320
1470
|
# ---------??===lower==|--|==|--|=====upper===|-- join to upper
|
1321
1471
|
def tuple_add(tuple)
|
1472
|
+
modifying!
|
1322
1473
|
min, max = tuple
|
1323
1474
|
lower, lower_idx = tuple_gte_with_index(min - 1)
|
1324
|
-
if lower.nil? then tuples <<
|
1325
|
-
elsif (max + 1) < lower.first then tuples.insert(lower_idx,
|
1475
|
+
if lower.nil? then tuples << [min, max]
|
1476
|
+
elsif (max + 1) < lower.first then tuples.insert(lower_idx, [min, max])
|
1326
1477
|
else tuple_coalesce(lower, lower_idx, min, max)
|
1327
1478
|
end
|
1328
1479
|
end
|
@@ -1355,6 +1506,7 @@ module Net
|
|
1355
1506
|
# -------??=====lower====|--|====|---|====upper====|-- 7. delete until
|
1356
1507
|
# -------??=====lower====|--|====|--|=====upper====|-- 8. delete and trim
|
1357
1508
|
def tuple_subtract(tuple)
|
1509
|
+
modifying!
|
1358
1510
|
min, max = tuple
|
1359
1511
|
lower, idx = tuple_gte_with_index(min)
|
1360
1512
|
if lower.nil? then nil # case 1.
|
@@ -1395,12 +1547,11 @@ module Net
|
|
1395
1547
|
end
|
1396
1548
|
|
1397
1549
|
def nz_number(num)
|
1398
|
-
|
1399
|
-
|
1400
|
-
|
1401
|
-
|
1402
|
-
|
1403
|
-
num
|
1550
|
+
String === num && !/\A[1-9]\d*\z/.match?(num) and
|
1551
|
+
raise DataFormatError, "%p is not a valid nz-number" % [num]
|
1552
|
+
NumValidator.ensure_nz_number Integer num
|
1553
|
+
rescue TypeError # To catch errors from Integer()
|
1554
|
+
raise DataFormatError, $!.message
|
1404
1555
|
end
|
1405
1556
|
|
1406
1557
|
# intentionally defined after the class implementation
|
@@ -4,7 +4,7 @@ module Net
|
|
4
4
|
class IMAP
|
5
5
|
module StringPrep
|
6
6
|
|
7
|
-
# Defined in RFC3491[https://
|
7
|
+
# Defined in RFC3491[https://www.rfc-editor.org/rfc/rfc3491], the +nameprep+
|
8
8
|
# profile of "Stringprep" is:
|
9
9
|
# >>>
|
10
10
|
# used by the IDNA protocol for preparing domain names; it is not
|
@@ -4,11 +4,11 @@ module Net
|
|
4
4
|
class IMAP
|
5
5
|
module StringPrep
|
6
6
|
|
7
|
-
# Defined in RFC-4505[https://
|
7
|
+
# Defined in RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The +trace+
|
8
8
|
# profile of \StringPrep is used by the +ANONYMOUS+ \SASL mechanism.
|
9
9
|
module Trace
|
10
10
|
|
11
|
-
# Defined in RFC-4505[https://
|
11
|
+
# Defined in RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3.
|
12
12
|
STRINGPREP_PROFILE = "trace"
|
13
13
|
|
14
14
|
# >>>
|
@@ -23,7 +23,7 @@ module Net
|
|
23
23
|
# No Unicode normalization is required by this profile.
|
24
24
|
NORMALIZATION = nil
|
25
25
|
|
26
|
-
# From RFC-4505[https://
|
26
|
+
# From RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The "trace"
|
27
27
|
# Profile of "Stringprep":
|
28
28
|
# >>>
|
29
29
|
# Characters from the following tables of [StringPrep] are prohibited:
|
@@ -47,7 +47,7 @@ module Net
|
|
47
47
|
|
48
48
|
module_function
|
49
49
|
|
50
|
-
# From RFC-4505[https://
|
50
|
+
# From RFC-4505[https://www.rfc-editor.org/rfc/rfc4505] §3, The "trace"
|
51
51
|
# Profile of "Stringprep":
|
52
52
|
# >>>
|
53
53
|
# The character repertoire of this profile is Unicode 3.2 [Unicode].
|