net-imap 0.4.18 → 0.4.20

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.
@@ -60,18 +60,20 @@ module Net
60
60
  # set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
61
61
  # set.valid_string #=> "1:10,55,1024:2048"
62
62
  #
63
- # == Normalized form
63
+ # == Ordered and Normalized sets
64
64
  #
65
- # When a sequence set is created with a single String value, that #string
66
- # representation is preserved. SequenceSet's internal representation
67
- # implicitly sorts all entries, de-duplicates numbers, and coalesces
68
- # adjacent or overlapping ranges. Most enumeration methods and offset-based
69
- # methods use this normalized representation. Most modification methods
70
- # will convert #string to its normalized form.
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.
71
69
  #
72
- # In some cases the order of the string representation is significant, such
73
- # as the +ESORT+, <tt>CONTEXT=SORT</tt>, and +UIDPLUS+ extensions. Use
74
- # #entries or #each_entry to enumerate the set in its original order. To
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.
75
+ #
76
+ # Most modification methods convert #string to its normalized form. To
75
77
  # preserve #string order while modifying a set, use #append, #string=, or
76
78
  # #replace.
77
79
  #
@@ -164,7 +166,7 @@ module Net
164
166
  # - #===:
165
167
  # Returns whether a given object is fully contained within +self+, or
166
168
  # +nil+ if the object cannot be converted to a compatible type.
167
- # - #cover? (aliased as #===):
169
+ # - #cover?:
168
170
  # Returns whether a given object is fully contained within +self+.
169
171
  # - #intersect? (aliased as #overlap?):
170
172
  # Returns whether +self+ and a given object have any common elements.
@@ -176,7 +178,7 @@ module Net
176
178
  #
177
179
  # <i>Set membership:</i>
178
180
  # - #include? (aliased as #member?):
179
- # Returns whether a given object (nz-number, range, or <tt>*</tt>) is
181
+ # Returns whether a given element (nz-number, range, or <tt>*</tt>) is
180
182
  # contained by the set.
181
183
  # - #include_star?: Returns whether the set contains <tt>*</tt>.
182
184
  #
@@ -185,30 +187,41 @@ module Net
185
187
  # - #max: Returns the maximum number in the set.
186
188
  # - #minmax: Returns the minimum and maximum numbers in the set.
187
189
  #
188
- # <i>Accessing value by offset:</i>
190
+ # <i>Accessing value by offset in sorted set:</i>
189
191
  # - #[] (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
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.
193
200
  #
194
201
  # <i>Set cardinality:</i>
195
202
  # - #count (aliased as #size): Returns the count of numbers in the set.
203
+ # Duplicated numbers are not counted.
196
204
  # - #empty?: Returns whether the set has no members. \IMAP syntax does not
197
205
  # allow empty sequence sets.
198
206
  # - #valid?: Returns whether the set has any members.
199
207
  # - #full?: Returns whether the set contains every possible value, including
200
208
  # <tt>*</tt>.
201
209
  #
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
+ #
202
218
  # === Methods for Iterating
203
219
  #
220
+ # <i>Normalized (sorted and coalesced):</i>
204
221
  # - #each_element: Yields each number and range in the set, sorted and
205
222
  # coalesced, and returns +self+.
206
223
  # - #elements (aliased as #to_a): Returns an Array of every number and range
207
224
  # 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
225
  # - #each_range:
213
226
  # Yields each element in the set as a Range and returns +self+.
214
227
  # - #ranges: Returns an Array of every element in the set, converting
@@ -218,17 +231,25 @@ module Net
218
231
  # ranges into all of their contained numbers.
219
232
  # - #to_set: Returns a Set containing all of the #numbers in the set.
220
233
  #
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
+ #
221
242
  # === Methods for \Set Operations
222
243
  # These methods do not modify +self+.
223
244
  #
224
245
  # - #| (aliased as #union and #+): Returns a new set combining all members
225
- # from +self+ with all members from the other object.
246
+ # from +self+ with all members from the other set.
226
247
  # - #& (aliased as #intersection): Returns a new set containing all members
227
- # common to +self+ and the other object.
248
+ # common to +self+ and the other set.
228
249
  # - #- (aliased as #difference): Returns a copy of +self+ with all members
229
- # in the other object removed.
250
+ # in the other set removed.
230
251
  # - #^ (aliased as #xor): Returns a new set containing all members from
231
- # +self+ and the other object except those common to both.
252
+ # +self+ and the other set except those common to both.
232
253
  # - #~ (aliased as #complement): Returns a new set containing all members
233
254
  # that are not in +self+
234
255
  # - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
@@ -237,28 +258,39 @@ module Net
237
258
  # === Methods for Assigning
238
259
  # These methods add or replace elements in +self+.
239
260
  #
240
- # - #add (aliased as #<<): Adds a given object to the set; returns +self+.
241
- # - #add?: If the given object is not an element in the set, adds it and
261
+ # <i>Normalized (sorted and coalesced):</i>
262
+ #
263
+ # These methods always update #string to be fully sorted and coalesced.
264
+ #
265
+ # - #add (aliased as #<<): Adds a given element to the set; returns +self+.
266
+ # - #add?: If the given element is not fully included the set, adds it and
242
267
  # returns +self+; otherwise, returns +nil+.
243
- # - #merge: Merges multiple elements into the set; returns +self+.
244
- # - #append: Adds a given object to the set, appending it to the existing
268
+ # - #merge: Adds all members of the given sets into this 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
+ # - #append: Adds the given entry to the set, appending it to the existing
245
276
  # string, and returns +self+.
246
277
  # - #string=: Assigns a new #string value and replaces #elements to match.
247
278
  # - #replace: Replaces the contents of the set with the contents
248
279
  # of a given object.
249
- # - #complement!: Replaces the contents of the set with its own #complement.
250
280
  #
251
281
  # === Methods for Deleting
252
- # These methods remove elements from +self+.
282
+ # These methods remove elements from +self+, and update #string to be fully
283
+ # sorted and coalesced.
253
284
  #
254
285
  # - #clear: Removes all elements in the set; returns +self+.
255
- # - #delete: Removes a given object from the set; returns +self+.
256
- # - #delete?: If the given object is an element in the set, removes it and
286
+ # - #delete: Removes a given element from the set; returns +self+.
287
+ # - #delete?: If the given element is included in the set, removes it and
257
288
  # returns it; otherwise, returns +nil+.
258
289
  # - #delete_at: Removes the number at a given offset.
259
290
  # - #slice!: Removes the number or consecutive numbers at a given offset or
260
291
  # range of offsets.
261
- # - #subtract: Removes each given object from the set; returns +self+.
292
+ # - #subtract: Removes all members of the given sets from this set; returns
293
+ # +self+.
262
294
  # - #limit!: Replaces <tt>*</tt> with a given maximum value and removes all
263
295
  # members over that maximum; returns +self+.
264
296
  #
@@ -295,9 +327,12 @@ module Net
295
327
  class << self
296
328
 
297
329
  # :call-seq:
298
- # SequenceSet[*values] -> valid frozen sequence set
330
+ # SequenceSet[*inputs] -> valid frozen sequence set
299
331
  #
300
- # Returns a frozen SequenceSet, constructed from +values+.
332
+ # Returns a frozen SequenceSet, constructed from +inputs+.
333
+ #
334
+ # When only a single valid frozen SequenceSet is given, that same set is
335
+ # returned.
301
336
  #
302
337
  # An empty SequenceSet is invalid and will raise a DataFormatError.
303
338
  #
@@ -663,7 +698,7 @@ module Net
663
698
  alias complement :~
664
699
 
665
700
  # :call-seq:
666
- # add(object) -> self
701
+ # add(element) -> self
667
702
  # self << other -> self
668
703
  #
669
704
  # Adds a range or number to the set and returns +self+.
@@ -671,8 +706,8 @@ module Net
671
706
  # #string will be regenerated. Use #merge to add many elements at once.
672
707
  #
673
708
  # Related: #add?, #merge, #union
674
- def add(object)
675
- tuple_add input_to_tuple object
709
+ def add(element)
710
+ tuple_add input_to_tuple element
676
711
  normalize!
677
712
  end
678
713
  alias << add
@@ -681,28 +716,29 @@ module Net
681
716
  #
682
717
  # Unlike #add, #merge, or #union, the new value is appended to #string.
683
718
  # This may result in a #string which has duplicates or is out-of-order.
684
- def append(object)
719
+ def append(entry)
685
720
  modifying!
686
- tuple = input_to_tuple object
721
+ tuple = input_to_tuple entry
687
722
  entry = tuple_to_str tuple
723
+ string unless empty? # write @string before tuple_add
688
724
  tuple_add tuple
689
- @string = -(string ? "#{@string},#{entry}" : entry)
725
+ @string = -(@string ? "#{@string},#{entry}" : entry)
690
726
  self
691
727
  end
692
728
 
693
- # :call-seq: add?(object) -> self or nil
729
+ # :call-seq: add?(element) -> self or nil
694
730
  #
695
731
  # Adds a range or number to the set and returns +self+. Returns +nil+
696
- # when the object is already included in the set.
732
+ # when the element is already included in the set.
697
733
  #
698
734
  # #string will be regenerated. Use #merge to add many elements at once.
699
735
  #
700
736
  # Related: #add, #merge, #union, #include?
701
- def add?(object)
702
- add object unless include? object
737
+ def add?(element)
738
+ add element unless include? element
703
739
  end
704
740
 
705
- # :call-seq: delete(object) -> self
741
+ # :call-seq: delete(element) -> self
706
742
  #
707
743
  # Deletes the given range or number from the set and returns +self+.
708
744
  #
@@ -710,8 +746,8 @@ module Net
710
746
  # many elements at once.
711
747
  #
712
748
  # Related: #delete?, #delete_at, #subtract, #difference
713
- def delete(object)
714
- tuple_subtract input_to_tuple object
749
+ def delete(element)
750
+ tuple_subtract input_to_tuple element
715
751
  normalize!
716
752
  end
717
753
 
@@ -747,8 +783,8 @@ module Net
747
783
  # #string will be regenerated after deletion.
748
784
  #
749
785
  # Related: #delete, #delete_at, #subtract, #difference, #disjoint?
750
- def delete?(object)
751
- tuple = input_to_tuple object
786
+ def delete?(element)
787
+ tuple = input_to_tuple element
752
788
  if tuple.first == tuple.last
753
789
  return unless include_tuple? tuple
754
790
  tuple_subtract tuple
@@ -792,33 +828,31 @@ module Net
792
828
  deleted
793
829
  end
794
830
 
795
- # Merges all of the elements that appear in any of the +inputs+ into the
831
+ # Merges all of the elements that appear in any of the +sets+ into the
796
832
  # set, and returns +self+.
797
833
  #
798
- # The +inputs+ may be any objects that would be accepted by ::new:
799
- # non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
800
- # formatted strings, other sequence sets, or enumerables containing any of
801
- # these.
834
+ # The +sets+ may be any objects that would be accepted by ::new: non-zero
835
+ # 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
836
+ # strings, other sequence sets, or enumerables containing any of these.
802
837
  #
803
- # #string will be regenerated after all inputs have been merged.
838
+ # #string will be regenerated after all sets have been merged.
804
839
  #
805
840
  # Related: #add, #add?, #union
806
- def merge(*inputs)
807
- tuples_add input_to_tuples inputs
841
+ def merge(*sets)
842
+ tuples_add input_to_tuples sets
808
843
  normalize!
809
844
  end
810
845
 
811
- # Removes all of the elements that appear in any of the given +objects+
812
- # from the set, and returns +self+.
846
+ # Removes all of the elements that appear in any of the given +sets+ from
847
+ # the set, and returns +self+.
813
848
  #
814
- # The +objects+ may be any objects that would be accepted by ::new:
815
- # non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
816
- # formatted strings, other sequence sets, or enumerables containing any of
817
- # these.
849
+ # The +sets+ may be any objects that would be accepted by ::new: non-zero
850
+ # 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
851
+ # strings, other sequence sets, or enumerables containing any of these.
818
852
  #
819
853
  # Related: #difference
820
- def subtract(*objects)
821
- tuples_subtract input_to_tuples objects
854
+ def subtract(*sets)
855
+ tuples_subtract input_to_tuples sets
822
856
  normalize!
823
857
  end
824
858
 
@@ -842,8 +876,8 @@ module Net
842
876
  # <tt>*</tt> translates to an endless range. Use #limit to translate both
843
877
  # cases to a maximum value.
844
878
  #
845
- # If the original input was unordered or contains overlapping ranges, the
846
- # returned ranges will be ordered and coalesced.
879
+ # The returned elements will be sorted and coalesced, even when the input
880
+ # #string is not. <tt>*</tt> will sort last. See #normalize.
847
881
  #
848
882
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
849
883
  # #=> [2, 5..9, 11..12, :*]
@@ -861,7 +895,7 @@ module Net
861
895
  # translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
862
896
  # value.
863
897
  #
864
- # The returned ranges will be ordered and coalesced, even when the input
898
+ # The returned ranges will be sorted and coalesced, even when the input
865
899
  # #string is not. <tt>*</tt> will sort last. See #normalize.
866
900
  #
867
901
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
@@ -910,9 +944,7 @@ module Net
910
944
  # Related: #entries, #each_element
911
945
  def each_entry(&block) # :yields: integer or range or :*
912
946
  return to_enum(__method__) unless block_given?
913
- return each_element(&block) unless @string
914
- @string.split(",").each do yield tuple_to_entry str_to_tuple _1 end
915
- self
947
+ each_entry_tuple do yield tuple_to_entry _1 end
916
948
  end
917
949
 
918
950
  # Yields each number or range (or <tt>:*</tt>) in #elements to the block
@@ -930,6 +962,16 @@ module Net
930
962
 
931
963
  private
932
964
 
965
+ def each_entry_tuple(&block)
966
+ return to_enum(__method__) unless block_given?
967
+ if @string
968
+ @string.split(",") do block.call str_to_tuple _1 end
969
+ else
970
+ @tuples.each(&block)
971
+ end
972
+ self
973
+ end
974
+
933
975
  def tuple_to_entry((min, max))
934
976
  if min == STAR_INT then :*
935
977
  elsif max == STAR_INT then min..
@@ -961,19 +1003,36 @@ module Net
961
1003
  # Returns an enumerator when called without a block (even if the set
962
1004
  # contains <tt>*</tt>).
963
1005
  #
964
- # Related: #numbers
1006
+ # Related: #numbers, #each_ordered_number
965
1007
  def each_number(&block) # :yields: integer
966
1008
  return to_enum(__method__) unless block_given?
967
1009
  raise RangeError, '%s contains "*"' % [self.class] if include_star?
968
- each_element do |elem|
969
- case elem
970
- when Range then elem.each(&block)
971
- when Integer then block.(elem)
972
- end
973
- end
1010
+ @tuples.each do each_number_in_tuple _1, _2, &block end
974
1011
  self
975
1012
  end
976
1013
 
1014
+ # Yields each number in #entries to the block and returns self.
1015
+ # If the set contains a <tt>*</tt>, RangeError will be raised.
1016
+ #
1017
+ # Returns an enumerator when called without a block (even if the set
1018
+ # contains <tt>*</tt>).
1019
+ #
1020
+ # Related: #entries, #each_number
1021
+ def each_ordered_number(&block)
1022
+ return to_enum(__method__) unless block_given?
1023
+ raise RangeError, '%s contains "*"' % [self.class] if include_star?
1024
+ each_entry_tuple do each_number_in_tuple _1, _2, &block end
1025
+ end
1026
+
1027
+ private def each_number_in_tuple(min, max, &block)
1028
+ if min == STAR_INT then yield :*
1029
+ elsif min == max then yield min
1030
+ elsif max != STAR_INT then (min..max).each(&block)
1031
+ else
1032
+ raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
1033
+ end
1034
+ end
1035
+
977
1036
  # Returns a Set with all of the #numbers in the sequence set.
978
1037
  #
979
1038
  # If the set contains a <tt>*</tt>, RangeError will be raised.
@@ -985,8 +1044,10 @@ module Net
985
1044
 
986
1045
  # Returns the count of #numbers in the set.
987
1046
  #
988
- # If <tt>*</tt> and <tt>2**32 - 1</tt> (the maximum 32-bit unsigned
989
- # integer value) are both in the set, they will only be counted once.
1047
+ # <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
1048
+ # unsigned integer value).
1049
+ #
1050
+ # Related: #count_with_duplicates
990
1051
  def count
991
1052
  @tuples.sum(@tuples.count) { _2 - _1 } +
992
1053
  (include_star? && include?(UINT32_MAX) ? -1 : 0)
@@ -994,33 +1055,87 @@ module Net
994
1055
 
995
1056
  alias size count
996
1057
 
997
- # Returns the index of +number+ in the set, or +nil+ if +number+ isn't in
998
- # the set.
1058
+ # Returns the count of numbers in the ordered #entries, including any
1059
+ # repeated numbers.
1060
+ #
1061
+ # <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
1062
+ # unsigned integer value).
1063
+ #
1064
+ # When #string is normalized, this behaves the same as #count.
1065
+ #
1066
+ # Related: #entries, #count_duplicates, #has_duplicates?
1067
+ def count_with_duplicates
1068
+ return count unless @string
1069
+ each_entry_tuple.sum {|min, max|
1070
+ max - min + ((max == STAR_INT && min != STAR_INT) ? 0 : 1)
1071
+ }
1072
+ end
1073
+
1074
+ # Returns the count of repeated numbers in the ordered #entries, the
1075
+ # difference between #count_with_duplicates and #count.
1076
+ #
1077
+ # When #string is normalized, this is zero.
1078
+ #
1079
+ # Related: #entries, #count_with_duplicates, #has_duplicates?
1080
+ def count_duplicates
1081
+ return 0 unless @string
1082
+ count_with_duplicates - count
1083
+ end
1084
+
1085
+ # :call-seq: has_duplicates? -> true | false
1086
+ #
1087
+ # Returns whether or not the ordered #entries repeat any numbers.
1088
+ #
1089
+ # Always returns +false+ when #string is normalized.
1090
+ #
1091
+ # Related: #entries, #count_with_duplicates, #count_duplicates?
1092
+ def has_duplicates?
1093
+ return false unless @string
1094
+ count_with_duplicates != count
1095
+ end
1096
+
1097
+ # Returns the (sorted and deduplicated) index of +number+ in the set, or
1098
+ # +nil+ if +number+ isn't in the set.
999
1099
  #
1000
- # Related: #[]
1100
+ # Related: #[], #at, #find_ordered_index
1001
1101
  def find_index(number)
1002
1102
  number = to_tuple_int number
1003
- each_tuple_with_index do |min, max, idx_min|
1103
+ each_tuple_with_index(@tuples) do |min, max, idx_min|
1004
1104
  number < min and return nil
1005
1105
  number <= max and return from_tuple_int(idx_min + (number - min))
1006
1106
  end
1007
1107
  nil
1008
1108
  end
1009
1109
 
1110
+ # Returns the first index of +number+ in the ordered #entries, or
1111
+ # +nil+ if +number+ isn't in the set.
1112
+ #
1113
+ # Related: #find_index
1114
+ def find_ordered_index(number)
1115
+ number = to_tuple_int number
1116
+ each_tuple_with_index(each_entry_tuple) do |min, max, idx_min|
1117
+ if min <= number && number <= max
1118
+ return from_tuple_int(idx_min + (number - min))
1119
+ end
1120
+ end
1121
+ nil
1122
+ end
1123
+
1010
1124
  private
1011
1125
 
1012
- def each_tuple_with_index
1126
+ def each_tuple_with_index(tuples)
1013
1127
  idx_min = 0
1014
- @tuples.each do |min, max|
1015
- yield min, max, idx_min, (idx_max = idx_min + (max - min))
1128
+ tuples.each do |min, max|
1129
+ idx_max = idx_min + (max - min)
1130
+ yield min, max, idx_min, idx_max
1016
1131
  idx_min = idx_max + 1
1017
1132
  end
1018
1133
  idx_min
1019
1134
  end
1020
1135
 
1021
- def reverse_each_tuple_with_index
1136
+ def reverse_each_tuple_with_index(tuples)
1022
1137
  idx_max = -1
1023
- @tuples.reverse_each do |min, max|
1138
+ tuples.reverse_each do |min, max|
1024
1139
  yield min, max, (idx_min = idx_max - (max - min)), idx_max
1025
1140
  idx_max = idx_min - 1
1026
1141
  end
@@ -1031,18 +1146,38 @@ module Net
1031
1146
 
1032
1147
  # :call-seq: at(index) -> integer or nil
1033
1148
  #
1034
- # Returns a number from +self+, without modifying the set. Behaves the
1035
- # same as #[], except that #at only allows a single integer argument.
1149
+ # Returns the number at the given +index+ in the sorted set, without
1150
+ # modifying the set.
1036
1151
  #
1037
- # Related: #[], #slice
1152
+ # +index+ is interpreted the same as in #[], except that #at only allows a
1153
+ # single integer argument.
1154
+ #
1155
+ # Related: #[], #slice, #ordered_at
1038
1156
  def at(index)
1157
+ lookup_number_by_tuple_index(tuples, index)
1158
+ end
1159
+
1160
+ # :call-seq: ordered_at(index) -> integer or nil
1161
+ #
1162
+ # Returns the number at the given +index+ in the ordered #entries, without
1163
+ # modifying the set.
1164
+ #
1165
+ # +index+ is interpreted the same as in #at (and #[]), except that
1166
+ # #ordered_at applies to the ordered #entries, not the sorted set.
1167
+ #
1168
+ # Related: #[], #slice, #ordered_at
1169
+ def ordered_at(index)
1170
+ lookup_number_by_tuple_index(each_entry_tuple, index)
1171
+ end
1172
+
1173
+ private def lookup_number_by_tuple_index(tuples, index)
1039
1174
  index = Integer(index.to_int)
1040
1175
  if index.negative?
1041
- reverse_each_tuple_with_index do |min, max, idx_min, idx_max|
1176
+ reverse_each_tuple_with_index(tuples) do |min, max, idx_min, idx_max|
1042
1177
  idx_min <= index and return from_tuple_int(min + (index - idx_min))
1043
1178
  end
1044
1179
  else
1045
- each_tuple_with_index do |min, _, idx_min, idx_max|
1180
+ each_tuple_with_index(tuples) do |min, _, idx_min, idx_max|
1046
1181
  index <= idx_max and return from_tuple_int(min + (index - idx_min))
1047
1182
  end
1048
1183
  end
@@ -1057,17 +1192,18 @@ module Net
1057
1192
  # seqset[range] -> sequence set or nil
1058
1193
  # slice(range) -> sequence set or nil
1059
1194
  #
1060
- # Returns a number or a subset from +self+, without modifying the set.
1195
+ # Returns a number or a subset from the _sorted_ set, without modifying
1196
+ # the set.
1061
1197
  #
1062
1198
  # When an Integer argument +index+ is given, the number at offset +index+
1063
- # is returned:
1199
+ # in the sorted set is returned:
1064
1200
  #
1065
1201
  # set = Net::IMAP::SequenceSet["10:15,20:23,26"]
1066
1202
  # set[0] #=> 10
1067
1203
  # set[5] #=> 15
1068
1204
  # set[10] #=> 26
1069
1205
  #
1070
- # If +index+ is negative, it counts relative to the end of +self+:
1206
+ # If +index+ is negative, it counts relative to the end of the sorted set:
1071
1207
  # set = Net::IMAP::SequenceSet["10:15,20:23,26"]
1072
1208
  # set[-1] #=> 26
1073
1209
  # set[-3] #=> 22
@@ -1079,13 +1215,14 @@ module Net
1079
1215
  # set[11] #=> nil
1080
1216
  # set[-12] #=> nil
1081
1217
  #
1082
- # The result is based on the normalized set—sorted and de-duplicatednot
1083
- # on the assigned value of #string.
1218
+ # The result is based on the sorted and de-duplicated set, not on the
1219
+ # ordered #entries in #string.
1084
1220
  #
1085
1221
  # set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
1086
1222
  # set[0] #=> 11
1087
1223
  # set[-1] #=> 23
1088
1224
  #
1225
+ # Related: #at
1089
1226
  def [](index, length = nil)
1090
1227
  if length then slice_length(index, length)
1091
1228
  elsif index.is_a?(Range) then slice_range(index)
@@ -1255,29 +1392,29 @@ module Net
1255
1392
  super
1256
1393
  end
1257
1394
 
1258
- def input_to_tuple(obj)
1259
- obj = input_try_convert obj
1260
- case obj
1261
- when *STARS, Integer then [int = to_tuple_int(obj), int]
1262
- when Range then range_to_tuple(obj)
1263
- when String then str_to_tuple(obj)
1395
+ def input_to_tuple(entry)
1396
+ entry = input_try_convert entry
1397
+ case entry
1398
+ when *STARS, Integer then [int = to_tuple_int(entry), int]
1399
+ when Range then range_to_tuple(entry)
1400
+ when String then str_to_tuple(entry)
1264
1401
  else
1265
- raise DataFormatError, "expected number or range, got %p" % [obj]
1402
+ raise DataFormatError, "expected number or range, got %p" % [entry]
1266
1403
  end
1267
1404
  end
1268
1405
 
1269
- def input_to_tuples(obj)
1270
- obj = input_try_convert obj
1271
- case obj
1272
- when *STARS, Integer, Range then [input_to_tuple(obj)]
1273
- when String then str_to_tuples obj
1274
- when SequenceSet then obj.tuples
1275
- when ENUMABLE then obj.flat_map { input_to_tuples _1 }
1406
+ def input_to_tuples(set)
1407
+ set = input_try_convert set
1408
+ case set
1409
+ when *STARS, Integer, Range then [input_to_tuple(set)]
1410
+ when String then str_to_tuples set
1411
+ when SequenceSet then set.tuples
1412
+ when ENUMABLE then set.flat_map { input_to_tuples _1 }
1276
1413
  when nil then []
1277
1414
  else
1278
1415
  raise DataFormatError,
1279
1416
  "expected nz-number, range, string, or enumerable; " \
1280
- "got %p" % [obj]
1417
+ "got %p" % [set]
1281
1418
  end
1282
1419
  end
1283
1420
 
@@ -1341,8 +1478,8 @@ module Net
1341
1478
  modifying!
1342
1479
  min, max = tuple
1343
1480
  lower, lower_idx = tuple_gte_with_index(min - 1)
1344
- if lower.nil? then tuples << tuple
1345
- elsif (max + 1) < lower.first then tuples.insert(lower_idx, tuple)
1481
+ if lower.nil? then tuples << [min, max]
1482
+ elsif (max + 1) < lower.first then tuples.insert(lower_idx, [min, max])
1346
1483
  else tuple_coalesce(lower, lower_idx, min, max)
1347
1484
  end
1348
1485
  end