Skip to content

Commit 799cc94

Browse files
authored
🔀 Merge pull request #351 from ruby/search-coerce-sequence_set
✨ Coerce `Set`, `:*`, `#to_sequence_set` search args into sequence-set
2 parents 950a992 + 6413656 commit 799cc94

File tree

3 files changed

+47
-12
lines changed

3 files changed

+47
-12
lines changed

‎lib/net/imap.rb

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1944,8 +1944,12 @@ def uid_expunge(uid_set)
19441944
#
19451945
# * When +criteria+ is an array, each member is a +SEARCH+ command argument:
19461946
# * Any SequenceSet sends SequenceSet#valid_string.
1947-
# +Range+, <tt>-1</tt>, and nested +Array+ elements are converted to
1948-
# SequenceSet.
1947+
# These types are converted to SequenceSet for validation and encoding:
1948+
# * +Set+
1949+
# * +Range+
1950+
# * <tt>-1</tt> and +:*+ -- both translate to <tt>*</tt>
1951+
# * responds to +#to_sequence_set+
1952+
# * nested +Array+
19491953
# * Any +String+ is sent verbatim when it is a valid \IMAP atom,
19501954
# and encoded as an \IMAP quoted or literal string otherwise.
19511955
# * Any other +Integer+ (besides <tt>-1</tt>) will be sent as +#to_s+.
@@ -3191,13 +3195,21 @@ def thread_internal(cmd, algorithm, search_keys, charset)
31913195

31923196
def normalize_searching_criteria(criteria)
31933197
return RawData.new(criteria) if criteria.is_a?(String)
3194-
criteria.map do |i|
3195-
case i
3196-
when -1, Range, Array
3197-
SequenceSet.new(i)
3198+
criteria.map {|i|
3199+
if coerce_search_arg_to_seqset?(i)
3200+
SequenceSet[i]
31983201
else
31993202
i
32003203
end
3204+
}
3205+
end
3206+
3207+
def coerce_search_arg_to_seqset?(obj)
3208+
case obj
3209+
when Set, -1, :* then true
3210+
when Range then true
3211+
when Array then true
3212+
else obj.respond_to?(:to_sequence_set)
32013213
end
32023214
end
32033215

‎lib/net/imap/sequence_set.rb

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -282,10 +282,7 @@ class SequenceSet
282282

283283
# valid inputs for "*"
284284
STARS = [:*, ?*, -1].freeze
285-
private_constant :STAR_INT, :STARS
286-
287-
COERCIBLE = ->{ _1.respond_to? :to_sequence_set }
288-
private_constant :COERCIBLE
285+
private_constant :STARS
289286

290287
class << self
291288

‎test/net/imap/test_imap.rb

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,10 +1206,36 @@ def test_unselect
12061206
end
12071207

12081208
server.on "SEARCH", &search_resp
1209-
assert_equal search_result, imap.search(["subject", "hello",
1209+
assert_equal search_result, imap.search(["subject", "hello world",
12101210
[1..5, 8, 10..-1]])
12111211
cmd = server.commands.pop
1212-
assert_equal ["SEARCH", "subject hello 1:5,8,10:*"], [cmd.name, cmd.args]
1212+
assert_equal(
1213+
["SEARCH",'subject "hello world" 1:5,8,10:*'],
1214+
[cmd.name, cmd.args]
1215+
)
1216+
1217+
imap.search(["OR", 1..1000, -1, "UID", 12345..-1])
1218+
assert_equal "OR 1:1000 * UID 12345:*", server.commands.pop.args
1219+
1220+
imap.search([1..1000, "UID", 12345..])
1221+
assert_equal "1:1000 UID 12345:*", server.commands.pop.args
1222+
1223+
# Unfortunately, we can't send every sequence-set string directly
1224+
imap.search(["SUBJECT", "1,*"])
1225+
assert_equal 'SUBJECT "1,*"', server.commands.pop.args
1226+
1227+
imap.search(["subject", "hello", Set[1, 2, 3, 4, 5, 8, *(10..100)]])
1228+
assert_equal "subject hello 1:5,8,10:100", server.commands.pop.args
1229+
1230+
imap.search([:*])
1231+
assert_equal "*", server.commands.pop.args
1232+
1233+
seqset_coercible = Object.new
1234+
def seqset_coercible.to_sequence_set
1235+
Net::IMAP::SequenceSet[1..9]
1236+
end
1237+
imap.search([seqset_coercible])
1238+
assert_equal "1:9", server.commands.pop.args
12131239

12141240
server.on "UID SEARCH", &search_resp
12151241
assert_equal search_result, imap.uid_search(["subject", "hello",

0 commit comments

Comments
 (0)