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.
- checksums.yaml +4 -4
- data/lib/net/imap/config/attr_type_coercion.rb +25 -21
- data/lib/net/imap/config.rb +169 -19
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +3 -54
- data/lib/net/imap/response_parser.rb +28 -13
- data/lib/net/imap/response_reader.rb +75 -0
- data/lib/net/imap/sequence_set.rb +254 -117
- data/lib/net/imap/uidplus_data.rb +326 -0
- data/lib/net/imap.rb +114 -41
- metadata +5 -6
@@ -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
|
63
|
+
# == Ordered and Normalized sets
|
64
64
|
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
#
|
68
|
-
#
|
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
|
-
#
|
73
|
-
#
|
74
|
-
#
|
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
|
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
|
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
|
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
|
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
|
250
|
+
# in the other set removed.
|
230
251
|
# - #^ (aliased as #xor): Returns a new set containing all members from
|
231
|
-
# +self+ and the other
|
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
|
-
#
|
241
|
-
#
|
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:
|
244
|
-
# - #
|
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
|
256
|
-
# - #delete?: If the given
|
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
|
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[*
|
330
|
+
# SequenceSet[*inputs] -> valid frozen sequence set
|
299
331
|
#
|
300
|
-
# Returns a frozen SequenceSet, constructed from +
|
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(
|
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(
|
675
|
-
tuple_add input_to_tuple
|
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(
|
719
|
+
def append(entry)
|
685
720
|
modifying!
|
686
|
-
tuple = input_to_tuple
|
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?(
|
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
|
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?(
|
702
|
-
add
|
737
|
+
def add?(element)
|
738
|
+
add element unless include? element
|
703
739
|
end
|
704
740
|
|
705
|
-
# :call-seq: delete(
|
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(
|
714
|
-
tuple_subtract input_to_tuple
|
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?(
|
751
|
-
tuple = input_to_tuple
|
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 +
|
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 +
|
799
|
-
#
|
800
|
-
#
|
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
|
838
|
+
# #string will be regenerated after all sets have been merged.
|
804
839
|
#
|
805
840
|
# Related: #add, #add?, #union
|
806
|
-
def merge(*
|
807
|
-
tuples_add input_to_tuples
|
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 +
|
812
|
-
#
|
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 +
|
815
|
-
#
|
816
|
-
#
|
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(*
|
821
|
-
tuples_subtract input_to_tuples
|
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
|
-
#
|
846
|
-
#
|
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
|
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
|
-
|
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
|
-
|
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
|
-
#
|
989
|
-
# integer value)
|
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
|
998
|
-
#
|
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
|
-
|
1015
|
-
|
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
|
-
|
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
|
1035
|
-
#
|
1149
|
+
# Returns the number at the given +index+ in the sorted set, without
|
1150
|
+
# modifying the set.
|
1036
1151
|
#
|
1037
|
-
#
|
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
|
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
|
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
|
1083
|
-
#
|
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(
|
1259
|
-
|
1260
|
-
case
|
1261
|
-
when *STARS, Integer then [int = to_tuple_int(
|
1262
|
-
when Range then range_to_tuple(
|
1263
|
-
when String then str_to_tuple(
|
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" % [
|
1402
|
+
raise DataFormatError, "expected number or range, got %p" % [entry]
|
1266
1403
|
end
|
1267
1404
|
end
|
1268
1405
|
|
1269
|
-
def input_to_tuples(
|
1270
|
-
|
1271
|
-
case
|
1272
|
-
when *STARS, Integer, Range then [input_to_tuple(
|
1273
|
-
when String then str_to_tuples
|
1274
|
-
when SequenceSet then
|
1275
|
-
when ENUMABLE then
|
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" % [
|
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 <<
|
1345
|
-
elsif (max + 1) < lower.first then tuples.insert(lower_idx,
|
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
|