validation_profiler 0.1.0
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 +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +21 -0
- data/README.md +297 -0
- data/Rakefile +2 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/lib/validation_profiler/rules/rules.rb +437 -0
- data/lib/validation_profiler/rules/validation_rule_manager.rb +108 -0
- data/lib/validation_profiler/version.rb +3 -0
- data/lib/validation_profiler.rb +70 -0
- data/validation_profiler.gemspec +25 -0
- metadata +103 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 009ab57e0d9f853b5579576803bfd2fefa1369fe
|
4
|
+
data.tar.gz: 9c4f0fdff2487fdc274bb05bb6c977f3d6e10cef
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 04dc04f887ae68b8754ebbc5064ddc5d25ffc353b309084759d426d8e4de5d982643bfe950d4af4e9b7c611cf26af3f2590eddd86f19265b4e65bcf9b37540fb
|
7
|
+
data.tar.gz: 3e35caa074aa7e880cd1d6eb66764c44706790c39107faaa3b36de800876a742d478cda9aa7586cb197dcf6bf59d155a716bc4d82fedd48a077b12dd79b9ed55
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/CODE_OF_CONDUCT.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Contributor Code of Conduct
|
2
|
+
|
3
|
+
As contributors and maintainers of this project, and in the interest of
|
4
|
+
fostering an open and welcoming community, we pledge to respect all people who
|
5
|
+
contribute through reporting issues, posting feature requests, updating
|
6
|
+
documentation, submitting pull requests or patches, and other activities.
|
7
|
+
|
8
|
+
We are committed to making participation in this project a harassment-free
|
9
|
+
experience for everyone, regardless of level of experience, gender, gender
|
10
|
+
identity and expression, sexual orientation, disability, personal appearance,
|
11
|
+
body size, race, ethnicity, age, religion, or nationality.
|
12
|
+
|
13
|
+
Examples of unacceptable behavior by participants include:
|
14
|
+
|
15
|
+
* The use of sexualized language or imagery
|
16
|
+
* Personal attacks
|
17
|
+
* Trolling or insulting/derogatory comments
|
18
|
+
* Public or private harassment
|
19
|
+
* Publishing other's private information, such as physical or electronic
|
20
|
+
addresses, without explicit permission
|
21
|
+
* Other unethical or unprofessional conduct
|
22
|
+
|
23
|
+
Project maintainers have the right and responsibility to remove, edit, or
|
24
|
+
reject comments, commits, code, wiki edits, issues, and other contributions
|
25
|
+
that are not aligned to this Code of Conduct, or to ban temporarily or
|
26
|
+
permanently any contributor for other behaviors that they deem inappropriate,
|
27
|
+
threatening, offensive, or harmful.
|
28
|
+
|
29
|
+
By adopting this Code of Conduct, project maintainers commit themselves to
|
30
|
+
fairly and consistently applying these principles to every aspect of managing
|
31
|
+
this project. Project maintainers who do not follow or enforce the Code of
|
32
|
+
Conduct may be permanently removed from the project team.
|
33
|
+
|
34
|
+
This code of conduct applies both within project spaces and in public spaces
|
35
|
+
when an individual is representing the project or its community.
|
36
|
+
|
37
|
+
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
38
|
+
reported by contacting a project maintainer at vaughan.britton@sage.com. All
|
39
|
+
complaints will be reviewed and investigated and will result in a response that
|
40
|
+
is deemed necessary and appropriate to the circumstances. Maintainers are
|
41
|
+
obligated to maintain confidentiality with regard to the reporter of an
|
42
|
+
incident.
|
43
|
+
|
44
|
+
This Code of Conduct is adapted from the [Contributor Covenant][homepage],
|
45
|
+
version 1.3.0, available at
|
46
|
+
[http://contributor-covenant.org/version/1/3/0/][version]
|
47
|
+
|
48
|
+
[homepage]: http://contributor-covenant.org
|
49
|
+
[version]: http://contributor-covenant.org/version/1/3/0/
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 vaughanbrittonsage
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
# ValidationProfiler
|
2
|
+
|
3
|
+
Welcome to ValidationProfiler. This is a validation framework that allows you to seperate validation logic away from your objects and into validation profiles that can be re-used and changed without affecting your objects.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem 'validation_profiler'
|
11
|
+
```
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install validation_profiler
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
First you need to create a validation profile to hold the validation logic you want to apply, validation profiles must inherit from the ValidationProfile base class or another validation profile.
|
24
|
+
|
25
|
+
class SignUpValidationProfile < ValidationProfile
|
26
|
+
.....
|
27
|
+
end
|
28
|
+
|
29
|
+
Then you specify validation rules that should be checked when this profile is validated against an object.
|
30
|
+
|
31
|
+
class SignUpValidationProfile < ValidationProfile
|
32
|
+
validates :age, :min, { value: 18 }
|
33
|
+
validates :email, :email
|
34
|
+
.....
|
35
|
+
end
|
36
|
+
|
37
|
+
When specifying a validation rule you need to specify the following arguments:
|
38
|
+
|
39
|
+
- Field name
|
40
|
+
- Rule key
|
41
|
+
- Hash containing any options required for the validation rule
|
42
|
+
|
43
|
+
So if we take another look at the first validation rule we specified in the **SignUpValidationProfile** above:
|
44
|
+
|
45
|
+
Field name = :age
|
46
|
+
Rule key = :min
|
47
|
+
Attributes Hash = { value: 18 }
|
48
|
+
|
49
|
+
This validation statement will be interpreted as:
|
50
|
+
*"The field :age must have a minimum value of 18"*
|
51
|
+
|
52
|
+
To use a validation profile you need to make a call to the **ValidationManager** class, and pass the object you want to validate along with the profile you want to use for the validation:
|
53
|
+
|
54
|
+
#create the validation manager
|
55
|
+
manager = ValidationManager.new
|
56
|
+
|
57
|
+
#call the validate method and pass the object and profile
|
58
|
+
result = manager.validate(user, profile)
|
59
|
+
|
60
|
+
Calls to the validate method will return a **ValidationManagerResult** that will detail the results of the validation.
|
61
|
+
|
62
|
+
A **ValidationManagerResult** has the following attributes:
|
63
|
+
|
64
|
+
- #outcome = [Boolean] overall outcome of the validation (passed or failed)
|
65
|
+
- #errors = [Array] containing details of each field error that occurred during validation.
|
66
|
+
|
67
|
+
Each item in the errors array has the following attributes:
|
68
|
+
|
69
|
+
- #field = The name of the field that this error occurred for.
|
70
|
+
- #message = A message that describes the validation error
|
71
|
+
|
72
|
+
## Validation Rules
|
73
|
+
|
74
|
+
**RequiredValidationRule**
|
75
|
+
|
76
|
+
This rule is used to specify a field must contain a value:
|
77
|
+
|
78
|
+
validates :name, :required
|
79
|
+
|
80
|
+
Attributes:
|
81
|
+
|
82
|
+
- **:message** [String] [Optional]
|
83
|
+
This is used to allow a custom error message to be specified.
|
84
|
+
|
85
|
+
|
86
|
+
----------
|
87
|
+
|
88
|
+
|
89
|
+
**LengthValidationRule**
|
90
|
+
|
91
|
+
This rule is used to specify a [String] or [Array] must be of a certain length:
|
92
|
+
|
93
|
+
validates :name, :length, { min: 5, max: 10 }
|
94
|
+
|
95
|
+
Attributes:
|
96
|
+
|
97
|
+
- **:min** [Numeric]
|
98
|
+
This is used to specify the minimum length of the field value.
|
99
|
+
|
100
|
+
- **:max** [Numeric]
|
101
|
+
This is used to specify the maximum length of the field value.
|
102
|
+
|
103
|
+
> **:min** & **:max** can be included together or independently providing at least 1 is specified.
|
104
|
+
|
105
|
+
- **:message** [String] [Optional]
|
106
|
+
This is used to allow a custom error message to be specified.
|
107
|
+
|
108
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
109
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
110
|
+
> **True** always executes, **False** only executes when the field contains a value)*
|
111
|
+
|
112
|
+
|
113
|
+
----------
|
114
|
+
|
115
|
+
**MinValidationRule**
|
116
|
+
|
117
|
+
This rule is used to specify a minimum value a [DateTime] or [Numeric] field must have.
|
118
|
+
|
119
|
+
Attributes:
|
120
|
+
|
121
|
+
- **:value** [Numeric/DateTime]
|
122
|
+
This is used to specify the minimum value of the field.
|
123
|
+
|
124
|
+
- **:message** [String] [Optional]
|
125
|
+
This is used to allow a custom error message to be specified.
|
126
|
+
|
127
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
128
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
129
|
+
> **True** always executes, **False** only executes when the field contains a value)*
|
130
|
+
|
131
|
+
----------
|
132
|
+
|
133
|
+
**MaxValidationRule**
|
134
|
+
|
135
|
+
This rule is used to specify a maximum value a [DateTime] or [Numeric] field must have.
|
136
|
+
|
137
|
+
Attributes:
|
138
|
+
|
139
|
+
- **:value** [Numeric/DateTime]
|
140
|
+
This is used to specify the maximum value of the field.
|
141
|
+
|
142
|
+
- **:message** [String] [Optional]
|
143
|
+
This is used to allow a custom error message to be specified.
|
144
|
+
|
145
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
146
|
+
This is used to specify if this rule should only be executed the field contains a value.
|
147
|
+
> **True** always executes, **False** only executes when the field contains a value)*
|
148
|
+
|
149
|
+
----------
|
150
|
+
|
151
|
+
**EmailValidationRule**
|
152
|
+
|
153
|
+
This rule is used to specify a field value must contain a valid email address.
|
154
|
+
|
155
|
+
Attributes:
|
156
|
+
|
157
|
+
- **:message** [String] [Optional]
|
158
|
+
This is used to allow a custom error message to be specified.
|
159
|
+
|
160
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
161
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
162
|
+
> **True** always executes, **False** only executes when the field contains a value)*
|
163
|
+
|
164
|
+
----------
|
165
|
+
|
166
|
+
**RegexValidationRule**
|
167
|
+
|
168
|
+
This rule is used to specify a regex pattern that a field value must validate against.
|
169
|
+
|
170
|
+
Attributes:
|
171
|
+
|
172
|
+
- **:regex** [Regex]
|
173
|
+
This is used to specify the regex pattern.
|
174
|
+
|
175
|
+
- **:message** [String] [Optional]
|
176
|
+
This is used to allow a custom error message to be specified.
|
177
|
+
|
178
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
179
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
180
|
+
> **True** always executes, **False** only executes when the field contains a value)*
|
181
|
+
|
182
|
+
----------
|
183
|
+
|
184
|
+
**MatchValidationRule**
|
185
|
+
|
186
|
+
This rule is used to specify a field value must match the value of another field.
|
187
|
+
|
188
|
+
Attributes:
|
189
|
+
|
190
|
+
- **:field** [Symbol]
|
191
|
+
This is used to specify the name of the other field this field's value must match.
|
192
|
+
|
193
|
+
- **:message** [String] [Optional]
|
194
|
+
This is used to allow a custom error message to be specified.
|
195
|
+
|
196
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
197
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
198
|
+
> **True** always executes, **False** only executes when the field contains a value)
|
199
|
+
|
200
|
+
----------
|
201
|
+
|
202
|
+
**ConditionValidationRule**
|
203
|
+
|
204
|
+
This rule is used to specify a condition statement.
|
205
|
+
|
206
|
+
e.g.
|
207
|
+
|
208
|
+
> format:
|
209
|
+
>
|
210
|
+
> When [:condition_field] [:condition_expression] [:condition_value] then [:field] [:field_expression] [:field_value]
|
211
|
+
>
|
212
|
+
>could be read as:
|
213
|
+
>
|
214
|
+
> When :age >= 18 then :accept == true
|
215
|
+
|
216
|
+
Attributes:
|
217
|
+
|
218
|
+
- **:condition_field** [Symbol]
|
219
|
+
This is used to specify the name of the condition field.
|
220
|
+
|
221
|
+
- **:condition_expression** [String]
|
222
|
+
This is used to specify the expression to use between the condition_field and the condition_value.
|
223
|
+
|
224
|
+
> **Supported expression types:**
|
225
|
+
> '=='
|
226
|
+
> '>'
|
227
|
+
> '>='
|
228
|
+
> '<'
|
229
|
+
> '<='
|
230
|
+
> '!='
|
231
|
+
|
232
|
+
|
233
|
+
- **:condition_value** [String/Numeric/DateTime/nil]
|
234
|
+
This is used to specify the value to use for the condition statement.
|
235
|
+
|
236
|
+
- **:field_expression** [String]
|
237
|
+
This is used to specify the expression to use between the field's value and the field_value attribute.
|
238
|
+
|
239
|
+
- **:field_value** [String/Numeric/DateTime/nil]
|
240
|
+
This is used to specify the value to use for the field statement.
|
241
|
+
|
242
|
+
- **:message** [String] [Optional]
|
243
|
+
This is used to allow a custom error message to be specified.
|
244
|
+
|
245
|
+
- **:required** [Boolean] [Default=True] [Optional]
|
246
|
+
This is used to specify if this rule should only be executed when the field contains a value.
|
247
|
+
> **True** always executes, **False** only executes when the field contains a value)
|
248
|
+
|
249
|
+
----------
|
250
|
+
|
251
|
+
##Custom Validation Rules
|
252
|
+
|
253
|
+
To create a custom validation rule you must create a class that inherits from the **ValidationRule** base class and implement the #error_message and #validate methods, see the **RequiredValidationRule** below as an example:
|
254
|
+
|
255
|
+
class RequiredValidationRule < ValidationRule
|
256
|
+
#implement this method to return the error message when
|
257
|
+
#this rule fails validation
|
258
|
+
def error_message(field, attributes = {})
|
259
|
+
#check if custom message was specified
|
260
|
+
if attributes[:message] == nil
|
261
|
+
#return default method
|
262
|
+
"#{field} is not valid"
|
263
|
+
else
|
264
|
+
#return custom message
|
265
|
+
attributes[:message]
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
def validate(obj, field, attributes = {})
|
270
|
+
#attempt to get the field value from the object
|
271
|
+
field_value = get_field_value(obj, field)
|
272
|
+
|
273
|
+
if field_value == nil
|
274
|
+
return false
|
275
|
+
end
|
276
|
+
|
277
|
+
return !field_value.empty?
|
278
|
+
end
|
279
|
+
end
|
280
|
+
|
281
|
+
The **ValidationRule** base class provides the *#get_field_value(obj, field)* method to cater for fetching the field value from the object to perform the validation against.
|
282
|
+
|
283
|
+
## Development
|
284
|
+
|
285
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
286
|
+
|
287
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
288
|
+
|
289
|
+
## Contributing
|
290
|
+
|
291
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/vaughanbrittonsage/validation_profiler. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
|
292
|
+
|
293
|
+
|
294
|
+
## License
|
295
|
+
|
296
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
297
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "validation_profiler"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
@@ -0,0 +1,437 @@
|
|
1
|
+
require 'pry'
|
2
|
+
|
3
|
+
class InvalidRuleAttributes < StandardError
|
4
|
+
|
5
|
+
def initialize(rule, field)
|
6
|
+
@rule = rule
|
7
|
+
@field = field
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
rule = @rule
|
12
|
+
field = @field
|
13
|
+
"Incorrect attributes specified for Validation rule: #{rule} Field: #{field}."
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
|
18
|
+
class FieldNotFound < StandardError
|
19
|
+
|
20
|
+
def initialize(field)
|
21
|
+
@field = field
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_s
|
25
|
+
field = @field
|
26
|
+
"Field: #{field} could not be found."
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
|
31
|
+
class InvalidFieldType < StandardError
|
32
|
+
|
33
|
+
def initialize(rule, field)
|
34
|
+
@rule = rule
|
35
|
+
@field = field
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
rule = @rule
|
40
|
+
field = @field
|
41
|
+
"Field: #{field} has an incorrect value type for Validation Rule: #{rule}."
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
|
46
|
+
class ValidationRule
|
47
|
+
|
48
|
+
def get_field_value(obj, field)
|
49
|
+
#attempt to get the field value from the object
|
50
|
+
field_value = nil
|
51
|
+
#check if the object is a hash
|
52
|
+
if obj.is_a?(Hash)
|
53
|
+
#get the field value
|
54
|
+
field_value = obj[field]
|
55
|
+
else
|
56
|
+
#if the object does not contain the specified field raise an exception
|
57
|
+
if !obj.respond_to?(field)
|
58
|
+
raise FieldNotFound.new(field)
|
59
|
+
end
|
60
|
+
|
61
|
+
#get the field value
|
62
|
+
field_value = obj.send(field)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def is_required?(field_value, attributes = {})
|
67
|
+
required = attributes[:required]
|
68
|
+
if required == nil
|
69
|
+
required = true
|
70
|
+
end
|
71
|
+
|
72
|
+
#check if the field is required
|
73
|
+
if (field_value == nil || ((field_value.is_a?(String) || field_value.is_a?(Array)) && field_value.empty?)) && required == false
|
74
|
+
return false
|
75
|
+
else
|
76
|
+
return true
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
class LengthValidationRule < ValidationRule
|
83
|
+
|
84
|
+
def error_message(field, attributes)
|
85
|
+
#check if a custom error message has been specified in the attributes
|
86
|
+
if attributes[:message] == nil
|
87
|
+
#no custom error message has been specified so create the default message.
|
88
|
+
min = attributes[:min]
|
89
|
+
max = attributes[:max]
|
90
|
+
if min && max
|
91
|
+
"#{field} must have a min length of #{min} and a max length of #{max}"
|
92
|
+
elsif min
|
93
|
+
"#{field} must have a min length of #{min}"
|
94
|
+
else
|
95
|
+
"#{field} must have a max length of #{max}"
|
96
|
+
end
|
97
|
+
else
|
98
|
+
attributes[:message]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
def validate(obj, field, attributes)
|
103
|
+
|
104
|
+
min = attributes[:min]
|
105
|
+
max = attributes[:max]
|
106
|
+
|
107
|
+
#verify the expected attributes have been specified.
|
108
|
+
if min == nil && max == nil
|
109
|
+
raise InvalidRuleAttributes.new(LengthValidationRule, field)
|
110
|
+
end
|
111
|
+
|
112
|
+
#attempt to get the field value from the object
|
113
|
+
field_value = get_field_value(obj, field)
|
114
|
+
|
115
|
+
if field_value.is_a?(Array)
|
116
|
+
length = field_value.length
|
117
|
+
else
|
118
|
+
length = field_value.to_s.length
|
119
|
+
end
|
120
|
+
|
121
|
+
#validate the field value
|
122
|
+
if min && max
|
123
|
+
return length >= min && length <= max
|
124
|
+
elsif min
|
125
|
+
return length >= min
|
126
|
+
elsif max
|
127
|
+
return length <= max
|
128
|
+
end
|
129
|
+
|
130
|
+
return false
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
class MinValidationRule < ValidationRule
|
136
|
+
|
137
|
+
def error_message(field, attributes)
|
138
|
+
#check if a custom error message has been specified in the attributes
|
139
|
+
if attributes[:message] == nil
|
140
|
+
#no custom error message has been specified so create the default message.
|
141
|
+
min = attributes[:value]
|
142
|
+
"#{field} must have a minimum value of #{min}"
|
143
|
+
else
|
144
|
+
attributes[:message]
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
def validate(obj, field, attributes)
|
149
|
+
|
150
|
+
min = attributes[:value]
|
151
|
+
|
152
|
+
#verify the expected attributes have been specified.
|
153
|
+
if min == nil
|
154
|
+
raise InvalidRuleAttributes.new(MinValidationRule, field)
|
155
|
+
end
|
156
|
+
|
157
|
+
#attempt to get the field value from the object
|
158
|
+
field_value = get_field_value(obj, field)
|
159
|
+
|
160
|
+
if !is_required?(field_value, attributes)
|
161
|
+
return true
|
162
|
+
end
|
163
|
+
|
164
|
+
if field_value.is_a?(DateTime) || field_value.is_a?(Numeric)
|
165
|
+
field_value >= min
|
166
|
+
else
|
167
|
+
raise InvalidFieldType.new(MinValidationRule, field)
|
168
|
+
end
|
169
|
+
|
170
|
+
end
|
171
|
+
|
172
|
+
end
|
173
|
+
|
174
|
+
class MaxValidationRule < ValidationRule
|
175
|
+
|
176
|
+
def error_message(field, attributes)
|
177
|
+
#check if a custom error message has been specified in the attributes
|
178
|
+
if attributes[:message] == nil
|
179
|
+
#no custom error message has been specified so create the default message.
|
180
|
+
max = attributes[:value]
|
181
|
+
"#{field} must not have a value greater than #{max}"
|
182
|
+
else
|
183
|
+
attributes[:message]
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def validate(obj, field, attributes)
|
188
|
+
|
189
|
+
max = attributes[:value]
|
190
|
+
|
191
|
+
#verify the expected attributes have been specified.
|
192
|
+
if max == nil
|
193
|
+
raise InvalidRuleAttributes.new(MinValidationRule, field)
|
194
|
+
end
|
195
|
+
|
196
|
+
#attempt to get the field value from the object
|
197
|
+
field_value = get_field_value(obj, field)
|
198
|
+
|
199
|
+
if !is_required?(field_value, attributes)
|
200
|
+
return true
|
201
|
+
end
|
202
|
+
|
203
|
+
if field_value.is_a?(DateTime) || field_value.is_a?(Numeric)
|
204
|
+
field_value <= max
|
205
|
+
else
|
206
|
+
raise InvalidFieldType.new(MaxValidationRule, field)
|
207
|
+
end
|
208
|
+
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
class RequiredValidationRule < ValidationRule
|
214
|
+
|
215
|
+
def error_message(field, attributes = {})
|
216
|
+
#check if a custom error message has been specified in the attributes
|
217
|
+
if attributes[:message] == nil
|
218
|
+
#no custom error message has been specified so create the default message.
|
219
|
+
"#{field} is required"
|
220
|
+
else
|
221
|
+
attributes[:message]
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
|
226
|
+
def validate(obj, field, attributes = {})
|
227
|
+
|
228
|
+
#attempt to get the field value from the object
|
229
|
+
field_value = get_field_value(obj, field)
|
230
|
+
|
231
|
+
if field_value == nil
|
232
|
+
return false
|
233
|
+
end
|
234
|
+
|
235
|
+
return !field_value.empty?
|
236
|
+
|
237
|
+
end
|
238
|
+
|
239
|
+
end
|
240
|
+
|
241
|
+
class EmailValidationRule < ValidationRule
|
242
|
+
|
243
|
+
REGEX = /^[^@]+@[^@]+\.[^@]+$/
|
244
|
+
|
245
|
+
def error_message(field, attributes = {})
|
246
|
+
#check if a custom error message has been specified in the attributes
|
247
|
+
if attributes[:message] == nil
|
248
|
+
#no custom error message has been specified so create the default message.
|
249
|
+
"#{field} is not a valid email address"
|
250
|
+
else
|
251
|
+
attributes[:message]
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
|
256
|
+
def validate(obj, field, attributes = {})
|
257
|
+
|
258
|
+
#attempt to get the field value from the object
|
259
|
+
field_value = get_field_value(obj, field)
|
260
|
+
|
261
|
+
if !is_required?(field_value, attributes)
|
262
|
+
return true
|
263
|
+
end
|
264
|
+
|
265
|
+
#validate the value against the regex
|
266
|
+
if field_value =~ REGEX
|
267
|
+
return true
|
268
|
+
end
|
269
|
+
|
270
|
+
return false
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
275
|
+
|
276
|
+
class RegexValidationRule < ValidationRule
|
277
|
+
|
278
|
+
def error_message(field, attributes = {})
|
279
|
+
#check if a custom error message has been specified in the attributes
|
280
|
+
if attributes[:message] == nil
|
281
|
+
#no custom error message has been specified so create the default message.
|
282
|
+
"#{field} is not a valid"
|
283
|
+
else
|
284
|
+
attributes[:message]
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
|
289
|
+
def validate(obj, field, attributes)
|
290
|
+
|
291
|
+
#attempt to get the field value from the object
|
292
|
+
field_value = get_field_value(obj, field)
|
293
|
+
|
294
|
+
regex = attributes[:regex]
|
295
|
+
if regex == nil
|
296
|
+
raise InvalidRuleAttributes.new(RegexValidationRule, field)
|
297
|
+
end
|
298
|
+
|
299
|
+
if !is_required?(field_value, attributes)
|
300
|
+
return true
|
301
|
+
end
|
302
|
+
|
303
|
+
#validate the value against the regex
|
304
|
+
if field_value =~ regex
|
305
|
+
return true
|
306
|
+
end
|
307
|
+
|
308
|
+
return false
|
309
|
+
|
310
|
+
end
|
311
|
+
|
312
|
+
end
|
313
|
+
|
314
|
+
class MatchValidationRule < ValidationRule
|
315
|
+
|
316
|
+
def error_message(field, attributes)
|
317
|
+
|
318
|
+
match_field = attributes[:field]
|
319
|
+
|
320
|
+
#check if a custom error message has been specified in the attributes
|
321
|
+
if attributes[:message] == nil
|
322
|
+
#no custom error message has been specified so create the default message.
|
323
|
+
"#{field} does not match #{match_field}"
|
324
|
+
else
|
325
|
+
attributes[:message]
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
def validate(obj, field, attributes)
|
331
|
+
|
332
|
+
#attempt to get the field value from the object
|
333
|
+
field_value = get_field_value(obj, field)
|
334
|
+
|
335
|
+
match_field = attributes[:field]
|
336
|
+
if match_field == nil
|
337
|
+
raise InvalidRuleAttributes.new(MatchValidationRule, field)
|
338
|
+
end
|
339
|
+
|
340
|
+
if !is_required?(field_value, attributes)
|
341
|
+
return true
|
342
|
+
end
|
343
|
+
|
344
|
+
match_field_value = get_field_value(obj, match_field)
|
345
|
+
|
346
|
+
return field_value == match_field_value
|
347
|
+
|
348
|
+
end
|
349
|
+
|
350
|
+
end
|
351
|
+
|
352
|
+
class ConditionValidationRule < ValidationRule
|
353
|
+
|
354
|
+
def error_message(field, attributes = {})
|
355
|
+
|
356
|
+
match_field = attributes[:field]
|
357
|
+
|
358
|
+
#check if a custom error message has been specified in the attributes
|
359
|
+
if attributes[:message] == nil
|
360
|
+
#no custom error message has been specified so create the default message.
|
361
|
+
"#{field} is not valid"
|
362
|
+
else
|
363
|
+
attributes[:message]
|
364
|
+
end
|
365
|
+
end
|
366
|
+
|
367
|
+
|
368
|
+
def validate(obj, field, attributes)
|
369
|
+
|
370
|
+
#attempt to get the field value from the object
|
371
|
+
value = get_field_value(obj, field)
|
372
|
+
|
373
|
+
condition_field = attributes[:condition_field]
|
374
|
+
if condition_field == nil
|
375
|
+
raise InvalidRuleAttributes.new(ConditionValidationRule, field)
|
376
|
+
end
|
377
|
+
|
378
|
+
condition_value = attributes[:condition_value]
|
379
|
+
if condition_value == nil
|
380
|
+
raise InvalidRuleAttributes.new(ConditionValidationRule, field)
|
381
|
+
end
|
382
|
+
|
383
|
+
condition_expression = attributes[:condition_expression]
|
384
|
+
if condition_expression == nil
|
385
|
+
raise InvalidRuleAttributes.new(ConditionValidationRule, field)
|
386
|
+
end
|
387
|
+
|
388
|
+
field_expression = attributes[:field_expression]
|
389
|
+
if field_expression == nil
|
390
|
+
raise InvalidRuleAttributes.new(ConditionValidationRule, field)
|
391
|
+
end
|
392
|
+
|
393
|
+
field_value = attributes[:field_value]
|
394
|
+
if field_value == nil
|
395
|
+
raise InvalidRuleAttributes.new(ConditionValidationRule, field)
|
396
|
+
end
|
397
|
+
|
398
|
+
if !is_required?(value, attributes)
|
399
|
+
return true
|
400
|
+
end
|
401
|
+
|
402
|
+
condition_field_value = get_field_value(obj, condition_field)
|
403
|
+
|
404
|
+
#check if the condition is valid
|
405
|
+
if confirm_expression?(condition_field_value, condition_expression, condition_value)
|
406
|
+
#check if the field value is correct for the condition
|
407
|
+
if confirm_expression?(value, field_expression, field_value)
|
408
|
+
return true
|
409
|
+
else
|
410
|
+
return false
|
411
|
+
end
|
412
|
+
end
|
413
|
+
|
414
|
+
return true
|
415
|
+
|
416
|
+
end
|
417
|
+
|
418
|
+
def confirm_expression?(value_a, expression, value_b)
|
419
|
+
a = value_a
|
420
|
+
b = value_b
|
421
|
+
|
422
|
+
if value_a.is_a?(String)
|
423
|
+
a = "'#{value_a}'"
|
424
|
+
elsif value_a == nil
|
425
|
+
a = 'nil'
|
426
|
+
end
|
427
|
+
|
428
|
+
if value_b.is_a?(String)
|
429
|
+
b = "'#{value_b}'"
|
430
|
+
elsif value_b == nil
|
431
|
+
b = 'nil'
|
432
|
+
end
|
433
|
+
|
434
|
+
eval("#{a} #{expression} #{b}")
|
435
|
+
end
|
436
|
+
|
437
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'pry'
|
2
|
+
require_relative '../../../lib/validation_profiler/rules/rules'
|
3
|
+
|
4
|
+
# This is the manager class that holds all registered validation rules.
|
5
|
+
class ValidationRuleManager
|
6
|
+
|
7
|
+
class << self
|
8
|
+
attr_accessor :instance
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize
|
12
|
+
@rules = []
|
13
|
+
ValidationRuleManager.instance = self
|
14
|
+
load_rules
|
15
|
+
end
|
16
|
+
|
17
|
+
# This method is called to get a validation rule by it's registered key.
|
18
|
+
#
|
19
|
+
# @params key [Symbol] This is the key of the validation rule you want to request.
|
20
|
+
#
|
21
|
+
# @return [ValidationRule] This is the requested ValidationRule instance.
|
22
|
+
def get_rule(key)
|
23
|
+
|
24
|
+
results = @rules.select { |r| r[:key] == key }
|
25
|
+
if !results.empty?
|
26
|
+
results[0][:instance]
|
27
|
+
else
|
28
|
+
raise ValidationRuleNotFound.new(key)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
# This method is called to add a validation rule to the manager for use.
|
33
|
+
#
|
34
|
+
# @param key [Symbol] This is the key to register the validation rule for.
|
35
|
+
# @param rule [ClassName] This is the class name of the validation rule to register.
|
36
|
+
def add_rule(key, rule)
|
37
|
+
|
38
|
+
instance = rule.new
|
39
|
+
|
40
|
+
#verify the rule instance inherits ValidationRule
|
41
|
+
if instance == nil || !instance.is_a?(ValidationRule)
|
42
|
+
raise InvalidRuleType.new(instance.class)
|
43
|
+
end
|
44
|
+
|
45
|
+
#verify the rule name has not already been registered
|
46
|
+
if !@rules.select { |r| r[:key] == key }.empty?
|
47
|
+
raise RuleAlreadyExists.new(key)
|
48
|
+
end
|
49
|
+
|
50
|
+
@rules.push({ key: key, instance: instance})
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def load_rules
|
57
|
+
|
58
|
+
@rules.push({ key: :required, instance: RequiredValidationRule.new })
|
59
|
+
@rules.push({ key: :length, instance: LengthValidationRule.new })
|
60
|
+
@rules.push({ key: :min, instance: MinValidationRule.new })
|
61
|
+
@rules.push({ key: :max, instance: MaxValidationRule.new })
|
62
|
+
@rules.push({ key: :email, instance: EmailValidationRule.new })
|
63
|
+
@rules.push({ key: :regex, instance: RegexValidationRule.new })
|
64
|
+
@rules.push({ key: :match, instance: MatchValidationRule.new })
|
65
|
+
@rules.push({ key: :condition, instance: ConditionValidationRule.new })
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
70
|
+
|
71
|
+
class ValidationRuleNotFound < StandardError
|
72
|
+
|
73
|
+
def initialize(rule)
|
74
|
+
@rule = rule
|
75
|
+
end
|
76
|
+
|
77
|
+
def to_s
|
78
|
+
rule = @rule
|
79
|
+
"Validation rule: #{rule} could not be found."
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
class InvalidRuleType < StandardError
|
85
|
+
|
86
|
+
def initialize(rule)
|
87
|
+
@rule = rule
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s
|
91
|
+
rule = @rule
|
92
|
+
"Validation rule: #{rule} is not a valid type. Rules must inherit from the ValidationRule base class."
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
class RuleAlreadyExists < StandardError
|
98
|
+
|
99
|
+
def initialize(key)
|
100
|
+
@key = key
|
101
|
+
end
|
102
|
+
|
103
|
+
def to_s
|
104
|
+
key = @key
|
105
|
+
"A Rule has already been registered for the key: #{key}."
|
106
|
+
end
|
107
|
+
|
108
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "validation_profiler/version"
|
2
|
+
require 'pry'
|
3
|
+
class Class
|
4
|
+
|
5
|
+
# Specifies a validation rule to use within a validation profile.
|
6
|
+
#
|
7
|
+
# @param field [Symbol] The name of the field to validate
|
8
|
+
# @param rule [Symbol] The name of the validation rule to use
|
9
|
+
# @param attributes [Hash] A has containing the validation rule options
|
10
|
+
def validates(field, rule, attributes)
|
11
|
+
|
12
|
+
if !defined?(self.validation_rules)
|
13
|
+
self.class_variable_set(:@@validation_rules, [])
|
14
|
+
end
|
15
|
+
|
16
|
+
validation_rules = self.class_variable_get(:@@validation_rules)
|
17
|
+
validation_rules.push({ name: rule, field: field, attributes: attributes })
|
18
|
+
|
19
|
+
self.class_variable_set(:@@validation_rules, validation_rules)
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
class ValidationManager
|
26
|
+
|
27
|
+
# Called to validate an object against a validation profile.
|
28
|
+
#
|
29
|
+
# @param obj [Object] The object to validate
|
30
|
+
# @param profile [ClassName] The class name of the validation profile to validate against
|
31
|
+
#
|
32
|
+
# @return [ValidationManagerResult] The result of the validation
|
33
|
+
def validate(obj, profile)
|
34
|
+
|
35
|
+
result = ValidationManagerResult.new
|
36
|
+
|
37
|
+
validation_rules = profile.class_variable_get(:@@validation_rules)
|
38
|
+
validation_rules.each do |r|
|
39
|
+
|
40
|
+
rule = ValidationRuleManager.instance.get_rule(r[:name])
|
41
|
+
outcome = rule.validate(obj, r[:field], r[:attributes])
|
42
|
+
|
43
|
+
if !outcome
|
44
|
+
result.outcome = false
|
45
|
+
result.errors.push({ field: r[:field], message: rule.error_message(r[:field], r[:attributes]) })
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
result
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
55
|
+
|
56
|
+
# This is used to specify validation results from the #validate method of the ValidationManager
|
57
|
+
class ValidationManagerResult
|
58
|
+
|
59
|
+
# @!attribute outcome
|
60
|
+
# @return [Boolean] The outcome of the validation.
|
61
|
+
attr_accessor :outcome
|
62
|
+
# @!attribute errors
|
63
|
+
# @return [Array[{:field, :error_message}]] An array of field errors that occurred during validation.
|
64
|
+
attr_accessor :errors
|
65
|
+
|
66
|
+
def initialize
|
67
|
+
@errors = []
|
68
|
+
@outcome = true
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'validation_profiler/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "validation_profiler"
|
8
|
+
spec.version = ValidationProfiler::VERSION
|
9
|
+
spec.authors = ["vaughanbrittonsage"]
|
10
|
+
spec.email = ["vaughanbritton@gmail.com"]
|
11
|
+
|
12
|
+
spec.summary = 'A Validation framework for creating validation profiles, allowing for the separation & reuse of validation logic from the object being validated.'
|
13
|
+
spec.description = 'A Validation framework for creating validation profiles, allowing for the separation & reuse of validation logic from the object being validated.'
|
14
|
+
spec.homepage = "https://github.com/vaughanbrittonsage/validation_profiler"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
18
|
+
spec.bindir = "exe"
|
19
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.11"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
end
|
metadata
ADDED
@@ -0,0 +1,103 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validation_profiler
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- vaughanbrittonsage
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-02-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.11'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.11'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: A Validation framework for creating validation profiles, allowing for
|
56
|
+
the separation & reuse of validation logic from the object being validated.
|
57
|
+
email:
|
58
|
+
- vaughanbritton@gmail.com
|
59
|
+
executables: []
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- ".gitignore"
|
64
|
+
- ".rspec"
|
65
|
+
- CODE_OF_CONDUCT.md
|
66
|
+
- Gemfile
|
67
|
+
- LICENSE.txt
|
68
|
+
- README.md
|
69
|
+
- Rakefile
|
70
|
+
- bin/console
|
71
|
+
- bin/setup
|
72
|
+
- lib/validation_profiler.rb
|
73
|
+
- lib/validation_profiler/rules/rules.rb
|
74
|
+
- lib/validation_profiler/rules/validation_rule_manager.rb
|
75
|
+
- lib/validation_profiler/version.rb
|
76
|
+
- validation_profiler.gemspec
|
77
|
+
homepage: https://github.com/vaughanbrittonsage/validation_profiler
|
78
|
+
licenses:
|
79
|
+
- MIT
|
80
|
+
metadata: {}
|
81
|
+
post_install_message:
|
82
|
+
rdoc_options: []
|
83
|
+
require_paths:
|
84
|
+
- lib
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
91
|
+
requirements:
|
92
|
+
- - ">="
|
93
|
+
- !ruby/object:Gem::Version
|
94
|
+
version: '0'
|
95
|
+
requirements: []
|
96
|
+
rubyforge_project:
|
97
|
+
rubygems_version: 2.5.1
|
98
|
+
signing_key:
|
99
|
+
specification_version: 4
|
100
|
+
summary: A Validation framework for creating validation profiles, allowing for the
|
101
|
+
separation & reuse of validation logic from the object being validated.
|
102
|
+
test_files: []
|
103
|
+
has_rdoc:
|