Skip to content

Commit 1741c0a

Browse files
committed
🔧 Add default configs for each x.y version
1 parent c1891ed commit 1741c0a

File tree

2 files changed

+101
-3
lines changed

2 files changed

+101
-3
lines changed

lib/net/imap/config.rb

Lines changed: 71 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -54,22 +54,66 @@ class IMAP
5454
# plain_client.config.inherited?(:debug) # => true
5555
# plain_client.config.debug? # => false
5656
#
57+
# == Versioned defaults
58+
#
59+
# The effective default configuration for a specific +x.y+ version of
60+
# +net-imap+ can be loaded with the +config+ keyword argument to
61+
# Net::IMAP.new. Requesting default configurations for previous versions
62+
# enables extra backward compatibility with those versions:
63+
#
64+
# client = Net::IMAP.new(hostname, config: 0.3)
65+
# client.config.sasl_ir # => false
66+
# client.config.responses_without_block # => :silence_deprecation_warning
67+
#
68+
# client = Net::IMAP.new(hostname, config: 0.4)
69+
# client.config.sasl_ir # => true
70+
# client.config.responses_without_block # => :silence_deprecation_warning
71+
#
72+
# client = Net::IMAP.new(hostname, config: 0.5)
73+
# client.config.sasl_ir # => true
74+
# client.config.responses_without_block # => :warn
75+
#
76+
# The versioned default configs inherit certain specific config options from
77+
# Config.global, for example #debug:
78+
#
79+
# client = Net::IMAP.new(hostname, config: 0.4)
80+
# Net::IMAP.debug = false
81+
# client.config.debug? # => false
82+
#
83+
# Net::IMAP.debug = true
84+
# client.config.debug? # => true
5785
#
5886
# == Thread Safety
5987
#
6088
# *NOTE:* Updates to config objects are not synchronized for thread-safety.
6189
#
6290
class Config
91+
# Array of attribute names that are _not_ loaded by #load_defaults.
92+
DEFAULT_TO_INHERIT = %i[debug].freeze
93+
private_constant :DEFAULT_TO_INHERIT
94+
6395
# The default config, which is hardcoded and frozen.
6496
def self.default; @default end
6597

6698
# The global config object. Also available from Net::IMAP.config.
6799
def self.global; @global end
68100

101+
# A hash of hard-coded configurations, indexed by version number.
102+
def self.version_defaults; @version_defaults end
103+
@version_defaults = {}
104+
69105
# :call-seq:
106+
# Net::IMAP::Config[number] -> versioned config
107+
# Net::IMAP::Config[symbol] -> named config
70108
# Net::IMAP::Config[hash] -> new frozen config
71109
# Net::IMAP::Config[config] -> same config
72110
#
111+
# Given a version number, returns the default configuration for the target
112+
# version. See Config@Versioned+defaults.
113+
#
114+
# Given a version name, returns the default configuration for the target
115+
# version. See Config@Named+defaults.
116+
#
73117
# Given a Hash, creates a new _frozen_ config which inherits from
74118
# Config.global. Use Config.new for an unfrozen config.
75119
#
@@ -80,9 +124,16 @@ def self.[](config)
80124
elsif config.respond_to?(:to_hash)
81125
new(global, **config).freeze
82126
else
83-
raise TypeError, "no implicit conversion of %s to %s" % [
84-
config.class, Config
85-
]
127+
version_defaults.fetch(config) {
128+
case config
129+
when Numeric
130+
raise RangeError, "unknown config version: %p" % [config]
131+
else
132+
raise TypeError, "no implicit conversion of %s to %s" % [
133+
config.class, Config
134+
]
135+
end
136+
}
86137
end
87138
end
88139

@@ -208,6 +259,23 @@ def to_h; data.members.to_h { [_1, send(_1)] } end
208259

209260
@global = default.new
210261

262+
version_defaults[0.4] = Config[
263+
default.to_h.reject {|k,v| DEFAULT_TO_INHERIT.include?(k) }
264+
]
265+
266+
version_defaults[0] = Config[0.4].dup.update(
267+
sasl_ir: false,
268+
).freeze
269+
version_defaults[0.0] = Config[0]
270+
version_defaults[0.1] = Config[0]
271+
version_defaults[0.2] = Config[0]
272+
version_defaults[0.3] = Config[0]
273+
274+
version_defaults[0.5] = Config[0.4].dup.update(
275+
responses_without_block: :warn,
276+
).freeze
277+
278+
version_defaults.freeze
211279
end
212280
end
213281
end

test/net/imap/test_config.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,35 @@ class ConfigTest < Test::Unit::TestCase
135135
assert_equal false, child.debug?
136136
end
137137

138+
test ".version_defaults are all frozen, and inherit debug from global" do
139+
Config.version_defaults.each do |name, config|
140+
assert [0, Float, Symbol].any? { _1 === name }
141+
assert_kind_of Config, config
142+
assert config.frozen?, "#{name} isn't frozen"
143+
assert config.inherited?(:debug), "#{name} doesn't inherit debug"
144+
assert_same Config.global, config.parent
145+
end
146+
end
147+
148+
test ".[] for all x.y versions" do
149+
original = Config[0]
150+
assert_kind_of Config, original
151+
assert_same original, Config[0.0]
152+
assert_same original, Config[0.1]
153+
assert_same original, Config[0.2]
154+
assert_same original, Config[0.3]
155+
assert_kind_of Config, Config[0.4]
156+
assert_kind_of Config, Config[0.5]
157+
end
158+
159+
test ".[] range errors" do
160+
assert_raise(RangeError) do Config[0.01] end
161+
assert_raise(RangeError) do Config[0.11] end
162+
assert_raise(RangeError) do Config[0.111] end
163+
assert_raise(RangeError) do Config[0.9] end
164+
assert_raise(RangeError) do Config[1] end
165+
end
166+
138167
test ".[] with a hash" do
139168
config = Config[{responses_without_block: :raise, sasl_ir: false}]
140169
assert config.frozen?
@@ -149,6 +178,7 @@ class ConfigTest < Test::Unit::TestCase
149178
assert_same Config.global, Config.new.parent
150179
assert_same Config.default, Config.new(Config.default).parent
151180
assert_same Config.global, Config.new(Config.global).parent
181+
assert_same Config[0.4], Config.new(0.4).parent
152182
assert_equal true, Config.new({debug: true}, debug: false).parent.debug?
153183
assert_equal true, Config.new({debug: true}, debug: false).parent.frozen?
154184
end

0 commit comments

Comments
 (0)