Skip to content

Commit 2d6dbde

Browse files
authored
🔀 Merge pull request #345 from ruby/search-parenthesized-lists
✨ Enable parenthesized lists in search criteria
2 parents 799cc94 + 1d9afd5 commit 2d6dbde

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

‎lib/net/imap.rb

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1949,9 +1949,13 @@ def uid_expunge(uid_set)
19491949
# * +Range+
19501950
# * <tt>-1</tt> and +:*+ -- both translate to <tt>*</tt>
19511951
# * responds to +#to_sequence_set+
1952-
# * nested +Array+
1952+
# * +Array+, when each element is one of the above types, a positive
1953+
# +Integer+, a sequence-set formatted +String+, or a deeply nested
1954+
# +Array+ of these same types.
19531955
# * Any +String+ is sent verbatim when it is a valid \IMAP atom,
19541956
# and encoded as an \IMAP quoted or literal string otherwise.
1957+
# * Any other nested +Array+ is encoded as a parenthesized list, to group
1958+
# multiple search keys (e.g., for use with +OR+ and +NOT+).
19551959
# * Any other +Integer+ (besides <tt>-1</tt>) will be sent as +#to_s+.
19561960
# * +Date+ objects will be encoded as an \IMAP date (see ::encode_date).
19571961
#
@@ -1976,13 +1980,13 @@ def uid_expunge(uid_set)
19761980
# The following searches send the exact same command to the server:
19771981
#
19781982
# # criteria array, charset arg
1979-
# imap.search(%w[OR UNSEEN FLAGGED SUBJECT foo], "UTF-8")
1983+
# imap.search(["OR", "UNSEEN", %w(FLAGGED SUBJECT foo)], "UTF-8")
19801984
# # criteria string, charset arg
1981-
# imap.search("OR UNSEEN FLAGGED SUBJECT foo", "UTF-8")
1985+
# imap.search("OR UNSEEN (FLAGGED SUBJECT foo)", "UTF-8")
19821986
# # criteria array contains charset arg
1983-
# imap.search(%w[CHARSET UTF-8 OR UNSEEN FLAGGED SUBJECT foo])
1987+
# imap.search([*%w[CHARSET UTF-8], "OR", "UNSEEN", %w(FLAGGED SUBJECT foo)])
19841988
# # criteria string contains charset arg
1985-
# imap.search("CHARSET UTF-8 OR UNSEEN FLAGGED SUBJECT foo")
1989+
# imap.search("CHARSET UTF-8 OR UNSEEN (FLAGGED SUBJECT foo)")
19861990
#
19871991
# ===== Search keys
19881992
#
@@ -3208,11 +3212,20 @@ def coerce_search_arg_to_seqset?(obj)
32083212
case obj
32093213
when Set, -1, :* then true
32103214
when Range then true
3211-
when Array then true
3215+
when Array then obj.all? { coerce_search_array_arg_to_seqset? _1 }
32123216
else obj.respond_to?(:to_sequence_set)
32133217
end
32143218
end
32153219

3220+
def coerce_search_array_arg_to_seqset?(obj)
3221+
case obj
3222+
when Integer then obj.positive? || obj == -1
3223+
when String then ResponseParser::Patterns::SEQUENCE_SET_STR.match?(obj.b)
3224+
else
3225+
coerce_search_arg_to_seqset?(obj)
3226+
end
3227+
end
3228+
32163229
def build_ssl_ctx(ssl)
32173230
if ssl
32183231
params = (Hash.try_convert(ssl) || {}).freeze

‎test/net/imap/test_imap.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1242,6 +1242,18 @@ def seqset_coercible.to_sequence_set
12421242
[1..22, 30..-1]])
12431243
cmd = server.commands.pop
12441244
assert_equal ["UID SEARCH", "subject hello 1:22,30:*"], [cmd.name, cmd.args]
1245+
1246+
assert_equal search_result, imap.search(
1247+
"RETURN (COUNT) NOT (FLAGGED (OR SEEN ANSWERED))"
1248+
)
1249+
cmd = server.commands.pop
1250+
assert_equal "RETURN (COUNT) NOT (FLAGGED (OR SEEN ANSWERED))", cmd.args
1251+
1252+
assert_equal search_result, imap.search([
1253+
"RETURN", %w(MIN MAX COUNT), "NOT", ["FLAGGED", %w(OR SEEN ANSWERED)]
1254+
])
1255+
cmd = server.commands.pop
1256+
assert_equal "RETURN (MIN MAX COUNT) NOT (FLAGGED (OR SEEN ANSWERED))", cmd.args
12451257
end
12461258
end
12471259

0 commit comments

Comments
 (0)