option_initializer 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +59 -6
- data/lib/option_initializer.rb +124 -46
- data/lib/option_initializer/version.rb +1 -1
- data/option_initializer.gemspec +2 -0
- data/test/test_option_initializer.rb +192 -30
- metadata +19 -3
data/README.md
CHANGED
@@ -15,12 +15,15 @@ require 'option_initializer'
|
|
15
15
|
|
16
16
|
class Person
|
17
17
|
include OptionInitializer
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
|
19
|
+
option_initializer :id,
|
20
|
+
:name => String,
|
21
|
+
:greetings => :&,
|
22
|
+
:birthday => 1..3,
|
23
|
+
:sex => Set[:male, :female]
|
24
|
+
|
25
|
+
option_validator :name do |v|
|
26
|
+
raise ArgumentError, "invalid name" if v.empty?
|
24
27
|
end
|
25
28
|
|
26
29
|
def initialize opts
|
@@ -39,6 +42,7 @@ john = Person.
|
|
39
42
|
birthday(1990, 1, 1).
|
40
43
|
greetings { |name| "Hi, I'm #{name}!" }.
|
41
44
|
id(1000).
|
45
|
+
sex(:male).
|
42
46
|
new
|
43
47
|
|
44
48
|
# becomes equivalent to
|
@@ -46,6 +50,7 @@ john = Person.new(
|
|
46
50
|
:id => 1000,
|
47
51
|
:name => 'John Doe',
|
48
52
|
:birthday => [1990, 1, 1],
|
53
|
+
:sex => :male,
|
49
54
|
:greetings => proc { |name| "Hi, I'm #{name}!" }
|
50
55
|
)
|
51
56
|
|
@@ -62,3 +67,51 @@ Person.
|
|
62
67
|
say_hello
|
63
68
|
```
|
64
69
|
|
70
|
+
## Option definitions and validators
|
71
|
+
|
72
|
+
```ruby
|
73
|
+
class MyClass
|
74
|
+
include OptionInitializer
|
75
|
+
|
76
|
+
option_initializer :a, # Single object of any type
|
77
|
+
:b => 2, # Two objects of any type
|
78
|
+
:c => 1..3, # 1, 2, or 3 objects of any type
|
79
|
+
:d => :*, # Any number of objects of any type
|
80
|
+
:e => :&, # Block
|
81
|
+
:f => Fixnum, # Single Fixnum object
|
82
|
+
:g => [Fixnum, String, Symbol], # Fixnum, String, and Symbol
|
83
|
+
:h => Set[true, false], # Value must be either true or false
|
84
|
+
:i => [Fixnum, Set[true, false]] # Fixnum and boolean
|
85
|
+
|
86
|
+
# Validator for :f
|
87
|
+
option_validator :f do |v|
|
88
|
+
raise ArgumentError if v < 0
|
89
|
+
end
|
90
|
+
|
91
|
+
# Generic validator
|
92
|
+
option_validator do |k, v|
|
93
|
+
case k
|
94
|
+
when :a
|
95
|
+
# ...
|
96
|
+
when :b
|
97
|
+
# ...
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def initialize arg1, arg2, options
|
102
|
+
validate_options options
|
103
|
+
@options = options
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
object = MyClass.a(o).
|
108
|
+
b(o1, o2).
|
109
|
+
c(o1, o2, o3).
|
110
|
+
d(o1, o2).
|
111
|
+
e { |o| o ** o }.
|
112
|
+
f(f).
|
113
|
+
g(f, str, sym).
|
114
|
+
h(true).
|
115
|
+
i(100, false).
|
116
|
+
new(a1, a2)
|
117
|
+
```
|
data/lib/option_initializer.rb
CHANGED
@@ -1,12 +1,11 @@
|
|
1
|
-
require
|
1
|
+
require 'option_initializer/version'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module OptionInitializer
|
4
5
|
class OptionInitializingTemplate
|
5
6
|
attr_reader :options
|
6
7
|
alias to_h options
|
7
8
|
|
8
|
-
const_set :VALIDATORS, []
|
9
|
-
|
10
9
|
def initialize base, options, need_validation
|
11
10
|
validate options if need_validation
|
12
11
|
@base = base
|
@@ -42,10 +41,13 @@ module OptionInitializer
|
|
42
41
|
end
|
43
42
|
|
44
43
|
def validate hash
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
44
|
+
avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s|
|
45
|
+
self.class.const_get(s)
|
46
|
+
}
|
47
|
+
hash.each do |k, v|
|
48
|
+
avals[k] && avals[k].call(v)
|
49
|
+
vals[k] && vals[k].call(v)
|
50
|
+
vals[nil] && vals[nil].call(k, v)
|
49
51
|
end
|
50
52
|
end
|
51
53
|
end
|
@@ -65,19 +67,25 @@ module OptionInitializer
|
|
65
67
|
raise TypeError,
|
66
68
|
"wrong argument type #{options.class} (expected Hash)" unless
|
67
69
|
options.is_a?(Hash)
|
68
|
-
return if options.respond_to?(:option_validated?)
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
70
|
+
return if options.respond_to?(:option_validated?) && options.option_validated?
|
71
|
+
avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s|
|
72
|
+
self.class.const_get(:OptionInitializing).const_get(s)
|
73
|
+
}
|
74
|
+
options.each do |k, v|
|
75
|
+
avals[k] && avals[k].call(v)
|
76
|
+
vals[k] && vals[k].call(v)
|
77
|
+
vals[nil] && vals[nil].call(k, v)
|
74
78
|
end
|
75
79
|
options
|
76
80
|
end
|
77
81
|
|
78
82
|
def self.included base
|
79
83
|
unless base.constants.map(&:to_sym).include?(:OptionInitializing)
|
80
|
-
base.const_set :OptionInitializing, OptionInitializingTemplate.dup
|
84
|
+
base.const_set :OptionInitializing, oi = OptionInitializingTemplate.dup
|
85
|
+
oi.class_eval do
|
86
|
+
const_set :VALIDATORS, {}
|
87
|
+
const_set :ARG_VALIDATORS, {}
|
88
|
+
end
|
81
89
|
end
|
82
90
|
|
83
91
|
base.class_eval do
|
@@ -87,11 +95,12 @@ module OptionInitializer
|
|
87
95
|
end
|
88
96
|
end
|
89
97
|
|
90
|
-
def base.option_validator &block
|
98
|
+
def base.option_validator sym = nil, &block
|
91
99
|
raise ArgumentError, "block must be given" unless block
|
92
|
-
|
100
|
+
a = sym ? 1 : 2
|
101
|
+
raise ArgumentError, "invalid arity (expected: #{a})" unless block.arity == a
|
93
102
|
oi = self.const_get(:OptionInitializing)
|
94
|
-
oi.const_get(:VALIDATORS)
|
103
|
+
oi.const_get(:VALIDATORS)[sym] = block
|
95
104
|
end
|
96
105
|
|
97
106
|
def base.option_initializer *syms
|
@@ -103,16 +112,98 @@ module OptionInitializer
|
|
103
112
|
arr << [sym.to_sym, 1]
|
104
113
|
when Hash
|
105
114
|
arr.concat sym.map { |k, v|
|
106
|
-
|
107
|
-
|
115
|
+
case v
|
116
|
+
when Fixnum
|
117
|
+
raise ArgumentError, "invalid number of arguments specified for #{k}" if v <= 0
|
118
|
+
when Range
|
119
|
+
raise ArgumentError, "invalid number of arguments specified for #{k}" if v.begin < 0
|
120
|
+
when Set
|
121
|
+
raise ArgumentError, "empty set of values specified for #{k}" if v.length == 0
|
122
|
+
when Array
|
123
|
+
raise ArgumentError, "invalid option definition: `#{v}'" unless v.all? { |e| e.is_a?(Class) || e.is_a?(Set) }
|
124
|
+
when Class, :*, :&
|
125
|
+
# noop
|
126
|
+
else
|
127
|
+
raise ArgumentError, "invalid option definition: `#{v}'"
|
108
128
|
end
|
109
129
|
[k.to_sym, v]
|
110
130
|
}
|
111
131
|
else
|
112
|
-
raise ArgumentError, "invalid option
|
132
|
+
raise ArgumentError, "invalid option definition"
|
113
133
|
end
|
114
134
|
}
|
115
135
|
|
136
|
+
# Setup validators
|
137
|
+
vals = oi.const_get(:ARG_VALIDATORS)
|
138
|
+
pairs.each do |pair|
|
139
|
+
sym, nargs = pair
|
140
|
+
case nargs
|
141
|
+
when :&
|
142
|
+
vals[sym] = proc { |v|
|
143
|
+
if !v.is_a?(Proc)
|
144
|
+
raise TypeError, "wrong argument type #{v.class} (expected Proc)"
|
145
|
+
end
|
146
|
+
}
|
147
|
+
when 1
|
148
|
+
# good to go
|
149
|
+
vals.delete sym
|
150
|
+
when :*
|
151
|
+
vals[sym] = proc { |v|
|
152
|
+
if !v.is_a?(Array)
|
153
|
+
raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
|
154
|
+
end
|
155
|
+
}
|
156
|
+
when Fixnum
|
157
|
+
vals[sym] = proc { |v|
|
158
|
+
if !v.is_a?(Array)
|
159
|
+
raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
|
160
|
+
elsif nargs != v.length
|
161
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
|
162
|
+
end
|
163
|
+
}
|
164
|
+
when Range
|
165
|
+
vals[sym] = proc { |v|
|
166
|
+
if !v.is_a?(Array)
|
167
|
+
raise ArgumentError, "wrong number of arguments (1 for #{nargs})"
|
168
|
+
elsif !nargs.include?(v.length)
|
169
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
|
170
|
+
end
|
171
|
+
}
|
172
|
+
when Set
|
173
|
+
vals[sym] = proc { |v|
|
174
|
+
if !nargs.include?(v)
|
175
|
+
raise ArgumentError, "invalid option value: `#{v}' (expected one of #{nargs.to_a.inspect})"
|
176
|
+
end
|
177
|
+
}
|
178
|
+
when Array
|
179
|
+
vals[sym] = proc { |v|
|
180
|
+
if !v.is_a?(Array)
|
181
|
+
raise ArgumentError, "wrong number of arguments (1 for #{nargs.length})"
|
182
|
+
elsif nargs.length != v.length
|
183
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs.length})"
|
184
|
+
else
|
185
|
+
v.zip(nargs).each do |ec|
|
186
|
+
e, c = ec
|
187
|
+
case c
|
188
|
+
when Class
|
189
|
+
raise TypeError, "wrong argument type #{e.class} (expected #{c})" unless e.is_a?(c)
|
190
|
+
when Set
|
191
|
+
unless c.include?(e)
|
192
|
+
raise ArgumentError, "invalid option value: `#{e}' (expected one of #{c.to_a.inspect})"
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
end
|
197
|
+
}
|
198
|
+
when Class
|
199
|
+
vals[sym] = proc { |v|
|
200
|
+
if !v.is_a?(nargs)
|
201
|
+
raise TypeError, "wrong argument type #{v.class} (expected #{nargs})"
|
202
|
+
end
|
203
|
+
}
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
116
207
|
# Class methods
|
117
208
|
pairs.each do |pair|
|
118
209
|
sym = pair.first
|
@@ -133,38 +224,25 @@ module OptionInitializer
|
|
133
224
|
sym, nargs = pair
|
134
225
|
undef_method(sym) if method_defined?(sym)
|
135
226
|
define_method(sym) do |*v, &b|
|
136
|
-
|
137
|
-
|
138
|
-
if b
|
139
|
-
if v.empty?
|
140
|
-
merge(sym => b)
|
141
|
-
else
|
142
|
-
raise ArgumentError, "only block expected"
|
143
|
-
end
|
144
|
-
else
|
145
|
-
raise ArgumentError, "block expected but not given"
|
146
|
-
end
|
147
|
-
when 1
|
148
|
-
if b && v.empty?
|
227
|
+
if nargs == :&
|
228
|
+
if v.empty?
|
149
229
|
merge(sym => b)
|
150
|
-
elsif b && !v.empty?
|
151
|
-
raise ArgumentError, "wrong number of arguments (#{v.length} for 0 when block given)"
|
152
|
-
elsif v.length == 1
|
153
|
-
merge(sym => v.first)
|
154
230
|
else
|
155
|
-
raise ArgumentError, "wrong number of arguments (#{v.length} for
|
231
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 0)"
|
156
232
|
end
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
233
|
+
elsif b
|
234
|
+
raise ArgumentError, "block not expected"
|
235
|
+
else
|
236
|
+
case nargs
|
237
|
+
when 1, Class, Set
|
238
|
+
if v.length == 1
|
239
|
+
merge(sym => v.first)
|
240
|
+
else
|
241
|
+
raise ArgumentError, "wrong number of arguments (#{v.length} for 1)"
|
242
|
+
end
|
163
243
|
else
|
164
244
|
merge(sym => v)
|
165
245
|
end
|
166
|
-
else
|
167
|
-
raise ArgumentError, "invalid option specification"
|
168
246
|
end
|
169
247
|
end
|
170
248
|
end
|
data/option_initializer.gemspec
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
$VERBOSE = true
|
2
2
|
|
3
3
|
require 'rubygems'
|
4
|
+
require 'simplecov'
|
5
|
+
SimpleCov.start
|
4
6
|
require 'minitest/autorun'
|
5
7
|
require 'option_initializer'
|
8
|
+
require 'set'
|
6
9
|
|
7
10
|
class MyClass
|
8
11
|
include OptionInitializer
|
9
|
-
option_initializer :aaa, :bbb
|
10
|
-
option_initializer :ccc, :ddd
|
12
|
+
option_initializer :aaa, :bbb => 1
|
11
13
|
option_initializer :ccc, :ddd
|
14
|
+
option_initializer :ccc, :ddd => :&
|
12
15
|
|
13
16
|
attr_reader :a, :b, :options, :y
|
14
17
|
|
@@ -38,19 +41,23 @@ class MyClass2
|
|
38
41
|
option_initializer! :aaa
|
39
42
|
option_initializer :bbb, :ccc
|
40
43
|
option_validator do |k, v|
|
41
|
-
@@validate_count +=
|
44
|
+
@@validate_count += 100
|
42
45
|
case k
|
43
46
|
when :aaa
|
44
|
-
raise ArgumentError
|
47
|
+
raise ArgumentError
|
45
48
|
end
|
46
49
|
end
|
47
50
|
option_validator do |k, v|
|
48
51
|
@@validate_count += 1
|
49
52
|
case k
|
50
53
|
when :aaa
|
51
|
-
raise ArgumentError if v
|
54
|
+
raise ArgumentError if v == 0
|
52
55
|
end
|
53
56
|
end
|
57
|
+
option_validator :aaa do |v|
|
58
|
+
@@validate_count += 1
|
59
|
+
raise ArgumentError if v < 0
|
60
|
+
end
|
54
61
|
|
55
62
|
def initialize options
|
56
63
|
validate_options options
|
@@ -79,14 +86,15 @@ class MyClass3
|
|
79
86
|
end
|
80
87
|
end
|
81
88
|
|
82
|
-
class
|
89
|
+
class MyClassVarArgs
|
83
90
|
attr_reader :options
|
84
91
|
|
85
92
|
include OptionInitializer
|
86
93
|
option_initializer :two => 2,
|
87
94
|
:two_or_three => 2..3,
|
88
95
|
:yet_two_or_three => 2...4,
|
89
|
-
:b =>
|
96
|
+
:b => :&,
|
97
|
+
:v => :*
|
90
98
|
|
91
99
|
def initialize options
|
92
100
|
validate_options @options = options
|
@@ -97,15 +105,36 @@ class MyClass5
|
|
97
105
|
include OptionInitializer
|
98
106
|
end
|
99
107
|
|
108
|
+
class MyClassWithTypes
|
109
|
+
include OptionInitializer
|
110
|
+
option_initializer :a => Fixnum,
|
111
|
+
:b => String,
|
112
|
+
:c => Numeric,
|
113
|
+
:d => Array,
|
114
|
+
:e => [Fixnum, String, Array],
|
115
|
+
:f => Set[true, false],
|
116
|
+
:g => [ Set[true, false], Set[1, 2, 3] ]
|
117
|
+
|
118
|
+
attr_reader :options
|
119
|
+
def initialize options
|
120
|
+
validate_options options
|
121
|
+
@options = options
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
100
125
|
# Excerpt from README
|
101
126
|
class Person
|
102
127
|
include OptionInitializer
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
128
|
+
|
129
|
+
option_initializer :id,
|
130
|
+
:name => String,
|
131
|
+
:greetings => :&,
|
132
|
+
:birthday => 1..3,
|
133
|
+
:sex => Set[:male, :female]
|
134
|
+
option_initializer!
|
135
|
+
|
136
|
+
option_validator :name do |v|
|
137
|
+
raise ArgumentError, "invalid name" if v.empty?
|
109
138
|
end
|
110
139
|
|
111
140
|
def initialize opts
|
@@ -119,6 +148,16 @@ class Person
|
|
119
148
|
end
|
120
149
|
|
121
150
|
class TestOptionInitializer < MiniTest::Unit::TestCase
|
151
|
+
def assert_raises x, &b
|
152
|
+
begin
|
153
|
+
b.call
|
154
|
+
assert false
|
155
|
+
rescue Exception => e
|
156
|
+
puts "#{e.class}: #{e}"
|
157
|
+
assert e.is_a?(x)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
122
161
|
def test_oi
|
123
162
|
o = MyClass.aaa(1).bbb(2).ddd { 4 }.ccc(3).new(1, 2)
|
124
163
|
assert_equal 1, o.options[:aaa]
|
@@ -129,11 +168,11 @@ class TestOptionInitializer < MiniTest::Unit::TestCase
|
|
129
168
|
assert_equal 2, o.b
|
130
169
|
assert_equal nil, o.y
|
131
170
|
|
132
|
-
o = MyClass.aaa(1).bbb(2).ccc(3).aaa(4).new(1, 2, :ddd => 4) { :y }
|
171
|
+
o = MyClass.aaa(1).bbb(2).ccc(3).aaa(4).new(1, 2, :ddd => proc { 4 }) { :y }
|
133
172
|
assert_equal 4, o.options[:aaa]
|
134
173
|
assert_equal 2, o.options[:bbb]
|
135
174
|
assert_equal 3, o.options[:ccc]
|
136
|
-
assert_equal 4, o.options[:ddd]
|
175
|
+
assert_equal 4, o.options[:ddd].call
|
137
176
|
assert_equal 1, o.a
|
138
177
|
assert_equal 2, o.b
|
139
178
|
assert_equal :y, o.y
|
@@ -146,9 +185,18 @@ class TestOptionInitializer < MiniTest::Unit::TestCase
|
|
146
185
|
assert_raises(ArgumentError) { MyClass.aaa(1).new(1, 2, 3) }
|
147
186
|
end
|
148
187
|
|
188
|
+
def test_default_1
|
189
|
+
MyClass.aaa(1)
|
190
|
+
assert_raises(ArgumentError) { MyClass.aaa { } }
|
191
|
+
|
192
|
+
MyClass.bbb(1)
|
193
|
+
assert_raises(ArgumentError) { MyClass.bbb { } }
|
194
|
+
end
|
195
|
+
|
149
196
|
def test_method_missing
|
150
197
|
assert_equal 2, MyClass2.aaa(1).bbb(2).num_options(true)
|
151
198
|
assert_equal 2, MyClass2.aaa(1).bbb(2).echo(1) { |a| a * 2 }
|
199
|
+
assert_raises(NoMethodError) { MyClass2.aaa(1).bbb(2).echo? }
|
152
200
|
|
153
201
|
assert_raises(NoMethodError) do
|
154
202
|
MyClass3.aaa(1).bbb(2).echo(1) { |a| a * 2 }
|
@@ -169,37 +217,69 @@ class TestOptionInitializer < MiniTest::Unit::TestCase
|
|
169
217
|
|
170
218
|
MyClass2.reset_count
|
171
219
|
MyClass2.aaa(1).bbb(2)
|
172
|
-
assert_equal 2 +
|
220
|
+
assert_equal 2 + 1, MyClass2.count
|
173
221
|
|
174
222
|
MyClass2.reset_count
|
175
223
|
MyClass2.aaa(1).bbb(2).new(:aaa => 3)
|
176
|
-
assert_equal 2 +
|
224
|
+
assert_equal 2 + 1 + 2, MyClass2.count
|
177
225
|
|
178
226
|
MyClass2.reset_count
|
179
227
|
MyClass2.aaa(1).bbb(2).new
|
180
|
-
assert_equal 2 +
|
228
|
+
assert_equal 2 + 1, MyClass2.count
|
181
229
|
|
182
230
|
MyClass2.reset_count
|
183
231
|
MyClass2.new :aaa => 1, :bbb => 2
|
184
|
-
assert_equal
|
232
|
+
assert_equal 2 + 1, MyClass2.count
|
185
233
|
|
186
234
|
assert_raises(TypeError) { MyClass2.new 'str' }
|
187
235
|
end
|
188
236
|
|
189
237
|
def test_varargs
|
190
|
-
obj =
|
238
|
+
obj = MyClassVarArgs.two(1, 2).two_or_three(2, 3, 4).yet_two_or_three(3, 4, 5).b { :r }.new
|
191
239
|
assert_equal [1, 2], obj.options[:two]
|
192
240
|
assert_equal [2, 3, 4], obj.options[:two_or_three]
|
193
241
|
assert_equal [3, 4, 5], obj.options[:yet_two_or_three]
|
194
242
|
assert_equal :r, obj.options[:b].call
|
195
|
-
assert_raises(ArgumentError) {
|
196
|
-
assert_raises(ArgumentError) {
|
197
|
-
assert_raises(ArgumentError) {
|
198
|
-
assert_raises(ArgumentError) {
|
199
|
-
assert_raises(ArgumentError) {
|
200
|
-
assert_raises(ArgumentError) {
|
201
|
-
assert_raises(ArgumentError) {
|
202
|
-
assert_raises(ArgumentError) {
|
243
|
+
assert_raises(ArgumentError) { MyClassVarArgs.two }
|
244
|
+
assert_raises(ArgumentError) { MyClassVarArgs.two(1) }
|
245
|
+
assert_raises(ArgumentError) { MyClassVarArgs.two(1, 2) { } }
|
246
|
+
assert_raises(ArgumentError) { MyClassVarArgs.two { } }
|
247
|
+
assert_raises(ArgumentError) { MyClassVarArgs.two_or_three(1) }
|
248
|
+
assert_raises(ArgumentError) { MyClassVarArgs.yet_two_or_three(1, 2, 3, 4) }
|
249
|
+
assert_raises(ArgumentError) { MyClassVarArgs.yet_two_or_three {} }
|
250
|
+
assert_raises(ArgumentError) { MyClassVarArgs.b(1) }
|
251
|
+
assert_raises(ArgumentError) { MyClassVarArgs.b(1) {} }
|
252
|
+
assert_raises(ArgumentError) { MyClassVarArgs.b(1) {} }
|
253
|
+
assert_equal [], MyClassVarArgs.v.new.options[:v]
|
254
|
+
assert_equal [1, 2, 3], MyClassVarArgs.v(1, 2, 3).new.options[:v]
|
255
|
+
|
256
|
+
MyClassVarArgs.class_eval do
|
257
|
+
option_initializer :b2 => :&
|
258
|
+
end
|
259
|
+
MyClassVarArgs.b2 {}
|
260
|
+
assert_raises(ArgumentError) { MyClassVarArgs.b2(5) }
|
261
|
+
|
262
|
+
MyClassVarArgs.class_eval do
|
263
|
+
option_initializer :b2
|
264
|
+
end
|
265
|
+
MyClassVarArgs.b2(5)
|
266
|
+
assert_raises(ArgumentError) { MyClassVarArgs.b2 {} }
|
267
|
+
end
|
268
|
+
|
269
|
+
def test_varargs_validate_options
|
270
|
+
assert_raises(TypeError) { MyClassVarArgs.new(:b => 1) }
|
271
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:two => 1) }
|
272
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:two => [1]) }
|
273
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:two_or_three => 1) }
|
274
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:two_or_three => [1]) }
|
275
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:yet_two_or_three => [1]) }
|
276
|
+
assert_raises(ArgumentError) { MyClassVarArgs.new(:v => 1) }
|
277
|
+
|
278
|
+
opts = MyClassVarArgs.new(:two => [1, 2], :two_or_three => [2, 3, 4], :v => []).options
|
279
|
+
|
280
|
+
assert_equal [1, 2], opts[:two]
|
281
|
+
assert_equal [2, 3, 4], opts[:two_or_three]
|
282
|
+
assert_equal [], opts[:v]
|
203
283
|
end
|
204
284
|
|
205
285
|
def test_varargs_def
|
@@ -212,20 +292,102 @@ class TestOptionInitializer < MiniTest::Unit::TestCase
|
|
212
292
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b => 0 } }
|
213
293
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b => 3.14 } }
|
214
294
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b => [1] } }
|
215
|
-
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b =>
|
295
|
+
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b => -1..3 } }
|
216
296
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer 3.14 } }
|
217
297
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer 3.14 => nil } }
|
218
298
|
assert_raises(ArgumentError) { MyClass5.class_eval { option_initializer :b => :block? } }
|
219
299
|
end
|
220
300
|
|
301
|
+
def test_validator_block_arity
|
302
|
+
MyClass5.class_eval { option_validator { |k, v| } }
|
303
|
+
assert_raises(ArgumentError) { MyClass5.class_eval { option_validator { |v| } } }
|
304
|
+
MyClass5.class_eval { option_validator :aaa do |v| end }
|
305
|
+
assert_raises(ArgumentError) { MyClass5.class_eval { option_validator :aaa do |k, v| end } }
|
306
|
+
end
|
307
|
+
|
308
|
+
def test_typed_option
|
309
|
+
MyClassWithTypes.a(3)
|
310
|
+
assert_raises(TypeError) { MyClassWithTypes.a('str') }
|
311
|
+
assert_raises(TypeError) { MyClassWithTypes.b(1) }
|
312
|
+
assert_raises(ArgumentError) { MyClassWithTypes.c(1, 2) }
|
313
|
+
assert_raises(ArgumentError) { MyClassWithTypes.e(1) }
|
314
|
+
assert_raises(ArgumentError) { MyClassWithTypes.e(1, 'str') }
|
315
|
+
assert_raises(TypeError) { MyClassWithTypes.e(1, 'str', :array) }
|
316
|
+
|
317
|
+
|
318
|
+
assert_raises(TypeError) { MyClassWithTypes.new(:a => 'str') }
|
319
|
+
assert_raises(ArgumentError) { MyClassWithTypes.new(:e => :e) }
|
320
|
+
assert_raises(ArgumentError) { MyClassWithTypes.new(:e => []) }
|
321
|
+
assert_raises(TypeError) { MyClassWithTypes.new(:e => [1, 1, 1]) }
|
322
|
+
|
323
|
+
[
|
324
|
+
MyClassWithTypes.a(3).b('str').c(1).c(3.14).d([1, 2, 3]).e(1, 'str', [0, 1, 2]).options,
|
325
|
+
MyClassWithTypes.new(:a => 3, :b => 'str', :c => 3.14, :d => [1, 2, 3], :e => [1, 'str', [0, 1, 2]]).options
|
326
|
+
].each do |opts|
|
327
|
+
assert_equal 3, opts[:a]
|
328
|
+
assert_equal 'str', opts[:b]
|
329
|
+
assert_equal 3.14, opts[:c]
|
330
|
+
assert_equal [1, 2, 3], opts[:d]
|
331
|
+
assert_equal [1, 'str', [0, 1, 2]], opts[:e]
|
332
|
+
|
333
|
+
end
|
334
|
+
end
|
335
|
+
|
336
|
+
def test_set
|
337
|
+
opts = MyClassWithTypes.f(true).g(false, 2).options
|
338
|
+
assert_equal true, opts[:f]
|
339
|
+
assert_equal [false, 2], opts[:g]
|
340
|
+
|
341
|
+
assert_raises(ArgumentError) { MyClassWithTypes.f(5) }
|
342
|
+
assert_raises(ArgumentError) { MyClassWithTypes.new(:f => 5) }
|
343
|
+
assert_raises(ArgumentError) { MyClassWithTypes.g(false, 10) }
|
344
|
+
assert_raises(ArgumentError) { MyClassWithTypes.g(nil, 2) }
|
345
|
+
|
346
|
+
assert_raises(ArgumentError) { MyClassWithTypes.class_eval { option_initializer :set => Set[] } }
|
347
|
+
end
|
348
|
+
|
221
349
|
def test_readme
|
222
|
-
john = Person.name('John Doe').birthday(1990, 1, 1).
|
350
|
+
john = Person.name('John Doe').birthday(1990, 1, 1).sex(:male).
|
223
351
|
greetings { |name| "Hi, I'm #{name}!" }.id(1000).new
|
224
352
|
john = Person.new :id => 1000, :name => 'John Doe',
|
225
353
|
:birthday => [1990, 1, 1],
|
354
|
+
:sex => :male,
|
226
355
|
:greetings => proc { |name| "Hi, I'm #{name}!" }
|
227
356
|
Person.name('John Doe').birthday(1990, 1, 1).
|
228
357
|
greetings { |name| "Hi, I'm #{name}!" }.id(1000).say_hello
|
229
358
|
end
|
230
359
|
end
|
231
360
|
|
361
|
+
class MyReadmeClass
|
362
|
+
include OptionInitializer
|
363
|
+
|
364
|
+
option_initializer :a, # Single object of any type
|
365
|
+
:b => 2, # Two objects of any type
|
366
|
+
:c => 1..3, # 1, 2, or 3 objects of any type
|
367
|
+
:d => :*, # Any number of objects
|
368
|
+
:e => :&, # Block
|
369
|
+
:f => Fixnum, # Single Fixnum object
|
370
|
+
:g => [Fixnum, String, Symbol] # Fixnum, String, and Symbol
|
371
|
+
|
372
|
+
# Validator for :f
|
373
|
+
option_validator :f do |v|
|
374
|
+
raise ArgumentError if v < 0
|
375
|
+
end
|
376
|
+
|
377
|
+
# Generic validator
|
378
|
+
option_validator do |k, v|
|
379
|
+
case k
|
380
|
+
when :a
|
381
|
+
# ...
|
382
|
+
when :b
|
383
|
+
# ...
|
384
|
+
else
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
def initialize options
|
389
|
+
validate_options options
|
390
|
+
@options = options
|
391
|
+
end
|
392
|
+
end
|
393
|
+
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: option_initializer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.5.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-03-
|
13
|
-
dependencies:
|
12
|
+
date: 2013-03-18 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: simplecov
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :development
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
14
30
|
description: Object construction with method chaining
|
15
31
|
email:
|
16
32
|
- junegunn.c@gmail.com
|