net-imap 0.4.19 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of net-imap might be problematic. Click here for more details.

@@ -4,16 +4,72 @@ module Net
4
4
  class IMAP
5
5
  module SASL
6
6
 
7
+ # SASL::ProtocolAdapters modules are meant to be used as mixins for
8
+ # SASL::ClientAdapter and its subclasses. Where the client adapter must
9
+ # be customized for each client library, the protocol adapter mixin
10
+ # handles \SASL requirements that are part of the protocol specification,
11
+ # but not specific to any particular client library. In particular, see
12
+ # {RFC4422 §4}[https://www.rfc-editor.org/rfc/rfc4422.html#section-4]
13
+ #
14
+ # === Interface
15
+ #
16
+ # >>>
17
+ # NOTE: This API is experimental, and may change.
18
+ #
19
+ # - {#command_name}[rdoc-ref:Generic#command_name] -- The name of the
20
+ # command used to to initiate an authentication exchange.
21
+ # - {#service}[rdoc-ref:Generic#service] -- The GSSAPI service name.
22
+ # - {#encode_ir}[rdoc-ref:Generic#encode_ir]--Encodes an initial response.
23
+ # - {#decode}[rdoc-ref:Generic#decode] -- Decodes a server challenge.
24
+ # - {#encode}[rdoc-ref:Generic#encode] -- Encodes a client response.
25
+ # - {#cancel_response}[rdoc-ref:Generic#cancel_response] -- The encoded
26
+ # client response used to cancel an authentication exchange.
27
+ #
28
+ # Other protocol requirements of the \SASL authentication exchange are
29
+ # handled by SASL::ClientAdapter.
30
+ #
31
+ # === Included protocol adapters
32
+ #
33
+ # - Generic -- a basic implementation of all of the methods listed above.
34
+ # - IMAP -- An adapter for the IMAP4 protocol.
35
+ # - SMTP -- An adapter for the \SMTP protocol with the +AUTH+ capability.
36
+ # - POP -- An adapter for the POP3 protocol with the +SASL+ capability.
7
37
  module ProtocolAdapters
8
- # This API is experimental, and may change.
38
+ # See SASL::ProtocolAdapters@Interface.
9
39
  module Generic
40
+ # The name of the protocol command used to initiate a \SASL
41
+ # authentication exchange.
42
+ #
43
+ # The generic implementation returns <tt>"AUTHENTICATE"</tt>.
10
44
  def command_name; "AUTHENTICATE" end
11
- def service; raise "Implement in subclass or module" end
12
- def host; client.host end
13
- def port; client.port end
45
+
46
+ # A service name from the {GSSAPI/Kerberos/SASL Service Names
47
+ # registry}[https://www.iana.org/assignments/gssapi-service-names/gssapi-service-names.xhtml].
48
+ #
49
+ # The generic implementation returns <tt>"host"</tt>, which is the
50
+ # generic GSSAPI host-based service name.
51
+ def service; "host" end
52
+
53
+ # Encodes an initial response string.
54
+ #
55
+ # The generic implementation returns the result of #encode, or returns
56
+ # <tt>"="</tt> when +string+ is empty.
14
57
  def encode_ir(string) string.empty? ? "=" : encode(string) end
58
+
59
+ # Encodes a client response string.
60
+ #
61
+ # The generic implementation returns the Base64 encoding of +string+.
15
62
  def encode(string) [string].pack("m0") end
63
+
64
+ # Decodes a server challenge string.
65
+ #
66
+ # The generic implementation returns the Base64 decoding of +string+.
16
67
  def decode(string) string.unpack1("m0") end
68
+
69
+ # Returns the message used by the client to abort an authentication
70
+ # exchange.
71
+ #
72
+ # The generic implementation returns <tt>"*"</tt>.
17
73
  def cancel_response; "*" end
18
74
  end
19
75
 
data/lib/net/imap/sasl.rb CHANGED
@@ -114,8 +114,8 @@ module Net
114
114
  # messages has not passed integrity checks.
115
115
  AuthenticationFailed = Class.new(Error)
116
116
 
117
- # Indicates that authentication cannot proceed because one of the server's
118
- # ended authentication prematurely.
117
+ # Indicates that authentication cannot proceed because the server ended
118
+ # authentication prematurely.
119
119
  class AuthenticationIncomplete < AuthenticationFailed
120
120
  # The success response from the server
121
121
  attr_reader :response
@@ -159,7 +159,10 @@ module Net
159
159
  # Returns the default global SASL::Authenticators instance.
160
160
  def self.authenticators; @authenticators ||= Authenticators.new end
161
161
 
162
- # Delegates to <tt>registry.new</tt> See Authenticators#new.
162
+ # Creates a new SASL authenticator, using SASL::Authenticators#new.
163
+ #
164
+ # +registry+ defaults to SASL.authenticators. All other arguments are
165
+ # forwarded to to <tt>registry.new</tt>.
163
166
  def self.authenticator(*args, registry: authenticators, **kwargs, &block)
164
167
  registry.new(*args, **kwargs, &block)
165
168
  end
@@ -12,7 +12,6 @@ module Net
12
12
 
13
13
  def response_errors; RESPONSE_ERRORS end
14
14
  def sasl_ir_capable?; client.capable?("SASL-IR") end
15
- def auth_capable?(mechanism); client.auth_capable?(mechanism) end
16
15
  def drop_connection; client.logout! end
17
16
  def drop_connection!; client.disconnect end
18
17
  end
@@ -14,13 +14,6 @@ module Net
14
14
  # receive a SequenceSet as an argument, for example IMAP#search, IMAP#fetch,
15
15
  # and IMAP#store.
16
16
  #
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
17
  # == Creating sequence sets
25
18
  #
26
19
  # SequenceSet.new with no arguments creates an empty sequence set. Note
@@ -37,7 +30,8 @@ module Net
37
30
  #
38
31
  # SequenceSet.new may receive a single optional argument: a non-zero 32 bit
39
32
  # unsigned integer, a range, a <tt>sequence-set</tt> formatted string,
40
- # another sequence set, or an enumerable containing any of these.
33
+ # another sequence set, a Set (containing only numbers or <tt>*</tt>), or an
34
+ # Array containing any of these (array inputs may be nested).
41
35
  #
42
36
  # set = Net::IMAP::SequenceSet.new(1)
43
37
  # set.valid_string #=> "1"
@@ -60,20 +54,18 @@ module Net
60
54
  # set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
61
55
  # set.valid_string #=> "1:10,55,1024:2048"
62
56
  #
63
- # == Ordered and Normalized sets
64
- #
65
- # Sometimes the order of the set's members is significant, such as with the
66
- # +ESORT+, <tt>CONTEXT=SORT</tt>, and +UIDPLUS+ extensions. So, when a
67
- # sequence set is created by the parser or with a single string value, that
68
- # #string representation is preserved.
57
+ # == Normalized form
69
58
  #
70
- # Internally, SequenceSet stores a normalized representation which sorts all
71
- # entries, de-duplicates numbers, and coalesces adjacent or overlapping
72
- # ranges. Most methods use this normalized representation to achieve
73
- # <tt>O(lg n)</tt> porformance. Use #entries or #each_entry to enumerate
74
- # the set in its original order.
59
+ # When a sequence set is created with a single String value, that #string
60
+ # representation is preserved. SequenceSet's internal representation
61
+ # implicitly sorts all entries, de-duplicates numbers, and coalesces
62
+ # adjacent or overlapping ranges. Most enumeration methods and offset-based
63
+ # methods use this normalized representation. Most modification methods
64
+ # will convert #string to its normalized form.
75
65
  #
76
- # Most modification methods convert #string to its normalized form. To
66
+ # In some cases the order of the string representation is significant, such
67
+ # as the +ESORT+, <tt>CONTEXT=SORT</tt>, and +UIDPLUS+ extensions. Use
68
+ # #entries or #each_entry to enumerate the set in its original order. To
77
69
  # preserve #string order while modifying a set, use #append, #string=, or
78
70
  # #replace.
79
71
  #
@@ -166,7 +158,7 @@ module Net
166
158
  # - #===:
167
159
  # Returns whether a given object is fully contained within +self+, or
168
160
  # +nil+ if the object cannot be converted to a compatible type.
169
- # - #cover?:
161
+ # - #cover? (aliased as #===):
170
162
  # Returns whether a given object is fully contained within +self+.
171
163
  # - #intersect? (aliased as #overlap?):
172
164
  # Returns whether +self+ and a given object have any common elements.
@@ -187,41 +179,30 @@ module Net
187
179
  # - #max: Returns the maximum number in the set.
188
180
  # - #minmax: Returns the minimum and maximum numbers in the set.
189
181
  #
190
- # <i>Accessing value by offset in sorted set:</i>
182
+ # <i>Accessing value by offset:</i>
191
183
  # - #[] (aliased as #slice): Returns the number or consecutive subset at a
192
- # given offset or range of offsets in the sorted set.
193
- # - #at: Returns the number at a given offset in the sorted set.
194
- # - #find_index: Returns the given number's offset in the sorted set.
195
- #
196
- # <i>Accessing value by offset in ordered entries</i>
197
- # - #ordered_at: Returns the number at a given offset in the ordered entries.
198
- # - #find_ordered_index: Returns the index of the given number's first
199
- # occurrence in entries.
184
+ # given offset or range of offsets.
185
+ # - #at: Returns the number at a given offset.
186
+ # - #find_index: Returns the given number's offset in the set
200
187
  #
201
188
  # <i>Set cardinality:</i>
202
189
  # - #count (aliased as #size): Returns the count of numbers in the set.
203
- # Duplicated numbers are not counted.
204
190
  # - #empty?: Returns whether the set has no members. \IMAP syntax does not
205
191
  # allow empty sequence sets.
206
192
  # - #valid?: Returns whether the set has any members.
207
193
  # - #full?: Returns whether the set contains every possible value, including
208
194
  # <tt>*</tt>.
209
195
  #
210
- # <i>Denormalized properties:</i>
211
- # - #has_duplicates?: Returns whether the ordered entries repeat any
212
- # numbers.
213
- # - #count_duplicates: Returns the count of repeated numbers in the ordered
214
- # entries.
215
- # - #count_with_duplicates: Returns the count of numbers in the ordered
216
- # entries, including any repeated numbers.
217
- #
218
196
  # === Methods for Iterating
219
197
  #
220
- # <i>Normalized (sorted and coalesced):</i>
221
198
  # - #each_element: Yields each number and range in the set, sorted and
222
199
  # coalesced, and returns +self+.
223
200
  # - #elements (aliased as #to_a): Returns an Array of every number and range
224
201
  # in the set, sorted and coalesced.
202
+ # - #each_entry: Yields each number and range in the set, unsorted and
203
+ # without deduplicating numbers or coalescing ranges, and returns +self+.
204
+ # - #entries: Returns an Array of every number and range in the set,
205
+ # unsorted and without deduplicating numbers or coalescing ranges.
225
206
  # - #each_range:
226
207
  # Yields each element in the set as a Range and returns +self+.
227
208
  # - #ranges: Returns an Array of every element in the set, converting
@@ -231,14 +212,6 @@ module Net
231
212
  # ranges into all of their contained numbers.
232
213
  # - #to_set: Returns a Set containing all of the #numbers in the set.
233
214
  #
234
- # <i>Order preserving:</i>
235
- # - #each_entry: Yields each number and range in the set, unsorted and
236
- # without deduplicating numbers or coalescing ranges, and returns +self+.
237
- # - #entries: Returns an Array of every number and range in the set,
238
- # unsorted and without deduplicating numbers or coalescing ranges.
239
- # - #each_ordered_number: Yields each number in the ordered entries and
240
- # returns +self+.
241
- #
242
215
  # === Methods for \Set Operations
243
216
  # These methods do not modify +self+.
244
217
  #
@@ -258,29 +231,19 @@ module Net
258
231
  # === Methods for Assigning
259
232
  # These methods add or replace elements in +self+.
260
233
  #
261
- # <i>Normalized (sorted and coalesced):</i>
262
- #
263
- # These methods always update #string to be fully sorted and coalesced.
264
- #
265
234
  # - #add (aliased as #<<): Adds a given object to the set; returns +self+.
266
235
  # - #add?: If the given object is not an element in the set, adds it and
267
236
  # returns +self+; otherwise, returns +nil+.
268
237
  # - #merge: Merges multiple elements into the set; returns +self+.
269
- # - #complement!: Replaces the contents of the set with its own #complement.
270
- #
271
- # <i>Order preserving:</i>
272
- #
273
- # These methods _may_ cause #string to not be sorted or coalesced.
274
- #
275
238
  # - #append: Adds a given object to the set, appending it to the existing
276
239
  # string, and returns +self+.
277
240
  # - #string=: Assigns a new #string value and replaces #elements to match.
278
241
  # - #replace: Replaces the contents of the set with the contents
279
242
  # of a given object.
243
+ # - #complement!: Replaces the contents of the set with its own #complement.
280
244
  #
281
245
  # === Methods for Deleting
282
- # These methods remove elements from +self+, and update #string to be fully
283
- # sorted and coalesced.
246
+ # These methods remove elements from +self+.
284
247
  #
285
248
  # - #clear: Removes all elements in the set; returns +self+.
286
249
  # - #delete: Removes a given object from the set; returns +self+.
@@ -320,8 +283,7 @@ module Net
320
283
  private_constant :STAR_INT, :STARS
321
284
 
322
285
  COERCIBLE = ->{ _1.respond_to? :to_sequence_set }
323
- ENUMABLE = ->{ _1.respond_to?(:each) && _1.respond_to?(:empty?) }
324
- private_constant :COERCIBLE, :ENUMABLE
286
+ private_constant :COERCIBLE
325
287
 
326
288
  class << self
327
289
 
@@ -356,7 +318,7 @@ module Net
356
318
  # raised.
357
319
  def try_convert(obj)
358
320
  return obj if obj.is_a?(SequenceSet)
359
- return nil unless obj.respond_to?(:to_sequence_set)
321
+ return nil unless respond_to?(:to_sequence_set)
360
322
  obj = obj.to_sequence_set
361
323
  return obj if obj.is_a?(SequenceSet)
362
324
  raise DataFormatError, "invalid object returned from to_sequence_set"
@@ -716,9 +678,8 @@ module Net
716
678
  modifying!
717
679
  tuple = input_to_tuple object
718
680
  entry = tuple_to_str tuple
719
- string unless empty? # write @string before tuple_add
720
681
  tuple_add tuple
721
- @string = -(@string ? "#{@string},#{entry}" : entry)
682
+ @string = -(string ? "#{@string},#{entry}" : entry)
722
683
  self
723
684
  end
724
685
 
@@ -874,8 +835,8 @@ module Net
874
835
  # <tt>*</tt> translates to an endless range. Use #limit to translate both
875
836
  # cases to a maximum value.
876
837
  #
877
- # The returned elements will be sorted and coalesced, even when the input
878
- # #string is not. <tt>*</tt> will sort last. See #normalize.
838
+ # If the original input was unordered or contains overlapping ranges, the
839
+ # returned ranges will be ordered and coalesced.
879
840
  #
880
841
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
881
842
  # #=> [2, 5..9, 11..12, :*]
@@ -893,7 +854,7 @@ module Net
893
854
  # translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
894
855
  # value.
895
856
  #
896
- # The returned ranges will be sorted and coalesced, even when the input
857
+ # The returned ranges will be ordered and coalesced, even when the input
897
858
  # #string is not. <tt>*</tt> will sort last. See #normalize.
898
859
  #
899
860
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
@@ -942,7 +903,9 @@ module Net
942
903
  # Related: #entries, #each_element
943
904
  def each_entry(&block) # :yields: integer or range or :*
944
905
  return to_enum(__method__) unless block_given?
945
- each_entry_tuple do yield tuple_to_entry _1 end
906
+ return each_element(&block) unless @string
907
+ @string.split(",").each do yield tuple_to_entry str_to_tuple _1 end
908
+ self
946
909
  end
947
910
 
948
911
  # Yields each number or range (or <tt>:*</tt>) in #elements to the block
@@ -960,16 +923,6 @@ module Net
960
923
 
961
924
  private
962
925
 
963
- def each_entry_tuple(&block)
964
- return to_enum(__method__) unless block_given?
965
- if @string
966
- @string.split(",") do block.call str_to_tuple _1 end
967
- else
968
- @tuples.each(&block)
969
- end
970
- self
971
- end
972
-
973
926
  def tuple_to_entry((min, max))
974
927
  if min == STAR_INT then :*
975
928
  elsif max == STAR_INT then min..
@@ -1001,34 +954,17 @@ module Net
1001
954
  # Returns an enumerator when called without a block (even if the set
1002
955
  # contains <tt>*</tt>).
1003
956
  #
1004
- # Related: #numbers, #each_ordered_number
957
+ # Related: #numbers
1005
958
  def each_number(&block) # :yields: integer
1006
959
  return to_enum(__method__) unless block_given?
1007
960
  raise RangeError, '%s contains "*"' % [self.class] if include_star?
1008
- @tuples.each do each_number_in_tuple _1, _2, &block end
1009
- self
1010
- end
1011
-
1012
- # Yields each number in #entries to the block and returns self.
1013
- # If the set contains a <tt>*</tt>, RangeError will be raised.
1014
- #
1015
- # Returns an enumerator when called without a block (even if the set
1016
- # contains <tt>*</tt>).
1017
- #
1018
- # Related: #entries, #each_number
1019
- def each_ordered_number(&block)
1020
- return to_enum(__method__) unless block_given?
1021
- raise RangeError, '%s contains "*"' % [self.class] if include_star?
1022
- each_entry_tuple do each_number_in_tuple _1, _2, &block end
1023
- end
1024
-
1025
- private def each_number_in_tuple(min, max, &block)
1026
- if min == STAR_INT then yield :*
1027
- elsif min == max then yield min
1028
- elsif max != STAR_INT then (min..max).each(&block)
1029
- else
1030
- raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
961
+ each_element do |elem|
962
+ case elem
963
+ when Range then elem.each(&block)
964
+ when Integer then block.(elem)
965
+ end
1031
966
  end
967
+ self
1032
968
  end
1033
969
 
1034
970
  # Returns a Set with all of the #numbers in the sequence set.
@@ -1042,10 +978,8 @@ module Net
1042
978
 
1043
979
  # Returns the count of #numbers in the set.
1044
980
  #
1045
- # <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
1046
- # unsigned integer value).
1047
- #
1048
- # Related: #count_with_duplicates
981
+ # If <tt>*</tt> and <tt>2**32 - 1</tt> (the maximum 32-bit unsigned
982
+ # integer value) are both in the set, they will only be counted once.
1049
983
  def count
1050
984
  @tuples.sum(@tuples.count) { _2 - _1 } +
1051
985
  (include_star? && include?(UINT32_MAX) ? -1 : 0)
@@ -1053,87 +987,33 @@ module Net
1053
987
 
1054
988
  alias size count
1055
989
 
1056
- # Returns the count of numbers in the ordered #entries, including any
1057
- # repeated numbers.
1058
- #
1059
- # <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
1060
- # unsigned integer value).
1061
- #
1062
- # When #string is normalized, this behaves the same as #count.
1063
- #
1064
- # Related: #entries, #count_duplicates, #has_duplicates?
1065
- def count_with_duplicates
1066
- return count unless @string
1067
- each_entry_tuple.sum {|min, max|
1068
- max - min + ((max == STAR_INT && min != STAR_INT) ? 0 : 1)
1069
- }
1070
- end
1071
-
1072
- # Returns the count of repeated numbers in the ordered #entries, the
1073
- # difference between #count_with_duplicates and #count.
1074
- #
1075
- # When #string is normalized, this is zero.
1076
- #
1077
- # Related: #entries, #count_with_duplicates, #has_duplicates?
1078
- def count_duplicates
1079
- return 0 unless @string
1080
- count_with_duplicates - count
1081
- end
1082
-
1083
- # :call-seq: has_duplicates? -> true | false
1084
- #
1085
- # Returns whether or not the ordered #entries repeat any numbers.
1086
- #
1087
- # Always returns +false+ when #string is normalized.
1088
- #
1089
- # Related: #entries, #count_with_duplicates, #count_duplicates?
1090
- def has_duplicates?
1091
- return false unless @string
1092
- count_with_duplicates != count
1093
- end
1094
-
1095
- # Returns the (sorted and deduplicated) index of +number+ in the set, or
1096
- # +nil+ if +number+ isn't in the set.
990
+ # Returns the index of +number+ in the set, or +nil+ if +number+ isn't in
991
+ # the set.
1097
992
  #
1098
- # Related: #[], #at, #find_ordered_index
993
+ # Related: #[]
1099
994
  def find_index(number)
1100
995
  number = to_tuple_int number
1101
- each_tuple_with_index(@tuples) do |min, max, idx_min|
996
+ each_tuple_with_index do |min, max, idx_min|
1102
997
  number < min and return nil
1103
998
  number <= max and return from_tuple_int(idx_min + (number - min))
1104
999
  end
1105
1000
  nil
1106
1001
  end
1107
1002
 
1108
- # Returns the first index of +number+ in the ordered #entries, or
1109
- # +nil+ if +number+ isn't in the set.
1110
- #
1111
- # Related: #find_index
1112
- def find_ordered_index(number)
1113
- number = to_tuple_int number
1114
- each_tuple_with_index(each_entry_tuple) do |min, max, idx_min|
1115
- if min <= number && number <= max
1116
- return from_tuple_int(idx_min + (number - min))
1117
- end
1118
- end
1119
- nil
1120
- end
1121
-
1122
1003
  private
1123
1004
 
1124
- def each_tuple_with_index(tuples)
1005
+ def each_tuple_with_index
1125
1006
  idx_min = 0
1126
- tuples.each do |min, max|
1127
- idx_max = idx_min + (max - min)
1128
- yield min, max, idx_min, idx_max
1007
+ @tuples.each do |min, max|
1008
+ yield min, max, idx_min, (idx_max = idx_min + (max - min))
1129
1009
  idx_min = idx_max + 1
1130
1010
  end
1131
1011
  idx_min
1132
1012
  end
1133
1013
 
1134
- def reverse_each_tuple_with_index(tuples)
1014
+ def reverse_each_tuple_with_index
1135
1015
  idx_max = -1
1136
- tuples.reverse_each do |min, max|
1016
+ @tuples.reverse_each do |min, max|
1137
1017
  yield min, max, (idx_min = idx_max - (max - min)), idx_max
1138
1018
  idx_max = idx_min - 1
1139
1019
  end
@@ -1144,38 +1024,18 @@ module Net
1144
1024
 
1145
1025
  # :call-seq: at(index) -> integer or nil
1146
1026
  #
1147
- # Returns the number at the given +index+ in the sorted set, without
1148
- # modifying the set.
1149
- #
1150
- # +index+ is interpreted the same as in #[], except that #at only allows a
1151
- # single integer argument.
1027
+ # Returns a number from +self+, without modifying the set. Behaves the
1028
+ # same as #[], except that #at only allows a single integer argument.
1152
1029
  #
1153
- # Related: #[], #slice, #ordered_at
1030
+ # Related: #[], #slice
1154
1031
  def at(index)
1155
- lookup_number_by_tuple_index(tuples, index)
1156
- end
1157
-
1158
- # :call-seq: ordered_at(index) -> integer or nil
1159
- #
1160
- # Returns the number at the given +index+ in the ordered #entries, without
1161
- # modifying the set.
1162
- #
1163
- # +index+ is interpreted the same as in #at (and #[]), except that
1164
- # #ordered_at applies to the ordered #entries, not the sorted set.
1165
- #
1166
- # Related: #[], #slice, #ordered_at
1167
- def ordered_at(index)
1168
- lookup_number_by_tuple_index(each_entry_tuple, index)
1169
- end
1170
-
1171
- private def lookup_number_by_tuple_index(tuples, index)
1172
1032
  index = Integer(index.to_int)
1173
1033
  if index.negative?
1174
- reverse_each_tuple_with_index(tuples) do |min, max, idx_min, idx_max|
1034
+ reverse_each_tuple_with_index do |min, max, idx_min, idx_max|
1175
1035
  idx_min <= index and return from_tuple_int(min + (index - idx_min))
1176
1036
  end
1177
1037
  else
1178
- each_tuple_with_index(tuples) do |min, _, idx_min, idx_max|
1038
+ each_tuple_with_index do |min, _, idx_min, idx_max|
1179
1039
  index <= idx_max and return from_tuple_int(min + (index - idx_min))
1180
1040
  end
1181
1041
  end
@@ -1190,18 +1050,17 @@ module Net
1190
1050
  # seqset[range] -> sequence set or nil
1191
1051
  # slice(range) -> sequence set or nil
1192
1052
  #
1193
- # Returns a number or a subset from the _sorted_ set, without modifying
1194
- # the set.
1053
+ # Returns a number or a subset from +self+, without modifying the set.
1195
1054
  #
1196
1055
  # When an Integer argument +index+ is given, the number at offset +index+
1197
- # in the sorted set is returned:
1056
+ # is returned:
1198
1057
  #
1199
1058
  # set = Net::IMAP::SequenceSet["10:15,20:23,26"]
1200
1059
  # set[0] #=> 10
1201
1060
  # set[5] #=> 15
1202
1061
  # set[10] #=> 26
1203
1062
  #
1204
- # If +index+ is negative, it counts relative to the end of the sorted set:
1063
+ # If +index+ is negative, it counts relative to the end of +self+:
1205
1064
  # set = Net::IMAP::SequenceSet["10:15,20:23,26"]
1206
1065
  # set[-1] #=> 26
1207
1066
  # set[-3] #=> 22
@@ -1213,14 +1072,13 @@ module Net
1213
1072
  # set[11] #=> nil
1214
1073
  # set[-12] #=> nil
1215
1074
  #
1216
- # The result is based on the sorted and de-duplicated set, not on the
1217
- # ordered #entries in #string.
1075
+ # The result is based on the normalized set—sorted and de-duplicatednot
1076
+ # on the assigned value of #string.
1218
1077
  #
1219
1078
  # set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
1220
1079
  # set[0] #=> 11
1221
1080
  # set[-1] #=> 23
1222
1081
  #
1223
- # Related: #at
1224
1082
  def [](index, length = nil)
1225
1083
  if length then slice_length(index, length)
1226
1084
  elsif index.is_a?(Range) then slice_range(index)
@@ -1407,7 +1265,8 @@ module Net
1407
1265
  when *STARS, Integer, Range then [input_to_tuple(obj)]
1408
1266
  when String then str_to_tuples obj
1409
1267
  when SequenceSet then obj.tuples
1410
- when ENUMABLE then obj.flat_map { input_to_tuples _1 }
1268
+ when Set then obj.map { [to_tuple_int(_1)] * 2 }
1269
+ when Array then obj.flat_map { input_to_tuples _1 }
1411
1270
  when nil then []
1412
1271
  else
1413
1272
  raise DataFormatError,
@@ -1420,8 +1279,7 @@ module Net
1420
1279
  # String, Set, Array, or... any type of object.
1421
1280
  def input_try_convert(input)
1422
1281
  SequenceSet.try_convert(input) ||
1423
- # Integer.try_convert(input) || # ruby 3.1+
1424
- input.respond_to?(:to_int) && Integer(input.to_int) ||
1282
+ Integer.try_convert(input) ||
1425
1283
  String.try_convert(input) ||
1426
1284
  input
1427
1285
  end
@@ -1476,8 +1334,8 @@ module Net
1476
1334
  modifying!
1477
1335
  min, max = tuple
1478
1336
  lower, lower_idx = tuple_gte_with_index(min - 1)
1479
- if lower.nil? then tuples << [min, max]
1480
- elsif (max + 1) < lower.first then tuples.insert(lower_idx, [min, max])
1337
+ if lower.nil? then tuples << tuple
1338
+ elsif (max + 1) < lower.first then tuples.insert(lower_idx, tuple)
1481
1339
  else tuple_coalesce(lower, lower_idx, min, max)
1482
1340
  end
1483
1341
  end
@@ -1551,12 +1409,11 @@ module Net
1551
1409
  end
1552
1410
 
1553
1411
  def nz_number(num)
1554
- case num
1555
- when Integer, /\A[1-9]\d*\z/ then num = Integer(num)
1556
- else raise DataFormatError, "%p is not a valid nz-number" % [num]
1557
- end
1558
- NumValidator.ensure_nz_number(num)
1559
- num
1412
+ String === num && !/\A[1-9]\d*\z/.match?(num) and
1413
+ raise DataFormatError, "%p is not a valid nz-number" % [num]
1414
+ NumValidator.ensure_nz_number Integer num
1415
+ rescue TypeError # To catch errors from Integer()
1416
+ raise DataFormatError, $!.message
1560
1417
  end
1561
1418
 
1562
1419
  # intentionally defined after the class implementation