diff --git a/lib/net/imap/sequence_set.rb b/lib/net/imap/sequence_set.rb
index 2fd5b695b..3a159912d 100644
--- a/lib/net/imap/sequence_set.rb
+++ b/lib/net/imap/sequence_set.rb
@@ -108,11 +108,15 @@ class IMAP
# When a set includes *, some methods may have surprising behavior.
#
# For example, #complement treats * as its own number. This way,
- # the #intersection of a set and its #complement will always be empty.
- # This is not how an \IMAP server interprets the set: it will convert
- # * to either the number of messages in the mailbox or +UIDNEXT+,
- # as appropriate. And there _will_ be overlap between a set and its
- # complement after #limit is applied to each:
+ # the #intersection of a set and its #complement will always be empty. And
+ # * is sorted as greater than any other number in the set. This is
+ # not how an \IMAP server interprets the set: it will convert * to
+ # the number of messages in the mailbox, the +UID+ of the last message in
+ # the mailbox, or +UIDNEXT+, as appropriate. Several methods have an
+ # argument for how * should be interpreted.
+ #
+ # But, for example, this means that there may be overlap between a set and
+ # its complement after #limit is applied to each:
#
# ~Net::IMAP::SequenceSet["*"] == Net::IMAP::SequenceSet[1..(2**32-1)]
# ~Net::IMAP::SequenceSet[1..5] == Net::IMAP::SequenceSet["6:*"]
@@ -179,9 +183,9 @@ class IMAP
# - #include_star?: Returns whether the set contains *.
#
# Minimum and maximum value elements:
- # - #min: Returns one or more minimum numbers in the set.
- # - #max: Returns one or more maximum numbers in the set.
- # - #minmax: Returns the minimum and maximum numbers in the set.
+ # - #min: Returns one or more of the lowest numbers in the set.
+ # - #max: Returns one or more of the highest numbers in the set.
+ # - #minmax: Returns the lowest and highest numbers in the set.
#
# Accessing value by offset in sorted set:
# - #[] (aliased as #slice): Returns the number or consecutive subset at a
@@ -643,7 +647,14 @@ def full?; @tuples == [[1, STAR_INT]] end
# Net::IMAP::SequenceSet["1:5"] | 2 | [4..6, 99]
# #=> Net::IMAP::SequenceSet["1:6,99"]
#
- # Related: #add, #merge
+ # Related: #add, #merge, #&, #-, #^, #~
+ #
+ # ==== Set identities
+ #
+ # lhs | rhs is equivalent to:
+ # * rhs | lhs (commutative)
+ # * ~(~lhs & ~rhs) (De Morgan's Law)
+ # * (lhs & rhs) ^ (lhs ^ rhs)
def |(other) remain_frozen dup.merge other end
alias :+ :|
alias union :|
@@ -662,7 +673,17 @@ def |(other) remain_frozen dup.merge other end
# Net::IMAP::SequenceSet[1..5] - 2 - 4 - 6
# #=> Net::IMAP::SequenceSet["1,3,5"]
#
- # Related: #subtract
+ # Related: #subtract, #|, #&, #^, #~
+ #
+ # ==== Set identities
+ #
+ # lhs - rhs is equivalent to:
+ # * ~r - ~l
+ # * lhs & ~rhs
+ # * ~(~lhs | rhs)
+ # * lhs & (lhs ^ rhs)
+ # * lhs ^ (lhs & rhs)
+ # * rhs ^ (lhs | rhs)
def -(other) remain_frozen dup.subtract other end
alias difference :-
@@ -680,7 +701,17 @@ def -(other) remain_frozen dup.subtract other end
# Net::IMAP::SequenceSet[1..5] & [2, 4, 6]
# #=> Net::IMAP::SequenceSet["2,4"]
#
- # (seqset & other) is equivalent to (seqset - ~other).
+ # Related: #intersect?, #|, #-, #^, #~
+ #
+ # ==== Set identities
+ #
+ # lhs & rhs is equivalent to:
+ # * rhs & lhs (commutative)
+ # * ~(~lhs | ~rhs) (De Morgan's Law)
+ # * lhs - ~rhs
+ # * lhs - (lhs - rhs)
+ # * lhs - (lhs ^ rhs)
+ # * lhs ^ (lhs - rhs)
def &(other)
remain_frozen dup.subtract SequenceSet.new(other).complement!
end
@@ -700,8 +731,16 @@ def &(other)
# Net::IMAP::SequenceSet[1..5] ^ [2, 4, 6]
# #=> Net::IMAP::SequenceSet["1,3,5:6"]
#
- # (seqset ^ other) is equivalent to ((seqset | other) -
- # (seqset & other)).
+ # Related: #|, #&, #-, #~
+ #
+ # ==== Set identities
+ #
+ # lhs ^ rhs is equivalent to:
+ # * rhs ^ lhs (commutative)
+ # * ~lhs ^ ~rhs
+ # * (lhs | rhs) - (lhs & rhs)
+ # * (lhs - rhs) | (rhs - lhs)
+ # * (lhs ^ other) ^ (other ^ rhs)
def ^(other) remain_frozen (dup | other).subtract(self & other) end
alias xor :^
@@ -719,7 +758,12 @@ def ^(other) remain_frozen (dup | other).subtract(self & other) end
# ~Net::IMAP::SequenceSet["6:99,223:*"]
# #=> Net::IMAP::SequenceSet["1:5,100:222"]
#
- # Related: #complement!
+ # Related: #complement!, #|, #&, #-, #^
+ #
+ # ==== Set identities
+ #
+ # ~set is equivalent to:
+ # * full - set, where "full" is Net::IMAP::SequenceSet.full
def ~; remain_frozen dup.complement! end
alias complement :~
@@ -731,7 +775,10 @@ def ~; remain_frozen dup.complement! end
#
# #string will be regenerated. Use #merge to add many elements at once.
#
- # Related: #add?, #merge, #union
+ # Use #append to append new elements to #string. See
+ # Net::IMAP@Ordered+and+Normalized+Sets.
+ #
+ # Related: #add?, #merge, #union, #append
def add(element)
tuple_add input_to_tuple element
normalize!
@@ -742,6 +789,10 @@ def add(element)
#
# Unlike #add, #merge, or #union, the new value is appended to #string.
# This may result in a #string which has duplicates or is out-of-order.
+ #
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
+ #
+ # Related: #add, #merge, #union
def append(entry)
modifying!
tuple = input_to_tuple entry
@@ -890,21 +941,21 @@ def subtract(*sets)
# This is useful when the given order is significant, for example in a
# ESEARCH response to IMAP#sort.
#
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
+ #
# Related: #each_entry, #elements
def entries; each_entry.to_a end
# Returns an array of ranges and integers and :*.
#
# The returned elements are sorted and coalesced, even when the input
- # #string is not. * will sort last. See #normalize.
+ # #string is not. * will sort last. See #normalize,
+ # Net::IMAP@Ordered+and+Normalized+Sets.
#
# By itself, * translates to :*. A range containing
# * translates to an endless range. Use #limit to translate both
# cases to a maximum value.
#
- # The returned elements will be sorted and coalesced, even when the input
- # #string is not. * will sort last. See #normalize.
- #
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
# #=> [2, 5..9, 11..12, :*]
#
@@ -915,15 +966,13 @@ def elements; each_element.to_a end
# Returns an array of ranges
#
# The returned elements are sorted and coalesced, even when the input
- # #string is not. * will sort last. See #normalize.
+ # #string is not. * will sort last. See #normalize,
+ # Net::IMAP@Ordered+and+Normalized+Sets.
#
# * translates to an endless range. By itself, *
# translates to :*... Use #limit to set * to a maximum
# value.
#
- # The returned ranges will be sorted and coalesced, even when the input
- # #string is not. * will sort last. See #normalize.
- #
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
# #=> [2..2, 5..9, 11..12, :*..]
# Net::IMAP::SequenceSet["123,999:*,456:789"].ranges
@@ -935,7 +984,7 @@ def ranges; each_range.to_a end
# Returns a sorted array of all of the number values in the sequence set.
#
# The returned numbers are sorted and de-duplicated, even when the input
- # #string is not. See #normalize.
+ # #string is not. See #normalize, Net::IMAP@Ordered+and+Normalized+Sets.
#
# Net::IMAP::SequenceSet["2,5:9,6,12:11"].numbers
# #=> [2, 5, 6, 7, 8, 9, 11, 12]
@@ -967,6 +1016,8 @@ def numbers; each_number.to_a end
# no sorting, deduplication, or coalescing. When #string is in its
# normalized form, this will yield the same values as #each_element.
#
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
+ #
# Related: #entries, #each_element
def each_entry(&block) # :yields: integer or range or :*
return to_enum(__method__) unless block_given?
@@ -977,7 +1028,7 @@ def each_entry(&block) # :yields: integer or range or :*
# and returns self. Returns an enumerator when called without a block.
#
# The returned numbers are sorted and de-duplicated, even when the input
- # #string is not. See #normalize.
+ # #string is not. See #normalize, Net::IMAP@Ordered+and+Normalized+Sets.
#
# Related: #elements, #each_entry
def each_element # :yields: integer or range or :*
@@ -1400,6 +1451,7 @@ def complement!
#
# The returned set's #string is sorted and deduplicated. Adjacent or
# overlapping elements will be merged into a single larger range.
+ # See Net::IMAP@Ordered+and+Normalized+Sets.
#
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalize
# #=> Net::IMAP::SequenceSet["1:7,9:11"]
@@ -1412,7 +1464,7 @@ def normalize
end
# Resets #string to be sorted, deduplicated, and coalesced. Returns
- # +self+.
+ # +self+. See Net::IMAP@Ordered+and+Normalized+Sets.
#
# Related: #normalize, #normalized_string
def normalize!
@@ -1422,11 +1474,13 @@ def normalize!
# Returns a normalized +sequence-set+ string representation, sorted
# and deduplicated. Adjacent or overlapping elements will be merged into
- # a single larger range. Returns +nil+ when the set is empty.
+ # a single larger range. See Net::IMAP@Ordered+and+Normalized+Sets.
#
# Net::IMAP::SequenceSet["1:5,3:7,10:9,10:11"].normalized_string
# #=> "1:7,9:11"
#
+ # Returns +nil+ when the set is empty.
+ #
# Related: #normalize!, #normalize
def normalized_string
@tuples.empty? ? nil : -@tuples.map { tuple_to_str _1 }.join(",")