hash_validator 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/README.md +34 -3
- data/lib/hash_validator/validators.rb +11 -1
- data/lib/hash_validator/validators/base.rb +16 -1
- data/lib/hash_validator/validators/email_validator.rb +17 -0
- data/lib/hash_validator/validators/hash_validator.rb +2 -6
- data/lib/hash_validator/validators/presence_validator.rb +2 -7
- data/lib/hash_validator/validators/simple_type_validators.rb +8 -0
- data/lib/hash_validator/validators/simple_validator.rb +20 -0
- data/lib/hash_validator/version.rb +1 -1
- data/spec/hash_validator_spec.rb +158 -132
- data/spec/validators/base_spec.rb +13 -6
- data/spec/validators/email_spec.rb +40 -0
- data/spec/validators/simple_spec.rb +46 -0
- data/spec/validators/simple_types_spec.rb +45 -0
- data/spec/validators/user_defined_spec.rb +95 -0
- metadata +13 -5
- data/lib/hash_validator/validators/simple_type_validator.rb +0 -32
- data/spec/validators/simple_type_spec.rb +0 -34
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: fcfb909853b164442c3070897b294b05aad88a35
|
4
|
+
data.tar.gz: 6168c0b13dac5c47959bd9d8b98edaa82710857a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ee681f842e79645713cc7775eaf2e4d57cda92a90b52052e34d8a1b92717328a227b09f5c272d633753f3363e47f3cad899c24ffb9751836caf6cda75bdbb99c
|
7
|
+
data.tar.gz: e053babc5e9091973d04680c5a64e5aa11365701cfe1fc3e164a174341f3079bb48e6b9965009e2c58d988fdbb491c674a4f2b5ea28f6b09bf9ba15c0ccb669d
|
data/README.md
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# Hash Validator
|
2
2
|
|
3
|
-
[](https://travis-ci.org/JamesBrooks/hash_validator)
|
4
|
-
[](https://codeclimate.com/github/JamesBrooks/hash_validator)
|
5
3
|
[](http://badge.fury.io/rb/hash_validator)
|
4
|
+
[](https://travis-ci.org/JamesBrooks/hash_validator)
|
6
5
|
[](https://coveralls.io/r/JamesBrooks/hash_validator)
|
6
|
+
[](https://codeclimate.com/github/JamesBrooks/hash_validator)
|
7
7
|
[](https://gemnasium.com/JamesBrooks/hash_validator)
|
8
8
|
|
9
9
|
Ruby library to validate hashes (Hash) against user-defined requirements
|
@@ -53,7 +53,7 @@ validator.valid?
|
|
53
53
|
validator.errors
|
54
54
|
# {
|
55
55
|
:user => {
|
56
|
-
:last_name => "
|
56
|
+
:last_name => "string required",
|
57
57
|
:age => "numeric required",
|
58
58
|
:likes => "array required"
|
59
59
|
}
|
@@ -71,8 +71,39 @@ Define a validation hash which will be used to validate. This has can be nested
|
|
71
71
|
* `required`: just requires any value to be present for the designated key.
|
72
72
|
* hashes are validates by nesting validations, or if just the presence of a hash is required `{}` can be used.
|
73
73
|
|
74
|
+
Additional validations exist to validate beyond simple typing, such as:
|
75
|
+
|
76
|
+
* `email`: email address validation (string + email address)
|
77
|
+
|
74
78
|
Example use-cases include Ruby APIs (I'm currently using it in a Rails API that I'm building for better error responses to developers).
|
75
79
|
|
80
|
+
## Custom validations
|
81
|
+
|
82
|
+
Allows custom defined validations (must inherit from `HashValidator::Validator::Base`). Example:
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# Define our custom validator
|
86
|
+
class HashValidator::Validator::OddValidator < HashValidator::Validator::Base
|
87
|
+
def initialize
|
88
|
+
super('odd') # The name of the validator
|
89
|
+
end
|
90
|
+
|
91
|
+
def validate(key, value, validations, errors)
|
92
|
+
unless value.is_a?(Integer) && value.odd?
|
93
|
+
errors[key] = presence_error_message
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Add the validator
|
99
|
+
HashValidator.append_validator(HashValidator::Validator::OddValidator.new)
|
100
|
+
|
101
|
+
# Now the validator can be used! e.g.
|
102
|
+
validator = HashValidator.validate({ age: 27 }, { age: 'odd' })
|
103
|
+
validator.valid? # => true
|
104
|
+
validator.errors # => {}
|
105
|
+
```
|
106
|
+
|
76
107
|
## Contributing
|
77
108
|
|
78
109
|
1. Fork it
|
@@ -3,6 +3,14 @@ module HashValidator
|
|
3
3
|
|
4
4
|
|
5
5
|
def self.append_validator(validator)
|
6
|
+
unless validator.is_a?(HashValidator::Validator::Base)
|
7
|
+
raise StandardError.new('validators need to inherit from HashValidator::Validator::Base')
|
8
|
+
end
|
9
|
+
|
10
|
+
if @@validators.detect { |v| v.name == validator.name }
|
11
|
+
raise StandardError.new('validators need to have unique names')
|
12
|
+
end
|
13
|
+
|
6
14
|
@@validators << validator
|
7
15
|
end
|
8
16
|
|
@@ -16,6 +24,8 @@ end
|
|
16
24
|
|
17
25
|
# Load validators
|
18
26
|
require 'hash_validator/validators/base'
|
27
|
+
require 'hash_validator/validators/simple_validator'
|
19
28
|
require 'hash_validator/validators/hash_validator'
|
20
29
|
require 'hash_validator/validators/presence_validator'
|
21
|
-
require 'hash_validator/validators/
|
30
|
+
require 'hash_validator/validators/simple_type_validators'
|
31
|
+
require 'hash_validator/validators/email_validator'
|
@@ -1,6 +1,21 @@
|
|
1
1
|
class HashValidator::Validator::Base
|
2
|
+
attr_accessor :name
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(name)
|
6
|
+
unless name.is_a?(String) && name.size > 0
|
7
|
+
raise StandardError.new('Validator must be initialized with a valid name (string with length greater than zero)')
|
8
|
+
end
|
9
|
+
|
10
|
+
self.name = name
|
11
|
+
end
|
12
|
+
|
2
13
|
def should_validate?(name)
|
3
|
-
|
14
|
+
self.name == name
|
15
|
+
end
|
16
|
+
|
17
|
+
def presence_error_message
|
18
|
+
"#{self.name} required"
|
4
19
|
end
|
5
20
|
|
6
21
|
def validate(key, value, validations, errors)
|
@@ -0,0 +1,17 @@
|
|
1
|
+
class HashValidator::Validator::EmailValidator < HashValidator::Validator::Base
|
2
|
+
def initialize
|
3
|
+
super('email') # The name of the validator
|
4
|
+
end
|
5
|
+
|
6
|
+
def presence_error_message
|
7
|
+
'is not a valid email'
|
8
|
+
end
|
9
|
+
|
10
|
+
def validate(key, value, validations, errors)
|
11
|
+
unless value.is_a?(String) && value.include?("@")
|
12
|
+
errors[key] = presence_error_message
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
HashValidator.append_validator(HashValidator::Validator::EmailValidator.new)
|
@@ -1,16 +1,12 @@
|
|
1
1
|
class HashValidator::Validator::PresenceValidator < HashValidator::Validator::Base
|
2
|
-
def
|
3
|
-
'required'
|
2
|
+
def initialize
|
3
|
+
super('required')
|
4
4
|
end
|
5
5
|
|
6
6
|
def presence_error_message
|
7
7
|
'is required'
|
8
8
|
end
|
9
9
|
|
10
|
-
def should_validate?(rhs)
|
11
|
-
rhs == name
|
12
|
-
end
|
13
|
-
|
14
10
|
def validate(key, value, validations, errors)
|
15
11
|
unless value
|
16
12
|
errors[key] = presence_error_message
|
@@ -18,5 +14,4 @@ class HashValidator::Validator::PresenceValidator < HashValidator::Validator::Ba
|
|
18
14
|
end
|
19
15
|
end
|
20
16
|
|
21
|
-
|
22
17
|
HashValidator.append_validator(HashValidator::Validator::PresenceValidator.new)
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class HashValidator::Validator::SimpleValidator < HashValidator::Validator::Base
|
2
|
+
attr_accessor :lambda
|
3
|
+
|
4
|
+
|
5
|
+
def initialize(name, lambda)
|
6
|
+
# lambda must accept one argument (the value)
|
7
|
+
if lambda.arity != 1
|
8
|
+
raise StandardError.new("lambda should take only one argument - passed lambda takes #{lambda.arity}")
|
9
|
+
end
|
10
|
+
|
11
|
+
super(name)
|
12
|
+
self.lambda = lambda
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate(key, value, validations, errors)
|
16
|
+
unless lambda.call(value)
|
17
|
+
errors[key] = presence_error_message
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/spec/hash_validator_spec.rb
CHANGED
@@ -1,166 +1,192 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe HashValidator do
|
4
|
-
describe '
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
4
|
+
describe 'Adding validators' do
|
5
|
+
let(:new_validator1) { HashValidator::Validator::SimpleValidator.new('my_type1', lambda { |v| true }) }
|
6
|
+
let(:new_validator2) { HashValidator::Validator::SimpleValidator.new('my_type2', lambda { |v| true }) }
|
7
|
+
|
8
|
+
it 'allows validators with unique names' do
|
9
|
+
expect {
|
10
|
+
HashValidator.append_validator(new_validator1)
|
11
|
+
}.to_not raise_error
|
10
12
|
end
|
11
13
|
|
12
|
-
it '
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
validate({ v: nil }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
18
|
-
|
19
|
-
validate({ x: 'test' }, { v: 'required' }).valid?.should be_false
|
20
|
-
validate({ x: 'test' }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
21
|
-
|
22
|
-
validate({ x: 1234 }, { v: 'required' }).valid?.should be_false
|
23
|
-
validate({ x: 1234 }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
14
|
+
it 'does not allow validators with conflicting names' do
|
15
|
+
expect {
|
16
|
+
HashValidator.append_validator(new_validator2)
|
17
|
+
HashValidator.append_validator(new_validator2)
|
18
|
+
}.to raise_error(StandardError, 'validators need to have unique names')
|
24
19
|
end
|
25
20
|
|
26
|
-
it '
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
validate({ v: 123456 }, { v: 'string' }).errors.should eq({ v: 'string required' })
|
21
|
+
it 'does not allow validators that do not inherit from the base validator class' do
|
22
|
+
expect {
|
23
|
+
HashValidator.append_validator('Not a validator')
|
24
|
+
}.to raise_error(StandardError, 'validators need to inherit from HashValidator::Validator::Base')
|
31
25
|
end
|
26
|
+
end
|
32
27
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
28
|
+
describe '#validate' do
|
29
|
+
describe 'individual type validations' do
|
30
|
+
it 'should validate hash' do
|
31
|
+
validate({ v: {} }, { v: {} }).valid?.should be_true
|
37
32
|
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
end
|
33
|
+
validate({ v: '' }, { v: {} }).valid?.should be_false
|
34
|
+
validate({ v: '' }, { v: {} }).errors.should eq({ v: 'hash required' })
|
35
|
+
end
|
42
36
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
47
|
-
end
|
37
|
+
it 'should validate presence' do
|
38
|
+
validate({ v: 'test' }, { v: 'required' }).valid?.should be_true
|
39
|
+
validate({ v: 1234 }, { v: 'required' }).valid?.should be_true
|
48
40
|
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
let(:simple_hash) {{
|
53
|
-
foo: 1,
|
54
|
-
bar: 'baz'
|
55
|
-
}}
|
56
|
-
|
57
|
-
let(:invalid_simple_hash) {{
|
58
|
-
foo: 1,
|
59
|
-
bar: 2
|
60
|
-
}}
|
61
|
-
|
62
|
-
let(:complex_hash) {{
|
63
|
-
foo: 1,
|
64
|
-
bar: 'baz',
|
65
|
-
user: {
|
66
|
-
first_name: 'James',
|
67
|
-
last_name: 'Brooks',
|
68
|
-
age: 27,
|
69
|
-
likes: [ 'Ruby', 'Kendo', 'Board Games' ]
|
70
|
-
}
|
71
|
-
}}
|
72
|
-
|
73
|
-
let(:invalid_complex_hash) {{
|
74
|
-
foo: 1,
|
75
|
-
bar: 2,
|
76
|
-
user: {
|
77
|
-
first_name: 'James',
|
78
|
-
last_name: 'Brooks',
|
79
|
-
likes: 'Ruby, Kendo, Board Games'
|
80
|
-
}
|
81
|
-
}}
|
82
|
-
|
83
|
-
describe 'no validations' do
|
84
|
-
let(:validations) {{}}
|
85
|
-
|
86
|
-
it 'should validate an empty hash' do
|
87
|
-
v = validate(empty_hash, validations)
|
88
|
-
v.valid?.should be_true
|
89
|
-
v.errors.should be_empty
|
90
|
-
end
|
41
|
+
validate({ v: nil }, { v: 'required' }).valid?.should be_false
|
42
|
+
validate({ v: nil }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
91
43
|
|
92
|
-
|
93
|
-
v
|
94
|
-
v.valid?.should be_true
|
95
|
-
v.errors.should be_empty
|
96
|
-
end
|
44
|
+
validate({ x: 'test' }, { v: 'required' }).valid?.should be_false
|
45
|
+
validate({ x: 'test' }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
97
46
|
|
98
|
-
|
99
|
-
v
|
100
|
-
v.valid?.should be_true
|
101
|
-
v.errors.should be_empty
|
47
|
+
validate({ x: 1234 }, { v: 'required' }).valid?.should be_false
|
48
|
+
validate({ x: 1234 }, { v: 'required' }).errors.should eq({ v: 'is required' })
|
102
49
|
end
|
103
50
|
|
104
|
-
it 'should validate
|
105
|
-
v
|
106
|
-
v.valid?.should be_true
|
107
|
-
v.errors.should be_empty
|
108
|
-
end
|
51
|
+
it 'should validate string' do
|
52
|
+
validate({ v: 'test' }, { v: 'string' }).valid?.should be_true
|
109
53
|
|
110
|
-
|
111
|
-
v
|
112
|
-
v.valid?.should be_true
|
113
|
-
v.errors.should be_empty
|
54
|
+
validate({ v: 123456 }, { v: 'string' }).valid?.should be_false
|
55
|
+
validate({ v: 123456 }, { v: 'string' }).errors.should eq({ v: 'string required' })
|
114
56
|
end
|
115
|
-
end
|
116
57
|
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
it 'should not validate an empty hash (stating missing with required)' do
|
121
|
-
v = validate(empty_hash, validations)
|
122
|
-
v.valid?.should be_false
|
123
|
-
v.errors.should eq({ foo: 'numeric required', bar: 'string required' })
|
58
|
+
it 'should validate numeric' do
|
59
|
+
validate({ v: 1234 }, { v: 'numeric' }).valid?.should be_true
|
60
|
+
validate({ v: '12' }, { v: 'numeric' }).valid?.should be_false
|
124
61
|
end
|
125
62
|
|
126
|
-
it 'should validate
|
127
|
-
v
|
128
|
-
v.valid?.should
|
129
|
-
v.errors.should be_empty
|
63
|
+
it 'should validate array' do
|
64
|
+
validate({ v: [ 1,2,3 ] }, { v: 'array' }).valid?.should be_true
|
65
|
+
validate({ v: ' 1,2,3 ' }, { v: 'array' }).valid?.should be_false
|
130
66
|
end
|
131
67
|
|
132
|
-
it 'should
|
133
|
-
v
|
134
|
-
v.valid?.should be_false
|
135
|
-
v.errors.should eq({ bar: 'string required' })
|
68
|
+
it 'should validate time' do
|
69
|
+
validate({ v: Time.now }, { v: 'time' }).valid?.should be_true
|
70
|
+
validate({ v: '2013-04-12 13:18:05 +0930' }, { v: 'time' }).valid?.should be_false
|
136
71
|
end
|
72
|
+
end
|
137
73
|
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
74
|
+
describe 'full validations' do
|
75
|
+
let(:empty_hash) {{}}
|
76
|
+
|
77
|
+
let(:simple_hash) {{
|
78
|
+
foo: 1,
|
79
|
+
bar: 'baz'
|
80
|
+
}}
|
81
|
+
|
82
|
+
let(:invalid_simple_hash) {{
|
83
|
+
foo: 1,
|
84
|
+
bar: 2
|
85
|
+
}}
|
86
|
+
|
87
|
+
let(:complex_hash) {{
|
88
|
+
foo: 1,
|
89
|
+
bar: 'baz',
|
90
|
+
user: {
|
91
|
+
first_name: 'James',
|
92
|
+
last_name: 'Brooks',
|
93
|
+
age: 27,
|
94
|
+
likes: [ 'Ruby', 'Kendo', 'Board Games' ]
|
95
|
+
}
|
96
|
+
}}
|
97
|
+
|
98
|
+
let(:invalid_complex_hash) {{
|
99
|
+
foo: 1,
|
100
|
+
bar: 2,
|
101
|
+
user: {
|
102
|
+
first_name: 'James',
|
103
|
+
last_name: 'Brooks',
|
104
|
+
likes: 'Ruby, Kendo, Board Games'
|
105
|
+
}
|
106
|
+
}}
|
107
|
+
|
108
|
+
describe 'no validations' do
|
109
|
+
let(:validations) {{}}
|
110
|
+
|
111
|
+
it 'should validate an empty hash' do
|
112
|
+
v = validate(empty_hash, validations)
|
113
|
+
v.valid?.should be_true
|
114
|
+
v.errors.should be_empty
|
115
|
+
end
|
116
|
+
|
117
|
+
it 'should validate a simple hash' do
|
118
|
+
v = validate(simple_hash, validations)
|
119
|
+
v.valid?.should be_true
|
120
|
+
v.errors.should be_empty
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'should validate a simple hash 2' do
|
124
|
+
v = validate(invalid_simple_hash, validations)
|
125
|
+
v.valid?.should be_true
|
126
|
+
v.errors.should be_empty
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'should validate a complex hash' do
|
130
|
+
v = validate(complex_hash, validations)
|
131
|
+
v.valid?.should be_true
|
132
|
+
v.errors.should be_empty
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'should validate a complex hash 2' do
|
136
|
+
v = validate(invalid_complex_hash, validations)
|
137
|
+
v.valid?.should be_true
|
138
|
+
v.errors.should be_empty
|
139
|
+
end
|
142
140
|
end
|
143
141
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
142
|
+
describe 'simple validations' do
|
143
|
+
let(:validations) {{ foo: 'numeric', bar: 'string' }}
|
144
|
+
|
145
|
+
it 'should not validate an empty hash (stating missing with required)' do
|
146
|
+
v = validate(empty_hash, validations)
|
147
|
+
v.valid?.should be_false
|
148
|
+
v.errors.should eq({ foo: 'numeric required', bar: 'string required' })
|
149
|
+
end
|
150
|
+
|
151
|
+
it 'should validate a simple hash' do
|
152
|
+
v = validate(simple_hash, validations)
|
153
|
+
v.valid?.should be_true
|
154
|
+
v.errors.should be_empty
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'should not validate a simple hash 2' do
|
158
|
+
v = validate(invalid_simple_hash, validations)
|
159
|
+
v.valid?.should be_false
|
160
|
+
v.errors.should eq({ bar: 'string required' })
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'should validate a complex hash' do
|
164
|
+
v = validate(complex_hash, validations)
|
165
|
+
v.valid?.should be_true
|
166
|
+
v.errors.should be_empty
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'should not validate a complex hash 2' do
|
170
|
+
v = validate(invalid_complex_hash, validations)
|
171
|
+
v.valid?.should be_false
|
172
|
+
v.errors.should eq({ bar: 'string required' })
|
173
|
+
end
|
148
174
|
end
|
149
|
-
end
|
150
175
|
|
151
|
-
|
152
|
-
|
176
|
+
describe 'nested validations' do
|
177
|
+
let(:validations) {{ foo: 'numeric', bar: 'string', user: { first_name: 'string', age: 'required', likes: 'array' } }}
|
153
178
|
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
179
|
+
it 'should validate a complex hash' do
|
180
|
+
v = validate(complex_hash, validations)
|
181
|
+
v.valid?.should be_true
|
182
|
+
v.errors.should be_empty
|
183
|
+
end
|
159
184
|
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
185
|
+
it 'should not validate a complex hash 2' do
|
186
|
+
v = validate(invalid_complex_hash, validations)
|
187
|
+
v.valid?.should be_false
|
188
|
+
v.errors.should eq({ bar: 'string required', user: { age: 'is required', likes: 'array required' } })
|
189
|
+
end
|
164
190
|
end
|
165
191
|
end
|
166
192
|
end
|
@@ -1,16 +1,23 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe HashValidator::Validator::Base do
|
4
|
-
let(:
|
4
|
+
let(:name) { 'my_validator' }
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
|
7
|
+
it 'allows a validator to be created with a valid name' do
|
8
|
+
expect { HashValidator::Validator::Base.new(name) }.to_not raise_error
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'does not allow a validator to be created with an invalid name' do
|
12
|
+
expect { HashValidator::Validator::Base.new(nil) }.to raise_error(StandardError, 'Validator must be initialized with a valid name (string with length greater than zero)')
|
13
|
+
expect { HashValidator::Validator::Base.new(123) }.to raise_error(StandardError, 'Validator must be initialized with a valid name (string with length greater than zero)')
|
14
|
+
expect { HashValidator::Validator::Base.new('') }.to raise_error(StandardError, 'Validator must be initialized with a valid name (string with length greater than zero)')
|
10
15
|
end
|
11
16
|
|
12
17
|
describe '#validate' do
|
13
|
-
|
18
|
+
let(:validator) { HashValidator::Validator::Base.new('test') }
|
19
|
+
|
20
|
+
it 'throws an exception as base validators cant actually validate' do
|
14
21
|
expect { validator.validate('key', 'value', {}, {}) }.to raise_error(StandardError, 'validate should not be called directly on BaseValidator')
|
15
22
|
end
|
16
23
|
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::Base do
|
4
|
+
let(:validator) { HashValidator::Validator::EmailValidator.new }
|
5
|
+
let(:errors) { Hash.new }
|
6
|
+
|
7
|
+
describe '#should_validate?' do
|
8
|
+
it 'should validate the name "email"' do
|
9
|
+
validator.should_validate?('email').should be_true
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should not validate other names' do
|
13
|
+
validator.should_validate?('string').should be_false
|
14
|
+
validator.should_validate?('array').should be_false
|
15
|
+
validator.should_validate?(nil).should be_false
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe '#validate' do
|
20
|
+
it 'should validate an email with true' do
|
21
|
+
validator.validate(:key, "johndoe@gmail.com", {}, errors)
|
22
|
+
|
23
|
+
errors.should be_empty
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'should validate a string without an @ symbol with false' do
|
27
|
+
validator.validate(:key, 'test', {}, errors)
|
28
|
+
|
29
|
+
errors.should_not be_empty
|
30
|
+
errors.should eq({ key: 'is not a valid email' })
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should validate a number with false' do
|
34
|
+
validator.validate(:key, 123, {}, errors)
|
35
|
+
|
36
|
+
errors.should_not be_empty
|
37
|
+
errors.should eq({ key: 'is not a valid email' })
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe HashValidator::Validator::SimpleValidator do
|
4
|
+
describe '#initialize' do
|
5
|
+
it 'accepts blocks with one argument' do
|
6
|
+
expect {
|
7
|
+
HashValidator::Validator::SimpleValidator.new('name', lambda { |a| true })
|
8
|
+
}.to_not raise_error
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'does not accept blocks with no arguments' do
|
12
|
+
expect {
|
13
|
+
HashValidator::Validator::SimpleValidator.new('name', lambda { true })
|
14
|
+
}.to raise_error(StandardError, 'lambda should take only one argument - passed lambda takes 0')
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'does not accept blocks with two arguments' do
|
18
|
+
expect {
|
19
|
+
HashValidator::Validator::SimpleValidator.new('name', lambda { |a,b| true })
|
20
|
+
}.to raise_error(StandardError, 'lambda should take only one argument - passed lambda takes 2')
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe '#validate' do
|
25
|
+
# Lambda that accepts strings that are 4 characters or shorter
|
26
|
+
let(:short_string_lambda) { lambda { |v| v.is_a?(String) && v.size < 5 } }
|
27
|
+
let(:short_string_validator) { HashValidator::Validator::SimpleValidator.new('short_string', short_string_lambda) }
|
28
|
+
let(:errors) { Hash.new }
|
29
|
+
|
30
|
+
[ '', '1', '12', '123', '1234' ].each do |value|
|
31
|
+
it "validates the string '#{value}'" do
|
32
|
+
short_string_validator.validate(:key, value, {}, errors)
|
33
|
+
|
34
|
+
errors.should be_empty
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
[ nil, '12345', '123456', 123, 123456, Time.now, (1..5) ].each do |value|
|
39
|
+
it "does not validate bad value '#{value}'" do
|
40
|
+
short_string_validator.validate(:key, value, {}, errors)
|
41
|
+
|
42
|
+
errors.should eq({ key: 'short_string required' })
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'Simple validator types' do
|
4
|
+
let(:errors) { Hash.new }
|
5
|
+
|
6
|
+
# Simple types
|
7
|
+
{
|
8
|
+
string: {
|
9
|
+
valid: [ '', 'Hello World', '12345' ],
|
10
|
+
invalid: [ nil, 12345, Time.now ]
|
11
|
+
},
|
12
|
+
numeric: {
|
13
|
+
valid: [ 0, 123, 123.45 ],
|
14
|
+
invalid: [ nil, '', '123', Time.now ]
|
15
|
+
},
|
16
|
+
array: {
|
17
|
+
valid: [ [], [1], ['foo'], [1,['foo'],Time.now] ],
|
18
|
+
invalid: [ nil, '', 123, '123', Time.now, '[1]' ]
|
19
|
+
},
|
20
|
+
time: {
|
21
|
+
valid: [ Time.now ],
|
22
|
+
invalid: [ nil, '', 123, '123', "#{Time.now}" ]
|
23
|
+
}
|
24
|
+
}.each do |type, data|
|
25
|
+
describe type do
|
26
|
+
data[:valid].each do |value|
|
27
|
+
it "validates '#{value}' successful" do
|
28
|
+
validator = HashValidator.validate({ v: value }, { v: type.to_s })
|
29
|
+
|
30
|
+
validator.valid?.should be_true
|
31
|
+
validator.errors.should be_empty
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
data[:invalid].each do |value|
|
36
|
+
it "validates '#{value}' with failure" do
|
37
|
+
validator = HashValidator.validate({ v: value }, { v: type.to_s })
|
38
|
+
|
39
|
+
validator.valid?.should be_false
|
40
|
+
validator.errors.should eq({ v: "#{type} required" })
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe 'User-defined validator' do
|
4
|
+
let(:validator) do
|
5
|
+
unless defined?(HashValidator::Validator::OddValidator)
|
6
|
+
# Define our custom validator
|
7
|
+
class HashValidator::Validator::OddValidator < HashValidator::Validator::Base
|
8
|
+
def initialize
|
9
|
+
super('odd')
|
10
|
+
end
|
11
|
+
|
12
|
+
def validate(key, value, validations, errors)
|
13
|
+
unless value.is_a?(Integer) && value.odd?
|
14
|
+
errors[key] = presence_error_message
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
HashValidator::Validator::OddValidator.new
|
21
|
+
end
|
22
|
+
|
23
|
+
let(:errors) { Hash.new }
|
24
|
+
|
25
|
+
|
26
|
+
describe '#should_validate?' do
|
27
|
+
it 'validates the name "odd"' do
|
28
|
+
validator.should_validate?('odd').should be_true
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'does not validate other names' do
|
32
|
+
validator.should_validate?('string').should be_false
|
33
|
+
validator.should_validate?('array').should be_false
|
34
|
+
validator.should_validate?(nil).should be_false
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe '#validate' do
|
39
|
+
it 'validates odd integers with true' do
|
40
|
+
validator.validate(:key, 1, {}, errors)
|
41
|
+
|
42
|
+
errors.should be_empty
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'validates even integers with errrors' do
|
46
|
+
validator.validate(:key, 2, {}, errors)
|
47
|
+
|
48
|
+
errors.should_not be_empty
|
49
|
+
errors.should eq({ key: 'odd required' })
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'validates even floats with errrors' do
|
53
|
+
validator.validate(:key, 2.0, {}, errors)
|
54
|
+
|
55
|
+
errors.should_not be_empty
|
56
|
+
errors.should eq({ key: 'odd required' })
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'validates odd floats with errrors' do
|
60
|
+
validator.validate(:key, 1.0, {}, errors)
|
61
|
+
|
62
|
+
errors.should_not be_empty
|
63
|
+
errors.should eq({ key: 'odd required' })
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'validates an odd integer string with errrors' do
|
67
|
+
validator.validate(:key, '1', {}, errors)
|
68
|
+
|
69
|
+
errors.should_not be_empty
|
70
|
+
errors.should eq({ key: 'odd required' })
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe 'Integrating with the entire validation system' do
|
75
|
+
before { HashValidator.append_validator(validator) rescue nil } # rescue to prevent: validators need to have unique names
|
76
|
+
|
77
|
+
it 'can be looked up using #validator_for' do
|
78
|
+
HashValidator.validator_for('odd').should be_a_kind_of(HashValidator::Validator::OddValidator)
|
79
|
+
end
|
80
|
+
|
81
|
+
it 'can be used in validations - test 1' do
|
82
|
+
validator = HashValidator.validate({ age: 27 }, { age: 'odd' })
|
83
|
+
|
84
|
+
validator.valid?.should be_true
|
85
|
+
validator.errors.should be_empty
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'can be used in validations - test 2' do
|
89
|
+
validator = HashValidator.validate({ age: 40 }, { age: 'odd' })
|
90
|
+
|
91
|
+
validator.valid?.should be_false
|
92
|
+
validator.errors.should eq({ age: 'odd required' })
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- James Brooks
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-
|
11
|
+
date: 2013-07-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -85,16 +85,21 @@ files:
|
|
85
85
|
- lib/hash_validator/base.rb
|
86
86
|
- lib/hash_validator/validators.rb
|
87
87
|
- lib/hash_validator/validators/base.rb
|
88
|
+
- lib/hash_validator/validators/email_validator.rb
|
88
89
|
- lib/hash_validator/validators/hash_validator.rb
|
89
90
|
- lib/hash_validator/validators/presence_validator.rb
|
90
|
-
- lib/hash_validator/validators/
|
91
|
+
- lib/hash_validator/validators/simple_type_validators.rb
|
92
|
+
- lib/hash_validator/validators/simple_validator.rb
|
91
93
|
- lib/hash_validator/version.rb
|
92
94
|
- spec/hash_validator_spec.rb
|
93
95
|
- spec/hash_validator_spec_helper.rb
|
94
96
|
- spec/spec_helper.rb
|
95
97
|
- spec/validators/base_spec.rb
|
98
|
+
- spec/validators/email_spec.rb
|
96
99
|
- spec/validators/presence_spec.rb
|
97
|
-
- spec/validators/
|
100
|
+
- spec/validators/simple_spec.rb
|
101
|
+
- spec/validators/simple_types_spec.rb
|
102
|
+
- spec/validators/user_defined_spec.rb
|
98
103
|
homepage: https://github.com/JamesBrooks/hash_validator
|
99
104
|
licenses:
|
100
105
|
- MIT
|
@@ -124,5 +129,8 @@ test_files:
|
|
124
129
|
- spec/hash_validator_spec_helper.rb
|
125
130
|
- spec/spec_helper.rb
|
126
131
|
- spec/validators/base_spec.rb
|
132
|
+
- spec/validators/email_spec.rb
|
127
133
|
- spec/validators/presence_spec.rb
|
128
|
-
- spec/validators/
|
134
|
+
- spec/validators/simple_spec.rb
|
135
|
+
- spec/validators/simple_types_spec.rb
|
136
|
+
- spec/validators/user_defined_spec.rb
|
@@ -1,32 +0,0 @@
|
|
1
|
-
class HashValidator::Validator::SimpleTypeValidator < HashValidator::Validator::Base
|
2
|
-
attr_accessor :name, :klass
|
3
|
-
|
4
|
-
|
5
|
-
def initialize(name, klass)
|
6
|
-
self.name = name
|
7
|
-
self.klass = klass
|
8
|
-
end
|
9
|
-
|
10
|
-
def presence_error_message
|
11
|
-
"#{name} required"
|
12
|
-
end
|
13
|
-
|
14
|
-
def should_validate?(rhs)
|
15
|
-
rhs == self.name
|
16
|
-
end
|
17
|
-
|
18
|
-
def validate(key, value, validations, errors)
|
19
|
-
unless value.is_a?(klass)
|
20
|
-
errors[key] = presence_error_message
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
|
26
|
-
# Create simple type validators
|
27
|
-
[
|
28
|
-
[ 'array', Array ],
|
29
|
-
[ 'numeric', Numeric ],
|
30
|
-
[ 'string', String ],
|
31
|
-
[ 'time', Time ]
|
32
|
-
].each { |name, klass| HashValidator.append_validator(HashValidator::Validator::SimpleTypeValidator.new(name, klass)) }
|
@@ -1,34 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe HashValidator::Validator::Base do
|
4
|
-
let(:my_class) { Class.new }
|
5
|
-
let(:validator) { HashValidator::Validator::SimpleTypeValidator.new('my_class', my_class) }
|
6
|
-
let(:errors) { Hash.new }
|
7
|
-
|
8
|
-
describe '#should_validate?' do
|
9
|
-
it 'should validate the name "my_class"' do
|
10
|
-
validator.should_validate?('my_class').should be_true
|
11
|
-
end
|
12
|
-
|
13
|
-
it 'should not validate other names' do
|
14
|
-
validator.should_validate?('string').should be_false
|
15
|
-
validator.should_validate?('array').should be_false
|
16
|
-
validator.should_validate?(nil).should be_false
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe '#validate' do
|
21
|
-
it 'should validate the my_class class with true' do
|
22
|
-
validator.validate(:key, my_class.new, {}, errors)
|
23
|
-
|
24
|
-
errors.should be_empty
|
25
|
-
end
|
26
|
-
|
27
|
-
it 'should validate other classes with errrors' do
|
28
|
-
validator.validate(:key, "foo bar", {}, errors)
|
29
|
-
|
30
|
-
errors.should_not be_empty
|
31
|
-
errors.should eq({ key: 'my_class required' })
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|