oval 0.0.5 → 0.0.6
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/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
|