Skip to content

Commit 2bc753f

Browse files
authored
🔀 Merge pull request #489 from ruby/sequence_set/rdoc-updates
📚 RDoc updates for SequenceSet
2 parents 982ba13 + 22633e3 commit 2bc753f

File tree

1 file changed

+156
-36
lines changed

1 file changed

+156
-36
lines changed

lib/net/imap/sequence_set.rb

Lines changed: 156 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,9 @@ class IMAP
1818
#
1919
# == Creating sequence sets
2020
#
21-
# SequenceSet.new with no arguments creates an empty sequence set. Note
22-
# that an empty sequence set is invalid in the \IMAP grammar.
23-
#
24-
# set = Net::IMAP::SequenceSet.new
25-
# set.empty? #=> true
26-
# set.valid? #=> false
27-
# set.valid_string #!> raises DataFormatError
28-
# set << 1..10
29-
# set.empty? #=> false
30-
# set.valid? #=> true
31-
# set.valid_string #=> "1:10"
32-
#
3321
# SequenceSet.new may receive a single optional argument: a non-zero 32 bit
3422
# unsigned integer, a range, a <tt>sequence-set</tt> formatted string,
35-
# another sequence set, a Set (containing only numbers or <tt>*</tt>), or an
23+
# another SequenceSet, a Set (containing only numbers or <tt>*</tt>), or an
3624
# Array containing any of these (array inputs may be nested).
3725
#
3826
# set = Net::IMAP::SequenceSet.new(1)
@@ -48,30 +36,92 @@ class IMAP
4836
# set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024)
4937
# set.valid_string #=> "1:10,55,1024:2048"
5038
#
51-
# Use ::[] with one or more arguments to create a frozen SequenceSet. An
52-
# invalid (empty) set cannot be created with ::[].
39+
# SequenceSet.new with no arguments creates an empty sequence set. Note
40+
# that an empty sequence set is invalid in the \IMAP grammar.
5341
#
42+
# set = Net::IMAP::SequenceSet.new
43+
# set.empty? #=> true
44+
# set.valid? #=> false
45+
# set.valid_string #!> raises DataFormatError
46+
# set << 1..10
47+
# set.empty? #=> false
48+
# set.valid? #=> true
49+
# set.valid_string #=> "1:10"
50+
#
51+
# Using SequenceSet.new with another SequenceSet input behaves the same as
52+
# calling #dup on the other set. The input's #string will be preserved.
53+
#
54+
# input = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
55+
# copy = Net::IMAP::SequenceSet.new(input)
56+
# input.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
57+
# copy.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
58+
# copy2 = input.dup # same as calling new with a SequenceSet input
59+
# copy == input #=> true, same set membership
60+
# copy.eql? input #=> true, same string value
61+
# copy.equal? input #=> false, different objects
62+
#
63+
# copy.normalize!
64+
# copy.valid_string #=> "1:10,1024,2048"
65+
# copy == input #=> true, same set membership
66+
# copy.eql? input #=> false, different string value
67+
#
68+
# copy << 999
69+
# copy.valid_string #=> "1:10,999,1024,2048"
70+
# copy == input #=> false, different set membership
71+
# copy.eql? input #=> false, different string value
72+
#
73+
# Use ::[] to coerce one or more arguments into a valid frozen SequenceSet.
74+
# A valid frozen SequenceSet is returned directly, without allocating a new
75+
# object. ::[] will not create an invalid (empty) set.
76+
#
77+
# Net::IMAP::SequenceSet[] #!> raises ArgumentError
78+
# Net::IMAP::SequenceSet[nil] #!> raises DataFormatError
79+
# Net::IMAP::SequenceSet[""] #!> raises DataFormatError
80+
#
81+
# # String order is preserved
5482
# set = Net::IMAP::SequenceSet["1,2,3:7,5,6:10,2048,1024"]
5583
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
84+
# set.frozen? #=> true
85+
#
86+
# # Other inputs are normalized
5687
# set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024]
5788
# set.valid_string #=> "1:10,55,1024:2048"
89+
# set.frozen? #=> true
90+
#
91+
# frozen = set
92+
# unfrozen = set.dup
93+
# frozen.equal? Net::IMAP::SequenceSet[frozen] #=> true
94+
# unfrozen.equal? Net::IMAP::SequenceSet[unfrozen] #=> false
95+
#
96+
# Objects which respond to +to_sequence_set+ (such as SearchResult and
97+
# ThreadMember) can be coerced to a SequenceSet with ::new, ::try_convert,
98+
# or ::[].
99+
#
100+
# search = imap.uid_search(["SUBJECT", "hello", "NOT", "SEEN"])
101+
# seqset = Net::IMAP::SequenceSet(search) - already_fetched
102+
# fetch = imap.uid_fetch(seqset, "FAST")
58103
#
59104
# == Ordered and Normalized sets
60105
#
61106
# Sometimes the order of the set's members is significant, such as with the
62107
# +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.
108+
# sequence set is created from a single string (such as by the parser), that
109+
# #string representation is preserved. Assigning a string with #string= or
110+
# #replace will also preserve that string. Use #each_entry, #entries, or
111+
# #each_ordered_number to enumerate the entries in their #string order.
112+
# Hash equality (using #eql?) is based on the string representation.
65113
#
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.
114+
# Internally, SequenceSet uses a normalized uint32 set representation which
115+
# sorts and de-duplicates all numbers and coalesces adjacent or overlapping
116+
# entries. Many methods use this sorted set representation for <tt>O(lg
117+
# n)</tt> searches. Use #each_element, #elements, #each_range, #ranges,
118+
# #each_number, or #numbers to enumerate the set in sorted order. Basic
119+
# object equality (using #==) is based on set membership, without regard to
120+
# #entry order or #string normalization.
71121
#
72-
# Most modification methods convert #string to its normalized form. To
73-
# preserve #string order while modifying a set, use #append, #string=, or
74-
# #replace.
122+
# Most modification methods reset #string to its #normalized form, so that
123+
# #entries and #elements are identical. Use #append to preserve #entries
124+
# order while modifying a set.
75125
#
76126
# == Using <tt>*</tt>
77127
#
@@ -178,8 +228,7 @@ class IMAP
178228
#
179229
# <i>Set membership:</i>
180230
# - #include? (aliased as #member?):
181-
# Returns whether a given element (nz-number, range, or <tt>*</tt>) is
182-
# contained by the set.
231+
# Returns whether a given element is contained by the set.
183232
# - #include_star?: Returns whether the set contains <tt>*</tt>.
184233
#
185234
# <i>Minimum and maximum value elements:</i>
@@ -337,6 +386,8 @@ class << self
337386
# An empty SequenceSet is invalid and will raise a DataFormatError.
338387
#
339388
# Use ::new to create a mutable or empty SequenceSet.
389+
#
390+
# Related: ::new, ::try_convert
340391
def [](first, *rest)
341392
if rest.empty?
342393
if first.is_a?(SequenceSet) && first.frozen? && first.valid?
@@ -358,6 +409,8 @@ def [](first, *rest)
358409
#
359410
# If +obj.to_sequence_set+ doesn't return a SequenceSet, an exception is
360411
# raised.
412+
#
413+
# Related: ::new, ::[]
361414
def try_convert(obj)
362415
return obj if obj.is_a?(SequenceSet)
363416
return nil unless obj.respond_to?(:to_sequence_set)
@@ -376,10 +429,69 @@ def full; FULL end
376429
end
377430

378431
# Create a new SequenceSet object from +input+, which may be another
379-
# SequenceSet, an IMAP formatted +sequence-set+ string, a number, a
380-
# range, <tt>:*</tt>, a Set of numbers, or an Array of these.
381-
#
382-
# Use ::[] to create a frozen (non-empty) SequenceSet.
432+
# SequenceSet, an IMAP formatted +sequence-set+ string, a non-zero 32 bit
433+
# unsigned integer, a range, <tt>:*</tt>, a Set of numbers or <tt>*</tt>,
434+
# an object that responds to +to_sequence_set+ (such as SearchResult) or
435+
# an Array of these (array inputs may be nested).
436+
#
437+
# set = Net::IMAP::SequenceSet.new(1)
438+
# set.valid_string #=> "1"
439+
# set = Net::IMAP::SequenceSet.new(1..100)
440+
# set.valid_string #=> "1:100"
441+
# set = Net::IMAP::SequenceSet.new(1...100)
442+
# set.valid_string #=> "1:99"
443+
# set = Net::IMAP::SequenceSet.new([1, 2, 5..])
444+
# set.valid_string #=> "1:2,5:*"
445+
# set = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
446+
# set.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
447+
# set = Net::IMAP::SequenceSet.new(1, 2, 3..7, 5, 6..10, 2048, 1024)
448+
# set.valid_string #=> "1:10,55,1024:2048"
449+
#
450+
# With no arguments (or +nil+) creates an empty sequence set. Note that
451+
# an empty sequence set is invalid in the \IMAP grammar.
452+
#
453+
# set = Net::IMAP::SequenceSet.new
454+
# set.empty? #=> true
455+
# set.valid? #=> false
456+
# set.valid_string #!> raises DataFormatError
457+
# set << 1..10
458+
# set.empty? #=> false
459+
# set.valid? #=> true
460+
# set.valid_string #=> "1:10"
461+
#
462+
# When +input+ is a SequenceSet, ::new behaves the same as calling #dup on
463+
# that other set. The input's #string will be preserved.
464+
#
465+
# input = Net::IMAP::SequenceSet.new("1,2,3:7,5,6:10,2048,1024")
466+
# copy = Net::IMAP::SequenceSet.new(input)
467+
# input.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
468+
# copy.valid_string #=> "1,2,3:7,5,6:10,2048,1024"
469+
# copy2 = input.dup # same as calling new with a SequenceSet input
470+
# copy == input #=> true, same set membership
471+
# copy.eql? input #=> true, same string value
472+
# copy.equal? input #=> false, different objects
473+
#
474+
# copy.normalize!
475+
# copy.valid_string #=> "1:10,1024,2048"
476+
# copy == input #=> true, same set membership
477+
# copy.eql? input #=> false, different string value
478+
#
479+
# copy << 999
480+
# copy.valid_string #=> "1:10,999,1024,2048"
481+
# copy == input #=> false, different set membership
482+
# copy.eql? input #=> false, different string value
483+
#
484+
# === Alternative set creation methods
485+
#
486+
# * ::[] returns a frozen validated (non-empty) SequenceSet, without
487+
# allocating a new object when the input is already a valid frozen
488+
# SequenceSet.
489+
# * ::try_convert calls +to_sequence_set+ on inputs that support it and
490+
# returns +nil+ for inputs that don't.
491+
# * ::empty and ::full both return frozen singleton sets which can be
492+
# combined with set operations (#|, #&, #^, #-, etc) to make new sets.
493+
#
494+
# See SequenceSet@Creating+sequence+sets.
383495
def initialize(input = nil) input ? replace(input) : clear end
384496

385497
# Removes all elements and returns self.
@@ -525,7 +637,7 @@ def ===(other)
525637
# Returns whether +other+ is contained within the set. +other+ may be any
526638
# object that would be accepted by ::new.
527639
#
528-
# Related: #===, #include?, #include_star?
640+
# Related: #===, #include?, #include_star?, #intersect?
529641
def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
530642

531643
# Returns +true+ when a given number or range is in +self+, and +false+
@@ -551,7 +663,7 @@ def cover?(other) input_to_tuples(other).none? { !include_tuple?(_1) } end
551663
# set.include?(200..) #=> true
552664
# set.include?(100..) #=> false
553665
#
554-
# Related: #include_star?, #cover?, #===
666+
# Related: #include_star?, #cover?, #===, #intersect?
555667
def include?(element)
556668
tuple = input_to_tuple element rescue nil
557669
!!include_tuple?(tuple) if tuple
@@ -568,7 +680,7 @@ def include_star?; @tuples.last&.last == STAR_INT end
568680
# Net::IMAP::SequenceSet["5:10"].intersect? "7,9,11" #=> true
569681
# Net::IMAP::SequenceSet["5:10"].intersect? "11:33" #=> false
570682
#
571-
# Related: #intersection, #disjoint?
683+
# Related: #intersection, #disjoint?, #cover?, #include?
572684
def intersect?(other)
573685
valid? && input_to_tuples(other).any? { intersect_tuple? _1 }
574686
end
@@ -685,7 +797,7 @@ def |(other) remain_frozen dup.merge other end
685797
# ==== Set identities
686798
#
687799
# <tt>lhs - rhs</tt> is equivalent to:
688-
# * <tt>~r - ~l</tt>
800+
# * <tt>~rhs - ~lhs</tt>
689801
# * <tt>lhs & ~rhs</tt>
690802
# * <tt>~(~lhs | rhs)</tt>
691803
# * <tt>lhs & (lhs ^ rhs)</tt>
@@ -1504,7 +1616,15 @@ def inspect
15041616
end
15051617
end
15061618

1507-
# Returns self
1619+
##
1620+
# :method: to_sequence_set
1621+
# :call-seq: to_sequence_set -> self
1622+
#
1623+
# Returns +self+
1624+
#
1625+
# Related: ::try_convert
1626+
1627+
# :nodoc: (work around rdoc bug)
15081628
alias to_sequence_set itself
15091629

15101630
# Unstable API: currently for internal use only (Net::IMAP#validate_data)

0 commit comments

Comments
 (0)