hydra-validations 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CONTRIBUTORS.md +1 -0
- data/README.md +164 -53
- data/lib/hydra/validations/presence.rb +16 -0
- data/lib/hydra/validations/version.rb +1 -1
- data/spec/validations/presence_validator_spec.rb +40 -0
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5e3b8f594ffb78eea70a27d91d92ed195988ae54
|
4
|
+
data.tar.gz: 1d2abb83db312b502a3570bd428a90e13d355750
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 77946326c106d26eef65cc9e41380a5a2eb01bab261f637dafb6400e84b710b31b2d3f04b22b7c8ba426a62043270708ebe78156bb467b904cf64b3175accdbd
|
7
|
+
data.tar.gz: 6084c27aaf6326df5adc5216b3466ecce67d67d0558cab7a0993c8fce488f8c263fe4ee5011cfd66d152b121c13593c95e803fc218e84fe844fab8784941608d
|
data/CONTRIBUTORS.md
CHANGED
data/README.md
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
hydra-validations
|
2
2
|
=======================
|
3
3
|
|
4
|
-
Custom validators for Hydra applications, based on ActiveModel::Validations.
|
5
|
-
|
6
4
|
[![Build Status](https://travis-ci.org/projecthydra-labs/hydra-validations.svg?branch=master)](https://travis-ci.org/projecthydra-labs/hydra-validations)
|
7
5
|
[![Gem Version](https://badge.fury.io/rb/hydra-validations.svg)](http://badge.fury.io/rb/hydra-validations)
|
8
6
|
|
7
|
+
Custom validators based on ActiveModel::Validations, developed for Hydra applications.
|
8
|
+
|
9
9
|
## Dependencies
|
10
10
|
|
11
11
|
* Ruby >= 1.9.3
|
12
12
|
* ActiveModel 4.x
|
13
13
|
|
14
|
+
ActiveFedora 7.x is a run-time dependency of the UniquenessValidator only, and is not provided by this gem.
|
15
|
+
|
14
16
|
## Installation
|
15
17
|
|
16
18
|
Include in your Gemfile:
|
@@ -25,17 +27,109 @@ and
|
|
25
27
|
bundle install
|
26
28
|
```
|
27
29
|
|
30
|
+
## Why?
|
31
|
+
|
32
|
+
- Metadata values are (often) arrays (XML or RDF).
|
33
|
+
- ActiveModel validators don't distinguish between array values and scalar values.
|
34
|
+
- We want validators that validate each member of an array value.
|
35
|
+
|
36
|
+
### Example: PORO with ActiveModel::Validations
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
class Validatable
|
40
|
+
include ActiveModel::Validations
|
41
|
+
attr_accessor :type
|
42
|
+
validates_inclusion_of :type, in: %w(text image audio video)
|
43
|
+
end
|
44
|
+
|
45
|
+
>> record = Validatable.new
|
46
|
+
>> record.type = "text"
|
47
|
+
>> record.valid?
|
48
|
+
=> true
|
49
|
+
|
50
|
+
>> record.type = ["text", "image"]
|
51
|
+
>> record.valid?
|
52
|
+
=> false # not what we want :(
|
53
|
+
|
54
|
+
# now let's add Hydra::Validations ...
|
55
|
+
|
56
|
+
class CorrectlyValidatable
|
57
|
+
include ActiveModel::Validations
|
58
|
+
include Hydra::Validations
|
59
|
+
attr_accessor :type
|
60
|
+
validates_inclusion_of :type, in: %w(text image audio video)
|
61
|
+
end
|
62
|
+
|
63
|
+
>> record = CorrectlyValidatable.new
|
64
|
+
>> record.type = ["text", "image"]
|
65
|
+
>> record.valid?
|
66
|
+
=> true # Yay!
|
67
|
+
|
68
|
+
>> record.type = ["text", "newspaper"]
|
69
|
+
>> record.valid?
|
70
|
+
=> false
|
71
|
+
|
72
|
+
# tailors error message to specific invalid array value
|
73
|
+
>> puts record.errors.full_messages
|
74
|
+
Type value "newspaper" is not included in the list
|
75
|
+
```
|
76
|
+
|
77
|
+
### Example: ActiveTriples::Resource
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
class MyResource < ActiveTriples::Resource
|
81
|
+
# ActiveTriples::Resource includes ActiveModel::Validations
|
82
|
+
property :type, predicate: RDF::DC.type
|
83
|
+
validates_inclusion_of :type, in: %w(text image audio video)
|
84
|
+
end
|
85
|
+
|
86
|
+
>> resource = MyResource.new
|
87
|
+
>> resource.type = "text"
|
88
|
+
>> resource.valid?
|
89
|
+
=> false # Huh? Oh yeah, resource.type is actually an array ...
|
90
|
+
>> resource.type
|
91
|
+
=> ["text"]
|
92
|
+
|
93
|
+
class YourResource < ActiveTriples::Resource
|
94
|
+
include Hydra::Validations
|
95
|
+
property :type, predicate: RDF::DC.type
|
96
|
+
validates_inclusion_of :type, in: %w(text image audio video)
|
97
|
+
end
|
98
|
+
|
99
|
+
>> resource = YourResource.new
|
100
|
+
>> resource.type = "text"
|
101
|
+
=> "text"
|
102
|
+
>> resource.valid?
|
103
|
+
=> true # Yay!
|
104
|
+
|
105
|
+
>> resource.type << "newspapers"
|
106
|
+
>> resource.type
|
107
|
+
=> ["text", "newspapers"]
|
108
|
+
>> resource.valid?
|
109
|
+
=> false
|
110
|
+
>> puts resource.errors.full_messages
|
111
|
+
Type value "newspapers" is not included in the list
|
112
|
+
```
|
113
|
+
|
28
114
|
## EnumerableBehavior Mixin
|
29
115
|
|
116
|
+
`Hydra::Validations::EnumerableBehavior` is a mixin for an `ActiveModel::EachValidator` that validates each member of an enumerable value. See the [FormatValidator](#formatvalidator) and [InclusionValidator](#inclusionvalidator) below for examples.
|
117
|
+
|
118
|
+
EnumerableBehavior overrides `validate_each(record, attribute, value)` calling `super(record, attribute, member)` for each member of an enumerable value (i.e., responds to `:each`). The module "fixes" any error messages to include the specific member that failed validation -- for example, `"is invalid"` becomes `"value \"foo1\" is invalid"`, so the full message `"Identifier is invalid"` becomes `"Identifer value \"foo1\" is invalid"`.
|
119
|
+
|
120
|
+
**allow_nil, allow_blank, and allow_empty**
|
121
|
+
|
122
|
+
With EnumerableBehavior, validation of non-enumerables is unchanged (`validate_each` simply returns `super`); however, the validator options `allow_nil` and `allow_blank` *apply only to the original value* (the enumerable) and not to its members. For example, the value `[""]` with the option `allow_blank: true` will *not* bypass validation. As a result, empty enumerables will fail validation unless `allow_blank` is true or the special enumerable option `allow_empty` is true (that option does not bypass validation for non-enumerables that respond to `:empty?`, e.g., empty strings).
|
123
|
+
|
30
124
|
## Validators
|
31
125
|
|
32
126
|
See also the source code and spec tests.
|
33
127
|
|
34
128
|
### FormatValidator
|
35
129
|
|
36
|
-
Extends
|
130
|
+
Extends `ActiveModel::Validations::FormatValidator`, adding EnumerableBehavior.
|
37
131
|
|
38
|
-
See
|
132
|
+
See `ActiveModel::Validations::FormatValidator` for usage and options.
|
39
133
|
|
40
134
|
```ruby
|
41
135
|
class FormatValidatable
|
@@ -47,27 +141,34 @@ class FormatValidatable
|
|
47
141
|
# validates_format_of :field, with: /\A[[:alpha:]]+\Z/
|
48
142
|
end
|
49
143
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
144
|
+
>> record = FormatValidatable.new
|
145
|
+
=> #<FormatValidatable:0x007fe3cc0ece70>
|
146
|
+
>> record.field = "foo"
|
147
|
+
=> "foo"
|
148
|
+
>> record.valid?
|
149
|
+
=> true
|
150
|
+
>> record.field = ["foo"]
|
151
|
+
=> ["foo"]
|
152
|
+
>> record.valid?
|
153
|
+
=> true
|
154
|
+
>> record.field = ["foo", "bar"]
|
155
|
+
=> ["foo", "bar"]
|
156
|
+
>> record.valid?
|
157
|
+
=> true
|
158
|
+
>> record.field = ["foo1", "bar2"]
|
159
|
+
=> ["foo1", "bar2"]
|
160
|
+
>> record.valid?
|
161
|
+
=> false
|
162
|
+
>> puts record.errors.full_messages
|
163
|
+
Field value "foo1" is invalid
|
164
|
+
Field value "bar2" is invalid
|
64
165
|
```
|
65
166
|
|
66
167
|
### InclusionValidator
|
67
168
|
|
68
|
-
Extends ActiveModel::Validations::InclusionValidator
|
169
|
+
Extends `ActiveModel::Validations::InclusionValidator`, adding EnumerableBehavior.
|
69
170
|
|
70
|
-
See
|
171
|
+
See `ActiveModel::Validations::InclusionValidator` for usage and options.
|
71
172
|
|
72
173
|
```ruby
|
73
174
|
class InclusionValidatable
|
@@ -79,20 +180,30 @@ class InclusionValidatable
|
|
79
180
|
# validates_inclusion_of :field, in: ["foo", "bar", "baz"]
|
80
181
|
end
|
81
182
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
183
|
+
>> record = InclusionValidatable.new
|
184
|
+
=> #<InclusionValidatable:0x007fe3cbc40098>
|
185
|
+
>> record.field = "foo"
|
186
|
+
=> "foo"
|
187
|
+
>> record.valid?
|
188
|
+
=> true
|
189
|
+
>> record.field = "foo1"
|
190
|
+
=> "foo1"
|
191
|
+
>> record.valid?
|
192
|
+
=> false
|
193
|
+
>> record.field = ["foo"]
|
194
|
+
=> ["foo"]
|
195
|
+
>> record.valid?
|
196
|
+
=> true
|
197
|
+
>> record.field = ["foo", "bar"]
|
198
|
+
=> ["foo", "bar"]
|
199
|
+
>> record.valid?
|
200
|
+
=> true
|
201
|
+
>> record.field = ["foo", "bar1", "baz"]
|
202
|
+
=> ["foo", "bar1", "baz"]
|
203
|
+
>> record.valid?
|
204
|
+
=> false
|
205
|
+
>> puts record.errors.full_messages
|
206
|
+
Field value "bar1" is not included in the list
|
96
207
|
```
|
97
208
|
|
98
209
|
### UniquenessValidator
|
@@ -103,7 +214,7 @@ Intended for ActiveFedora 7.x.
|
|
103
214
|
|
104
215
|
```ruby
|
105
216
|
class UniquenessValidatable < ActiveFedora::Base
|
106
|
-
include Hydra::Validations
|
217
|
+
include Hydra::Validations # ActiveFedora::Base includes ActiveModel::Validations
|
107
218
|
has_metadata name: 'descMetadata', type: ActiveFedora::QualifiedDublinCoreDatastream
|
108
219
|
has_attributes :title, datastream: 'descMetadata', multiple: false
|
109
220
|
# Can use with multi-value attributes, but single cardinality is required.
|
@@ -118,9 +229,9 @@ end
|
|
118
229
|
|
119
230
|
Validates the cardinality of the attribute value.
|
120
231
|
|
121
|
-
CardinalityValidator
|
232
|
+
CardinalityValidator extends `ActiveModel::Validations::LengthValidator` and
|
122
233
|
"tokenizes" values with `Array.wrap(value)`. The "cardinality" of the value
|
123
|
-
is the length the array.
|
234
|
+
is therefore the length the array. Accordingly,
|
124
235
|
|
125
236
|
- `nil` and empty enumerables have cardinality 0
|
126
237
|
- scalar values (including empty string) have cardinality 1.
|
@@ -141,20 +252,20 @@ class CardinalityValidatable
|
|
141
252
|
# validates_single_cardinality_of :field
|
142
253
|
end
|
143
254
|
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
255
|
+
>> record = CardinalityValidatable.new
|
256
|
+
=> #<CardinalityValidatable:0x007fe3cbc632c8>
|
257
|
+
>> record.field = "foo"
|
258
|
+
=> "foo"
|
259
|
+
>> record.valid?
|
260
|
+
=> true
|
261
|
+
>> record.field = ["foo"]
|
262
|
+
=> ["foo"]
|
263
|
+
>> record.valid?
|
264
|
+
=> true
|
265
|
+
>> record.field = ["foo", "bar"]
|
266
|
+
=> ["foo", "bar"]
|
267
|
+
>> record.valid?
|
268
|
+
=> false
|
269
|
+
>> puts record.errors.full_messages
|
270
|
+
Field has the wrong cardinality (should have 1 value(s))
|
160
271
|
```
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'hydra/validations/enumerable_behavior'
|
2
|
+
module Hydra
|
3
|
+
module Validations
|
4
|
+
class PresenceValidator < ActiveModel::Validations::PresenceValidator
|
5
|
+
def validate_each(record, attribute, values)
|
6
|
+
values = Array.wrap(values)
|
7
|
+
record.errors.add(attribute, :blank, options) if values.blank? || values.any?(&:blank?)
|
8
|
+
end
|
9
|
+
end
|
10
|
+
module HelperMethods
|
11
|
+
def validates_presence_of *attr_names
|
12
|
+
validates_with PresenceValidator, _merge_attributes(attr_names)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Hydra::Validations::PresenceValidator do
|
4
|
+
let(:validatable) do
|
5
|
+
Class.new do
|
6
|
+
def self.name
|
7
|
+
'Validatable'
|
8
|
+
end
|
9
|
+
include ActiveModel::Validations
|
10
|
+
include Hydra::Validations
|
11
|
+
attr_accessor :an_attribute
|
12
|
+
validates_presence_of :an_attribute, message: "Can't have blank values"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'validation scenarios' do
|
17
|
+
subject { validatable.new }
|
18
|
+
[
|
19
|
+
{ values: [], valid?: false } ,
|
20
|
+
{ values: [''], valid?: false } ,
|
21
|
+
{ values: nil, valid?: false },
|
22
|
+
{ values: '', valid?: false },
|
23
|
+
{ values: ['work', ''], valid?: false },
|
24
|
+
{ values: ['work', nil], valid?: false },
|
25
|
+
{ values: ['work'], valid?: true },
|
26
|
+
{ values: 'work', valid?: true }
|
27
|
+
].each do |scenario|
|
28
|
+
it "will validate #{scenario.fetch(:values).inspect} as valid? == #{scenario.fetch(:valid?)}" do
|
29
|
+
subject.an_attribute = scenario.fetch(:values)
|
30
|
+
expect(subject.valid?).to eq(scenario.fetch(:valid?))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'should add error message' do
|
35
|
+
subject.an_attribute = nil
|
36
|
+
subject.valid?
|
37
|
+
expect(subject.errors[:an_attribute]).to eq(["Can't have blank values"])
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra-validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dchandekstark
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2015-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -88,6 +88,7 @@ files:
|
|
88
88
|
- lib/hydra/validations/enumerable_behavior.rb
|
89
89
|
- lib/hydra/validations/format.rb
|
90
90
|
- lib/hydra/validations/inclusion.rb
|
91
|
+
- lib/hydra/validations/presence.rb
|
91
92
|
- lib/hydra/validations/uniqueness.rb
|
92
93
|
- lib/hydra/validations/version.rb
|
93
94
|
- spec/spec_helper.rb
|
@@ -96,6 +97,7 @@ files:
|
|
96
97
|
- spec/validations/format_validator_spec.rb
|
97
98
|
- spec/validations/helper_methods_spec.rb
|
98
99
|
- spec/validations/inclusion_validator_spec.rb
|
100
|
+
- spec/validations/presence_validator_spec.rb
|
99
101
|
- spec/validations/uniqueness_validator_spec.rb
|
100
102
|
homepage: https://github.com/duke-libraries/hydra-validations
|
101
103
|
licenses:
|
@@ -129,4 +131,5 @@ test_files:
|
|
129
131
|
- spec/validations/format_validator_spec.rb
|
130
132
|
- spec/validations/helper_methods_spec.rb
|
131
133
|
- spec/validations/inclusion_validator_spec.rb
|
134
|
+
- spec/validations/presence_validator_spec.rb
|
132
135
|
- spec/validations/uniqueness_validator_spec.rb
|