oval 0.0.5 → 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +5 -0
- data/Modulefile +1 -1
- data/README.md +67 -58
- data/oval.gemspec +1 -1
- data/spec/unit/oval/base_spec.rb +28 -62
- data/spec/unit/oval_spec.rb +2 -2
- metadata +4 -4
data/CHANGELOG
CHANGED
@@ -1,4 +1,9 @@
|
|
1
|
+
2014-02-08 Pawel Tomulik <ptomulik@meil.pw.edu.pl>
|
2
|
+
* release 0.0.6
|
3
|
+
* documented a way for validating arbitrary arguments
|
1
4
|
2014-02-03 Pawel Tomulik <ptomulik@meil.pw.edu.pl>
|
5
|
+
* added more navigation links to README.md
|
6
|
+
* added specs for Oval::Base.it_should
|
2
7
|
* release 0.0.5
|
3
8
|
* refactored ensure_match -> validate
|
4
9
|
* added Oval::Match declarator
|
data/Modulefile
CHANGED
data/README.md
CHANGED
@@ -18,17 +18,18 @@
|
|
18
18
|
|
19
19
|
##<a id="overview"></a>Overview
|
20
20
|
|
21
|
-
Validate option hashes when passed to methods.
|
21
|
+
Validate arguments and option hashes when passed to methods.
|
22
22
|
|
23
23
|
[[Table of Contents](#table-of-contents)]
|
24
24
|
|
25
25
|
##<a id="module-description"></a>Module Description
|
26
26
|
|
27
|
-
|
28
|
-
|
29
|
-
|
27
|
+
This module implements simple to use data validators. It was initially thought
|
28
|
+
to validate option hashes (so the name *Oval* stands for Options' Validator),
|
29
|
+
but it appeared early that it's suitable to validate arbitrary parameters
|
30
|
+
(variables).
|
30
31
|
|
31
|
-
The shape of acceptable
|
32
|
+
The shape of acceptable data is described by a simple grammar. The validation
|
32
33
|
is then carried out by a recursive-descent parser that matches the actual
|
33
34
|
values provided by caller against [declarators](#declarators) that comprise the
|
34
35
|
hash declaration.
|
@@ -38,28 +39,27 @@ declarators are created by methods of `Oval` module which have names starting
|
|
38
39
|
with `ov_` prefix. All other values (such as `:symbol`, `'string'`, `nil`, or
|
39
40
|
`Class`) are terminals. Terminals use `==` operator to match the values
|
40
41
|
provided by caller. Non-terminal use its own logic introducing more elaborate
|
41
|
-
matching criteria (see for example [
|
42
|
+
matching criteria (see for example [ov\_collection](#ov_collection)).
|
42
43
|
|
43
|
-
**Oval** raises **Oval::DeclError** if the declaration is not well-formed
|
44
|
-
is
|
45
|
-
|
46
|
-
|
47
|
-
a method which takes the options as an argument.
|
44
|
+
**Oval** raises **Oval::DeclError** if the declaration is not well-formed. This
|
45
|
+
is raised from the point of declaration. Other, more common exception is the
|
46
|
+
**Oval::ValueError** which is raised each time the validation fails. This one
|
47
|
+
is raised from within a method which validates its arguments.
|
48
48
|
|
49
49
|
[[Table of Contents](#table-of-contents)]
|
50
50
|
|
51
51
|
##<a id="usage"></a>Usage
|
52
52
|
|
53
53
|
The usage is basically a two-step procedure. The first step is to declare
|
54
|
-
|
55
|
-
validate
|
56
|
-
|
57
|
-
|
54
|
+
data to be validated. This would create a validator object. The second step is
|
55
|
+
to validate data using the previously constructed validator. For simple cases
|
56
|
+
the entire construction may fit to a single line. Let's start with such a
|
57
|
+
simple example.
|
58
58
|
|
59
59
|
###<a id="example-1-declaring-simple-options"></a>Example 1: Declaring Simple Options
|
60
60
|
|
61
61
|
The method `foo` in the following code accepts only `{}` and `{:foo => value}`
|
62
|
-
as `ops
|
62
|
+
as `ops` hash, and the `value` may be anything:
|
63
63
|
|
64
64
|
```ruby
|
65
65
|
# Options validator
|
@@ -67,7 +67,7 @@ require 'oval'
|
|
67
67
|
class C
|
68
68
|
extend Oval
|
69
69
|
def self.foo(ops = {})
|
70
|
-
ov_options[ :foo => ov_anything ]
|
70
|
+
Oval.validate(ops, ov_options[ :foo => ov_anything ], 'ops')
|
71
71
|
end
|
72
72
|
end
|
73
73
|
```
|
@@ -80,12 +80,13 @@ C.foo :foo => 10 # should pass
|
|
80
80
|
C.foo :foo => 10, :bar => 20 # Oval::ValueError "Invalid option :bar for ops. Allowed options are :foo"
|
81
81
|
```
|
82
82
|
|
83
|
-
Options are declared with [
|
84
|
-
[
|
85
|
-
the allowed options should be listed inside of
|
86
|
-
be any values convertible to strings (i.e. a key
|
87
|
-
`respond_to? :to_s`). Values are declared recursively
|
88
|
-
declarators](#declarators) or terminal declarators (any other
|
83
|
+
Options are declared with [ov\_xxx declarators](#declarators). The
|
84
|
+
[ov\_options](#ov_options), for example, declares a hash of options. In
|
85
|
+
[ov\_options](#ov_options) all the allowed options should be listed inside of
|
86
|
+
`[]` square brackets. Keys may be any values convertible to strings (i.e. a key
|
87
|
+
given in declaration must `respond_to? :to_s`). Values are declared recursively
|
88
|
+
using [ov_xxx declarators](#declarators) or terminal declarators (any other
|
89
|
+
ruby values).
|
89
90
|
|
90
91
|
In [Example 1](#example-1-declaring-simple-options) we have declared options
|
91
92
|
inside of a method for simplicity. This isn't an optimal technique. Usually
|
@@ -112,7 +113,7 @@ class C
|
|
112
113
|
end
|
113
114
|
# use ov to validate ops
|
114
115
|
def self.foo(ops = {})
|
115
|
-
|
116
|
+
Oval.validate(ops, ov, 'ops')
|
116
117
|
end
|
117
118
|
end
|
118
119
|
```
|
@@ -123,36 +124,30 @@ end
|
|
123
124
|
|
124
125
|
###<a id="declarators"></a>Declarators
|
125
126
|
|
126
|
-
A declaration of
|
127
|
-
**declarators**. The
|
128
|
-
|
129
|
-
|
127
|
+
A declaration of data being validated consists entirely of what we call
|
128
|
+
**declarators**. The grammar for defining acceptable data uses non-terminal and
|
129
|
+
terminal declarators. Non-terminal declarators are most of the
|
130
|
+
[ov\_xxx](#declarators) methods of **Oval** module, for example
|
131
|
+
[ov\_options](#ov_options). General syntax for non-terminal declarator is
|
132
|
+
`ov_xxx[ args ]`, where `args` are declarator-specific arguments.
|
130
133
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
as an argument. The **optname#** is an option name, and **optdecl#** is a
|
136
|
-
declarator restricting the option's value. Each option name (key) must be
|
137
|
-
convertible to a `String`. Option value declarators are non-terminal
|
138
|
-
declarators (defined later in this section) or terminals (any other ruby
|
139
|
-
values). The simple declaration
|
140
|
-
|
141
|
-
```ruby
|
142
|
-
ov_options[ :foo => :bar ]
|
143
|
-
```
|
134
|
+
Terminal declarators include all the other ruby values, for example `nil`. They
|
135
|
+
are matched exactly against data being validated, so if the data doesn't equal
|
136
|
+
the given value an exception is raised.
|
144
137
|
|
145
|
-
|
146
|
-
|
147
|
-
how terminal declarators (`:foo` and `:bar` in this example) work. More freedom
|
148
|
-
may be introduced with non-terminal declarators, for example:
|
138
|
+
In what follows, we'll document all the core declarators implemented in
|
139
|
+
**Oval**.
|
149
140
|
|
150
|
-
|
151
|
-
ov_options[ :foo => ov_anything ]
|
152
|
-
```
|
141
|
+
###<a id="index-of-declarators"></a>Index of Declarators
|
153
142
|
|
154
|
-
|
155
|
-
|
143
|
+
- [ov\_anything](#ov_anything)
|
144
|
+
- [ov\_collection](#ov_collection)
|
145
|
+
- [ov\_instance\_of](#ov_instance_of)
|
146
|
+
- [ov\_kind\_of](#ov_kind_of)
|
147
|
+
- [ov\_match](#ov_match)
|
148
|
+
- [ov\_one\_of](#ov_one_of)
|
149
|
+
- [ov\_options](#ov_options)
|
150
|
+
- [ov\_subclass_of](#ov_subclass_of)
|
156
151
|
|
157
152
|
####<a id="ov\_anything"></a>ov\_anything
|
158
153
|
|
@@ -174,10 +169,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
174
169
|
```ruby
|
175
170
|
ov = ov_options[ :bar => ov_anything ]
|
176
171
|
def foo(ops = {})
|
177
|
-
|
172
|
+
Oval.validate(ops, ov, 'ops')
|
178
173
|
end
|
179
174
|
```
|
180
175
|
|
176
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
177
|
+
|
181
178
|
|
182
179
|
####<a id="ov\_collection"></a>ov\_collection
|
183
180
|
|
@@ -206,10 +203,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
206
203
|
:geez => ov_collection [ Array, instance_of[String] ]
|
207
204
|
]
|
208
205
|
def foo(ops = {})
|
209
|
-
|
206
|
+
Oval.validate(ops, ov, 'ops')
|
210
207
|
end
|
211
208
|
```
|
212
209
|
|
210
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
211
|
+
|
213
212
|
####<a id="ov\_instance\_of"></a>ov\_instance\_of
|
214
213
|
|
215
214
|
- Declaration
|
@@ -225,10 +224,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
225
224
|
```ruby
|
226
225
|
ov = ov_options[ :bar => ov_instance_of[String] ]
|
227
226
|
def foo(ops = {})
|
228
|
-
|
227
|
+
Oval.validate(ops, ov, 'ops')
|
229
228
|
end
|
230
229
|
```
|
231
230
|
|
231
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
232
|
+
|
232
233
|
####<a id="ov\_kind\_of"></a>ov\_kind\_of
|
233
234
|
|
234
235
|
- Declaration
|
@@ -244,10 +245,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
244
245
|
```ruby
|
245
246
|
ov = ov_options[ :bar => ov_kind_of[Numeric] ]
|
246
247
|
def foo(ops = {})
|
247
|
-
|
248
|
+
Oval.validate(ops, ov, 'ops')
|
248
249
|
end
|
249
250
|
```
|
250
251
|
|
252
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
253
|
+
|
251
254
|
####<a id="ov\_match"></a>ov\_match
|
252
255
|
|
253
256
|
- Declaration
|
@@ -264,10 +267,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
264
267
|
# Only valid identifiers are allowed as :bar option
|
265
268
|
ov = ov_options[ :bar => ov_match[/^[a-z_]\w+$/] ]
|
266
269
|
def foo(ops = {})
|
267
|
-
|
270
|
+
Oval.validate(ops, ov, 'ops')
|
268
271
|
end
|
269
272
|
```
|
270
273
|
|
274
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
275
|
+
|
271
276
|
####<a id="ov\_one\_of"></a>ov\_one\_of
|
272
277
|
|
273
278
|
- Declaration
|
@@ -284,10 +289,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
284
289
|
:bar => ov_one_of[ ov_instance_of[String], ov_kind_of[Numeric], nil ]
|
285
290
|
]
|
286
291
|
def foo(ops = {})
|
287
|
-
|
292
|
+
Oval.validate(ops, ov, 'ops')
|
288
293
|
end
|
289
294
|
```
|
290
295
|
|
296
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
297
|
+
|
291
298
|
####<a id="ov\_options"></a>ov\_options
|
292
299
|
|
293
300
|
- Declaration
|
@@ -308,10 +315,12 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
308
315
|
# ...
|
309
316
|
]
|
310
317
|
def foo(ops = {})
|
311
|
-
|
318
|
+
Oval.validate(ops, ov, 'ops')
|
312
319
|
end
|
313
320
|
```
|
314
321
|
|
322
|
+
[[Table of Contents](#table-of-contents)|[Index of Declarators](#index-of-declarators)]
|
323
|
+
|
315
324
|
####<a id="ov\_subclass\_of"></a>ov\_subclass\_of
|
316
325
|
|
317
326
|
- Declaration
|
@@ -327,7 +336,7 @@ document all the core non-terminal declarators implemented in **Oval**.
|
|
327
336
|
```ruby
|
328
337
|
ov = ov_options[ :bar => ov_subclass_of[Numeric] ]
|
329
338
|
def foo(ops = {})
|
330
|
-
|
339
|
+
Oval.validate(ops, ov, 'ops')
|
331
340
|
end
|
332
341
|
```
|
333
342
|
|
data/oval.gemspec
CHANGED
@@ -3,7 +3,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
3
3
|
|
4
4
|
Gem::Specification.new do |gem|
|
5
5
|
gem.name = 'oval'
|
6
|
-
gem.version = '0.0.
|
6
|
+
gem.version = '0.0.6'
|
7
7
|
gem.authors = ["Pawel Tomulik"]
|
8
8
|
gem.email = ["ptomulik@meil.pw.edu.pl"]
|
9
9
|
gem.description = %q{Validate options when passed to methods}
|
data/spec/unit/oval/base_spec.rb
CHANGED
@@ -15,7 +15,7 @@ describe Oval::Base do
|
|
15
15
|
end
|
16
16
|
|
17
17
|
context "an instance" do
|
18
|
-
let(:subject) { described_class[:
|
18
|
+
let(:subject) { described_class[:decl0] }
|
19
19
|
[
|
20
20
|
:validate,
|
21
21
|
].each do |method|
|
@@ -36,18 +36,18 @@ describe Oval::Base do
|
|
36
36
|
expect { described_class.validate(:foo,:bar,'subj1') }.to_not raise_error
|
37
37
|
end
|
38
38
|
end
|
39
|
-
context "validate(:foo,
|
40
|
-
let(:
|
41
|
-
it "should invoke
|
42
|
-
|
43
|
-
expect { described_class.validate(:foo,
|
39
|
+
context "validate(:foo,decl)" do
|
40
|
+
let(:decl) { described_class[:decl0] }
|
41
|
+
it "should invoke decl.validate(:foo,nil) once" do
|
42
|
+
decl.expects(:validate).once.with(:foo,nil)
|
43
|
+
expect { described_class.validate(:foo,decl) }.to_not raise_error
|
44
44
|
end
|
45
45
|
end
|
46
|
-
context "validate(:foo,
|
47
|
-
let(:
|
48
|
-
it "should invoke
|
49
|
-
|
50
|
-
expect { described_class.validate(:foo,
|
46
|
+
context "validate(:foo,decl,'subj1')" do
|
47
|
+
let(:decl) { described_class[:decl0] }
|
48
|
+
it "should invoke decl.validate(:foo,'subj1') once" do
|
49
|
+
decl.expects(:validate).once.with(:foo,'subj1')
|
50
|
+
expect { described_class.validate(:foo,decl,'subj1') }.to_not raise_error
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -65,7 +65,7 @@ describe Oval::Base do
|
|
65
65
|
end
|
66
66
|
|
67
67
|
describe "#validate" do
|
68
|
-
let(:subject) { described_class[:
|
68
|
+
let(:subject) { described_class[:decl0] }
|
69
69
|
let(:msg) { "This method should be overwritten by a subclass" }
|
70
70
|
[ [], [:arg1,:arg2,:arg3] ].each do |args|
|
71
71
|
context "validate(#{args.map{|x| x.inspect}.join(', ')})" do
|
@@ -82,52 +82,20 @@ describe Oval::Base do
|
|
82
82
|
end
|
83
83
|
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
## end
|
100
|
-
## end
|
101
|
-
|
102
|
-
|
103
|
-
## describe "shape" do
|
104
|
-
#### before { described_class.stubs(:validate_shape) }
|
105
|
-
## context "new(:shape0).shape" do
|
106
|
-
## it { described_class.new(:shape0).shape.should be :shape0 }
|
107
|
-
## end
|
108
|
-
## context "when @shape == :shape1" do
|
109
|
-
## let(:subject) { described_class.new(:shape0) }
|
110
|
-
## before { subject.instance_variable_set(:@shape,:shape1) }
|
111
|
-
## it { subject.shape.should be :shape1 }
|
112
|
-
## end
|
113
|
-
## end
|
114
|
-
##
|
115
|
-
## describe "#shape=" do
|
116
|
-
#### before { described_class.stubs(:validate_shape) }
|
117
|
-
## let(:subject) { described_class.new(:shape0) }
|
118
|
-
## context "#shape = :shape1" do
|
119
|
-
#### it "should call self.class.validate_shape(:shape1) once" do
|
120
|
-
#### subject # reference before re-stubbing validate_shape
|
121
|
-
#### described_class.stubs(:validate_shape).never
|
122
|
-
#### described_class.stubs(:validate_shape).once.with(:shape1,'Base')
|
123
|
-
#### expect { subject.send(:shape=,:shape1) }.to_not raise_error
|
124
|
-
#### end
|
125
|
-
## it "should assign @shape = :shape1" do
|
126
|
-
## subject.send(:shape=, :shape1)
|
127
|
-
## subject.instance_variable_get(:@shape).should be :shape1
|
128
|
-
## end
|
129
|
-
## end
|
130
|
-
## end
|
85
|
+
describe "#it_should" do
|
86
|
+
let(:subject) { described_class[:decl0] }
|
87
|
+
let(:msg) { "This method should be overwritten by a subclass" }
|
88
|
+
[ [:arg1], [:arg1,:arg2] ].each do |args|
|
89
|
+
context "it_should(#{args.map{|x| x.inspect}.join(', ')})" do
|
90
|
+
let(:args) { args }
|
91
|
+
before { described_class.expects(:it_should).never }
|
92
|
+
it { expect { subject.it_should(*args) }.to raise_error ArgumentError }
|
93
|
+
end
|
94
|
+
end
|
95
|
+
context "it_should" do
|
96
|
+
it { expect { subject.it_should }.to raise_error NotImplementedError, msg}
|
97
|
+
end
|
98
|
+
end
|
131
99
|
|
132
100
|
describe "for_subject" do
|
133
101
|
[
|
@@ -144,8 +112,7 @@ describe Oval::Base do
|
|
144
112
|
end
|
145
113
|
|
146
114
|
describe "#for_subject" do
|
147
|
-
|
148
|
-
let(:subject) { described_class.new(:shape0) }
|
115
|
+
let(:subject) { described_class.new(:decl0) }
|
149
116
|
context "for_subject(:subj1)" do
|
150
117
|
it "should == self.class.for_subject(subject)" do
|
151
118
|
described_class.expects(:for_subject).once.with(:subj1).returns :ok
|
@@ -170,8 +137,7 @@ describe Oval::Base do
|
|
170
137
|
end
|
171
138
|
|
172
139
|
describe "#enumerate" do
|
173
|
-
|
174
|
-
let(:subject) { described_class.new(:shape0) }
|
140
|
+
let(:subject) { described_class.new(:decl0) }
|
175
141
|
context "enumerate([],'and')" do
|
176
142
|
it "should == self.class.enumerate(subject)" do
|
177
143
|
described_class.expects(:enumerate).once.with([],'and').returns :ok
|
data/spec/unit/oval_spec.rb
CHANGED
@@ -47,7 +47,7 @@ describe Oval do
|
|
47
47
|
Class.new do
|
48
48
|
extend Oval
|
49
49
|
def self.foo(ops = {})
|
50
|
-
ov_options[ :foo => ov_anything ]
|
50
|
+
Oval.validate(ops, ov_options[ :foo => ov_anything ], 'ops')
|
51
51
|
end
|
52
52
|
end
|
53
53
|
end
|
@@ -73,7 +73,7 @@ describe Oval do
|
|
73
73
|
end
|
74
74
|
# use ov to validate ops
|
75
75
|
def self.foo(ops = {})
|
76
|
-
|
76
|
+
Oval.validate(ops, ov, 'ops')
|
77
77
|
end
|
78
78
|
end
|
79
79
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oval
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
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: 2014-02-
|
12
|
+
date: 2014-02-08 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -202,7 +202,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
202
202
|
version: '0'
|
203
203
|
segments:
|
204
204
|
- 0
|
205
|
-
hash:
|
205
|
+
hash: 3909914024463358041
|
206
206
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
207
207
|
none: false
|
208
208
|
requirements:
|
@@ -211,7 +211,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
211
211
|
version: '0'
|
212
212
|
segments:
|
213
213
|
- 0
|
214
|
-
hash:
|
214
|
+
hash: 3909914024463358041
|
215
215
|
requirements: []
|
216
216
|
rubyforge_project:
|
217
217
|
rubygems_version: 1.8.23
|