net-imap 0.4.12 → 0.4.21
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/command_data.rb +2 -2
- data/lib/net/imap/config/attr_accessors.rb +75 -0
- data/lib/net/imap/config/attr_inheritance.rb +90 -0
- data/lib/net/imap/config/attr_type_coercion.rb +65 -0
- data/lib/net/imap/config.rb +524 -0
- data/lib/net/imap/deprecated_client_options.rb +2 -2
- data/lib/net/imap/errors.rb +33 -0
- data/lib/net/imap/response_data.rb +3 -54
- data/lib/net/imap/response_parser/parser_utils.rb +6 -6
- data/lib/net/imap/response_parser.rb +34 -15
- data/lib/net/imap/response_reader.rb +75 -0
- data/lib/net/imap/sequence_set.rb +274 -123
- data/lib/net/imap/uidplus_data.rb +326 -0
- data/lib/net/imap.rb +297 -86
- data/net-imap.gemspec +2 -2
- metadata +9 -9
- data/.github/dependabot.yml +0 -6
- data/.github/workflows/pages.yml +0 -46
- data/.github/workflows/push_gem.yml +0 -48
- data/.github/workflows/test.yml +0 -31
- data/.gitignore +0 -12
- data/.mailmap +0 -13
@@ -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,16 +327,19 @@ 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
|
#
|
304
339
|
# Use ::new to create a mutable or empty SequenceSet.
|
305
340
|
def [](first, *rest)
|
306
341
|
if rest.empty?
|
307
|
-
if first.is_a?(SequenceSet) &&
|
342
|
+
if first.is_a?(SequenceSet) && first.frozen? && first.valid?
|
308
343
|
first
|
309
344
|
else
|
310
345
|
new(first).validate.freeze
|
@@ -325,7 +360,7 @@ module Net
|
|
325
360
|
# raised.
|
326
361
|
def try_convert(obj)
|
327
362
|
return obj if obj.is_a?(SequenceSet)
|
328
|
-
return nil unless respond_to?(:to_sequence_set)
|
363
|
+
return nil unless obj.respond_to?(:to_sequence_set)
|
329
364
|
obj = obj.to_sequence_set
|
330
365
|
return obj if obj.is_a?(SequenceSet)
|
331
366
|
raise DataFormatError, "invalid object returned from to_sequence_set"
|
@@ -641,7 +676,7 @@ module Net
|
|
641
676
|
#
|
642
677
|
# <tt>(seqset ^ other)</tt> is equivalent to <tt>((seqset | other) -
|
643
678
|
# (seqset & other))</tt>.
|
644
|
-
def ^(other) remain_frozen (
|
679
|
+
def ^(other) remain_frozen (dup | other).subtract(self & other) end
|
645
680
|
alias xor :^
|
646
681
|
|
647
682
|
# :call-seq:
|
@@ -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,27 +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(
|
685
|
-
|
719
|
+
def append(entry)
|
720
|
+
modifying!
|
721
|
+
tuple = input_to_tuple entry
|
686
722
|
entry = tuple_to_str tuple
|
723
|
+
string unless empty? # write @string before tuple_add
|
687
724
|
tuple_add tuple
|
688
|
-
@string = -(string ? "#{@string},#{entry}" : entry)
|
725
|
+
@string = -(@string ? "#{@string},#{entry}" : entry)
|
689
726
|
self
|
690
727
|
end
|
691
728
|
|
692
|
-
# :call-seq: add?(
|
729
|
+
# :call-seq: add?(element) -> self or nil
|
693
730
|
#
|
694
731
|
# Adds a range or number to the set and returns +self+. Returns +nil+
|
695
|
-
# when the
|
732
|
+
# when the element is already included in the set.
|
696
733
|
#
|
697
734
|
# #string will be regenerated. Use #merge to add many elements at once.
|
698
735
|
#
|
699
736
|
# Related: #add, #merge, #union, #include?
|
700
|
-
def add?(
|
701
|
-
add
|
737
|
+
def add?(element)
|
738
|
+
add element unless include? element
|
702
739
|
end
|
703
740
|
|
704
|
-
# :call-seq: delete(
|
741
|
+
# :call-seq: delete(element) -> self
|
705
742
|
#
|
706
743
|
# Deletes the given range or number from the set and returns +self+.
|
707
744
|
#
|
@@ -709,8 +746,8 @@ module Net
|
|
709
746
|
# many elements at once.
|
710
747
|
#
|
711
748
|
# Related: #delete?, #delete_at, #subtract, #difference
|
712
|
-
def delete(
|
713
|
-
tuple_subtract input_to_tuple
|
749
|
+
def delete(element)
|
750
|
+
tuple_subtract input_to_tuple element
|
714
751
|
normalize!
|
715
752
|
end
|
716
753
|
|
@@ -746,8 +783,8 @@ module Net
|
|
746
783
|
# #string will be regenerated after deletion.
|
747
784
|
#
|
748
785
|
# Related: #delete, #delete_at, #subtract, #difference, #disjoint?
|
749
|
-
def delete?(
|
750
|
-
tuple = input_to_tuple
|
786
|
+
def delete?(element)
|
787
|
+
tuple = input_to_tuple element
|
751
788
|
if tuple.first == tuple.last
|
752
789
|
return unless include_tuple? tuple
|
753
790
|
tuple_subtract tuple
|
@@ -791,33 +828,31 @@ module Net
|
|
791
828
|
deleted
|
792
829
|
end
|
793
830
|
|
794
|
-
# 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
|
795
832
|
# set, and returns +self+.
|
796
833
|
#
|
797
|
-
# The +
|
798
|
-
#
|
799
|
-
#
|
800
|
-
# 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.
|
801
837
|
#
|
802
|
-
# #string will be regenerated after all
|
838
|
+
# #string will be regenerated after all sets have been merged.
|
803
839
|
#
|
804
840
|
# Related: #add, #add?, #union
|
805
|
-
def merge(*
|
806
|
-
tuples_add input_to_tuples
|
841
|
+
def merge(*sets)
|
842
|
+
tuples_add input_to_tuples sets
|
807
843
|
normalize!
|
808
844
|
end
|
809
845
|
|
810
|
-
# Removes all of the elements that appear in any of the given +
|
811
|
-
#
|
846
|
+
# Removes all of the elements that appear in any of the given +sets+ from
|
847
|
+
# the set, and returns +self+.
|
812
848
|
#
|
813
|
-
# The +
|
814
|
-
#
|
815
|
-
#
|
816
|
-
# 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.
|
817
852
|
#
|
818
853
|
# Related: #difference
|
819
|
-
def subtract(*
|
820
|
-
tuples_subtract input_to_tuples
|
854
|
+
def subtract(*sets)
|
855
|
+
tuples_subtract input_to_tuples sets
|
821
856
|
normalize!
|
822
857
|
end
|
823
858
|
|
@@ -841,8 +876,8 @@ module Net
|
|
841
876
|
# <tt>*</tt> translates to an endless range. Use #limit to translate both
|
842
877
|
# cases to a maximum value.
|
843
878
|
#
|
844
|
-
#
|
845
|
-
#
|
879
|
+
# The returned elements will be sorted and coalesced, even when the input
|
880
|
+
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
846
881
|
#
|
847
882
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
|
848
883
|
# #=> [2, 5..9, 11..12, :*]
|
@@ -860,7 +895,7 @@ module Net
|
|
860
895
|
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
|
861
896
|
# value.
|
862
897
|
#
|
863
|
-
# The returned ranges will be
|
898
|
+
# The returned ranges will be sorted and coalesced, even when the input
|
864
899
|
# #string is not. <tt>*</tt> will sort last. See #normalize.
|
865
900
|
#
|
866
901
|
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
|
@@ -909,9 +944,7 @@ module Net
|
|
909
944
|
# Related: #entries, #each_element
|
910
945
|
def each_entry(&block) # :yields: integer or range or :*
|
911
946
|
return to_enum(__method__) unless block_given?
|
912
|
-
|
913
|
-
@string.split(",").each do yield tuple_to_entry str_to_tuple _1 end
|
914
|
-
self
|
947
|
+
each_entry_tuple do yield tuple_to_entry _1 end
|
915
948
|
end
|
916
949
|
|
917
950
|
# Yields each number or range (or <tt>:*</tt>) in #elements to the block
|
@@ -929,6 +962,16 @@ module Net
|
|
929
962
|
|
930
963
|
private
|
931
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
|
+
|
932
975
|
def tuple_to_entry((min, max))
|
933
976
|
if min == STAR_INT then :*
|
934
977
|
elsif max == STAR_INT then min..
|
@@ -960,19 +1003,36 @@ module Net
|
|
960
1003
|
# Returns an enumerator when called without a block (even if the set
|
961
1004
|
# contains <tt>*</tt>).
|
962
1005
|
#
|
963
|
-
# Related: #numbers
|
1006
|
+
# Related: #numbers, #each_ordered_number
|
964
1007
|
def each_number(&block) # :yields: integer
|
965
1008
|
return to_enum(__method__) unless block_given?
|
966
1009
|
raise RangeError, '%s contains "*"' % [self.class] if include_star?
|
967
|
-
|
968
|
-
case elem
|
969
|
-
when Range then elem.each(&block)
|
970
|
-
when Integer then block.(elem)
|
971
|
-
end
|
972
|
-
end
|
1010
|
+
@tuples.each do each_number_in_tuple _1, _2, &block end
|
973
1011
|
self
|
974
1012
|
end
|
975
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
|
+
|
976
1036
|
# Returns a Set with all of the #numbers in the sequence set.
|
977
1037
|
#
|
978
1038
|
# If the set contains a <tt>*</tt>, RangeError will be raised.
|
@@ -984,8 +1044,10 @@ module Net
|
|
984
1044
|
|
985
1045
|
# Returns the count of #numbers in the set.
|
986
1046
|
#
|
987
|
-
#
|
988
|
-
# 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
|
989
1051
|
def count
|
990
1052
|
@tuples.sum(@tuples.count) { _2 - _1 } +
|
991
1053
|
(include_star? && include?(UINT32_MAX) ? -1 : 0)
|
@@ -993,33 +1055,87 @@ module Net
|
|
993
1055
|
|
994
1056
|
alias size count
|
995
1057
|
|
996
|
-
# Returns the
|
997
|
-
#
|
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.
|
998
1078
|
#
|
999
|
-
# Related: #
|
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.
|
1099
|
+
#
|
1100
|
+
# Related: #[], #at, #find_ordered_index
|
1000
1101
|
def find_index(number)
|
1001
1102
|
number = to_tuple_int number
|
1002
|
-
each_tuple_with_index do |min, max, idx_min|
|
1103
|
+
each_tuple_with_index(@tuples) do |min, max, idx_min|
|
1003
1104
|
number < min and return nil
|
1004
1105
|
number <= max and return from_tuple_int(idx_min + (number - min))
|
1005
1106
|
end
|
1006
1107
|
nil
|
1007
1108
|
end
|
1008
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
|
+
|
1009
1124
|
private
|
1010
1125
|
|
1011
|
-
def each_tuple_with_index
|
1126
|
+
def each_tuple_with_index(tuples)
|
1012
1127
|
idx_min = 0
|
1013
|
-
|
1014
|
-
|
1128
|
+
tuples.each do |min, max|
|
1129
|
+
idx_max = idx_min + (max - min)
|
1130
|
+
yield min, max, idx_min, idx_max
|
1015
1131
|
idx_min = idx_max + 1
|
1016
1132
|
end
|
1017
1133
|
idx_min
|
1018
1134
|
end
|
1019
1135
|
|
1020
|
-
def reverse_each_tuple_with_index
|
1136
|
+
def reverse_each_tuple_with_index(tuples)
|
1021
1137
|
idx_max = -1
|
1022
|
-
|
1138
|
+
tuples.reverse_each do |min, max|
|
1023
1139
|
yield min, max, (idx_min = idx_max - (max - min)), idx_max
|
1024
1140
|
idx_max = idx_min - 1
|
1025
1141
|
end
|
@@ -1030,18 +1146,38 @@ module Net
|
|
1030
1146
|
|
1031
1147
|
# :call-seq: at(index) -> integer or nil
|
1032
1148
|
#
|
1033
|
-
# Returns
|
1034
|
-
#
|
1149
|
+
# Returns the number at the given +index+ in the sorted set, without
|
1150
|
+
# modifying the set.
|
1151
|
+
#
|
1152
|
+
# +index+ is interpreted the same as in #[], except that #at only allows a
|
1153
|
+
# single integer argument.
|
1035
1154
|
#
|
1036
|
-
# Related: #[], #slice
|
1155
|
+
# Related: #[], #slice, #ordered_at
|
1037
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)
|
1038
1174
|
index = Integer(index.to_int)
|
1039
1175
|
if index.negative?
|
1040
|
-
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|
|
1041
1177
|
idx_min <= index and return from_tuple_int(min + (index - idx_min))
|
1042
1178
|
end
|
1043
1179
|
else
|
1044
|
-
each_tuple_with_index do |min, _, idx_min, idx_max|
|
1180
|
+
each_tuple_with_index(tuples) do |min, _, idx_min, idx_max|
|
1045
1181
|
index <= idx_max and return from_tuple_int(min + (index - idx_min))
|
1046
1182
|
end
|
1047
1183
|
end
|
@@ -1056,17 +1192,18 @@ module Net
|
|
1056
1192
|
# seqset[range] -> sequence set or nil
|
1057
1193
|
# slice(range) -> sequence set or nil
|
1058
1194
|
#
|
1059
|
-
# Returns a number or a subset from
|
1195
|
+
# Returns a number or a subset from the _sorted_ set, without modifying
|
1196
|
+
# the set.
|
1060
1197
|
#
|
1061
1198
|
# When an Integer argument +index+ is given, the number at offset +index+
|
1062
|
-
# is returned:
|
1199
|
+
# in the sorted set is returned:
|
1063
1200
|
#
|
1064
1201
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1065
1202
|
# set[0] #=> 10
|
1066
1203
|
# set[5] #=> 15
|
1067
1204
|
# set[10] #=> 26
|
1068
1205
|
#
|
1069
|
-
# 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:
|
1070
1207
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
1071
1208
|
# set[-1] #=> 26
|
1072
1209
|
# set[-3] #=> 22
|
@@ -1078,13 +1215,14 @@ module Net
|
|
1078
1215
|
# set[11] #=> nil
|
1079
1216
|
# set[-12] #=> nil
|
1080
1217
|
#
|
1081
|
-
# The result is based on the
|
1082
|
-
#
|
1218
|
+
# The result is based on the sorted and de-duplicated set, not on the
|
1219
|
+
# ordered #entries in #string.
|
1083
1220
|
#
|
1084
1221
|
# set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
|
1085
1222
|
# set[0] #=> 11
|
1086
1223
|
# set[-1] #=> 23
|
1087
1224
|
#
|
1225
|
+
# Related: #at
|
1088
1226
|
def [](index, length = nil)
|
1089
1227
|
if length then slice_length(index, length)
|
1090
1228
|
elsif index.is_a?(Range) then slice_range(index)
|
@@ -1107,14 +1245,18 @@ module Net
|
|
1107
1245
|
def slice_range(range)
|
1108
1246
|
first = range.begin || 0
|
1109
1247
|
last = range.end || -1
|
1110
|
-
|
1248
|
+
if range.exclude_end?
|
1249
|
+
return remain_frozen_empty if last.zero?
|
1250
|
+
last -= 1 if range.end && last != STAR_INT
|
1251
|
+
end
|
1111
1252
|
if (first * last).positive? && last < first
|
1112
|
-
|
1253
|
+
remain_frozen_empty
|
1113
1254
|
elsif (min = at(first))
|
1114
1255
|
max = at(last)
|
1256
|
+
max = :* if max.nil?
|
1115
1257
|
if max == :* then self & (min..)
|
1116
1258
|
elsif min <= max then self & (min..max)
|
1117
|
-
else
|
1259
|
+
else remain_frozen_empty
|
1118
1260
|
end
|
1119
1261
|
end
|
1120
1262
|
end
|
@@ -1242,6 +1384,7 @@ module Net
|
|
1242
1384
|
private
|
1243
1385
|
|
1244
1386
|
def remain_frozen(set) frozen? ? set.freeze : set end
|
1387
|
+
def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end
|
1245
1388
|
|
1246
1389
|
# frozen clones are shallow copied
|
1247
1390
|
def initialize_clone(other)
|
@@ -1254,29 +1397,29 @@ module Net
|
|
1254
1397
|
super
|
1255
1398
|
end
|
1256
1399
|
|
1257
|
-
def input_to_tuple(
|
1258
|
-
|
1259
|
-
case
|
1260
|
-
when *STARS, Integer then [int = to_tuple_int(
|
1261
|
-
when Range then range_to_tuple(
|
1262
|
-
when String then str_to_tuple(
|
1400
|
+
def input_to_tuple(entry)
|
1401
|
+
entry = input_try_convert entry
|
1402
|
+
case entry
|
1403
|
+
when *STARS, Integer then [int = to_tuple_int(entry), int]
|
1404
|
+
when Range then range_to_tuple(entry)
|
1405
|
+
when String then str_to_tuple(entry)
|
1263
1406
|
else
|
1264
|
-
raise DataFormatError, "expected number or range, got %p" % [
|
1407
|
+
raise DataFormatError, "expected number or range, got %p" % [entry]
|
1265
1408
|
end
|
1266
1409
|
end
|
1267
1410
|
|
1268
|
-
def input_to_tuples(
|
1269
|
-
|
1270
|
-
case
|
1271
|
-
when *STARS, Integer, Range then [input_to_tuple(
|
1272
|
-
when String then str_to_tuples
|
1273
|
-
when SequenceSet then
|
1274
|
-
when ENUMABLE then
|
1411
|
+
def input_to_tuples(set)
|
1412
|
+
set = input_try_convert set
|
1413
|
+
case set
|
1414
|
+
when *STARS, Integer, Range then [input_to_tuple(set)]
|
1415
|
+
when String then str_to_tuples set
|
1416
|
+
when SequenceSet then set.tuples
|
1417
|
+
when ENUMABLE then set.flat_map { input_to_tuples _1 }
|
1275
1418
|
when nil then []
|
1276
1419
|
else
|
1277
1420
|
raise DataFormatError,
|
1278
1421
|
"expected nz-number, range, string, or enumerable; " \
|
1279
|
-
"got %p" % [
|
1422
|
+
"got %p" % [set]
|
1280
1423
|
end
|
1281
1424
|
end
|
1282
1425
|
|
@@ -1317,6 +1460,12 @@ module Net
|
|
1317
1460
|
range.include?(min) || range.include?(max) || (min..max).cover?(range)
|
1318
1461
|
end
|
1319
1462
|
|
1463
|
+
def modifying!
|
1464
|
+
if frozen?
|
1465
|
+
raise FrozenError, "can't modify frozen #{self.class}: %p" % [self]
|
1466
|
+
end
|
1467
|
+
end
|
1468
|
+
|
1320
1469
|
def tuples_add(tuples) tuples.each do tuple_add _1 end; self end
|
1321
1470
|
def tuples_subtract(tuples) tuples.each do tuple_subtract _1 end; self end
|
1322
1471
|
|
@@ -1331,10 +1480,11 @@ module Net
|
|
1331
1480
|
# ---------??===lower==|--|==|----|===upper===|-- join until upper
|
1332
1481
|
# ---------??===lower==|--|==|--|=====upper===|-- join to upper
|
1333
1482
|
def tuple_add(tuple)
|
1483
|
+
modifying!
|
1334
1484
|
min, max = tuple
|
1335
1485
|
lower, lower_idx = tuple_gte_with_index(min - 1)
|
1336
|
-
if lower.nil? then tuples <<
|
1337
|
-
elsif (max + 1) < lower.first then tuples.insert(lower_idx,
|
1486
|
+
if lower.nil? then tuples << [min, max]
|
1487
|
+
elsif (max + 1) < lower.first then tuples.insert(lower_idx, [min, max])
|
1338
1488
|
else tuple_coalesce(lower, lower_idx, min, max)
|
1339
1489
|
end
|
1340
1490
|
end
|
@@ -1367,6 +1517,7 @@ module Net
|
|
1367
1517
|
# -------??=====lower====|--|====|---|====upper====|-- 7. delete until
|
1368
1518
|
# -------??=====lower====|--|====|--|=====upper====|-- 8. delete and trim
|
1369
1519
|
def tuple_subtract(tuple)
|
1520
|
+
modifying!
|
1370
1521
|
min, max = tuple
|
1371
1522
|
lower, idx = tuple_gte_with_index(min)
|
1372
1523
|
if lower.nil? then nil # case 1.
|