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 CHANGED
@@ -1,6 +1,62 @@
1
- = deeply_valid
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.0
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.0"
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-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
  ]
@@ -1,5 +1,6 @@
1
1
  module DeeplyValid
2
2
 
3
+
3
4
  #
4
5
  # By subclassing the base class, you can easily create
5
6
  # groups of validations.
@@ -22,8 +22,7 @@ module DeeplyValid
22
22
  # @return [Validation] The validation
23
23
  #
24
24
  def token(size = nil)
25
- s = size ? "{#{size.is_a?(Range) ? [size.first, size.last].uniq.join(",") : size}}" : nil
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
- protected
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
- # Determine if a val is included in a range. Handles
153
- # range==int and range==nil correctly
154
- #
155
- def in_range?(val, range)
156
- return true unless range
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
@@ -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 "return correct regexp when no size specified" do
18
- assert Sample.token == /[0-9a-zA-Z_]/
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 "return correct regexp when exact size specified" do
22
- assert Sample.token(32) == /[0-9a-zA-Z_]{32}/
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 "return correct regexp when range size specified" do
26
- assert Sample.token(1..23) == /[0-9a-zA-Z_]{1,23}/
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
- - 0
9
- version: 0.1.0
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-06 00:00:00 -05:00
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