deeply_valid 0.1.0 → 0.1.1
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/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
|