net-imap 0.5.5 → 0.5.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +1 -0
- data/lib/net/imap/config/attr_type_coercion.rb +20 -23
- data/lib/net/imap/config.rb +168 -18
- data/lib/net/imap/connection_state.rb +48 -0
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +3 -49
- data/lib/net/imap/response_parser.rb +28 -13
- data/lib/net/imap/response_reader.rb +73 -0
- data/lib/net/imap/sequence_set.rb +267 -118
- data/lib/net/imap/uidplus_data.rb +244 -0
- data/lib/net/imap.rb +227 -48
- metadata +6 -3
@@ -56,18 +56,20 @@ module Net
|
|
56
56
|
# set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
|
57
57
|
# set.valid_string #=> "1:10,55,1024:2048"
|
58
58
|
#
|
59
|
-
# == Normalized
|
59
|
+
# == Ordered and Normalized sets
|
60
60
|
#
|
61
|
-
#
|
62
|
-
#
|
63
|
-
#
|
64
|
-
#
|
65
|
-
# methods use this normalized representation. Most modification methods
|
66
|
-
# 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.
|
67
65
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
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
|
71
73
|
# preserve #string order while modifying a set, use #append, #string=, or
|
72
74
|
# #replace.
|
73
75
|
#
|
@@ -160,7 +162,7 @@ module Net
|
|
160
162
|
# - #===:
|
161
163
|
# Returns whether a given object is fully contained within +self+, or
|
162
164
|
# +nil+ if the object cannot be converted to a compatible type.
|
163
|
-
# - #cover
|
165
|
+
# - #cover?:
|
164
166
|
# Returns whether a given object is fully contained within +self+.
|
165
167
|
# - #intersect? (aliased as #overlap?):
|
166
168
|
# Returns whether +self+ and a given object have any common elements.
|
@@ -172,7 +174,7 @@ module Net
|
|
172
174
|
#
|
173
175
|
# <i>Set membership:</i>
|
174
176
|
# - #include? (aliased as #member?):
|
175
|
-
# Returns whether a given
|
177
|
+
# Returns whether a given element (nz-number, range, or <tt>*</tt>) is
|
176
178
|
# contained by the set.
|
177
179
|
# - #include_star?: Returns whether the set contains <tt>*</tt>.
|
178
180
|
#
|
@@ -181,30 +183,41 @@ module Net
|
|
181
183
|
# - #max: Returns the maximum number in the set.
|
182
184
|
# - #minmax: Returns the minimum and maximum numbers in the set.
|
183
185
|
#
|
184
|
-
# <i>Accessing value by offset:</i>
|
186
|
+
# <i>Accessing value by offset in sorted set:</i>
|
185
187
|
# - #[] (aliased as #slice): Returns the number or consecutive subset at a
|
186
|
-
# given offset or range of offsets.
|
187
|
-
# - #at: Returns the number at a given offset.
|
188
|
-
# - #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.
|
189
196
|
#
|
190
197
|
# <i>Set cardinality:</i>
|
191
198
|
# - #count (aliased as #size): Returns the count of numbers in the set.
|
199
|
+
# Duplicated numbers are not counted.
|
192
200
|
# - #empty?: Returns whether the set has no members. \IMAP syntax does not
|
193
201
|
# allow empty sequence sets.
|
194
202
|
# - #valid?: Returns whether the set has any members.
|
195
203
|
# - #full?: Returns whether the set contains every possible value, including
|
196
204
|
# <tt>*</tt>.
|
197
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
|
+
#
|
198
214
|
# === Methods for Iterating
|
199
215
|
#
|
216
|
+
# <i>Normalized (sorted and coalesced):</i>
|
200
217
|
# - #each_element: Yields each number and range in the set, sorted and
|
201
218
|
# coalesced, and returns +self+.
|
202
219
|
# - #elements (aliased as #to_a): Returns an Array of every number and range
|
203
220
|
# in the set, sorted and coalesced.
|
204
|
-
# - #each_entry: Yields each number and range in the set, unsorted and
|
205
|
-
# without deduplicating numbers or coalescing ranges, and returns +self+.
|
206
|
-
# - #entries: Returns an Array of every number and range in the set,
|
207
|
-
# unsorted and without deduplicating numbers or coalescing ranges.
|
208
221
|
# - #each_range:
|
209
222
|
# Yields each element in the set as a Range and returns +self+.
|
210
223
|
# - #ranges: Returns an Array of every element in the set, converting
|
@@ -214,17 +227,25 @@ module Net
|
|
214
227
|
# ranges into all of their contained numbers.
|
215
228
|
# - #to_set: Returns a Set containing all of the #numbers in the set.
|
216
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
|
+
#
|
217
238
|
# === Methods for \Set Operations
|
218
239
|
# These methods do not modify +self+.
|
219
240
|
#
|
220
241
|
# - #| (aliased as #union and #+): Returns a new set combining all members
|
221
|
-
# from +self+ with all members from the other
|
242
|
+
# from +self+ with all members from the other set.
|
222
243
|
# - #& (aliased as #intersection): Returns a new set containing all members
|
223
|
-
# common to +self+ and the other
|
244
|
+
# common to +self+ and the other set.
|
224
245
|
# - #- (aliased as #difference): Returns a copy of +self+ with all members
|
225
|
-
# in the other
|
246
|
+
# in the other set removed.
|
226
247
|
# - #^ (aliased as #xor): Returns a new set containing all members from
|
227
|
-
# +self+ and the other
|
248
|
+
# +self+ and the other set except those common to both.
|
228
249
|
# - #~ (aliased as #complement): Returns a new set containing all members
|
229
250
|
# that are not in +self+
|
230
251
|
# - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
|
@@ -233,28 +254,39 @@ module Net
|
|
233
254
|
# === Methods for Assigning
|
234
255
|
# These methods add or replace elements in +self+.
|
235
256
|
#
|
236
|
-
#
|
237
|
-
#
|
257
|
+
# <i>Normalized (sorted and coalesced):</i>
|
258
|
+
#
|
259
|
+
# These methods always update #string to be fully sorted and coalesced.
|
260
|
+
#
|
261
|
+
# - #add (aliased as #<<): Adds a given element to the set; returns +self+.
|
262
|
+
# - #add?: If the given element is not fully included the set, adds it and
|
238
263
|
# returns +self+; otherwise, returns +nil+.
|
239
|
-
# - #merge:
|
240
|
-
# - #
|
264
|
+
# - #merge: Adds all members of the given sets into this 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
|
+
#
|
271
|
+
# - #append: Adds the given entry to the set, appending it to the existing
|
241
272
|
# string, and returns +self+.
|
242
273
|
# - #string=: Assigns a new #string value and replaces #elements to match.
|
243
274
|
# - #replace: Replaces the contents of the set with the contents
|
244
275
|
# of a given object.
|
245
|
-
# - #complement!: Replaces the contents of the set with its own #complement.
|
246
276
|
#
|
247
277
|
# === Methods for Deleting
|
248
|
-
# These methods remove elements from +self
|
278
|
+
# These methods remove elements from +self+, and update #string to be fully
|
279
|
+
# sorted and coalesced.
|
249
280
|
#
|
250
281
|
# - #clear: Removes all elements in the set; returns +self+.
|
251
|
-
# - #delete: Removes a given
|
252
|
-
# - #delete?: If the given
|
282
|
+
# - #delete: Removes a given element from the set; returns +self+.
|
283
|
+
# - #delete?: If the given element is included in the set, removes it and
|
253
284
|
# returns it; otherwise, returns +nil+.
|
254
285
|
# - #delete_at: Removes the number at a given offset.
|
255
286
|
# - #slice!: Removes the number or consecutive numbers at a given offset or
|
256
287
|
# range of offsets.
|
257
|
-
# - #subtract: Removes
|
288
|
+
# - #subtract: Removes all members of the given sets from this set; returns
|
289
|
+
# +self+.
|
258
290
|
# - #limit!: Replaces <tt>*</tt> with a given maximum value and removes all
|
259
291
|
# members over that maximum; returns +self+.
|
260
292
|
#
|
@@ -287,9 +319,12 @@ module Net
|
|
287
319
|
class << self
|
288
320
|
|
289
321
|
# :call-seq:
|
290
|
-
# SequenceSet[*
|
322
|
+
# SequenceSet[*inputs] -> valid frozen sequence set
|
323
|
+
#
|
324
|
+
# Returns a frozen SequenceSet, constructed from +inputs+.
|
291
325
|
#
|
292
|
-
#
|
326
|
+
# When only a single valid frozen SequenceSet is given, that same set is
|
327
|
+
# returned.
|
293
328
|
#
|
294
329
|
# An empty SequenceSet is invalid and will raise a DataFormatError.
|
295
330
|
#
|
@@ -659,7 +694,7 @@ module Net
|
|
659
694
|
alias complement :~
|
660
695
|
|
661
696
|
# :call-seq:
|
662
|
-
# add(
|
697
|
+
# add(element) -> self
|
663
698
|
# self << other -> self
|
664
699
|
#
|
665
700
|
# Adds a range or number to the set and returns +self+.
|
@@ -667,8 +702,8 @@ module Net
|
|
667
702
|
# #string will be regenerated. Use #merge to add many elements at once.
|
668
703
|
#
|
669
704
|
# Related: #add?, #merge, #union
|
670
|
-
def add(
|
671
|
-
tuple_add input_to_tuple
|
705
|
+
def add(element)
|
706
|
+
tuple_add input_to_tuple element
|
672
707
|
normalize!
|
673
708
|
end
|
674
709
|
alias << add
|
@@ -677,28 +712,29 @@ module Net
|
|
677
712
|
#
|
678
713
|
# Unlike #add, #merge, or #union, the new value is appended to #string.
|
679
714
|
# This may result in a #string which has duplicates or is out-of-order.
|
680
|
-
def append(
|
715
|
+
def append(entry)
|
681
716
|
modifying!
|
682
|
-
tuple = input_to_tuple
|
717
|
+
tuple = input_to_tuple entry
|
683
718
|
entry = tuple_to_str tuple
|
719
|
+
string unless empty? # write @string before tuple_add
|
684
720
|
tuple_add tuple
|
685
|
-
@string = -(string ? "#{@string},#{entry}" : entry)
|
721
|
+
@string = -(@string ? "#{@string},#{entry}" : entry)
|
686
722
|
self
|
687
723
|
end
|
688
724
|
|
689
|
-
# :call-seq: add?(
|
725
|
+
# :call-seq: add?(element) -> self or nil
|
690
726
|
#
|
691
727
|
# Adds a range or number to the set and returns +self+. Returns +nil+
|
692
|
-
# when the
|
728
|
+
# when the element is already included in the set.
|
693
729
|
#
|
694
730
|
# #string will be regenerated. Use #merge to add many elements at once.
|
695
731
|
#
|
696
732
|
# Related: #add, #merge, #union, #include?
|
697
|
-
def add?(
|
698
|
-
add
|
733
|
+
def add?(element)
|
734
|
+
add element unless include? element
|
699
735
|
end
|
700
736
|
|
701
|
-
# :call-seq: delete(
|
737
|
+
# :call-seq: delete(element) -> self
|
702
738
|
#
|
703
739
|
# Deletes the given range or number from the set and returns +self+.
|
704
740
|
#
|
@@ -706,8 +742,8 @@ module Net
|
|
706
742
|
# many elements at once.
|
707
743
|
#
|
708
744
|
# Related: #delete?, #delete_at, #subtract, #difference
|
709
|
-
def delete(
|
710
|
-
tuple_subtract input_to_tuple
|
745
|
+
def delete(element)
|
746
|
+
tuple_subtract input_to_tuple element
|
711
747
|
normalize!
|
712
748
|
end
|
713
749
|
|
@@ -743,8 +779,8 @@ module Net
|
|
743
779
|
# #string will be regenerated after deletion.
|
744
780
|
#
|
745
781
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
746
|
-
def delete?(
|
747
|
-
tuple = input_to_tuple
|
782
|
+
def delete?(element)
|
783
|
+
tuple = input_to_tuple element
|
748
784
|
if tuple.first == tuple.last
|
749
785
|
return unless include_tuple? tuple
|
750
786
|
tuple_subtract tuple
|
@@ -788,33 +824,31 @@ module Net
|
|
788
824
|
deleted
|
789
825
|
end
|
790
826
|
|
791
|
-
# Merges all of the elements that appear in any of the +
|
827
|
+
# Merges all of the elements that appear in any of the +sets+ into the
|
792
828
|
# set, and returns +self+.
|
793
829
|
#
|
794
|
-
# The +
|
795
|
-
#
|
796
|
-
#
|
797
|
-
# these.
|
830
|
+
# The +sets+ may be any objects that would be accepted by ::new: non-zero
|
831
|
+
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
832
|
+
# strings, other sequence sets, or enumerables containing any of these.
|
798
833
|
#
|
799
|
-
# #string will be regenerated after all
|
834
|
+
# #string will be regenerated after all sets have been merged.
|
800
835
|
#
|
801
836
|
# Related: #add, #add?, #union
|
802
|
-
def merge(*
|
803
|
-
tuples_add input_to_tuples
|
837
|
+
def merge(*sets)
|
838
|
+
tuples_add input_to_tuples sets
|
804
839
|
normalize!
|
805
840
|
end
|
806
841
|
|
807
|
-
# Removes all of the elements that appear in any of the given +
|
808
|
-
#
|
842
|
+
# Removes all of the elements that appear in any of the given +sets+ from
|
843
|
+
# the set, and returns +self+.
|
809
844
|
#
|
810
|
-
# The +
|
811
|
-
#
|
812
|
-
#
|
813
|
-
# these.
|
845
|
+
# The +sets+ may be any objects that would be accepted by ::new: non-zero
|
846
|
+
# 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
|
847
|
+
# strings, other sequence sets, or enumerables containing any of these.
|
814
848
|
#
|
815
849
|
# Related: #difference
|
816
|
-
def subtract(*
|
817
|
-
tuples_subtract input_to_tuples
|
850
|
+
def subtract(*sets)
|
851
|
+
tuples_subtract input_to_tuples sets
|
818
852
|
normalize!
|
819
853
|
end
|
820
854
|
|
@@ -838,8 +872,8 @@ module Net
|
|
838
872
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
839
873
|
# cases to a maximum value.
|
840
874
|
#
|
841
|
-
#
|
842
|
-
#
|
875
|
+
# The returned elements will be sorted and coalesced, even when the input
|
876
|
+
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
843
877
|
#
|
844
878
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
|
845
879
|
# #=> [2, 5..9, 11..12, :*]
|
@@ -857,7 +891,7 @@ module Net
|
|
857
891
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
858
892
|
# value.
|
859
893
|
#
|
860
|
-
# The returned ranges will be
|
894
|
+
# The returned ranges will be sorted and coalesced, even when the input
|
861
895
|
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
862
896
|
#
|
863
897
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
|
@@ -906,9 +940,7 @@ module Net
|
|
906
940
|
# Related: #entries, #each_element
|
907
941
|
def each_entry(&block) # :yields: integer or range or :*
|
908
942
|
return to_enum(__method__) unless block_given?
|
909
|
-
|
910
|
-
@string.split(",").each do yield tuple_to_entry str_to_tuple _1 end
|
911
|
-
self
|
943
|
+
each_entry_tuple do yield tuple_to_entry _1 end
|
912
944
|
end
|
913
945
|
|
914
946
|
# Yields each number or range (or <tt>:*</tt>) in #elements to the block
|
@@ -926,6 +958,16 @@ module Net
|
|
926
958
|
|
927
959
|
private
|
928
960
|
|
961
|
+
def each_entry_tuple(&block)
|
962
|
+
return to_enum(__method__) unless block_given?
|
963
|
+
if @string
|
964
|
+
@string.split(",") do block.call str_to_tuple _1 end
|
965
|
+
else
|
966
|
+
@tuples.each(&block)
|
967
|
+
end
|
968
|
+
self
|
969
|
+
end
|
970
|
+
|
929
971
|
def tuple_to_entry((min, max))
|
930
972
|
if min == STAR_INT then :*
|
931
973
|
elsif max == STAR_INT then min..
|
@@ -957,19 +999,36 @@ module Net
|
|
957
999
|
# Returns an enumerator when called without a block (even if the set
|
958
1000
|
# contains <tt>*</tt>).
|
959
1001
|
#
|
960
|
-
# Related: #numbers
|
1002
|
+
# Related: #numbers, #each_ordered_number
|
961
1003
|
def each_number(&block) # :yields: integer
|
962
1004
|
return to_enum(__method__) unless block_given?
|
963
1005
|
raise RangeError, '%s contains "*"' % [self.class] if include_star?
|
964
|
-
|
965
|
-
case elem
|
966
|
-
when Range then elem.each(&block)
|
967
|
-
when Integer then block.(elem)
|
968
|
-
end
|
969
|
-
end
|
1006
|
+
@tuples.each do each_number_in_tuple _1, _2, &block end
|
970
1007
|
self
|
971
1008
|
end
|
972
1009
|
|
1010
|
+
# Yields each number in #entries to the block and returns self.
|
1011
|
+
# If the set contains a <tt>*</tt>, RangeError will be raised.
|
1012
|
+
#
|
1013
|
+
# Returns an enumerator when called without a block (even if the set
|
1014
|
+
# contains <tt>*</tt>).
|
1015
|
+
#
|
1016
|
+
# Related: #entries, #each_number
|
1017
|
+
def each_ordered_number(&block)
|
1018
|
+
return to_enum(__method__) unless block_given?
|
1019
|
+
raise RangeError, '%s contains "*"' % [self.class] if include_star?
|
1020
|
+
each_entry_tuple do each_number_in_tuple _1, _2, &block end
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
private def each_number_in_tuple(min, max, &block)
|
1024
|
+
if min == STAR_INT then yield :*
|
1025
|
+
elsif min == max then yield min
|
1026
|
+
elsif max != STAR_INT then (min..max).each(&block)
|
1027
|
+
else
|
1028
|
+
raise RangeError, "#{SequenceSet} cannot enumerate range with '*'"
|
1029
|
+
end
|
1030
|
+
end
|
1031
|
+
|
973
1032
|
# Returns a Set with all of the #numbers in the sequence set.
|
974
1033
|
#
|
975
1034
|
# If the set contains a <tt>*</tt>, RangeError will be raised.
|
@@ -981,8 +1040,10 @@ module Net
|
|
981
1040
|
|
982
1041
|
# Returns the count of #numbers in the set.
|
983
1042
|
#
|
984
|
-
#
|
985
|
-
# integer value)
|
1043
|
+
# <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
|
1044
|
+
# unsigned integer value).
|
1045
|
+
#
|
1046
|
+
# Related: #count_with_duplicates
|
986
1047
|
def count
|
987
1048
|
@tuples.sum(@tuples.count) { _2 - _1 } +
|
988
1049
|
(include_star? && include?(UINT32_MAX) ? -1 : 0)
|
@@ -990,33 +1051,87 @@ module Net
|
|
990
1051
|
|
991
1052
|
alias size count
|
992
1053
|
|
993
|
-
# Returns the
|
994
|
-
#
|
1054
|
+
# Returns the count of numbers in the ordered #entries, including any
|
1055
|
+
# repeated numbers.
|
1056
|
+
#
|
1057
|
+
# <tt>*</tt> will be counted as <tt>2**32 - 1</tt> (the maximum 32-bit
|
1058
|
+
# unsigned integer value).
|
1059
|
+
#
|
1060
|
+
# When #string is normalized, this behaves the same as #count.
|
1061
|
+
#
|
1062
|
+
# Related: #entries, #count_duplicates, #has_duplicates?
|
1063
|
+
def count_with_duplicates
|
1064
|
+
return count unless @string
|
1065
|
+
each_entry_tuple.sum {|min, max|
|
1066
|
+
max - min + ((max == STAR_INT && min != STAR_INT) ? 0 : 1)
|
1067
|
+
}
|
1068
|
+
end
|
1069
|
+
|
1070
|
+
# Returns the count of repeated numbers in the ordered #entries, the
|
1071
|
+
# difference between #count_with_duplicates and #count.
|
995
1072
|
#
|
996
|
-
#
|
1073
|
+
# When #string is normalized, this is zero.
|
1074
|
+
#
|
1075
|
+
# Related: #entries, #count_with_duplicates, #has_duplicates?
|
1076
|
+
def count_duplicates
|
1077
|
+
return 0 unless @string
|
1078
|
+
count_with_duplicates - count
|
1079
|
+
end
|
1080
|
+
|
1081
|
+
# :call-seq: has_duplicates? -> true | false
|
1082
|
+
#
|
1083
|
+
# Returns whether or not the ordered #entries repeat any numbers.
|
1084
|
+
#
|
1085
|
+
# Always returns +false+ when #string is normalized.
|
1086
|
+
#
|
1087
|
+
# Related: #entries, #count_with_duplicates, #count_duplicates?
|
1088
|
+
def has_duplicates?
|
1089
|
+
return false unless @string
|
1090
|
+
count_with_duplicates != count
|
1091
|
+
end
|
1092
|
+
|
1093
|
+
# Returns the (sorted and deduplicated) index of +number+ in the set, or
|
1094
|
+
# +nil+ if +number+ isn't in the set.
|
1095
|
+
#
|
1096
|
+
# Related: #[], #at, #find_ordered_index
|
997
1097
|
def find_index(number)
|
998
1098
|
number = to_tuple_int number
|
999
|
-
each_tuple_with_index do |min, max, idx_min|
|
1099
|
+
each_tuple_with_index(@tuples) do |min, max, idx_min|
|
1000
1100
|
number < min and return nil
|
1001
1101
|
number <= max and return from_tuple_int(idx_min + (number - min))
|
1002
1102
|
end
|
1003
1103
|
nil
|
1004
1104
|
end
|
1005
1105
|
|
1106
|
+
# Returns the first index of +number+ in the ordered #entries, or
|
1107
|
+
# +nil+ if +number+ isn't in the set.
|
1108
|
+
#
|
1109
|
+
# Related: #find_index
|
1110
|
+
def find_ordered_index(number)
|
1111
|
+
number = to_tuple_int number
|
1112
|
+
each_tuple_with_index(each_entry_tuple) do |min, max, idx_min|
|
1113
|
+
if min <= number && number <= max
|
1114
|
+
return from_tuple_int(idx_min + (number - min))
|
1115
|
+
end
|
1116
|
+
end
|
1117
|
+
nil
|
1118
|
+
end
|
1119
|
+
|
1006
1120
|
private
|
1007
1121
|
|
1008
|
-
def each_tuple_with_index
|
1122
|
+
def each_tuple_with_index(tuples)
|
1009
1123
|
idx_min = 0
|
1010
|
-
|
1011
|
-
|
1124
|
+
tuples.each do |min, max|
|
1125
|
+
idx_max = idx_min + (max - min)
|
1126
|
+
yield min, max, idx_min, idx_max
|
1012
1127
|
idx_min = idx_max + 1
|
1013
1128
|
end
|
1014
1129
|
idx_min
|
1015
1130
|
end
|
1016
1131
|
|
1017
|
-
def reverse_each_tuple_with_index
|
1132
|
+
def reverse_each_tuple_with_index(tuples)
|
1018
1133
|
idx_max = -1
|
1019
|
-
|
1134
|
+
tuples.reverse_each do |min, max|
|
1020
1135
|
yield min, max, (idx_min = idx_max - (max - min)), idx_max
|
1021
1136
|
idx_max = idx_min - 1
|
1022
1137
|
end
|
@@ -1027,18 +1142,38 @@ module Net
|
|
1027
1142
|
|
1028
1143
|
# :call-seq: at(index) -> integer or nil
|
1029
1144
|
#
|
1030
|
-
# Returns
|
1031
|
-
#
|
1145
|
+
# Returns the number at the given +index+ in the sorted set, without
|
1146
|
+
# modifying the set.
|
1147
|
+
#
|
1148
|
+
# +index+ is interpreted the same as in #[], except that #at only allows a
|
1149
|
+
# single integer argument.
|
1032
1150
|
#
|
1033
|
-
# Related: #[], #slice
|
1151
|
+
# Related: #[], #slice, #ordered_at
|
1034
1152
|
def at(index)
|
1153
|
+
lookup_number_by_tuple_index(tuples, index)
|
1154
|
+
end
|
1155
|
+
|
1156
|
+
# :call-seq: ordered_at(index) -> integer or nil
|
1157
|
+
#
|
1158
|
+
# Returns the number at the given +index+ in the ordered #entries, without
|
1159
|
+
# modifying the set.
|
1160
|
+
#
|
1161
|
+
# +index+ is interpreted the same as in #at (and #[]), except that
|
1162
|
+
# #ordered_at applies to the ordered #entries, not the sorted set.
|
1163
|
+
#
|
1164
|
+
# Related: #[], #slice, #ordered_at
|
1165
|
+
def ordered_at(index)
|
1166
|
+
lookup_number_by_tuple_index(each_entry_tuple, index)
|
1167
|
+
end
|
1168
|
+
|
1169
|
+
private def lookup_number_by_tuple_index(tuples, index)
|
1035
1170
|
index = Integer(index.to_int)
|
1036
1171
|
if index.negative?
|
1037
|
-
reverse_each_tuple_with_index do |min, max, idx_min, idx_max|
|
1172
|
+
reverse_each_tuple_with_index(tuples) do |min, max, idx_min, idx_max|
|
1038
1173
|
idx_min <= index and return from_tuple_int(min + (index - idx_min))
|
1039
1174
|
end
|
1040
1175
|
else
|
1041
|
-
each_tuple_with_index do |min, _, idx_min, idx_max|
|
1176
|
+
each_tuple_with_index(tuples) do |min, _, idx_min, idx_max|
|
1042
1177
|
index <= idx_max and return from_tuple_int(min + (index - idx_min))
|
1043
1178
|
end
|
1044
1179
|
end
|
@@ -1053,17 +1188,18 @@ module Net
|
|
1053
1188
|
# seqset[range] -> sequence set or nil
|
1054
1189
|
# slice(range) -> sequence set or nil
|
1055
1190
|
#
|
1056
|
-
# Returns a number or a subset from
|
1191
|
+
# Returns a number or a subset from the _sorted_ set, without modifying
|
1192
|
+
# the set.
|
1057
1193
|
#
|
1058
1194
|
# When an Integer argument +index+ is given, the number at offset +index+
|
1059
|
-
# is returned:
|
1195
|
+
# in the sorted set is returned:
|
1060
1196
|
#
|
1061
1197
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1062
1198
|
# set[0] #=> 10
|
1063
1199
|
# set[5] #=> 15
|
1064
1200
|
# set[10] #=> 26
|
1065
1201
|
#
|
1066
|
-
# If +index+ is negative, it counts relative to the end of
|
1202
|
+
# If +index+ is negative, it counts relative to the end of the sorted set:
|
1067
1203
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1068
1204
|
# set[-1] #=> 26
|
1069
1205
|
# set[-3] #=> 22
|
@@ -1075,13 +1211,14 @@ module Net
|
|
1075
1211
|
# set[11] #=> nil
|
1076
1212
|
# set[-12] #=> nil
|
1077
1213
|
#
|
1078
|
-
# The result is based on the
|
1079
|
-
#
|
1214
|
+
# The result is based on the sorted and de-duplicated set, not on the
|
1215
|
+
# ordered #entries in #string.
|
1080
1216
|
#
|
1081
1217
|
# set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
|
1082
1218
|
# set[0] #=> 11
|
1083
1219
|
# set[-1] #=> 23
|
1084
1220
|
#
|
1221
|
+
# Related: #at
|
1085
1222
|
def [](index, length = nil)
|
1086
1223
|
if length then slice_length(index, length)
|
1087
1224
|
elsif index.is_a?(Range) then slice_range(index)
|
@@ -1232,6 +1369,18 @@ module Net
|
|
1232
1369
|
imap.__send__(:put_string, valid_string)
|
1233
1370
|
end
|
1234
1371
|
|
1372
|
+
# For YAML serialization
|
1373
|
+
def encode_with(coder) # :nodoc:
|
1374
|
+
# we can perfectly reconstruct from the string
|
1375
|
+
coder['string'] = to_s
|
1376
|
+
end
|
1377
|
+
|
1378
|
+
# For YAML deserialization
|
1379
|
+
def init_with(coder) # :nodoc:
|
1380
|
+
@tuples = []
|
1381
|
+
self.string = coder['string']
|
1382
|
+
end
|
1383
|
+
|
1235
1384
|
protected
|
1236
1385
|
|
1237
1386
|
attr_reader :tuples # :nodoc:
|
@@ -1251,30 +1400,30 @@ module Net
|
|
1251
1400
|
super
|
1252
1401
|
end
|
1253
1402
|
|
1254
|
-
def input_to_tuple(
|
1255
|
-
|
1256
|
-
case
|
1257
|
-
when *STARS, Integer then [int = to_tuple_int(
|
1258
|
-
when Range then range_to_tuple(
|
1259
|
-
when String then str_to_tuple(
|
1403
|
+
def input_to_tuple(entry)
|
1404
|
+
entry = input_try_convert entry
|
1405
|
+
case entry
|
1406
|
+
when *STARS, Integer then [int = to_tuple_int(entry), int]
|
1407
|
+
when Range then range_to_tuple(entry)
|
1408
|
+
when String then str_to_tuple(entry)
|
1260
1409
|
else
|
1261
|
-
raise DataFormatError, "expected number or range, got %p" % [
|
1410
|
+
raise DataFormatError, "expected number or range, got %p" % [entry]
|
1262
1411
|
end
|
1263
1412
|
end
|
1264
1413
|
|
1265
|
-
def input_to_tuples(
|
1266
|
-
|
1267
|
-
case
|
1268
|
-
when *STARS, Integer, Range then [input_to_tuple(
|
1269
|
-
when String then str_to_tuples
|
1270
|
-
when SequenceSet then
|
1271
|
-
when Set then
|
1272
|
-
when Array then
|
1414
|
+
def input_to_tuples(set)
|
1415
|
+
set = input_try_convert set
|
1416
|
+
case set
|
1417
|
+
when *STARS, Integer, Range then [input_to_tuple(set)]
|
1418
|
+
when String then str_to_tuples set
|
1419
|
+
when SequenceSet then set.tuples
|
1420
|
+
when Set then set.map { [to_tuple_int(_1)] * 2 }
|
1421
|
+
when Array then set.flat_map { input_to_tuples _1 }
|
1273
1422
|
when nil then []
|
1274
1423
|
else
|
1275
1424
|
raise DataFormatError,
|
1276
1425
|
"expected nz-number, range, string, or enumerable; " \
|
1277
|
-
"got %p" % [
|
1426
|
+
"got %p" % [set]
|
1278
1427
|
end
|
1279
1428
|
end
|
1280
1429
|
|
@@ -1337,8 +1486,8 @@ module Net
|
|
1337
1486
|
modifying!
|
1338
1487
|
min, max = tuple
|
1339
1488
|
lower, lower_idx = tuple_gte_with_index(min - 1)
|
1340
|
-
if lower.nil? then tuples <<
|
1341
|
-
elsif (max + 1) < lower.first then tuples.insert(lower_idx,
|
1489
|
+
if lower.nil? then tuples << [min, max]
|
1490
|
+
elsif (max + 1) < lower.first then tuples.insert(lower_idx, [min, max])
|
1342
1491
|
else tuple_coalesce(lower, lower_idx, min, max)
|
1343
1492
|
end
|
1344
1493
|
end
|