Skip to content

Commit 1a25273

Browse files
committed
✨ Responses with type can return frozen dup array
Because responses(type) is relatively new and has always raised an exception, we can update it to return a frozen dup array without breaking backward compatibility. Additionally, `config.responses_without_args` was added as an alias for `config.responses_without_block`. The original name is a little misleading now, but it's kept for backward compatibility.
1 parent 1c3f43c commit 1a25273

File tree

3 files changed

+48
-12
lines changed

3 files changed

+48
-12
lines changed

lib/net/imap.rb

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2497,17 +2497,21 @@ def idle_done
24972497
private_constant :RESPONSES_DEPRECATION_MSG
24982498

24992499
# :call-seq:
2500+
# responses(type) -> frozen array
25002501
# responses {|hash| ...} -> block result
25012502
# responses(type) {|array| ...} -> block result
25022503
#
2503-
# Yields unhandled server responses and returns the result of the block.
2504-
# Unhandled responses are stored in a hash, with arrays of
2505-
# <em>non-+nil+</em> UntaggedResponse#data keyed by UntaggedResponse#name
2506-
# and ResponseCode#data keyed by ResponseCode#name.
2504+
# Yields or returns unhandled server responses. Unhandled responses are
2505+
# stored in a hash, with arrays of UntaggedResponse#data keyed by
2506+
# UntaggedResponse#name and <em>non-+nil+</em> untagged ResponseCode#data
2507+
# keyed by ResponseCode#name.
2508+
#
2509+
# When a block is given, yields unhandled responses and returns the block's
2510+
# result. Without a block, returns the unhandled responses.
25072511
#
25082512
# [With +type+]
2509-
# Yield only the array of responses for that +type+.
2510-
# When no block is given, an +ArgumentError+ is raised.
2513+
# Yield or return only the array of responses for that +type+.
2514+
# When no block is given, the returned array is a frozen copy.
25112515
# [Without +type+]
25122516
# Yield or return the entire responses hash.
25132517
#
@@ -2528,7 +2532,7 @@ def idle_done
25282532
# For example:
25292533
#
25302534
# imap.select("inbox")
2531-
# p imap.responses("EXISTS", &:last)
2535+
# p imap.responses("EXISTS").last
25322536
# #=> 2
25332537
# p imap.responses("UIDNEXT", &:last)
25342538
# #=> 123456
@@ -2586,7 +2590,7 @@ def responses(type = nil)
25862590
if block_given?
25872591
synchronize { yield(type ? @responses[type.to_s.upcase] : @responses) }
25882592
elsif type
2589-
raise ArgumentError, "Pass a block or use #clear_responses"
2593+
synchronize { @responses[type.to_s.upcase].dup.freeze }
25902594
else
25912595
case config.responses_without_block
25922596
when :raise

lib/net/imap/config.rb

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -263,10 +263,19 @@ def self.[](config)
263263
# [+:raise+ <em>(planned future default)</em>]
264264
# Raise an ArgumentError with the deprecation warning.
265265
#
266+
# Note: #responses_without_args is an alias for #responses_without_block.
266267
attr_accessor :responses_without_block, type: [
267-
:silence_deprecation_warning, :warn, :raise,
268+
:silence_deprecation_warning, :warn, :frozen_dup, :raise,
268269
]
269270

271+
alias responses_without_args responses_without_block # :nodoc:
272+
alias responses_without_args= responses_without_block= # :nodoc:
273+
274+
##
275+
# :attr_accessor: responses_without_args
276+
#
277+
# Alias for responses_without_block
278+
270279
# Creates a new config object and initialize its attribute with +attrs+.
271280
#
272281
# If +parent+ is not given, the global config is used by default.

test/net/imap/test_imap_responses.rb

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,12 +89,35 @@ def for_each_config_option(imap)
8989
end
9090
end
9191

92-
# with with a type and no block: always raise an exception
92+
# with with a type and no block: always returns a frozen duplicate
9393
test "#responses(type, &nil)" do
9494
with_fake_server do |server, imap|
95-
for_each_config_option(imap) do
96-
assert_raise(ArgumentError) do imap.responses("CAPABILITY") end
95+
stderr = EnvUtil.verbose_warning do
96+
# Config options make no difference to responses(type)
97+
for_each_config_option(imap) do
98+
# responses available before SELECT/EXAMINE
99+
assert imap.responses("CAPABILITY").frozen?
100+
assert_equal(%w[IMAP4REV1 NAMESPACE MOVE IDLE UTF8=ACCEPT],
101+
imap.responses("CAPABILITY").last)
102+
end
103+
# responses are cleared after SELECT/EXAMINE
104+
imap.select "INBOX"
105+
for_each_config_option(imap) do
106+
assert imap.responses("CAPABILITY").frozen?
107+
assert imap.responses("EXISTS").frozen?
108+
assert imap.responses("UIDVALIDITIY").frozen?
109+
assert_equal [], imap.responses("CAPABILITY")
110+
assert_equal [172], imap.responses("EXISTS")
111+
assert_equal [3857529045], imap.responses("UIDVALIDITY")
112+
assert_equal 1, imap.responses("RECENT").last
113+
assert imap.responses("UIDNEXT").frozen?
114+
assert_equal [4392], imap.responses("UIDNEXT")
115+
assert imap.responses("FLAGS").frozen?
116+
assert_equal(%i[Answered Flagged Deleted Seen Draft],
117+
imap.responses("FLAGS").last)
118+
end
97119
end
120+
assert_empty stderr # never warn when type is given
98121
end
99122
end
100123

0 commit comments

Comments
 (0)