diff --git a/lib/net/imap/sequence_set.rb b/lib/net/imap/sequence_set.rb index ea8b0a67..b046b0eb 100644 --- a/lib/net/imap/sequence_set.rb +++ b/lib/net/imap/sequence_set.rb @@ -56,18 +56,20 @@ class IMAP # set = Net::IMAP::SequenceSet[1, 2, [3..7, 5], 6..10, 2048, 1024] # set.valid_string #=> "1:10,55,1024:2048" # - # == Normalized form + # == Ordered and Normalized sets # - # When a sequence set is created with a single String value, that #string - # representation is preserved. SequenceSet's internal representation - # implicitly sorts all entries, de-duplicates numbers, and coalesces - # adjacent or overlapping ranges. Most enumeration methods and offset-based - # methods use this normalized representation. Most modification methods - # will convert #string to its normalized form. + # Sometimes the order of the set's members is significant, such as with the + # +ESORT+, CONTEXT=SORT, and +UIDPLUS+ extensions. So, when a + # sequence set is created by the parser or with a single string value, that + # #string representation is preserved. # - # In some cases the order of the string representation is significant, such - # as the +ESORT+, CONTEXT=SORT, and +UIDPLUS+ extensions. Use - # #entries or #each_entry to enumerate the set in its original order. To + # Internally, SequenceSet stores a normalized representation which sorts all + # entries, de-duplicates numbers, and coalesces adjacent or overlapping + # ranges. Most methods use this normalized representation to achieve + # O(lg n) porformance. Use #entries or #each_entry to enumerate + # the set in its original order. + # + # Most modification methods convert #string to its normalized form. To # preserve #string order while modifying a set, use #append, #string=, or # #replace. # @@ -181,7 +183,7 @@ class IMAP # - #max: Returns the maximum number in the set. # - #minmax: Returns the minimum and maximum numbers in the set. # - # Accessing value by offset: + # Accessing value by (normalized) offset: # - #[] (aliased as #slice): Returns the number or consecutive subset at a # given offset or range of offsets. # - #at: Returns the number at a given offset. @@ -189,6 +191,7 @@ class IMAP # # Set cardinality: # - #count (aliased as #size): Returns the count of numbers in the set. + # Duplicated numbers are not counted. # - #empty?: Returns whether the set has no members. \IMAP syntax does not # allow empty sequence sets. # - #valid?: Returns whether the set has any members. @@ -681,8 +684,9 @@ def append(object) modifying! tuple = input_to_tuple object entry = tuple_to_str tuple + string unless empty? # write @string before tuple_add tuple_add tuple - @string = -(string ? "#{@string},#{entry}" : entry) + @string = -(@string ? "#{@string},#{entry}" : entry) self end @@ -838,8 +842,8 @@ def entries; each_entry.to_a end # * translates to an endless range. Use #limit to translate both # cases to a maximum value. # - # If the original input was unordered or contains overlapping ranges, the - # returned ranges will be ordered and coalesced. + # 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, :*] @@ -857,7 +861,7 @@ def elements; each_element.to_a end # translates to :*... Use #limit to set * to a maximum # value. # - # The returned ranges will be ordered and coalesced, even when the input + # 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 diff --git a/test/net/imap/test_sequence_set.rb b/test/net/imap/test_sequence_set.rb index 85204b24..94c096ba 100644 --- a/test/net/imap/test_sequence_set.rb +++ b/test/net/imap/test_sequence_set.rb @@ -344,6 +344,14 @@ def obj.to_sequence_set; 192_168.001_255 end assert_equal "1:6,4:9", SequenceSet.new("1:6").append("4:9").string assert_equal "1:4,5:*", SequenceSet.new("1:4").append(5..).string assert_equal "5:*,1:4", SequenceSet.new("5:*").append(1..4).string + # also works from empty + assert_equal "5,1", SequenceSet.new.append(5).append(1).string + # also works when *previously* input was non-strings + assert_equal "*,1", SequenceSet.new(:*).append(1).string + assert_equal "1,5", SequenceSet.new(1).append("5").string + assert_equal "1:6,4:9", SequenceSet.new(1..6).append(4..9).string + assert_equal "1:4,5:*", SequenceSet.new(1..4).append(5..).string + assert_equal "5:*,1:4", SequenceSet.new(5..).append(1..4).string end test "#merge" do