deeply_valid 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +58 -2
- data/VERSION +1 -1
- data/deeply_valid.gemspec +4 -2
- data/lib/deeply_valid/base.rb +1 -0
- data/lib/deeply_valid/validation_helpers.rb +63 -9
- data/test/system_test.rb +66 -0
- data/test/validation_helpers_test.rb +93 -6
- metadata +5 -3
data/README.rdoc
CHANGED
@@ -1,6 +1,62 @@
|
|
1
|
-
=
|
1
|
+
= DeeplyValid
|
2
|
+
|
3
|
+
There are times when you just can't fake it. Maybe you're
|
4
|
+
implementing an API, or interacting with a legacy system.
|
5
|
+
But for whatever reason, you have complex data structures
|
6
|
+
that absolutely have to be valid.
|
7
|
+
|
8
|
+
DeeplyValid lets you define a "schema" for your data structures
|
9
|
+
in a nice, declarative, way.
|
10
|
+
|
11
|
+
== The Simplest Example:
|
12
|
+
|
13
|
+
class MyValidations < DeeplyValid::Base
|
14
|
+
define :name, "bob"
|
15
|
+
end
|
16
|
+
|
17
|
+
# true
|
18
|
+
MyValidations[:name].valid?("bob")
|
19
|
+
|
20
|
+
# false
|
21
|
+
MyValidations[:name].valid?("joe")
|
22
|
+
|
23
|
+
|
24
|
+
== A more realistic example
|
25
|
+
|
26
|
+
class MyValidations < DeeplyValid::Base
|
27
|
+
define :person, {
|
28
|
+
:id => token(32),
|
29
|
+
:age => integer(1..100),
|
30
|
+
:name => string(1..100),
|
31
|
+
:department => {
|
32
|
+
:name => any('sales', 'accounting', 'engineering'),
|
33
|
+
:building => integer
|
34
|
+
},
|
35
|
+
:performace_reviews => array( structure(:review) )
|
36
|
+
}
|
37
|
+
|
38
|
+
# This structure is referenced in the "person" structure
|
39
|
+
define :review, {
|
40
|
+
:author => string(1..100),
|
41
|
+
:body => string(1..1024)
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
# true
|
46
|
+
MyValidations[:person].valid?({
|
47
|
+
:id => "x"*32,
|
48
|
+
:age => 22,
|
49
|
+
:name => "Bob Jones",
|
50
|
+
:department => {
|
51
|
+
:name => "sales",
|
52
|
+
:building => 33
|
53
|
+
},
|
54
|
+
:performace_reviews => [
|
55
|
+
{ :author => "joe", :body => "a review" },
|
56
|
+
{ :author => "bill", :body => "another review" }
|
57
|
+
]
|
58
|
+
})
|
2
59
|
|
3
|
-
Description goes here.
|
4
60
|
|
5
61
|
== Note on Patches/Pull Requests
|
6
62
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.1.
|
1
|
+
0.1.1
|
data/deeply_valid.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{deeply_valid}
|
8
|
-
s.version = "0.1.
|
8
|
+
s.version = "0.1.1"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Starr Horne"]
|
12
|
-
s.date = %q{2010-06-
|
12
|
+
s.date = %q{2010-06-07}
|
13
13
|
s.description = %q{This gem lets you declaratively specify validations for complex data structures, like those returned from an api.}
|
14
14
|
s.email = %q{starr@chromahq.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -30,6 +30,7 @@ Gem::Specification.new do |s|
|
|
30
30
|
"lib/deeply_valid/validation_helpers.rb",
|
31
31
|
"test/base_test.rb",
|
32
32
|
"test/helper.rb",
|
33
|
+
"test/system_test.rb",
|
33
34
|
"test/validation_helpers_test.rb",
|
34
35
|
"test/validation_test.rb"
|
35
36
|
]
|
@@ -41,6 +42,7 @@ Gem::Specification.new do |s|
|
|
41
42
|
s.test_files = [
|
42
43
|
"test/base_test.rb",
|
43
44
|
"test/helper.rb",
|
45
|
+
"test/system_test.rb",
|
44
46
|
"test/validation_helpers_test.rb",
|
45
47
|
"test/validation_test.rb"
|
46
48
|
]
|
data/lib/deeply_valid/base.rb
CHANGED
@@ -22,8 +22,7 @@ module DeeplyValid
|
|
22
22
|
# @return [Validation] The validation
|
23
23
|
#
|
24
24
|
def token(size = nil)
|
25
|
-
|
26
|
-
/[0-9a-zA-Z_]#{ s }/
|
25
|
+
Validation.new { |d| (d =~ /^[0-9a-zA-Z_]*$/) && in_range?(d.size, size) }
|
27
26
|
end
|
28
27
|
|
29
28
|
#
|
@@ -46,6 +45,36 @@ module DeeplyValid
|
|
46
45
|
Validation.new { |d| d.is_a?(Integer) && in_range?(d, limit) }
|
47
46
|
end
|
48
47
|
|
48
|
+
#
|
49
|
+
# Validates date with optional limit
|
50
|
+
#
|
51
|
+
# @param limit
|
52
|
+
# @return [Validation] The validation
|
53
|
+
#
|
54
|
+
def date(limit = nil)
|
55
|
+
Validation.new { |d| d.is_a?(Date) && in_range?(d, limit) }
|
56
|
+
end
|
57
|
+
|
58
|
+
#
|
59
|
+
# Validates float with optional limit
|
60
|
+
#
|
61
|
+
# @param limit
|
62
|
+
# @return [Validation] The validation
|
63
|
+
#
|
64
|
+
def float(limit = nil)
|
65
|
+
Validation.new { |d| d.is_a?(Float) && in_range?(d, limit) }
|
66
|
+
end
|
67
|
+
|
68
|
+
#
|
69
|
+
# Validates date with optional limit
|
70
|
+
#
|
71
|
+
# @param [Integer, Range] limit
|
72
|
+
# @return [Validation] The validation
|
73
|
+
#
|
74
|
+
def datetime(limit = nil)
|
75
|
+
Validation.new { |d| d.is_a?(DateTime) && in_range?(d, limit) }
|
76
|
+
end
|
77
|
+
|
49
78
|
#
|
50
79
|
# Validate by class
|
51
80
|
#
|
@@ -146,17 +175,42 @@ module DeeplyValid
|
|
146
175
|
end
|
147
176
|
end
|
148
177
|
|
149
|
-
|
178
|
+
#
|
179
|
+
# Determine if a val is included in a range. A number of
|
180
|
+
# range formats are supportet
|
181
|
+
#
|
182
|
+
# == Example:
|
183
|
+
#
|
184
|
+
# All these will return true
|
185
|
+
#
|
186
|
+
# in_range(1, 1)
|
187
|
+
# in_range(1, 0..9)
|
188
|
+
# in_range(1, :min => 0, :max => 9)
|
189
|
+
# in_range(1, :less_than_or_equal_to => 2)
|
190
|
+
#
|
191
|
+
# @param val A number, date, or other other object to compare
|
192
|
+
# @param [Integer, Range, Hash] range The range to test `val` against
|
193
|
+
#
|
194
|
+
def in_range?(val, range)
|
195
|
+
return true unless range
|
150
196
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
197
|
+
if range.is_a?(Hash)
|
198
|
+
result = true
|
199
|
+
result &= ( val < range[:before] ) if range[:before]
|
200
|
+
result &= ( val > range[:after] ) if range[:after]
|
201
|
+
result &= ( val <= range[:max] ) if range[:max]
|
202
|
+
result &= ( val >= range[:min] ) if range[:min]
|
203
|
+
result &= ( val < range[:less_than] ) if range[:less_than]
|
204
|
+
result &= ( val <= range[:less_than_or_equal_to] ) if range[:less_than_or_equal_to]
|
205
|
+
result &= ( val > range[:greater_than] ) if range[:greater_than]
|
206
|
+
result &= ( val >= range[:greater_than_or_equal_to] ) if range[:greater_than_or_equal_to]
|
207
|
+
result
|
208
|
+
else
|
157
209
|
range = [range] unless range.respond_to?(:include?)
|
158
210
|
range.include?(val)
|
159
211
|
end
|
212
|
+
|
213
|
+
end
|
160
214
|
end
|
161
215
|
end
|
162
216
|
end
|
data/test/system_test.rb
ADDED
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class SystemTest < Test::Unit::TestCase
|
4
|
+
|
5
|
+
include DeeplyValid
|
6
|
+
|
7
|
+
context "a complex of validation" do
|
8
|
+
setup do
|
9
|
+
|
10
|
+
class MyValidations < DeeplyValid::Base
|
11
|
+
define :person, {
|
12
|
+
:id => token(32),
|
13
|
+
:age => integer(1..100),
|
14
|
+
:name => string(1..100),
|
15
|
+
:department => {
|
16
|
+
:name => any('sales', 'accounting', 'engineering'),
|
17
|
+
:building => integer
|
18
|
+
},
|
19
|
+
:performace_reviews => array( structure(:review) )
|
20
|
+
}
|
21
|
+
|
22
|
+
# This structure is referenced in the "person" structure
|
23
|
+
define :review, {
|
24
|
+
:author => string(1..100),
|
25
|
+
:body => string(1..1024)
|
26
|
+
}
|
27
|
+
end
|
28
|
+
|
29
|
+
@valid_person = {
|
30
|
+
:id => "x"*32,
|
31
|
+
:age => 22,
|
32
|
+
:name => "Bob Jones",
|
33
|
+
:department => {
|
34
|
+
:name => "sales",
|
35
|
+
:building => 33
|
36
|
+
},
|
37
|
+
:performace_reviews => [
|
38
|
+
{ :author => "joe", :body => "a review" },
|
39
|
+
{ :author => "bill", :body => "another review" }
|
40
|
+
]
|
41
|
+
}
|
42
|
+
|
43
|
+
@invalid_person = {
|
44
|
+
:id => "x"*32,
|
45
|
+
:age => 22,
|
46
|
+
:name => "Bob Jones",
|
47
|
+
:department => {
|
48
|
+
:name => "sales",
|
49
|
+
:building => 33
|
50
|
+
},
|
51
|
+
:performace_reviews => [
|
52
|
+
{ :author => 11, :body => "a review" },
|
53
|
+
{ :author => "bill", :body => "another review" }
|
54
|
+
]
|
55
|
+
}
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
should "validate correctly" do
|
60
|
+
assert MyValidations[:person].valid?(@valid_person)
|
61
|
+
assert !MyValidations[:person].valid?(@invalid_person)
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
end
|
@@ -14,16 +14,19 @@ class ValidationHelpersTest < Test::Unit::TestCase
|
|
14
14
|
|
15
15
|
context "token helper" do
|
16
16
|
|
17
|
-
should "
|
18
|
-
assert Sample.token
|
17
|
+
should "validate correctly, without size" do
|
18
|
+
assert Sample.token.valid?("a_sdf123")
|
19
|
+
assert !Sample.token.valid?("a_!@#sdf123")
|
19
20
|
end
|
20
21
|
|
21
|
-
should "
|
22
|
-
assert Sample.token(
|
22
|
+
should "validate correctly, with exact size" do
|
23
|
+
assert Sample.token(4).valid?("asdf")
|
24
|
+
assert !Sample.token(4).valid?("a")
|
23
25
|
end
|
24
26
|
|
25
|
-
should "
|
26
|
-
assert Sample.token(1..
|
27
|
+
should "validate correctly, with range size" do
|
28
|
+
assert Sample.token(1..5).valid?("asdf")
|
29
|
+
assert !Sample.token(3..5).valid?("a")
|
27
30
|
end
|
28
31
|
|
29
32
|
end
|
@@ -64,6 +67,33 @@ class ValidationHelpersTest < Test::Unit::TestCase
|
|
64
67
|
|
65
68
|
end
|
66
69
|
|
70
|
+
context "float helper" do
|
71
|
+
|
72
|
+
should "validate correctly" do
|
73
|
+
assert Sample.float.valid?(1.234)
|
74
|
+
assert !Sample.float(:max => 0.5).valid?(1.234)
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
context "date helper" do
|
80
|
+
|
81
|
+
should "validate correctly" do
|
82
|
+
assert Sample.date.valid?(Date.today)
|
83
|
+
assert !Sample.date(:before => Date.today).valid?(Date.today)
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
context "datetime helper" do
|
89
|
+
|
90
|
+
should "validate correctly" do
|
91
|
+
assert Sample.datetime.valid?(DateTime.now)
|
92
|
+
assert !Sample.datetime(:before => DateTime.now).valid?(DateTime.now)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
67
97
|
context "instance_of helper" do
|
68
98
|
|
69
99
|
should "validate correctly" do
|
@@ -140,6 +170,63 @@ class ValidationHelpersTest < Test::Unit::TestCase
|
|
140
170
|
assert !Sample.array(Validation.new { |d| d > 10 }).valid?([ 11, 0, 12, 23 ])
|
141
171
|
end
|
142
172
|
end
|
173
|
+
|
174
|
+
context "in_range? method" do
|
175
|
+
|
176
|
+
should "work with int" do
|
177
|
+
assert Sample.in_range?(1, 1)
|
178
|
+
assert !Sample.in_range?(1, 2)
|
179
|
+
end
|
180
|
+
|
181
|
+
should "work with range" do
|
182
|
+
assert Sample.in_range?(1, 0..10)
|
183
|
+
assert !Sample.in_range?(20, 1..5)
|
184
|
+
end
|
185
|
+
|
186
|
+
should "work with min" do
|
187
|
+
assert Sample.in_range?(1, :min => 0 )
|
188
|
+
assert Sample.in_range?(0, :min => 0 )
|
189
|
+
assert !Sample.in_range?(-1, :min => 0 )
|
190
|
+
end
|
191
|
+
|
192
|
+
should "work with max" do
|
193
|
+
assert Sample.in_range?(-1, :max => 0 )
|
194
|
+
assert Sample.in_range?(0, :max => 0 )
|
195
|
+
assert !Sample.in_range?(1, :max => 0 )
|
196
|
+
end
|
197
|
+
|
198
|
+
should "work with before" do
|
199
|
+
assert Sample.in_range?(1, :before => 2 )
|
200
|
+
assert !Sample.in_range?(2, :before => 2 )
|
201
|
+
end
|
202
|
+
|
203
|
+
should "work with after" do
|
204
|
+
assert Sample.in_range?(3, :after => 2 )
|
205
|
+
assert !Sample.in_range?(2, :after => 2 )
|
206
|
+
end
|
207
|
+
|
208
|
+
should "work with less_than" do
|
209
|
+
assert Sample.in_range?(1, :less_than => 2 )
|
210
|
+
assert !Sample.in_range?(2, :less_than => 2 )
|
211
|
+
end
|
212
|
+
|
213
|
+
should "work with greater_than" do
|
214
|
+
assert Sample.in_range?(3, :greater_than => 2 )
|
215
|
+
assert !Sample.in_range?(2, :greater_than => 2 )
|
216
|
+
end
|
217
|
+
|
218
|
+
should "work with greater_than_or_equal_to" do
|
219
|
+
assert Sample.in_range?(1, :greater_than_or_equal_to => 0 )
|
220
|
+
assert Sample.in_range?(0, :greater_than_or_equal_to => 0 )
|
221
|
+
assert !Sample.in_range?(-1, :greater_than_or_equal_to => 0 )
|
222
|
+
end
|
223
|
+
|
224
|
+
should "work with less_than_or_equal_to" do
|
225
|
+
assert Sample.in_range?(-1, :less_than_or_equal_to => 0 )
|
226
|
+
assert Sample.in_range?(0, :less_than_or_equal_to => 0 )
|
227
|
+
assert !Sample.in_range?(1, :less_than_or_equal_to => 0 )
|
228
|
+
end
|
229
|
+
end
|
143
230
|
|
144
231
|
end
|
145
232
|
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Starr Horne
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date: 2010-06-
|
17
|
+
date: 2010-06-07 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -52,6 +52,7 @@ files:
|
|
52
52
|
- lib/deeply_valid/validation_helpers.rb
|
53
53
|
- test/base_test.rb
|
54
54
|
- test/helper.rb
|
55
|
+
- test/system_test.rb
|
55
56
|
- test/validation_helpers_test.rb
|
56
57
|
- test/validation_test.rb
|
57
58
|
has_rdoc: true
|
@@ -87,5 +88,6 @@ summary: Validation for complex data structures
|
|
87
88
|
test_files:
|
88
89
|
- test/base_test.rb
|
89
90
|
- test/helper.rb
|
91
|
+
- test/system_test.rb
|
90
92
|
- test/validation_helpers_test.rb
|
91
93
|
- test/validation_test.rb
|