Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

🐛 Fix SequenceSet#append when its @string is nil #376

Merged
merged 2 commits into from
Jan 17, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
34 changes: 19 additions & 15 deletions lib/net/imap/sequence_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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+, <tt>CONTEXT=SORT</tt>, 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+, <tt>CONTEXT=SORT</tt>, 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
# <tt>O(lg n)</tt> 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.
#
Expand Down Expand Up @@ -181,14 +183,15 @@ class IMAP
# - #max: Returns the maximum number in the set.
# - #minmax: Returns the minimum and maximum numbers in the set.
#
# <i>Accessing value by offset:</i>
# <i>Accessing value by (normalized) offset:</i>
# - #[] (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.
# - #find_index: Returns the given number's offset in the set
#
# <i>Set cardinality:</i>
# - #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.
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -838,8 +842,8 @@ def entries; each_entry.to_a end
# <tt>*</tt> 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. <tt>*</tt> will sort last. See #normalize.
#
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].elements
# #=> [2, 5..9, 11..12, :*]
Expand All @@ -857,7 +861,7 @@ def elements; each_element.to_a end
# translates to <tt>:*..</tt>. Use #limit to set <tt>*</tt> 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. <tt>*</tt> will sort last. See #normalize.
#
# Net::IMAP::SequenceSet["2,5:9,6,*,12:11"].ranges
Expand Down
8 changes: 8 additions & 0 deletions test/net/imap/test_sequence_set.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
Loading