net-imap 0.5.6 → 0.5.8

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.
@@ -108,11 +108,15 @@ module Net
108
108
  # When a set includes <tt>*</tt>, some methods may have surprising behavior.
109
109
  #
110
110
  # For example, #complement treats <tt>*</tt> as its own number. This way,
111
- # the #intersection of a set and its #complement will always be empty.
112
- # This is not how an \IMAP server interprets the set: it will convert
113
- # <tt>*</tt> to either the number of messages in the mailbox or +UIDNEXT+,
114
- # as appropriate. And there _will_ be overlap between a set and its
115
- # complement after #limit is applied to each:
111
+ # the #intersection of a set and its #complement will always be empty. And
112
+ # <tt>*</tt> is sorted as greater than any other number in the set. This is
113
+ # not how an \IMAP server interprets the set: it will convert <tt>*</tt> to
114
+ # the number of messages in the mailbox, the +UID+ of the last message in
115
+ # the mailbox, or +UIDNEXT+, as appropriate. Several methods have an
116
+ # argument for how <tt>*</tt> should be interpreted.
117
+ #
118
+ # But, for example, this means that there may be overlap between a set and
119
+ # its complement after #limit is applied to each:
116
120
  #
117
121
  # ~Net::IMAP::SequenceSet["*"] == Net::IMAP::SequenceSet[1..(2**32-1)]
118
122
  # ~Net::IMAP::SequenceSet[1..5] == Net::IMAP::SequenceSet["6:*"]
@@ -174,14 +178,14 @@ module Net
174
178
  #
175
179
  # <i>Set membership:</i>
176
180
  # - #include? (aliased as #member?):
177
- # 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
178
182
  # contained by the set.
179
183
  # - #include_star?: Returns whether the set contains <tt>*</tt>.
180
184
  #
181
185
  # <i>Minimum and maximum value elements:</i>
182
- # - #min: Returns the minimum number in the set.
183
- # - #max: Returns the maximum number in the set.
184
- # - #minmax: Returns the minimum and maximum numbers in the set.
186
+ # - #min: Returns one or more of the lowest numbers in the set.
187
+ # - #max: Returns one or more of the highest numbers in the set.
188
+ # - #minmax: Returns the lowest and highest numbers in the set.
185
189
  #
186
190
  # <i>Accessing value by offset in sorted set:</i>
187
191
  # - #[] (aliased as #slice): Returns the number or consecutive subset at a
@@ -239,15 +243,19 @@ module Net
239
243
  # These methods do not modify +self+.
240
244
  #
241
245
  # - #| (aliased as #union and #+): Returns a new set combining all members
242
- # from +self+ with all members from the other object.
246
+ # from +self+ with all members from the other set.
243
247
  # - #& (aliased as #intersection): Returns a new set containing all members
244
- # common to +self+ and the other object.
248
+ # common to +self+ and the other set.
245
249
  # - #- (aliased as #difference): Returns a copy of +self+ with all members
246
- # in the other object removed.
250
+ # in the other set removed.
247
251
  # - #^ (aliased as #xor): Returns a new set containing all members from
248
- # +self+ and the other object except those common to both.
252
+ # +self+ and the other set except those common to both.
249
253
  # - #~ (aliased as #complement): Returns a new set containing all members
250
254
  # that are not in +self+
255
+ # - #above: Return a copy of +self+ which only contains numbers above a
256
+ # given number.
257
+ # - #below: Return a copy of +self+ which only contains numbers below a
258
+ # given value.
251
259
  # - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
252
260
  # given maximum value and removed all members over that maximum.
253
261
  #
@@ -258,17 +266,17 @@ module Net
258
266
  #
259
267
  # These methods always update #string to be fully sorted and coalesced.
260
268
  #
261
- # - #add (aliased as #<<): Adds a given object to the set; returns +self+.
262
- # - #add?: If the given object is not an element in the set, adds it and
269
+ # - #add (aliased as #<<): Adds a given element to the set; returns +self+.
270
+ # - #add?: If the given element is not fully included the set, adds it and
263
271
  # returns +self+; otherwise, returns +nil+.
264
- # - #merge: Merges multiple elements into the set; returns +self+.
272
+ # - #merge: Adds all members of the given sets into this set; returns +self+.
265
273
  # - #complement!: Replaces the contents of the set with its own #complement.
266
274
  #
267
275
  # <i>Order preserving:</i>
268
276
  #
269
277
  # These methods _may_ cause #string to not be sorted or coalesced.
270
278
  #
271
- # - #append: Adds a given object to the set, appending it to the existing
279
+ # - #append: Adds the given entry to the set, appending it to the existing
272
280
  # string, and returns +self+.
273
281
  # - #string=: Assigns a new #string value and replaces #elements to match.
274
282
  # - #replace: Replaces the contents of the set with the contents
@@ -279,13 +287,14 @@ module Net
279
287
  # sorted and coalesced.
280
288
  #
281
289
  # - #clear: Removes all elements in the set; returns +self+.
282
- # - #delete: Removes a given object from the set; returns +self+.
283
- # - #delete?: If the given object is an element in the set, removes it and
290
+ # - #delete: Removes a given element from the set; returns +self+.
291
+ # - #delete?: If the given element is included in the set, removes it and
284
292
  # returns it; otherwise, returns +nil+.
285
293
  # - #delete_at: Removes the number at a given offset.
286
294
  # - #slice!: Removes the number or consecutive numbers at a given offset or
287
295
  # range of offsets.
288
- # - #subtract: Removes each given object from the set; returns +self+.
296
+ # - #subtract: Removes all members of the given sets from this set; returns
297
+ # +self+.
289
298
  # - #limit!: Replaces <tt>*</tt> with a given maximum value and removes all
290
299
  # members over that maximum; returns +self+.
291
300
  #
@@ -318,9 +327,12 @@ module Net
318
327
  class << self
319
328
 
320
329
  # :call-seq:
321
- # SequenceSet[*values] -> valid frozen sequence set
330
+ # SequenceSet[*inputs] -> valid frozen sequence set
331
+ #
332
+ # Returns a frozen SequenceSet, constructed from +inputs+.
322
333
  #
323
- # Returns a frozen SequenceSet, constructed from +values+.
334
+ # When only a single valid frozen SequenceSet is given, that same set is
335
+ # returned.
324
336
  #
325
337
  # An empty SequenceSet is invalid and will raise a DataFormatError.
326
338
  #
@@ -563,26 +575,52 @@ module Net
563
575
  empty? || input_to_tuples(other).none? { intersect_tuple? _1 }
564
576
  end
565
577
 
566
- # :call-seq: max(star: :*) => integer or star or nil
578
+ # :call-seq:
579
+ # max(star: :*) => integer or star or nil
580
+ # max(count, star: :*) => SequenceSet
567
581
  #
568
582
  # Returns the maximum value in +self+, +star+ when the set includes
569
583
  # <tt>*</tt>, or +nil+ when the set is empty.
570
- def max(star: :*)
571
- (val = @tuples.last&.last) && val == STAR_INT ? star : val
584
+ #
585
+ # When +count+ is given, a new SequenceSet is returned, containing only
586
+ # the last +count+ numbers. An empty SequenceSet is returned when +self+
587
+ # is empty. (+star+ is ignored when +count+ is given.)
588
+ #
589
+ # Related: #min, #minmax, #slice
590
+ def max(count = nil, star: :*)
591
+ if count
592
+ slice(-[count, size].min..) || remain_frozen_empty
593
+ elsif (val = @tuples.last&.last)
594
+ val == STAR_INT ? star : val
595
+ end
572
596
  end
573
597
 
574
- # :call-seq: min(star: :*) => integer or star or nil
598
+ # :call-seq:
599
+ # min(star: :*) => integer or star or nil
600
+ # min(count, star: :*) => SequenceSet
575
601
  #
576
602
  # Returns the minimum value in +self+, +star+ when the only value in the
577
603
  # set is <tt>*</tt>, or +nil+ when the set is empty.
578
- def min(star: :*)
579
- (val = @tuples.first&.first) && val == STAR_INT ? star : val
604
+ #
605
+ # When +count+ is given, a new SequenceSet is returned, containing only
606
+ # the first +count+ numbers. An empty SequenceSet is returned when +self+
607
+ # is empty. (+star+ is ignored when +count+ is given.)
608
+ #
609
+ # Related: #max, #minmax, #slice
610
+ def min(count = nil, star: :*)
611
+ if count
612
+ slice(0...count) || remain_frozen_empty
613
+ elsif (val = @tuples.first&.first)
614
+ val != STAR_INT ? val : star
615
+ end
580
616
  end
581
617
 
582
618
  # :call-seq: minmax(star: :*) => nil or [integer, integer or star]
583
619
  #
584
620
  # Returns a 2-element array containing the minimum and maximum numbers in
585
621
  # +self+, or +nil+ when the set is empty.
622
+ #
623
+ # Related: #min, #max
586
624
  def minmax(star: :*); [min(star: star), max(star: star)] unless empty? end
587
625
 
588
626
  # Returns false when the set is empty.
@@ -609,7 +647,14 @@ module Net
609
647
  # Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99]
610
648
  # #=> Net::IMAP::SequenceSet["1:6,99"]
611
649
  #
612
- # Related: #add, #merge
650
+ # Related: #add, #merge, #&, #-, #^, #~
651
+ #
652
+ # ==== Set identities
653
+ #
654
+ # <tt>lhs | rhs</tt> is equivalent to:
655
+ # * <tt>rhs | lhs</tt> (commutative)
656
+ # * <tt>~(~lhs & ~rhs)</tt> (De Morgan's Law)
657
+ # * <tt>(lhs & rhs) ^ (lhs ^ rhs)</tt>
613
658
  def |(other) remain_frozen dup.merge other end
614
659
  alias :+ :|
615
660
  alias union :|
@@ -628,7 +673,17 @@ module Net
628
673
  # Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6
629
674
  # #=> Net::IMAP::SequenceSet["1,3,5"]
630
675
  #
631
- # Related: #subtract
676
+ # Related: #subtract, #|, #&, #^, #~
677
+ #
678
+ # ==== Set identities
679
+ #
680
+ # <tt>lhs - rhs</tt> is equivalent to:
681
+ # * <tt>~r - ~l</tt>
682
+ # * <tt>lhs & ~rhs</tt>
683
+ # * <tt>~(~lhs | rhs)</tt>
684
+ # * <tt>lhs & (lhs ^ rhs)</tt>
685
+ # * <tt>lhs ^ (lhs & rhs)</tt>
686
+ # * <tt>rhs ^ (lhs | rhs)</tt>
632
687
  def -(other) remain_frozen dup.subtract other end
633
688
  alias difference :-
634
689
 
@@ -646,7 +701,17 @@ module Net
646
701
  # Net::IMAP::SequenceSet[1..5] & [2, 4, 6]
647
702
  # #=> Net::IMAP::SequenceSet["2,4"]
648
703
  #
649
- # <tt>(seqset & other)</tt> is equivalent to <tt>(seqset - ~other)</tt>.
704
+ # Related: #intersect?, #|, #-, #^, #~
705
+ #
706
+ # ==== Set identities
707
+ #
708
+ # <tt>lhs & rhs</tt> is equivalent to:
709
+ # * <tt>rhs & lhs</tt> (commutative)
710
+ # * <tt>~(~lhs | ~rhs)</tt> (De Morgan's Law)
711
+ # * <tt>lhs - ~rhs</tt>
712
+ # * <tt>lhs - (lhs - rhs)</tt>
713
+ # * <tt>lhs - (lhs ^ rhs)</tt>
714
+ # * <tt>lhs ^ (lhs - rhs)</tt>
650
715
  def &(other)
651
716
  remain_frozen dup.subtract SequenceSet.new(other).complement!
652
717
  end
@@ -666,9 +731,17 @@ module Net
666
731
  # Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6]
667
732
  # #=> Net::IMAP::SequenceSet["1,3,5:6"]
668
733
  #
669
- # <tt>(seqset ^ other)</tt> is equivalent to <tt>((seqset | other) -
670
- # (seqset & other))</tt>.
671
- def ^(other) remain_frozen (self | other).subtract(self & other) end
734
+ # Related: #|, #&, #-, #~
735
+ #
736
+ # ==== Set identities
737
+ #
738
+ # <tt>lhs ^ rhs</tt> is equivalent to:
739
+ # * <tt>rhs ^ lhs</tt> (commutative)
740
+ # * <tt>~lhs ^ ~rhs</tt>
741
+ # * <tt>(lhs | rhs) - (lhs & rhs)</tt>
742
+ # * <tt>(lhs - rhs) | (rhs - lhs)</tt>
743
+ # * <tt>(lhs ^ other) ^ (other ^ rhs)</tt>
744
+ def ^(other) remain_frozen (dup | other).subtract(self & other) end
672
745
  alias xor :^
673
746
 
674
747
  # :call-seq:
@@ -685,21 +758,29 @@ module Net
685
758
  # ~Net::IMAP::SequenceSet["6:99,223:*"]
686
759
  # #=> Net::IMAP::SequenceSet["1:5,100:222"]
687
760
  #
688
- # Related: #complement!
761
+ # Related: #complement!, #|, #&, #-, #^
762
+ #
763
+ # ==== Set identities
764
+ #
765
+ # <tt>~set</tt> is equivalent to:
766
+ # * <tt>full - set</tt>, where "full" is Net::IMAP::SequenceSet.full
689
767
  def ~; remain_frozen dup.complement! end
690
768
  alias complement :~
691
769
 
692
770
  # :call-seq:
693
- # add(object) -> self
771
+ # add(element) -> self
694
772
  # self << other -> self
695
773
  #
696
774
  # Adds a range or number to the set and returns +self+.
697
775
  #
698
776
  # #string will be regenerated. Use #merge to add many elements at once.
699
777
  #
700
- # Related: #add?, #merge, #union
701
- def add(object)
702
- tuple_add input_to_tuple object
778
+ # Use #append to append new elements to #string. See
779
+ # Net::IMAP@Ordered+and+Normalized+Sets.
780
+ #
781
+ # Related: #add?, #merge, #union, #append
782
+ def add(element)
783
+ tuple_add input_to_tuple element
703
784
  normalize!
704
785
  end
705
786
  alias << add
@@ -708,9 +789,13 @@ module Net
708
789
  #
709
790
  # Unlike #add, #merge, or #union, the new value is appended to #string.
710
791
  # This may result in a #string which has duplicates or is out-of-order.
711
- def append(object)
792
+ #
793
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
794
+ #
795
+ # Related: #add, #merge, #union
796
+ def append(entry)
712
797
  modifying!
713
- tuple = input_to_tuple object
798
+ tuple = input_to_tuple entry
714
799
  entry = tuple_to_str tuple
715
800
  string unless empty? # write @string before tuple_add
716
801
  tuple_add tuple
@@ -718,19 +803,19 @@ module Net
718
803
  self
719
804
  end
720
805
 
721
- # :call-seq: add?(object) -> self or nil
806
+ # :call-seq: add?(element) -> self or nil
722
807
  #
723
808
  # Adds a range or number to the set and returns +self+. Returns +nil+
724
- # when the object is already included in the set.
809
+ # when the element is already included in the set.
725
810
  #
726
811
  # #string will be regenerated. Use #merge to add many elements at once.
727
812
  #
728
813
  # Related: #add, #merge, #union, #include?
729
- def add?(object)
730
- add object unless include? object
814
+ def add?(element)
815
+ add element unless include? element
731
816
  end
732
817
 
733
- # :call-seq: delete(object) -> self
818
+ # :call-seq: delete(element) -> self
734
819
  #
735
820
  # Deletes the given range or number from the set and returns +self+.
736
821
  #
@@ -738,8 +823,8 @@ module Net
738
823
  # many elements at once.
739
824
  #
740
825
  # Related: #delete?, #delete_at, #subtract, #difference
741
- def delete(object)
742
- tuple_subtract input_to_tuple object
826
+ def delete(element)
827
+ tuple_subtract input_to_tuple element
743
828
  normalize!
744
829
  end
745
830
 
@@ -775,8 +860,8 @@ module Net
775
860
  # #string will be regenerated after deletion.
776
861
  #
777
862
  # Related: #delete, #delete_at, #subtract, #difference, #disjoint?
778
- def delete?(object)
779
- tuple = input_to_tuple object
863
+ def delete?(element)
864
+ tuple = input_to_tuple element
780
865
  if tuple.first == tuple.last
781
866
  return unless include_tuple? tuple
782
867
  tuple_subtract tuple
@@ -820,33 +905,31 @@ module Net
820
905
  deleted
821
906
  end
822
907
 
823
- # Merges all of the elements that appear in any of the +inputs+ into the
908
+ # Merges all of the elements that appear in any of the +sets+ into the
824
909
  # set, and returns +self+.
825
910
  #
826
- # The +inputs+ may be any objects that would be accepted by ::new:
827
- # non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
828
- # formatted strings, other sequence sets, or enumerables containing any of
829
- # these.
911
+ # The +sets+ may be any objects that would be accepted by ::new: non-zero
912
+ # 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
913
+ # strings, other sequence sets, or enumerables containing any of these.
830
914
  #
831
- # #string will be regenerated after all inputs have been merged.
915
+ # #string will be regenerated after all sets have been merged.
832
916
  #
833
917
  # Related: #add, #add?, #union
834
- def merge(*inputs)
835
- tuples_add input_to_tuples inputs
918
+ def merge(*sets)
919
+ tuples_add input_to_tuples sets
836
920
  normalize!
837
921
  end
838
922
 
839
- # Removes all of the elements that appear in any of the given +objects+
840
- # from the set, and returns +self+.
923
+ # Removes all of the elements that appear in any of the given +sets+ from
924
+ # the set, and returns +self+.
841
925
  #
842
- # The +objects+ may be any objects that would be accepted by ::new:
843
- # non-zero 32 bit unsigned integers, ranges, <tt>sequence-set</tt>
844
- # formatted strings, other sequence sets, or enumerables containing any of
845
- # these.
926
+ # The +sets+ may be any objects that would be accepted by ::new: non-zero
927
+ # 32 bit unsigned integers, ranges, <tt>sequence-set</tt> formatted
928
+ # strings, other sequence sets, or enumerables containing any of these.
846
929
  #
847
930
  # Related: #difference
848
- def subtract(*objects)
849
- tuples_subtract input_to_tuples objects
931
+ def subtract(*sets)
932
+ tuples_subtract input_to_tuples sets
850
933
  normalize!
851
934
  end
852
935
 
@@ -858,21 +941,21 @@ module Net
858
941
  # This is useful when the given order is significant, for example in a
859
942
  # ESEARCH response to IMAP#sort.
860
943
  #
944
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
945
+ #
861
946
  # Related: #each_entry, #elements
862
947
  def entries; each_entry.to_a end
863
948
 
864
949
  # Returns an array of ranges and integers and <tt>:*</tt>.
865
950
  #
866
951
  # The returned elements are sorted and coalesced, even when the input
867
- # #string is not. <tt>*</tt> will sort last. See #normalize.
952
+ # #string is not. <tt>*</tt> will sort last. See #normalize,
953
+ # Net::IMAP@Ordered+and+Normalized+Sets.
868
954
  #
869
955
  # By itself, <tt>*</tt> translates to <tt>:*</tt>. A range containing
870
956
  # <tt>*</tt> translates to an endless range. Use #limit to translate both
871
957
  # cases to a maximum value.
872
958
  #
873
- # The returned elements will be sorted and coalesced, even when the input
874
- # #string is not. <tt>*</tt> will sort last. See #normalize.
875
- #
876
959
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
877
960
  # #=> [2, 5..9, 11..12, :*]
878
961
  #
@@ -883,15 +966,13 @@ module Net
883
966
  # Returns an array of ranges
884
967
  #
885
968
  # The returned elements are sorted and coalesced, even when the input
886
- # #string is not. <tt>*</tt> will sort last. See #normalize.
969
+ # #string is not. <tt>*</tt> will sort last. See #normalize,
970
+ # Net::IMAP@Ordered+and+Normalized+Sets.
887
971
  #
888
972
  # <tt>*</tt> translates to an endless range. By itself, <tt>*</tt>
889
973
  # translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum
890
974
  # value.
891
975
  #
892
- # The returned ranges will be sorted and coalesced, even when the input
893
- # #string is not. <tt>*</tt> will sort last. See #normalize.
894
- #
895
976
  # Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
896
977
  # #=> [2..2, 5..9, 11..12, :*..]
897
978
  # Net::IMAP::SequenceSet["123,999:*,456:789"].ranges
@@ -903,7 +984,7 @@ module Net
903
984
  # Returns a sorted array of all of the number values in the sequence set.
904
985
  #
905
986
  # The returned numbers are sorted and de-duplicated, even when the input
906
- # #string is not. See #normalize.
987
+ # #string is not. See #normalize, Net::IMAP@Ordered+and+Normalized+Sets.
907
988
  #
908
989
  # Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers
909
990
  # #=> [2, 5, 6, 7, 8, 9, 11, 12]
@@ -935,6 +1016,8 @@ module Net
935
1016
  # no sorting, deduplication, or coalescing. When #string is in its
936
1017
  # normalized form, this will yield the same values as #each_element.
937
1018
  #
1019
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
1020
+ #
938
1021
  # Related: #entries, #each_element
939
1022
  def each_entry(&block) # :yields: integer or range or :*
940
1023
  return to_enum(__method__) unless block_given?
@@ -945,7 +1028,7 @@ module Net
945
1028
  # and returns self. Returns an enumerator when called without a block.
946
1029
  #
947
1030
  # The returned numbers are sorted and de-duplicated, even when the input
948
- # #string is not. See #normalize.
1031
+ # #string is not. See #normalize, Net::IMAP@Ordered+and+Normalized+Sets.
949
1032
  #
950
1033
  # Related: #elements, #each_entry
951
1034
  def each_element # :yields: integer or range or :*
@@ -1239,20 +1322,76 @@ module Net
1239
1322
  def slice_range(range)
1240
1323
  first = range.begin || 0
1241
1324
  last = range.end || -1
1242
- last -= 1 if range.exclude_end? && range.end && last != STAR_INT
1325
+ if range.exclude_end?
1326
+ return remain_frozen_empty if last.zero?
1327
+ last -= 1 if range.end && last != STAR_INT
1328
+ end
1243
1329
  if (first * last).positive? && last < first
1244
- SequenceSet.empty
1330
+ remain_frozen_empty
1245
1331
  elsif (min = at(first))
1246
1332
  max = at(last)
1333
+ max = :* if max.nil?
1247
1334
  if max == :* then self & (min..)
1248
1335
  elsif min <= max then self & (min..max)
1249
- else SequenceSet.empty
1336
+ else remain_frozen_empty
1250
1337
  end
1251
1338
  end
1252
1339
  end
1253
1340
 
1254
1341
  public
1255
1342
 
1343
+ # Returns a copy of +self+ which only contains the numbers above +num+.
1344
+ #
1345
+ # Net::IMAP::SequenceSet["5,10:22,50"].above(10) # to_s => "11:22,50"
1346
+ # Net::IMAP::SequenceSet["5,10:22,50"].above(20) # to_s => "21:22,50
1347
+ # Net::IMAP::SequenceSet["5,10:22,50"].above(30) # to_s => "50"
1348
+ #
1349
+ # This returns the same result as #intersection with <tt>((num+1)..)</tt>
1350
+ # or #difference with <tt>(..num)</tt>.
1351
+ #
1352
+ # Net::IMAP::SequenceSet["5,10:22,50"] & (11..) # to_s => "11:22,50"
1353
+ # Net::IMAP::SequenceSet["5,10:22,50"] - (..10) # to_s => "11:22,50"
1354
+ # Net::IMAP::SequenceSet["5,10:22,50"] & (21..) # to_s => "21:22,50"
1355
+ # Net::IMAP::SequenceSet["5,10:22,50"] - (..20) # to_s => "21:22,50"
1356
+ #
1357
+ # Related: #above, #-, #&
1358
+ def above(num)
1359
+ NumValidator.valid_nz_number?(num) or
1360
+ raise ArgumentError, "not a valid sequence set number"
1361
+ difference(..num)
1362
+ end
1363
+
1364
+ # Returns a copy of +self+ which only contains numbers below +num+.
1365
+ #
1366
+ # Net::IMAP::SequenceSet["5,10:22,50"].below(10) # to_s => "5"
1367
+ # Net::IMAP::SequenceSet["5,10:22,50"].below(20) # to_s => "5,10:19"
1368
+ # Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
1369
+ #
1370
+ # This returns the same result as #intersection with <tt>(..(num-1))</tt>
1371
+ # or #difference with <tt>(num..)</tt>.
1372
+ #
1373
+ # Net::IMAP::SequenceSet["5,10:22,50"] & (..9) # to_s => "5"
1374
+ # Net::IMAP::SequenceSet["5,10:22,50"] - (10..) # to_s => "5"
1375
+ # Net::IMAP::SequenceSet["5,10:22,50"] & (..19) # to_s => "5,10:19"
1376
+ # Net::IMAP::SequenceSet["5,10:22,50"] - (20..) # to_s => "5,10:19"
1377
+ #
1378
+ # When the set does not contain <tt>*</tt>, #below is identical to #limit
1379
+ # with <tt>max: num - 1</tt>. When the set does contain <tt>*</tt>,
1380
+ # #below always drops it from the result. Use #limit when the IMAP
1381
+ # semantics for <tt>*</tt> must be enforced.
1382
+ #
1383
+ # Net::IMAP::SequenceSet["5,10:22,50"].below(30) # to_s => "5,10:22"
1384
+ # Net::IMAP::SequenceSet["5,10:22,50"].limit(max: 29) # to_s => "5,10:22"
1385
+ # Net::IMAP::SequenceSet["5,10:22,*"].below(30) # to_s => "5,10:22"
1386
+ # Net::IMAP::SequenceSet["5,10:22,*"].limit(max: 29) # to_s => "5,10:22,29"
1387
+ #
1388
+ # Related: #above, #-, #&, #limit
1389
+ def below(num)
1390
+ NumValidator.valid_nz_number?(num) or
1391
+ raise ArgumentError, "not a valid sequence set number"
1392
+ difference(num..)
1393
+ end
1394
+
1256
1395
  # Returns a frozen SequenceSet with <tt>*</tt> converted to +max+, numbers
1257
1396
  # and ranges over +max+ removed, and ranges containing +max+ converted to
1258
1397
  # end at +max+.
@@ -1270,6 +1409,7 @@ module Net
1270
1409
  # Net::IMAP::SequenceSet["500:*"].limit(max: 37)
1271
1410
  # #=> Net::IMAP::SequenceSet["37"]
1272
1411
  #
1412
+ # Related: #limit!
1273
1413
  def limit(max:)
1274
1414
  max = to_tuple_int(max)
1275
1415
  if empty? then self.class.empty
@@ -1311,6 +1451,7 @@ module Net
1311
1451
  #
1312
1452
  # The returned set's #string is sorted and deduplicated. Adjacent or
1313
1453
  # overlapping elements will be merged into a single larger range.
1454
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
1314
1455
  #
1315
1456
  # Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize
1316
1457
  # #=> Net::IMAP::SequenceSet["1:7,9:11"]
@@ -1323,7 +1464,7 @@ module Net
1323
1464
  end
1324
1465
 
1325
1466
  # Resets #string to be sorted, deduplicated, and coalesced. Returns
1326
- # +self+.
1467
+ # +self+. See Net::IMAP@Ordered+and+Normalized+Sets.
1327
1468
  #
1328
1469
  # Related: #normalize, #normalized_string
1329
1470
  def normalize!
@@ -1333,11 +1474,13 @@ module Net
1333
1474
 
1334
1475
  # Returns a normalized +sequence-set+ string representation, sorted
1335
1476
  # and deduplicated. Adjacent or overlapping elements will be merged into
1336
- # a single larger range. Returns +nil+ when the set is empty.
1477
+ # a single larger range. See Net::IMAP@Ordered+and+Normalized+Sets.
1337
1478
  #
1338
1479
  # Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string
1339
1480
  # #=> "1:7,9:11"
1340
1481
  #
1482
+ # Returns +nil+ when the set is empty.
1483
+ #
1341
1484
  # Related: #normalize!, #normalize
1342
1485
  def normalized_string
1343
1486
  @tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",")
@@ -1367,6 +1510,18 @@ module Net
1367
1510
  imap.__send__(:put_string, valid_string)
1368
1511
  end
1369
1512
 
1513
+ # For YAML serialization
1514
+ def encode_with(coder) # :nodoc:
1515
+ # we can perfectly reconstruct from the string
1516
+ coder['string'] = to_s
1517
+ end
1518
+
1519
+ # For YAML deserialization
1520
+ def init_with(coder) # :nodoc:
1521
+ @tuples = []
1522
+ self.string = coder['string']
1523
+ end
1524
+
1370
1525
  protected
1371
1526
 
1372
1527
  attr_reader :tuples # :nodoc:
@@ -1374,6 +1529,7 @@ module Net
1374
1529
  private
1375
1530
 
1376
1531
  def remain_frozen(set) frozen? ? set.freeze : set end
1532
+ def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end
1377
1533
 
1378
1534
  # frozen clones are shallow copied
1379
1535
  def initialize_clone(other)
@@ -1386,30 +1542,30 @@ module Net
1386
1542
  super
1387
1543
  end
1388
1544
 
1389
- def input_to_tuple(obj)
1390
- obj = input_try_convert obj
1391
- case obj
1392
- when *STARS, Integer then [int = to_tuple_int(obj), int]
1393
- when Range then range_to_tuple(obj)
1394
- when String then str_to_tuple(obj)
1545
+ def input_to_tuple(entry)
1546
+ entry = input_try_convert entry
1547
+ case entry
1548
+ when *STARS, Integer then [int = to_tuple_int(entry), int]
1549
+ when Range then range_to_tuple(entry)
1550
+ when String then str_to_tuple(entry)
1395
1551
  else
1396
- raise DataFormatError, "expected number or range, got %p" % [obj]
1552
+ raise DataFormatError, "expected number or range, got %p" % [entry]
1397
1553
  end
1398
1554
  end
1399
1555
 
1400
- def input_to_tuples(obj)
1401
- obj = input_try_convert obj
1402
- case obj
1403
- when *STARS, Integer, Range then [input_to_tuple(obj)]
1404
- when String then str_to_tuples obj
1405
- when SequenceSet then obj.tuples
1406
- when Set then obj.map { [to_tuple_int(_1)] * 2 }
1407
- when Array then obj.flat_map { input_to_tuples _1 }
1556
+ def input_to_tuples(set)
1557
+ set = input_try_convert set
1558
+ case set
1559
+ when *STARS, Integer, Range then [input_to_tuple(set)]
1560
+ when String then str_to_tuples set
1561
+ when SequenceSet then set.tuples
1562
+ when Set then set.map { [to_tuple_int(_1)] * 2 }
1563
+ when Array then set.flat_map { input_to_tuples _1 }
1408
1564
  when nil then []
1409
1565
  else
1410
1566
  raise DataFormatError,
1411
1567
  "expected nz-number, range, string, or enumerable; " \
1412
- "got %p" % [obj]
1568
+ "got %p" % [set]
1413
1569
  end
1414
1570
  end
1415
1571