option_initializer 1.5.0 → 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -17,10 +17,10 @@ class Person
17
17
  include OptionInitializer
18
18
 
19
19
  option_initializer :id,
20
- :name => String,
20
+ :name => String,
21
21
  :greetings => :&,
22
- :birthday => 1..3,
23
- :sex => Set[:male, :female]
22
+ :birthday => 1..3,
23
+ :sex => Set[:male, :female]
24
24
 
25
25
  option_validator :name do |v|
26
26
  raise ArgumentError, "invalid name" if v.empty?
@@ -78,7 +78,7 @@ class MyClass
78
78
  :c => 1..3, # 1, 2, or 3 objects of any type
79
79
  :d => :*, # Any number of objects of any type
80
80
  :e => :&, # Block
81
- :f => Fixnum, # Single Fixnum object
81
+ :f => Fixnum | Range, # Single Fixnum or Range object
82
82
  :g => [Fixnum, String, Symbol], # Fixnum, String, and Symbol
83
83
  :h => Set[true, false], # Value must be either true or false
84
84
  :i => [Fixnum, Set[true, false]] # Fixnum and boolean
@@ -1,57 +1,94 @@
1
1
  require 'option_initializer/version'
2
2
  require 'set'
3
3
 
4
- module OptionInitializer
5
- class OptionInitializingTemplate
6
- attr_reader :options
7
- alias to_h options
8
-
9
- def initialize base, options, need_validation
10
- validate options if need_validation
11
- @base = base
12
- @options = options
4
+ unless Class.respond_to?(:|)
5
+ class Class
6
+ def | other_class
7
+ unless other_class.is_a?(Class)
8
+ raise TypeError, "wrong argument type (expected: Class)"
9
+ end
10
+ OptionInitializer::ClassMatch.new(self, other_class)
13
11
  end
12
+ end
13
+ else
14
+ Kernel.warn "Class already has `|' method. OptionInitializer will not override its behavior."
15
+ end
14
16
 
15
- def new *args, &block
16
- args = args.dup
17
- opts = @options
17
+ # @private
18
+ class OptionInitializingTemplate
19
+ attr_reader :options
20
+ alias to_h options
18
21
 
19
- # Convention. Deal with it.
20
- if args.last.is_a?(Hash)
21
- validate args.last
22
- opts = opts.merge(args.last)
23
- args.pop
24
- else
25
- opts = opts.dup
26
- end
22
+ def initialize base, options, need_validation
23
+ validate options if need_validation
24
+ @base = base
25
+ @options = options
26
+ end
27
27
 
28
- opts.instance_eval do
29
- def option_validated?
30
- true
31
- end
28
+ def new *args, &block
29
+ args = args.dup
30
+ opts = @options
31
+
32
+ # Convention. Deal with it.
33
+ if args.last.is_a?(Hash)
34
+ validate args.last
35
+ opts = opts.merge(args.last)
36
+ args.pop
37
+ else
38
+ opts = opts.dup
39
+ end
40
+
41
+ opts.instance_eval do
42
+ def option_validated?
43
+ true
32
44
  end
33
- args << opts
45
+ end
46
+ args << opts
34
47
 
35
- @base.new(*args, &block)
48
+ @base.new(*args, &block)
49
+ end
50
+
51
+ def merge opts
52
+ validate opts
53
+ self.class.new @base, @options.merge(opts), false
54
+ end
55
+
56
+ def validate hash
57
+ avals, vals = [:ARG_VALIDATORS, :VALIDATORS].map { |s|
58
+ self.class.const_get(s)
59
+ }
60
+ hash.each do |k, v|
61
+ avals[k] && avals[k].call(v)
62
+ vals[k] && vals[k].call(v)
63
+ vals[nil] && vals[nil].call(k, v)
36
64
  end
65
+ end
66
+ end
37
67
 
38
- def merge opts
39
- validate opts
40
- self.class.new @base, @options.merge(opts), false
68
+ module OptionInitializer
69
+ class ClassMatch
70
+ def initialize *classes
71
+ @classes = Set[*classes]
41
72
  end
42
73
 
43
- def validate hash
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)
74
+ def | other_class
75
+ unless other_class.is_a?(Class)
76
+ raise TypeError, "wrong argument type (expected: Class)"
51
77
  end
78
+ ClassMatch.new(*@classes.union([other_class]))
79
+ end
80
+
81
+ def match object
82
+ @classes.any? { |k| object.is_a? k }
83
+ end
84
+
85
+ def to_s
86
+ a = @classes.map(&:to_s)
87
+ [a[0...-1].join(', '), a.last].reject(&:empty?).join(', or ')
52
88
  end
53
89
  end
54
90
 
91
+ # @private
55
92
  module MethodCallShortcut
56
93
  def method_missing sym, *args, &block
57
94
  # 1.8
@@ -79,6 +116,7 @@ module OptionInitializer
79
116
  options
80
117
  end
81
118
 
119
+ # @private
82
120
  def self.included base
83
121
  unless base.constants.map(&:to_sym).include?(:OptionInitializing)
84
122
  base.const_set :OptionInitializing, oi = OptionInitializingTemplate.dup
@@ -120,9 +158,13 @@ module OptionInitializer
120
158
  when Set
121
159
  raise ArgumentError, "empty set of values specified for #{k}" if v.length == 0
122
160
  when Array
123
- raise ArgumentError, "invalid option definition: `#{v}'" unless v.all? { |e| e.is_a?(Class) || e.is_a?(Set) }
161
+ unless v.all? { |e| [Class, Set, ClassMatch].any? { |kl| e.is_a?(kl) } }
162
+ raise ArgumentError, "invalid option definition: `#{v}'"
163
+ end
124
164
  when Class, :*, :&
125
165
  # noop
166
+ when ClassMatch
167
+ # noop
126
168
  else
127
169
  raise ArgumentError, "invalid option definition: `#{v}'"
128
170
  end
@@ -191,6 +233,10 @@ module OptionInitializer
191
233
  unless c.include?(e)
192
234
  raise ArgumentError, "invalid option value: `#{e}' (expected one of #{c.to_a.inspect})"
193
235
  end
236
+ when ClassMatch
237
+ unless c.match e
238
+ raise TypeError, "wrong argument type #{e.class} (expected #{c})"
239
+ end
194
240
  end
195
241
  end
196
242
  end
@@ -201,6 +247,12 @@ module OptionInitializer
201
247
  raise TypeError, "wrong argument type #{v.class} (expected #{nargs})"
202
248
  end
203
249
  }
250
+ when ClassMatch
251
+ vals[sym] = proc { |v|
252
+ unless nargs.match v
253
+ raise TypeError, "wrong argument type #{v.class} (expected #{nargs})"
254
+ end
255
+ }
204
256
  end
205
257
  end
206
258
 
@@ -234,7 +286,7 @@ module OptionInitializer
234
286
  raise ArgumentError, "block not expected"
235
287
  else
236
288
  case nargs
237
- when 1, Class, Set
289
+ when 1, Class, Set, ClassMatch
238
290
  if v.length == 1
239
291
  merge(sym => v.first)
240
292
  else
@@ -1,3 +1,3 @@
1
1
  module OptionInitializer
2
- VERSION = "1.5.0"
2
+ VERSION = "1.5.1"
3
3
  end
@@ -18,4 +18,5 @@ Gem::Specification.new do |gem|
18
18
  gem.require_paths = ["lib"]
19
19
 
20
20
  gem.add_development_dependency 'simplecov'
21
+ gem.add_development_dependency 'minitest'
21
22
  end
@@ -122,6 +122,19 @@ class MyClassWithTypes
122
122
  end
123
123
  end
124
124
 
125
+ class MyClassWithClassOrOperator
126
+ include OptionInitializer
127
+ option_initializer :a => Fixnum | Float | Range,
128
+ :b => String,
129
+ :c => [String | Symbol, Numeric]
130
+
131
+ attr_reader :options
132
+ def initialize options
133
+ validate_options options
134
+ @options = options
135
+ end
136
+ end
137
+
125
138
  # Excerpt from README
126
139
  class Person
127
140
  include OptionInitializer
@@ -356,6 +369,21 @@ class TestOptionInitializer < MiniTest::Unit::TestCase
356
369
  Person.name('John Doe').birthday(1990, 1, 1).
357
370
  greetings { |name| "Hi, I'm #{name}!" }.id(1000).say_hello
358
371
  end
372
+
373
+ def test_disjunctive_class
374
+ init = MyClassWithClassOrOperator.a(1).a(1..2).a(3.14).b('hello').c(:hello, 100)
375
+ [init, init.new].each do |obj|
376
+ assert_equal 3.14, obj.options[:a]
377
+ assert_equal 'hello', obj.options[:b]
378
+ assert_equal [:hello, 100], obj.options[:c]
379
+ end
380
+ assert_raises(TypeError) { MyClassWithClassOrOperator.a(:hello) }
381
+ assert_raises(TypeError) { MyClassWithClassOrOperator.b(1) }
382
+ assert_raises(TypeError) { MyClassWithClassOrOperator.c(1, 1) }
383
+ assert_raises(TypeError) { MyClassWithClassOrOperator.new(:a => :hello) }
384
+ assert_raises(TypeError) { MyClassWithClassOrOperator.new(:b => 1) }
385
+ assert_raises(TypeError) { MyClassWithClassOrOperator.new(:c => [1, 1]) }
386
+ end
359
387
  end
360
388
 
361
389
  class MyReadmeClass
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.5.0
4
+ version: 1.5.1
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-03-18 00:00:00.000000000 Z
12
+ date: 2013-04-07 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: simplecov
@@ -27,6 +27,22 @@ dependencies:
27
27
  - - ! '>='
28
28
  - !ruby/object:Gem::Version
29
29
  version: '0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: minitest
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '0'
30
46
  description: Object construction with method chaining
31
47
  email:
32
48
  - junegunn.c@gmail.com