Skip to content

Commit 716804f

Browse files
committed
🔧🏷 Add type coercion for config attributes
This is implemented as another module included under the other two, still based on overriding `attr_accessor`. Types are only enforced by the attr_writer methods. Fortunately, rdoc isn't confused by keyword arguments to `attr_accessor`, so the type can be added to that. Currently, only `:boolean` and `Integer` are supported, but it should be easy to add more.
1 parent fd518a5 commit 716804f

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

lib/net/imap/config.rb

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
require_relative "config/attr_accessors"
55
require_relative "config/attr_inheritance"
6+
require_relative "config/attr_type_coercion"
67

78
module Net
89
class IMAP
@@ -48,14 +49,19 @@ def self.[](config) # :nodoc: unfinished API
4849

4950
include AttrAccessors
5051
include AttrInheritance
52+
include AttrTypeCoercion
5153

5254
# The debug mode (boolean)
5355
#
5456
# | Starting with version | The default value is |
5557
# |-----------------------|----------------------|
5658
# | _original_ | +false+ |
57-
attr_accessor :debug
58-
alias debug? debug
59+
attr_accessor :debug, type: :boolean
60+
61+
# method: debug?
62+
# :call-seq: debug? -> boolean
63+
#
64+
# Alias for #debug
5965

6066
# Seconds to wait until a connection is opened.
6167
#
@@ -65,15 +71,15 @@ def self.[](config) # :nodoc: unfinished API
6571
# | Starting with version | The default value is |
6672
# |-----------------------|----------------------|
6773
# | _original_ | +30+ seconds |
68-
attr_accessor :open_timeout
74+
attr_accessor :open_timeout, type: Integer
6975

7076
# Seconds to wait until an IDLE response is received, after
7177
# the client asks to leave the IDLE state. See Net::IMAP#idle_done.
7278
#
7379
# | Starting with version | The default value is |
7480
# |-----------------------|----------------------|
7581
# | _original_ | +5+ seconds |
76-
attr_accessor :idle_response_timeout
82+
attr_accessor :idle_response_timeout, type: Integer
7783

7884
# Creates a new config object and initialize its attribute with +attrs+.
7985
#
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
# frozen_string_literal: true
2+
3+
module Net
4+
class IMAP
5+
class Config
6+
# Adds a +type+ keyword parameter to +attr_accessor+, which enforces
7+
# config attributes have valid types, for example: boolean, numeric,
8+
# enumeration, non-nullable, etc.
9+
module AttrTypeCoercion
10+
# :stopdoc: internal APIs only
11+
12+
module Macros # :nodoc: internal API
13+
def attr_accessor(attr, type: nil)
14+
super(attr)
15+
AttrTypeCoercion.attr_accessor(attr, type: type)
16+
end
17+
end
18+
private_constant :Macros
19+
20+
def self.included(mod)
21+
mod.extend Macros
22+
end
23+
private_class_method :included
24+
25+
def self.attr_accessor(attr, type: nil)
26+
return unless type
27+
if :boolean == type then boolean attr
28+
elsif Integer == type then integer attr
29+
else raise ArgumentError, "unknown type coercion %p" % [type]
30+
end
31+
end
32+
33+
def self.boolean(attr)
34+
define_method :"#{attr}=" do |val| super !!val end
35+
define_method :"#{attr}?" do send attr end
36+
end
37+
38+
def self.integer(attr)
39+
define_method :"#{attr}=" do |val| super Integer val end
40+
end
41+
42+
end
43+
end
44+
end
45+
end

test/net/imap/test_config.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,28 @@ class ConfigTest < Test::Unit::TestCase
2828
refute config.debug?
2929
end
3030

31+
test "boolean type constraints and conversion" do
32+
config = Config.new
33+
config.debug = 111
34+
assert_equal true, config.debug
35+
config.debug = nil
36+
assert_equal false, config.debug
37+
end
38+
39+
test "integer type constraints and conversion" do
40+
config = Config.new
41+
config.open_timeout = "111"
42+
assert_equal 111, config.open_timeout
43+
config.open_timeout = 222.0
44+
assert_equal 222, config.open_timeout
45+
config.open_timeout = 333.3
46+
assert_equal 333, config.open_timeout
47+
assert_raise(ArgumentError) do
48+
config.open_timeout = "444 NaN"
49+
end
50+
assert_equal 333, config.open_timeout
51+
end
52+
3153
test ".default" do
3254
default = Config.default
3355
assert default.equal?(Config.default)

0 commit comments

Comments
 (0)