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 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