option_initializer 1.3.0 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -15,12 +15,15 @@ require 'option_initializer'
15
15
 
16
16
  class Person
17
17
  include OptionInitializer
18
- option_initializer :id, :name, :greetings => :block, :birthday => 1..3
19
- option_validator do |k, v|
20
- case k
21
- when :name
22
- raise ArgumentError, "invalid name" if v.empty?
23
- end
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
+ ```
@@ -1,12 +1,11 @@
1
- require "option_initializer/version"
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
- self.class.const_get(:VALIDATORS).each do |validator|
46
- hash.each do |k, v|
47
- validator.call k, v
48
- end
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
- validators = self.class.const_get(:OptionInitializing).const_get(:VALIDATORS)
70
- validators.each do |validator|
71
- options.each do |k, v|
72
- validator.call k, v
73
- end
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
- raise ArgumentError, "invalid arity (expected: 2)" unless block.arity == 2
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).push block
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
- unless (v.is_a?(Fixnum) && v > 0) || (v.is_a?(Range) && v.begin > 0) || v == :block
107
- raise ArgumentError, "invalid number of arguments specified for #{k}"
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 specification"
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
- case nargs
137
- when :block
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 1)"
231
+ raise ArgumentError, "wrong number of arguments (#{v.length} for 0)"
156
232
  end
157
- when Range, Fixnum
158
- if b
159
- raise ArgumentError, "block not expected"
160
- elsif (nargs.is_a?(Range) && !nargs.include?(v.length)) ||
161
- (nargs.is_a?(Fixnum) && nargs != v.length)
162
- raise ArgumentError, "wrong number of arguments (#{v.length} for #{nargs})"
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
@@ -1,3 +1,3 @@
1
1
  module OptionInitializer
2
- VERSION = "1.3.0"
2
+ VERSION = "1.5.0"
3
3
  end
@@ -16,4 +16,6 @@ Gem::Specification.new do |gem|
16
16
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
18
  gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'simplecov'
19
21
  end
@@ -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 += 1
44
+ @@validate_count += 100
42
45
  case k
43
46
  when :aaa
44
- raise ArgumentError if v == 0
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 < 0
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 MyClass4
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 => :block
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
- option_initializer! :id, :name, :greetings, :birthday => 1..3
104
- option_validator do |k, v|
105
- case k
106
- when :name
107
- raise ArgumentError, "invalid name" if v.empty?
108
- end
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 + 2, MyClass2.count
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 + 2 + 2, MyClass2.count
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 + 2, MyClass2.count
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 4, MyClass2.count
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 = MyClass4.two(1, 2).two_or_three(2, 3, 4).yet_two_or_three(3, 4, 5).b { :r }.new
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) { MyClass4.two(1) }
196
- assert_raises(ArgumentError) { MyClass4.two(1, 2) { } }
197
- assert_raises(ArgumentError) { MyClass4.two { } }
198
- assert_raises(ArgumentError) { MyClass4.two_or_three(1) }
199
- assert_raises(ArgumentError) { MyClass4.yet_two_or_three(1, 2, 3, 4) }
200
- assert_raises(ArgumentError) { MyClass4.yet_two_or_three {} }
201
- assert_raises(ArgumentError) { MyClass4.b(1) }
202
- assert_raises(ArgumentError) { MyClass4.b(1) {} }
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 => 0..3 } }
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.3.0
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-16 00:00:00.000000000 Z
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