diff --git a/lib/net/imap/sequence_set.rb b/lib/net/imap/sequence_set.rb index 2fd5b695..3a159912 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 <tt>*</tt>, some methods may have surprising behavior. # # For example, #complement treats <tt>*</tt> 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 - # <tt>*</tt> 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 + # <tt>*</tt> is sorted as greater than any other number in the set. This is + # not how an \IMAP server interprets the set: it will convert <tt>*</tt> 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 <tt>*</tt> 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 <tt>*</tt>. # # <i>Minimum and maximum value elements:</i> - # - #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. # # <i>Accessing value by offset in sorted set:</i> # - #[] (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 + # + # <tt>lhs | rhs</tt> is equivalent to: + # * <tt>rhs | lhs</tt> (commutative) + # * <tt>~(~lhs & ~rhs)</tt> (De Morgan's Law) + # * <tt>(lhs & rhs) ^ (lhs ^ rhs)</tt> 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 + # + # <tt>lhs - rhs</tt> is equivalent to: + # * <tt>~r - ~l</tt> + # * <tt>lhs & ~rhs</tt> + # * <tt>~(~lhs | rhs)</tt> + # * <tt>lhs & (lhs ^ rhs)</tt> + # * <tt>lhs ^ (lhs & rhs)</tt> + # * <tt>rhs ^ (lhs | rhs)</tt> 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"] # - # <tt>(seqset & other)</tt> is equivalent to <tt>(seqset - ~other)</tt>. + # Related: #intersect?, #|, #-, #^, #~ + # + # ==== Set identities + # + # <tt>lhs & rhs</tt> is equivalent to: + # * <tt>rhs & lhs</tt> (commutative) + # * <tt>~(~lhs | ~rhs)</tt> (De Morgan's Law) + # * <tt>lhs - ~rhs</tt> + # * <tt>lhs - (lhs - rhs)</tt> + # * <tt>lhs - (lhs ^ rhs)</tt> + # * <tt>lhs ^ (lhs - rhs)</tt> 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"] # - # <tt>(seqset ^ other)</tt> is equivalent to <tt>((seqset | other) - - # (seqset & other))</tt>. + # Related: #|, #&, #-, #~ + # + # ==== Set identities + # + # <tt>lhs ^ rhs</tt> is equivalent to: + # * <tt>rhs ^ lhs</tt> (commutative) + # * <tt>~lhs ^ ~rhs</tt> + # * <tt>(lhs | rhs) - (lhs & rhs)</tt> + # * <tt>(lhs - rhs) | (rhs - lhs)</tt> + # * <tt>(lhs ^ other) ^ (other ^ rhs)</tt> 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 + # + # <tt>~set</tt> is equivalent to: + # * <tt>full - set</tt>, 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 <tt>:*</tt>. # # The returned elements are sorted and coalesced, even when the input - # #string is not. <tt>*</tt> will sort last. See #normalize. + # #string is not. <tt>*</tt> will sort last. See #normalize, + # Net::IMAP@Ordered+and+Normalized+Sets. # # By itself, <tt>*</tt> translates to <tt>:*</tt>. A range containing # <tt>*</tt> 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. <tt>*</tt> 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. <tt>*</tt> will sort last. See #normalize. + # #string is not. <tt>*</tt> will sort last. See #normalize, + # Net::IMAP@Ordered+and+Normalized+Sets. # # <tt>*</tt> translates to an endless range. By itself, <tt>*</tt> # translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> to a maximum # value. # - # The returned ranges will be sorted and coalesced, even when the input - # #string is not. <tt>*</tt> 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(",")