net-imap 0.6.6 → 0.6.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.
- checksums.yaml +4 -4
- data/.simplecov +0 -2
- data/Gemfile +3 -3
- data/README.md +50 -24
- data/Rakefile +54 -4
- data/lib/net/imap/command_data.rb +13 -10
- data/lib/net/imap/config/attr_accessors.rb +2 -2
- data/lib/net/imap/config/attr_type_coercion.rb +14 -26
- data/lib/net/imap/config.rb +63 -3
- data/lib/net/imap/esearch_result.rb +2 -2
- data/lib/net/imap/fetch_data.rb +5 -5
- data/lib/net/imap/response_data.rb +79 -79
- data/lib/net/imap/response_parser/parser_utils.rb +1 -1
- data/lib/net/imap/response_parser.rb +2 -1
- data/lib/net/imap/sasl/client_adapter.rb +6 -6
- data/lib/net/imap/search_result.rb +4 -6
- data/lib/net/imap/sequence_set.rb +413 -52
- data/lib/net/imap/utils.rb +49 -0
- data/lib/net/imap.rb +195 -46
- data/rakelib/rdoc.rake +24 -0
- metadata +3 -2
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
require "set" unless defined?(::Set)
|
|
4
4
|
|
|
5
|
+
require_relative "utils"
|
|
6
|
+
|
|
5
7
|
module Net
|
|
6
8
|
class IMAP
|
|
7
9
|
|
|
@@ -256,6 +258,20 @@ module Net
|
|
|
256
258
|
# - #disjoint?:
|
|
257
259
|
# Returns whether +self+ and a given object have no common elements.
|
|
258
260
|
#
|
|
261
|
+
# <i>Comparison to a number:</i>
|
|
262
|
+
# - #all_above?:
|
|
263
|
+
# Returns whether every number in +self+ is greater than a given number.
|
|
264
|
+
# - #all_below?:
|
|
265
|
+
# Returns whether every number in +self+ is less than a given number.
|
|
266
|
+
# - #any_above?:
|
|
267
|
+
# Returns whether +self+ contains any numbers greater than a given number.
|
|
268
|
+
# - #any_below?:
|
|
269
|
+
# Returns whether +self+ contains any numbers less than a given number.
|
|
270
|
+
# - #none_above?:
|
|
271
|
+
# Returns whether +self+ contains no numbers greater than a given number.
|
|
272
|
+
# - #none_below?:
|
|
273
|
+
# Returns whether +self+ contains no numbers less than a given number.
|
|
274
|
+
#
|
|
259
275
|
# === Methods for Querying
|
|
260
276
|
# These methods do not modify +self+.
|
|
261
277
|
#
|
|
@@ -345,7 +361,7 @@ module Net
|
|
|
345
361
|
# - #above: Return a copy of +self+ which only contains numbers above a
|
|
346
362
|
# given number.
|
|
347
363
|
# - #below: Return a copy of +self+ which only contains numbers below a
|
|
348
|
-
# given
|
|
364
|
+
# given number.
|
|
349
365
|
# - #limit: Returns a copy of +self+ which has replaced <tt>*</tt> with a
|
|
350
366
|
# given maximum value and removed all members over that maximum.
|
|
351
367
|
#
|
|
@@ -409,6 +425,8 @@ module Net
|
|
|
409
425
|
# representation and returns +self+.
|
|
410
426
|
#
|
|
411
427
|
class SequenceSet
|
|
428
|
+
include Utils # :nodoc:
|
|
429
|
+
|
|
412
430
|
# The largest possible non-zero unsigned 32-bit integer
|
|
413
431
|
UINT32_MAX = 2**32 - 1
|
|
414
432
|
|
|
@@ -774,6 +792,225 @@ module Net
|
|
|
774
792
|
empty? || import_runs(other).none? { intersect_run? _1 }
|
|
775
793
|
end
|
|
776
794
|
|
|
795
|
+
# :call-seq:
|
|
796
|
+
# all_above?(number) -> true or false
|
|
797
|
+
#
|
|
798
|
+
# Returns whether the set only contains numbers greater than +number+ (not
|
|
799
|
+
# inclusive of +number+).
|
|
800
|
+
#
|
|
801
|
+
# Net::IMAP::SequenceSet["5:8"].all_above?(9) => true
|
|
802
|
+
# Net::IMAP::SequenceSet["5:8"].all_above?(7) => false
|
|
803
|
+
# Net::IMAP::SequenceSet["5:8"].all_above?(5) => false
|
|
804
|
+
#
|
|
805
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
806
|
+
# Net::IMAP::SequenceSet["*"].all_above?(UINT32_MAX - 1) => true
|
|
807
|
+
# Net::IMAP::SequenceSet["*"].all_above?(UINT32_MAX) => false
|
|
808
|
+
#
|
|
809
|
+
# This is roughly equivalent to several other comparisons:
|
|
810
|
+
#
|
|
811
|
+
# # Given the following assumptions:
|
|
812
|
+
# set.empty? => false
|
|
813
|
+
# set.include_star? => false
|
|
814
|
+
# number => ^(1...UINT32_MAX)
|
|
815
|
+
#
|
|
816
|
+
# # Then these expressions will always return the same result:
|
|
817
|
+
# set.all_above?(number) => result
|
|
818
|
+
# set.none_below?(number + 1) => ^result
|
|
819
|
+
# !set.any_below?(number + 1) => ^result
|
|
820
|
+
#
|
|
821
|
+
# set == set.above(number) => ^result
|
|
822
|
+
# set.disjoint?(..number) => ^result
|
|
823
|
+
# number < set.min => ^result
|
|
824
|
+
#
|
|
825
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
826
|
+
# #above
|
|
827
|
+
def all_above?(number)
|
|
828
|
+
number = nz_number(number)
|
|
829
|
+
empty? || number < min(star: UINT32_MAX)
|
|
830
|
+
end
|
|
831
|
+
|
|
832
|
+
# :call-seq:
|
|
833
|
+
# all_below?(number) -> true or false
|
|
834
|
+
#
|
|
835
|
+
# Returns whether the set only contains numbers less than +number+ (not
|
|
836
|
+
# inclusive of +number+).
|
|
837
|
+
#
|
|
838
|
+
# Net::IMAP::SequenceSet["5:8"].all_below?(9) => true
|
|
839
|
+
# Net::IMAP::SequenceSet["5:8"].all_below?(8) => false
|
|
840
|
+
# Net::IMAP::SequenceSet["5:8"].all_below?(5) => false
|
|
841
|
+
#
|
|
842
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
843
|
+
# Net::IMAP::SequenceSet["*"].all_below?(UINT32_MAX) => false
|
|
844
|
+
#
|
|
845
|
+
# This is roughly equivalent to several other comparisons:
|
|
846
|
+
#
|
|
847
|
+
# # Given the following assumptions:
|
|
848
|
+
# set.empty? => false
|
|
849
|
+
# set.include_star? => false
|
|
850
|
+
# number => ^(2..UINT32_MAX)
|
|
851
|
+
#
|
|
852
|
+
# # Then these expressions will always return the same result:
|
|
853
|
+
# set.all_below?(number) => result
|
|
854
|
+
# set.none_above?(number - 1) => ^result
|
|
855
|
+
# !set.any_above?(number - 1) => ^result
|
|
856
|
+
#
|
|
857
|
+
# set == set.below(number) => ^result
|
|
858
|
+
# set.disjoint?(number..) => ^result
|
|
859
|
+
# set.max < number => ^result
|
|
860
|
+
#
|
|
861
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
862
|
+
# #below
|
|
863
|
+
def all_below?(number)
|
|
864
|
+
number = nz_number(number)
|
|
865
|
+
empty? || max(star: UINT32_MAX) < number
|
|
866
|
+
end
|
|
867
|
+
|
|
868
|
+
# :call-seq:
|
|
869
|
+
# any_above?(number) -> true or false
|
|
870
|
+
#
|
|
871
|
+
# Returns whether the set contains any numbers greater than +number+ (not
|
|
872
|
+
# inclusive of +number+).
|
|
873
|
+
#
|
|
874
|
+
# Net::IMAP::SequenceSet["5:8"].any_above?(1) => true
|
|
875
|
+
# Net::IMAP::SequenceSet["5:8"].any_above?(7) => true
|
|
876
|
+
# Net::IMAP::SequenceSet["5:8"].any_above?(8) => false
|
|
877
|
+
#
|
|
878
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
879
|
+
# Net::IMAP::SequenceSet["1:*"].any_above?(UINT32_MAX - 1) => true
|
|
880
|
+
# Net::IMAP::SequenceSet["1:*"].any_above?(UINT32_MAX) => false
|
|
881
|
+
#
|
|
882
|
+
# This is roughly equivalent to several other comparisons:
|
|
883
|
+
#
|
|
884
|
+
# # Given the following assumptions:
|
|
885
|
+
# set.empty? => false
|
|
886
|
+
# set.include_star? => false
|
|
887
|
+
# number => ^(1...UINT32_MAX)
|
|
888
|
+
#
|
|
889
|
+
# # Then these expressions will always return the same result:
|
|
890
|
+
# set.any_above?(number) => result
|
|
891
|
+
# !set.none_above?(number) => ^result
|
|
892
|
+
# !set.all_below?(number + 1) => ^result
|
|
893
|
+
#
|
|
894
|
+
# set.cover?(set.above(number)) => ^result
|
|
895
|
+
# set.intersect?(number + 1..) => ^result
|
|
896
|
+
# number < set.max => ^result
|
|
897
|
+
#
|
|
898
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
899
|
+
# #above
|
|
900
|
+
def any_above?(number)
|
|
901
|
+
number = nz_number(number)
|
|
902
|
+
valid? && number < max(star: UINT32_MAX)
|
|
903
|
+
end
|
|
904
|
+
|
|
905
|
+
# :call-seq:
|
|
906
|
+
# any_below?(number) -> true or false
|
|
907
|
+
#
|
|
908
|
+
# Returns whether the set contains any numbers less than +number+ (not
|
|
909
|
+
# inclusive of +number+).
|
|
910
|
+
#
|
|
911
|
+
# Net::IMAP::SequenceSet["5:8"].any_below? 5 => false
|
|
912
|
+
# Net::IMAP::SequenceSet["5:8"].any_below? 6 => true
|
|
913
|
+
# Net::IMAP::SequenceSet["5:8"].any_below? 9 => true
|
|
914
|
+
#
|
|
915
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
916
|
+
# Net::IMAP::SequenceSet["*"].any_below?(UINT32_MAX) => false
|
|
917
|
+
#
|
|
918
|
+
# This is roughly equivalent to several other comparisons:
|
|
919
|
+
#
|
|
920
|
+
# # Given the following assumptions:
|
|
921
|
+
# set.empty? => false
|
|
922
|
+
# set.include_star? => false
|
|
923
|
+
# number => ^(2..UINT32_MAX)
|
|
924
|
+
#
|
|
925
|
+
# # Then these expressions will always return the same result:
|
|
926
|
+
# set.any_below?(number) => result
|
|
927
|
+
# !set.none_below?(number) => ^result
|
|
928
|
+
# !set.all_above?(number - 1) => ^result
|
|
929
|
+
#
|
|
930
|
+
# set.cover?(set.below(number)) => ^result
|
|
931
|
+
# set.intersect?(...number) => ^result
|
|
932
|
+
# set.min < number => ^result
|
|
933
|
+
#
|
|
934
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
935
|
+
# #below
|
|
936
|
+
def any_below?(number)
|
|
937
|
+
number = nz_number(number)
|
|
938
|
+
valid? && min(star: UINT32_MAX) < number
|
|
939
|
+
end
|
|
940
|
+
|
|
941
|
+
# :call-seq:
|
|
942
|
+
# none_above?(number) -> true or false
|
|
943
|
+
#
|
|
944
|
+
# Returns whether the set contains no numbers greater than +number+ (not
|
|
945
|
+
# inclusive of +number+).
|
|
946
|
+
#
|
|
947
|
+
# Net::IMAP::SequenceSet["5:8"].none_above?(9) => true
|
|
948
|
+
# Net::IMAP::SequenceSet["5:8"].none_above?(8) => true
|
|
949
|
+
# Net::IMAP::SequenceSet["5:8"].none_above?(7) => false
|
|
950
|
+
#
|
|
951
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
952
|
+
# Net::IMAP::SequenceSet["*"].none_above?(UINT32_MAX - 1) => false
|
|
953
|
+
# Net::IMAP::SequenceSet["*"].none_above?(UINT32_MAX) => true
|
|
954
|
+
#
|
|
955
|
+
# This is roughly equivalent to several other comparisons:
|
|
956
|
+
#
|
|
957
|
+
# # Given the following assumptions:
|
|
958
|
+
# set.empty? => false
|
|
959
|
+
# set.include_star? => false
|
|
960
|
+
# number => ^(1...UINT32_MAX)
|
|
961
|
+
#
|
|
962
|
+
# # Then these expressions will always return the same result:
|
|
963
|
+
# set.none_above?(number) => result
|
|
964
|
+
# !set.any_above?(number) => ^result
|
|
965
|
+
# set.all_below?(number + 1) => ^result
|
|
966
|
+
#
|
|
967
|
+
# set.above(number).empty? => ^result
|
|
968
|
+
# set.disjoint?(number..) => ^result
|
|
969
|
+
# set.max <= number => ^result
|
|
970
|
+
#
|
|
971
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
972
|
+
# #above
|
|
973
|
+
def none_above?(number)
|
|
974
|
+
number = nz_number(number)
|
|
975
|
+
empty? || max(star: UINT32_MAX) <= number
|
|
976
|
+
end
|
|
977
|
+
|
|
978
|
+
# :call-seq:
|
|
979
|
+
# none_below?(number) -> true or false
|
|
980
|
+
#
|
|
981
|
+
# Returns whether the set contains no numbers less than +number+ (not
|
|
982
|
+
# inclusive of +number+).
|
|
983
|
+
#
|
|
984
|
+
# Net::IMAP::SequenceSet["5:8"].none_below?(4) => true
|
|
985
|
+
# Net::IMAP::SequenceSet["5:8"].none_below?(5) => true
|
|
986
|
+
# Net::IMAP::SequenceSet["5:8"].none_below?(6) => false
|
|
987
|
+
#
|
|
988
|
+
# <tt>"*"</tt> is evaluated as +UINT32_MAX+:
|
|
989
|
+
# Net::IMAP::SequenceSet["*"].none_below?(UINT32_MAX) => true
|
|
990
|
+
#
|
|
991
|
+
# This is roughly equivalent to several other comparisons:
|
|
992
|
+
#
|
|
993
|
+
# # Given the following assumptions:
|
|
994
|
+
# set.empty? => false
|
|
995
|
+
# set.include_star? => false
|
|
996
|
+
# number => ^(2..UINT32_MAX)
|
|
997
|
+
#
|
|
998
|
+
# # Then these expressions will always return the same result:
|
|
999
|
+
# set.none_below?(number) => result
|
|
1000
|
+
# !set.any_below?(number) => ^result
|
|
1001
|
+
# set.all_above?(number - 1) => ^result
|
|
1002
|
+
#
|
|
1003
|
+
# set.above(number).empty? => ^result
|
|
1004
|
+
# set.disjoint?(...number) => ^result
|
|
1005
|
+
# number <= set.min => ^result
|
|
1006
|
+
#
|
|
1007
|
+
# Related: {other comparison methods}[rdoc-ref:SequenceSet@Methods+for+Comparing],
|
|
1008
|
+
# #below
|
|
1009
|
+
def none_below?(number)
|
|
1010
|
+
number = nz_number(number)
|
|
1011
|
+
empty? || number <= min(star: UINT32_MAX)
|
|
1012
|
+
end
|
|
1013
|
+
|
|
777
1014
|
# :call-seq:
|
|
778
1015
|
# max(star: :*) => integer or star or nil
|
|
779
1016
|
# max(count) => SequenceSet
|
|
@@ -786,8 +1023,11 @@ module Net
|
|
|
786
1023
|
# is empty. (+star+ is ignored when +count+ is given.)
|
|
787
1024
|
#
|
|
788
1025
|
# Related: #min, #minmax, #slice
|
|
789
|
-
def max(count = nil, star: :*)
|
|
790
|
-
if
|
|
1026
|
+
def max(count = (unset_count = true; nil), star: :*)
|
|
1027
|
+
if !unset_count
|
|
1028
|
+
count = implicit_int(count)
|
|
1029
|
+
raise ArgumentError, 'negative count' if count < 0
|
|
1030
|
+
return remain_frozen_empty if count == 0
|
|
791
1031
|
if cardinality <= count
|
|
792
1032
|
frozen? ? self : dup
|
|
793
1033
|
else
|
|
@@ -810,8 +1050,10 @@ module Net
|
|
|
810
1050
|
# is empty. (+star+ is ignored when +count+ is given.)
|
|
811
1051
|
#
|
|
812
1052
|
# Related: #max, #minmax, #slice
|
|
813
|
-
def min(count = nil, star: :*)
|
|
814
|
-
if
|
|
1053
|
+
def min(count = (unset_count = true; nil), star: :*)
|
|
1054
|
+
if !unset_count
|
|
1055
|
+
count = implicit_int(count)
|
|
1056
|
+
raise ArgumentError, 'negative count' if count < 0
|
|
815
1057
|
slice(0...count) || remain_frozen_empty
|
|
816
1058
|
elsif (val = min_num)
|
|
817
1059
|
val != STAR_INT ? val : star
|
|
@@ -1122,7 +1364,7 @@ module Net
|
|
|
1122
1364
|
#
|
|
1123
1365
|
# Related: #delete, #delete?, #slice!, #subtract, #difference
|
|
1124
1366
|
def delete_at(index)
|
|
1125
|
-
slice!
|
|
1367
|
+
slice! implicit_int index
|
|
1126
1368
|
end
|
|
1127
1369
|
|
|
1128
1370
|
# :call-seq:
|
|
@@ -1138,9 +1380,10 @@ module Net
|
|
|
1138
1380
|
# #string will be regenerated after deletion.
|
|
1139
1381
|
#
|
|
1140
1382
|
# Related: #slice, #delete_at, #delete, #delete?, #subtract, #difference
|
|
1141
|
-
def slice!(index, length = nil)
|
|
1383
|
+
def slice!(index, length = (length_unset = true; nil))
|
|
1142
1384
|
modifying! # short-circuit before slice
|
|
1143
|
-
deleted = slice(index, length)
|
|
1385
|
+
deleted = length_unset ? slice(index) : slice(index, length)
|
|
1386
|
+
subtract deleted if deleted
|
|
1144
1387
|
deleted
|
|
1145
1388
|
end
|
|
1146
1389
|
|
|
@@ -1453,7 +1696,7 @@ module Net
|
|
|
1453
1696
|
number = import_num number
|
|
1454
1697
|
each_minmax_with_index(minmaxes) do |min, max, idx_min|
|
|
1455
1698
|
number < min and return nil
|
|
1456
|
-
number <= max and return
|
|
1699
|
+
number <= max and return idx_min + (number - min)
|
|
1457
1700
|
end
|
|
1458
1701
|
nil
|
|
1459
1702
|
end
|
|
@@ -1466,7 +1709,7 @@ module Net
|
|
|
1466
1709
|
number = import_num number
|
|
1467
1710
|
each_minmax_with_index(each_entry_minmax) do |min, max, idx_min|
|
|
1468
1711
|
if min <= number && number <= max
|
|
1469
|
-
return
|
|
1712
|
+
return idx_min + (number - min)
|
|
1470
1713
|
end
|
|
1471
1714
|
end
|
|
1472
1715
|
nil
|
|
@@ -1482,7 +1725,7 @@ module Net
|
|
|
1482
1725
|
#
|
|
1483
1726
|
# Related: #[], #slice, #ordered_at
|
|
1484
1727
|
def at(index)
|
|
1485
|
-
|
|
1728
|
+
export_num sorted_set_num_at implicit_int index
|
|
1486
1729
|
end
|
|
1487
1730
|
|
|
1488
1731
|
# :call-seq: ordered_at(index) -> integer or nil
|
|
@@ -1495,22 +1738,55 @@ module Net
|
|
|
1495
1738
|
#
|
|
1496
1739
|
# Related: #[], #slice, #ordered_at
|
|
1497
1740
|
def ordered_at(index)
|
|
1498
|
-
|
|
1741
|
+
export_num ordered_list_num_at implicit_int index
|
|
1499
1742
|
end
|
|
1500
1743
|
|
|
1501
1744
|
# :call-seq:
|
|
1502
1745
|
# seqset[index] -> integer or :* or nil
|
|
1503
1746
|
# slice(index) -> integer or :* or nil
|
|
1504
|
-
# seqset[
|
|
1505
|
-
# slice(
|
|
1747
|
+
# seqset[index, length] -> sequence set or nil
|
|
1748
|
+
# slice(index, length) -> sequence set or nil
|
|
1506
1749
|
# seqset[range] -> sequence set or nil
|
|
1507
1750
|
# slice(range) -> sequence set or nil
|
|
1508
1751
|
#
|
|
1509
1752
|
# Returns a number or a subset from the _sorted_ set, without modifying
|
|
1510
1753
|
# the set.
|
|
1511
1754
|
#
|
|
1755
|
+
# With a single +index+ argument, returns an integer or +:*+ or nil:
|
|
1756
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1757
|
+
# set[0] #=> 10
|
|
1758
|
+
# set[-1] #=> 26
|
|
1759
|
+
#
|
|
1760
|
+
# With +index+ and +length+ arguments, returns a new SequenceSet or nil:
|
|
1761
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1762
|
+
# set[1, 2] #=> Net::IMAP::SequenceSet["11:12"]
|
|
1763
|
+
# set[-2, 2] #=> Net::IMAP::SequenceSet["23,26"]
|
|
1764
|
+
#
|
|
1765
|
+
# With a single +range+ argument, returns a new SequenceSet or nil:
|
|
1766
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1767
|
+
# set[0...2] #=> Net::IMAP::SequenceSet["10:11"]
|
|
1768
|
+
# set[0..2] #=> Net::IMAP::SequenceSet["11:12"]
|
|
1769
|
+
# set[0..-2] #=> Net::IMAP::SequenceSet["10:15,20:23"]
|
|
1770
|
+
# set[-6..6] #=> Net::IMAP::SequenceSet["15,20"]
|
|
1771
|
+
#
|
|
1772
|
+
# Note that the result is based on the sorted and de-duplicated set, not
|
|
1773
|
+
# on the ordered #entries in #string.
|
|
1774
|
+
#
|
|
1775
|
+
# set = Net::IMAP::SequenceSet["12,20:23,11:16,21"]
|
|
1776
|
+
# set[0] #=> 11
|
|
1777
|
+
# set[-1] #=> 23
|
|
1778
|
+
#
|
|
1779
|
+
# This behaves like <tt>Array#slice</tt> on a virtual array of all of the
|
|
1780
|
+
# monotonically sorted #numbers in +self+:
|
|
1781
|
+
# # WARNING: For illustration only. Do NOT do this with large sets.
|
|
1782
|
+
# sliced_array = seqset.numbers[*args] and
|
|
1783
|
+
# sliced_set = Net::IMAP::SequenceSet(sliced_array)
|
|
1784
|
+
# set.slice(*args) == sliced_set #=> true
|
|
1785
|
+
#
|
|
1786
|
+
# ==== Number lookup by index
|
|
1787
|
+
#
|
|
1512
1788
|
# When an Integer argument +index+ is given, the number at offset +index+
|
|
1513
|
-
# in the sorted set is returned
|
|
1789
|
+
# in the sorted set is returned.
|
|
1514
1790
|
#
|
|
1515
1791
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1516
1792
|
# set[0] #=> 10
|
|
@@ -1521,24 +1797,86 @@ module Net
|
|
|
1521
1797
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1522
1798
|
# set[-1] #=> 26
|
|
1523
1799
|
# set[-3] #=> 22
|
|
1524
|
-
# set[-
|
|
1525
|
-
#
|
|
1526
|
-
# If +index+ is out of range, +nil+ is returned.
|
|
1800
|
+
# set[-11] #=> 10
|
|
1527
1801
|
#
|
|
1802
|
+
# The range for +index+ is <tt>-cardinality...cardinality</tt>.
|
|
1803
|
+
# If +index+ is out of range, returns +nil+.
|
|
1528
1804
|
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1529
1805
|
# set[11] #=> nil
|
|
1530
1806
|
# set[-12] #=> nil
|
|
1531
1807
|
#
|
|
1532
|
-
#
|
|
1533
|
-
# ordered #entries in #string.
|
|
1808
|
+
# With a single Integer argument, this behaves identically to #at.
|
|
1534
1809
|
#
|
|
1535
|
-
#
|
|
1536
|
-
#
|
|
1537
|
-
#
|
|
1810
|
+
# ==== Subset slice by index and length
|
|
1811
|
+
#
|
|
1812
|
+
# When two Integer arguments, +index+ and +length+ are given, returns a
|
|
1813
|
+
# new SequenceSet containing the +length+ successive numbers beginning at
|
|
1814
|
+
# offset +index+.:
|
|
1815
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1816
|
+
# set[0, 2] #=> Net::IMAP::SequenceSet["10:11"]
|
|
1817
|
+
# set[1, 2] #=> Net::IMAP::SequenceSet["11:12"]
|
|
1818
|
+
#
|
|
1819
|
+
# If <tt>index + length</tt> is greater than #cardinality, returns all
|
|
1820
|
+
# elements from +index+ to the end:
|
|
1821
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1822
|
+
# set[0, 15] #=> Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1823
|
+
# set[5, 10] #=> Net::IMAP::SequenceSet["15,20:23,26"]
|
|
1824
|
+
# set[10, 5] #=> Net::IMAP::SequenceSet["26"]
|
|
1825
|
+
#
|
|
1826
|
+
# If +index+ is equal to #cardinality, returns a new empty SequenceSet.
|
|
1827
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1828
|
+
# set[11, 5] #=> Net::IMAP::SequenceSet.empty
|
|
1829
|
+
#
|
|
1830
|
+
# If +length+ is negative, returns +nil+.
|
|
1831
|
+
# set = Net::IMAP::SequenceSet[1..10]
|
|
1832
|
+
# set[5, -1] #=> nil
|
|
1833
|
+
#
|
|
1834
|
+
# If +index+ is out of range (absolute value greater than #cardinality),
|
|
1835
|
+
# returns +nil+.
|
|
1836
|
+
#
|
|
1837
|
+
# If +index+ is in range and +length+ is zero, returns a new empty
|
|
1838
|
+
# SequenceSet.
|
|
1839
|
+
#
|
|
1840
|
+
# ==== Subset slice by index range
|
|
1841
|
+
#
|
|
1842
|
+
# When a single Range argument +range+ is given, returns a new SequenceSet
|
|
1843
|
+
# containing the successive numbers at the offsets indicated by +range+.
|
|
1844
|
+
#
|
|
1845
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1846
|
+
# set[0...2] #=> Net::IMAP::SequenceSet["10:11"]
|
|
1847
|
+
# set[2..4] #=> Net::IMAP::SequenceSet["12:14"]
|
|
1848
|
+
#
|
|
1849
|
+
# set[-2..-1] #=> Net::IMAP::SequenceSet["23,26"]
|
|
1850
|
+
# set[-4...-2] #=> Net::IMAP::SequenceSet["21:22"]
|
|
1851
|
+
#
|
|
1852
|
+
# set[4..-4] #=> Net::IMAP::SequenceSet["14:15,20:21"]
|
|
1853
|
+
# set[-6...6] #=> Net::IMAP::SequenceSet["15"]
|
|
1538
1854
|
#
|
|
1539
|
-
#
|
|
1540
|
-
|
|
1541
|
-
|
|
1855
|
+
# An end-less range slices until the last number, and a begin-less range
|
|
1856
|
+
# slices from the first number.
|
|
1857
|
+
# set = Net::IMAP::SequenceSet["10:15,20:23,26"]
|
|
1858
|
+
# set[..3] #=> Net::IMAP::SequenceSet["10:13"]
|
|
1859
|
+
# set[..-3] #=> Net::IMAP::SequenceSet["10:15,20:22"]
|
|
1860
|
+
# set[-2..] #=> Net::IMAP::SequenceSet["23,26"]
|
|
1861
|
+
# set[2..] #=> Net::IMAP::SequenceSet["12:15,20:23,26"]
|
|
1862
|
+
#
|
|
1863
|
+
# When +range.begin+ points to a smaller index than +range.end+, a new
|
|
1864
|
+
# empty SequenceSet is returned.
|
|
1865
|
+
#
|
|
1866
|
+
# set = Net::IMAP::SequenceSet[1..10]
|
|
1867
|
+
# set[5.. 4] #=> SequenceSet.empty
|
|
1868
|
+
# set[-4..-5] #=> SequenceSet.empty
|
|
1869
|
+
# set[5..-6] #=> SequenceSet.empty
|
|
1870
|
+
#
|
|
1871
|
+
# If +range.begin+ is out of range (absolute value greater than
|
|
1872
|
+
# #cardinality), returns +nil+.
|
|
1873
|
+
#
|
|
1874
|
+
# This behaves similarly to a slice with +range.begin+ as +index+ and
|
|
1875
|
+
# +range.size+ as +length+, when that both sides of the range are either
|
|
1876
|
+
# negative or non-negative. Note that the minimum +range.size+ is zero,
|
|
1877
|
+
# so this can't return +nil+ for a negative range length.
|
|
1878
|
+
def [](index, length = (length_unset = true; nil))
|
|
1879
|
+
if !length_unset then slice_length(index, length)
|
|
1542
1880
|
elsif index.is_a?(Range) then slice_range(index)
|
|
1543
1881
|
else at(index)
|
|
1544
1882
|
end
|
|
@@ -1560,7 +1898,9 @@ module Net
|
|
|
1560
1898
|
# Net::IMAP::SequenceSet["5,10:22,50"] & (21..) # to_s => "21:22,50"
|
|
1561
1899
|
# Net::IMAP::SequenceSet["5,10:22,50"] - (..20) # to_s => "21:22,50"
|
|
1562
1900
|
#
|
|
1563
|
-
# Related: #
|
|
1901
|
+
# Related: #below,
|
|
1902
|
+
# {other set operations}[rdoc-ref:SequenceSet@Methods+for+Set+Operations],
|
|
1903
|
+
# #all_above?, #any_above?, #none_above?
|
|
1564
1904
|
def above(num)
|
|
1565
1905
|
NumValidator.valid_nz_number?(num) or
|
|
1566
1906
|
raise ArgumentError, "not a valid sequence set number"
|
|
@@ -1591,7 +1931,9 @@ module Net
|
|
|
1591
1931
|
# Net::IMAP::SequenceSet["5,10:22,*"].below(30) # to_s => "5,10:22"
|
|
1592
1932
|
# Net::IMAP::SequenceSet["5,10:22,*"].limit(max: 29) # to_s => "5,10:22,29"
|
|
1593
1933
|
#
|
|
1594
|
-
# Related: #above,
|
|
1934
|
+
# Related: #above,
|
|
1935
|
+
# {other set operations}[rdoc-ref:SequenceSet@Methods+for+Set+Operations],
|
|
1936
|
+
# #all_below?, #any_below?, #none_below?
|
|
1595
1937
|
def below(num)
|
|
1596
1938
|
NumValidator.valid_nz_number?(num) or
|
|
1597
1939
|
raise ArgumentError, "not a valid sequence set number"
|
|
@@ -1869,8 +2211,9 @@ module Net
|
|
|
1869
2211
|
def remain_frozen_empty; frozen? ? SequenceSet.empty : SequenceSet.new end
|
|
1870
2212
|
|
|
1871
2213
|
# frozen clones are shallow copied
|
|
1872
|
-
def initialize_clone(other)
|
|
1873
|
-
@set_data = other.dup_set_data unless other.frozen?
|
|
2214
|
+
def initialize_clone(other, freeze: nil)
|
|
2215
|
+
@set_data = other.dup_set_data unless other.frozen? && freeze != false
|
|
2216
|
+
freeze_set_data if freeze
|
|
1874
2217
|
super
|
|
1875
2218
|
end
|
|
1876
2219
|
|
|
@@ -1922,7 +2265,7 @@ module Net
|
|
|
1922
2265
|
def number_input?(input)
|
|
1923
2266
|
case input
|
|
1924
2267
|
when *STARS, Integer then true
|
|
1925
|
-
when String then !input.
|
|
2268
|
+
when String then !input.match?(/[:,]/)
|
|
1926
2269
|
end
|
|
1927
2270
|
end
|
|
1928
2271
|
|
|
@@ -2039,15 +2382,22 @@ module Net
|
|
|
2039
2382
|
######################################################################{{{2
|
|
2040
2383
|
# Number indexing methods
|
|
2041
2384
|
|
|
2385
|
+
def sorted_set_num_at(index)
|
|
2386
|
+
seek_number_in_minmaxes(minmaxes, index)
|
|
2387
|
+
end
|
|
2388
|
+
|
|
2389
|
+
def ordered_list_num_at(index)
|
|
2390
|
+
seek_number_in_minmaxes(each_entry_minmax, index)
|
|
2391
|
+
end
|
|
2392
|
+
|
|
2042
2393
|
def seek_number_in_minmaxes(minmaxes, index)
|
|
2043
|
-
index = Integer(index.to_int)
|
|
2044
2394
|
if index.negative?
|
|
2045
2395
|
reverse_each_minmax_with_index(minmaxes) do |min, max, idx_min, idx_max|
|
|
2046
|
-
idx_min <= index and return
|
|
2396
|
+
idx_min <= index and return min + (index - idx_min)
|
|
2047
2397
|
end
|
|
2048
2398
|
else
|
|
2049
2399
|
each_minmax_with_index(minmaxes) do |min, _, idx_min, idx_max|
|
|
2050
|
-
index <= idx_max and return
|
|
2400
|
+
index <= idx_max and return min + (index - idx_min)
|
|
2051
2401
|
end
|
|
2052
2402
|
end
|
|
2053
2403
|
nil
|
|
@@ -2073,30 +2423,41 @@ module Net
|
|
|
2073
2423
|
end
|
|
2074
2424
|
|
|
2075
2425
|
def slice_length(start, length)
|
|
2076
|
-
start =
|
|
2077
|
-
length =
|
|
2078
|
-
|
|
2079
|
-
|
|
2080
|
-
slice_range(start
|
|
2426
|
+
start = implicit_int(start)
|
|
2427
|
+
length = implicit_int(length)
|
|
2428
|
+
return nil if length.negative?
|
|
2429
|
+
stop = start + length unless start.negative? && start.abs <= length
|
|
2430
|
+
slice_range(start...stop)
|
|
2081
2431
|
end
|
|
2082
2432
|
|
|
2083
2433
|
def slice_range(range)
|
|
2084
|
-
first = range.begin ||
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
|
|
2089
|
-
|
|
2090
|
-
|
|
2091
|
-
|
|
2092
|
-
|
|
2093
|
-
max
|
|
2094
|
-
max = :* if max.nil?
|
|
2095
|
-
if max == :* then self & (min..)
|
|
2096
|
-
elsif min <= max then self & (min..max)
|
|
2434
|
+
first = implicit_int(range.begin || 0)
|
|
2435
|
+
rend = implicit_int(range.end) unless range.end.nil?
|
|
2436
|
+
excl = range.exclude_end?
|
|
2437
|
+
last = !(excl && rend == 0) && # (i...0)
|
|
2438
|
+
(excl && rend&.pred || rend || -1) # (i...j) vs (i..j) vs (i...)
|
|
2439
|
+
if !last || first.negative? == last.negative? && last < first
|
|
2440
|
+
remain_frozen_empty if valid_slice_start?(first)
|
|
2441
|
+
elsif (min = sorted_set_num_at(first))
|
|
2442
|
+
max = sorted_set_num_at(last) || (last.negative? ? 0 : STAR_INT)
|
|
2443
|
+
if min <= max then intersection export_minmax_entry [min, max]
|
|
2097
2444
|
else remain_frozen_empty
|
|
2098
2445
|
end
|
|
2446
|
+
elsif first.positive?
|
|
2447
|
+
remain_frozen_empty if valid_slice_start?(first)
|
|
2448
|
+
end
|
|
2449
|
+
end
|
|
2450
|
+
|
|
2451
|
+
# By short-circuiting, this is a small performance improvement over
|
|
2452
|
+
# `offset.abs <= cardinality`. But, slice_range should get a bigger
|
|
2453
|
+
# performance boost by combining this scan with the start offset scan.
|
|
2454
|
+
def valid_slice_start?(offset)
|
|
2455
|
+
offset = offset.abs
|
|
2456
|
+
minmaxes.each do |min, max|
|
|
2457
|
+
offset -= (max - min).succ
|
|
2458
|
+
return true if offset.negative?
|
|
2099
2459
|
end
|
|
2460
|
+
!offset.positive?
|
|
2100
2461
|
end
|
|
2101
2462
|
|
|
2102
2463
|
######################################################################{{{2
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
# shareable_constant_value: literal
|
|
3
|
+
|
|
4
|
+
# :enddoc:
|
|
5
|
+
|
|
6
|
+
module Net
|
|
7
|
+
class IMAP < Protocol
|
|
8
|
+
|
|
9
|
+
# INTERNAL utility methods. API is unstable and subject to change.
|
|
10
|
+
module Utils
|
|
11
|
+
module_function
|
|
12
|
+
|
|
13
|
+
# Something like this exists in ruby's C API. Why not in ruby's ruby?
|
|
14
|
+
def implicit_int(input)
|
|
15
|
+
Integer.try_convert(input) or
|
|
16
|
+
raise TypeError, case input
|
|
17
|
+
when nil
|
|
18
|
+
"no implicit conversion from %p to Integer" % [input]
|
|
19
|
+
when true, false
|
|
20
|
+
"no implicit conversion of %p into Integer" % [input]
|
|
21
|
+
else
|
|
22
|
+
"no implicit conversion of %s into Integer" % [input.class.name]
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
if defined?(Ractor.shareable_proc)
|
|
27
|
+
def shareable
|
|
28
|
+
case obj = yield
|
|
29
|
+
when Proc
|
|
30
|
+
Ractor.shareable_proc(&obj)
|
|
31
|
+
else
|
|
32
|
+
Ractor.make_shareable obj
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# simplecov:disable
|
|
37
|
+
elsif defined?(Ractor.make_shareable)
|
|
38
|
+
def shareable(&b)
|
|
39
|
+
obj = nil.instance_eval(&b).freeze
|
|
40
|
+
Ractor.make_shareable obj
|
|
41
|
+
end
|
|
42
|
+
else
|
|
43
|
+
def shareable(&b) nil.instance_eval(&b).freeze end
|
|
44
|
+
end
|
|
45
|
+
# simplecov:enable
|
|
46
|
+
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
end
|