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 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
@@ -1,5 +1,5 @@
1
1
  name 'ptomulik-oval'
2
- version '0.0.5'
2
+ version '0.0.6'
3
3
  source 'git://github.com/ptomulik/rubygems-oval.git'
4
4
  author 'ptomulik'
5
5
  license 'Apache License, Version 2.0'
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
- Using hashes to pass options to methods is a very common ruby practice. With
28
- **Oval** method authors may restrict callers to pass only declared options that
29
- meet requirements described in a hash declaration.
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 hashes is described by a simple grammar. The validation
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 [ov_collection](#ov_collection)).
42
+ matching criteria (see for example [ov\_collection](#ov_collection)).
42
43
 
43
- **Oval** raises **Oval::DeclError** if the declaration is not well-formed, that
44
- is if the description of options shape is erroneous. This is raised from the
45
- point of declaration. Other, more common exception is the **Oval::ValueError**
46
- which is raised each time the validation fails. This one is raised from within
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
- options shape. This would create a validator object. The second step is to
55
- validate options within a method using the previously constructed validator.
56
- For simple hashes the entire construction may fit to a single line. Let's start
57
- with such a simple example.
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`, where `value` is arbitrary:
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 ].validate(ops, 'ops')
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 [ov_xxx declarators](#declarators). The
84
- [ov_options](#ov_options) method should always be at the top level. Then all
85
- the allowed options should be listed inside of `[]` square brackets. Keys may
86
- be any values convertible to strings (i.e. a key given in declaration must
87
- `respond_to? :to_s`). Values are declared recursively using [ov_xxx
88
- declarators](#declarators) or terminal declarators (any other ruby values).
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
- ov.validate(ops, 'ops')
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 options consists entirely of what we call here
127
- **declarators**. The [ov_options](#ov_options) should be used as a root of
128
- every declaration (starting symbol in grammar terms). It accepts a Hash of the
129
- form
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
- {optname1 => optdecl1, optname2 => optdecl2, ... }
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
- uses only terminals inside of **ov_options** and literary permits only the
146
- `{:foo => :bar}` or the empty hash `{}` as options (and nothing else). This is
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
- ```ruby
151
- ov_options[ :foo => ov_anything ]
152
- ```
141
+ ###<a id="index-of-declarators"></a>Index of Declarators
153
142
 
154
- defines an option `:foo` which accepts any value. In what follows, we'll
155
- document all the core non-terminal declarators implemented in **Oval**.
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
- ov.validate(ops, 'ops')
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
- ov.validate(ops, 'ops')
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
- ov.validate(ops,'ops')
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
- ov.validate(ops,'ops')
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
- ov.validate(ops,'ops')
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
- ov.validate(ops,'ops')
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
- ov.validate(ops,'ops')
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
- ov.validate(ops,'ops')
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.5'
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}
@@ -15,7 +15,7 @@ describe Oval::Base do
15
15
  end
16
16
 
17
17
  context "an instance" do
18
- let(:subject) { described_class[:shape0] }
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,shape)" do
40
- let(:shape) { described_class[:shape0] }
41
- it "should invoke shape.validate(:foo,nil) once" do
42
- shape.expects(:validate).once.with(:foo,nil)
43
- expect { described_class.validate(:foo,shape) }.to_not raise_error
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,shape,'subj1')" do
47
- let(:shape) { described_class[:shape0] }
48
- it "should invoke shape.validate(:foo,'subj1') once" do
49
- shape.expects(:validate).once.with(:foo,'subj1')
50
- expect { described_class.validate(:foo,shape,'subj1') }.to_not raise_error
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[:shape0] }
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
- ## describe "#validate_shape" do
86
- ## let(:subject) { described_class[:shape0] }
87
- ## let(:msg) { "This method should be overwritten by a subclass" }
88
- ## [ [:arg1,:arg2] ].each do |args|
89
- ## context "validate_shape(#{args.map{|x| x.inspect}.join(', ')})" do
90
- ## let(:args) { args }
91
- ## it { expect { subject.validate_shape(*args) }.to raise_error ArgumentError }
92
- ## end
93
- ## end
94
- ## context "validate_shape()" do
95
- ## it { expect { subject.validate_shape() }.to raise_error NotImplementedError, msg}
96
- ## end
97
- ## context "validate_shape(:subj1)" do
98
- ## it { expect { subject.validate_shape(:subj1) }.to raise_error NotImplementedError, msg}
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
- ## before { described_class.stubs(:validate_shape) }
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
- ## before { described_class.stubs(:validate_shape) }
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
@@ -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 ].validate(ops, 'ops')
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
- ov.validate(ops, 'ops')
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.5
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-03 00:00:00.000000000 Z
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: 2837400115143885778
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: 2837400115143885778
214
+ hash: 3909914024463358041
215
215
  requirements: []
216
216
  rubyforge_project:
217
217
  rubygems_version: 1.8.23