hydra-validations 0.2.1 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +71 -8
- data/lib/hydra/validations/cardinality.rb +20 -0
- data/lib/hydra/validations/enumerable_behavior.rb +35 -0
- data/lib/hydra/validations/format.rb +21 -0
- data/lib/hydra/validations/inclusion.rb +21 -0
- data/lib/hydra/validations/single_cardinality.rb +32 -0
- data/lib/hydra/validations/{uniqueness_validator.rb → uniqueness.rb} +11 -9
- data/lib/hydra/validations/version.rb +1 -1
- data/spec/spec_helper.rb +2 -0
- data/spec/validators/format_validator_spec.rb +47 -0
- data/spec/validators/inclusion_validator_spec.rb +48 -0
- metadata +11 -3
- data/lib/hydra/validations/single_cardinality_validator.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f00975706cfd4a91b57c5a09f1213dd3c70d7f94
|
4
|
+
data.tar.gz: 5cd13aed9137be4e5b7a1d5a2613e480714c769e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c1693bbdea424392a36c1ce404bfa101c4b0b50018bcc3bcf547aeb3c9080f846a70e3c3db369cd65c8ab9bcf9a9f4815db8c52c73b3ea75d02e70f651676a2d
|
7
|
+
data.tar.gz: fcf3f038f0dea92121caab4e694c8acb2bbc3a34f11ec8e4abe52d4df7a8eeb12ad05d7143b3d3a30f238f219441c32df6b41097a7630ef928f1f9fe68f23f53
|
data/README.md
CHANGED
@@ -28,28 +28,91 @@ bundle install
|
|
28
28
|
|
29
29
|
## Validators
|
30
30
|
|
31
|
-
See also the source code
|
31
|
+
See also the source code and spec tests.
|
32
|
+
|
33
|
+
### FormatValidator
|
34
|
+
|
35
|
+
Extends the ActiveModel version to validate the format of *each member* of an enumerable attribute value.
|
36
|
+
|
37
|
+
See documentation for ActiveModel::Validations::FormatValidator for usage and options.
|
38
|
+
|
39
|
+
```ruby
|
40
|
+
class FormatValidatable
|
41
|
+
include ActiveModel::Validations # required if not already included in class
|
42
|
+
include Hydra::Validations
|
43
|
+
attr_accessor :field
|
44
|
+
validates :field, format: { with: /\A[[:alpha:]]+\Z/ }
|
45
|
+
# ... or
|
46
|
+
# validates_format_of :field, with: /\A[[:alpha:]]+\Z/
|
47
|
+
end
|
48
|
+
|
49
|
+
> v = FormatValidatable.new
|
50
|
+
=> #<FormatValidatable:0x007ffc55175300>
|
51
|
+
> v.field = ["foo", "bar"]
|
52
|
+
=> ["foo", "bar"]
|
53
|
+
> v.valid?
|
54
|
+
=> true
|
55
|
+
> v.field = ["foo1", "bar2"]
|
56
|
+
=> ["foo1", "bar2"]
|
57
|
+
> v.valid?
|
58
|
+
=> false
|
59
|
+
> v.errors[:field]
|
60
|
+
=> ["value \"foo1\" is invalid", "value \"bar2\" is invalid"]
|
61
|
+
> v.errors.full_messages
|
62
|
+
=> ["Field value \"foo1\" is invalid", "Field value \"bar2\" is invalid"]
|
63
|
+
```
|
64
|
+
|
65
|
+
### InclusionValidator
|
66
|
+
|
67
|
+
Extends the ActiveModel version to validate inclusion of *each member* of an enumerable attribute value.
|
68
|
+
|
69
|
+
See documentation for ActiveModel::Validations::InclusionValidator for usage and options.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
class InclusionValidatable
|
73
|
+
include ActiveModel::Validations # required if not already included in class
|
74
|
+
include Hydra::Validations
|
75
|
+
attr_accessor :field
|
76
|
+
validates :field, inclusion: { in: ["foo", "bar", "baz"] }
|
77
|
+
end
|
78
|
+
|
79
|
+
> v = InclusionValidatable.new
|
80
|
+
=> #<InclusionValidatable:0x007ffc53079318>
|
81
|
+
> v.field = ["foo", "bar"]
|
82
|
+
=> ["foo", "bar"]
|
83
|
+
> v.valid?
|
84
|
+
=> true
|
85
|
+
> v.field = ["foo", "bar", "spam", "eggs"]
|
86
|
+
=> ["foo", "bar", "spam", "eggs"]
|
87
|
+
> v.valid?
|
88
|
+
=> false
|
89
|
+
> v.errors[:field]
|
90
|
+
=> ["value \"spam\" is not included in the list", "value \"eggs\" is not included in the list"]
|
91
|
+
> v.errors.full_messages
|
92
|
+
=> ["Field value \"spam\" is not included in the list", "Field value \"eggs\" is not included in the list"]
|
93
|
+
```
|
32
94
|
|
33
95
|
### UniquenessValidator (ActiveFedora)
|
34
96
|
|
97
|
+
Validates the uniqueness of an attribute based on a Solr index query.
|
98
|
+
|
35
99
|
```ruby
|
36
|
-
class
|
100
|
+
class UniquenessValidatable < ActiveFedora::Base
|
37
101
|
include Hydra::Validations
|
38
102
|
has_metadata name: 'descMetadata', type: ActiveFedora::QualifiedDublinCoreDatastream
|
39
103
|
has_attributes :title, datastream: 'descMetadata', multiple: false
|
40
104
|
# Can use with multi-value attributes, but single cardinality is required.
|
41
105
|
# See SingleCardinalityValidator below.
|
42
106
|
has_attributes :source, datastream: 'descMetadata', multiple: true
|
43
|
-
|
44
|
-
#
|
107
|
+
validates :source, uniqueness: { solr_name: "source_ssim" }
|
108
|
+
# ... or using helper method
|
45
109
|
validates_uniqueness_of :title, solr_name: "title_ssi"
|
46
|
-
|
47
|
-
# Using `validates' with options
|
48
|
-
validates :source, uniqueness: { solr_name: "subject_ssim" }
|
49
110
|
end
|
50
111
|
```
|
51
112
|
|
52
|
-
### SingleCardinalityValidatory
|
113
|
+
### SingleCardinalityValidatory
|
114
|
+
|
115
|
+
Validates that the attribute value is a scaler or single-member enumerable.
|
53
116
|
|
54
117
|
```ruby
|
55
118
|
class Validatable
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Hydra
|
2
|
+
module Validations
|
3
|
+
#
|
4
|
+
# Cardinality - a mixin adding cardinality validation methods.
|
5
|
+
#
|
6
|
+
module Cardinality
|
7
|
+
|
8
|
+
def validate_cardinality(cardinality, record, attribute, value)
|
9
|
+
return validate_single_cardinality(record, attribute, value) if cardinality == :single
|
10
|
+
raise ArgumentError, "Cardinality validation not supported: #{cardinality.inspect}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def validate_single_cardinality(record, attribute, value)
|
14
|
+
# TODO i18n message
|
15
|
+
record.errors.add(attribute, "can't have more than one value") if value.respond_to?(:each) && value.size > 1
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Hydra
|
2
|
+
module Validations
|
3
|
+
#
|
4
|
+
# EnumerableBehavior - a mixin for subclasses of ActiveModel::EachValidator
|
5
|
+
# adding validation for each member of an enumerable attribute value.
|
6
|
+
#
|
7
|
+
# Behavior includes 'fixing' each error message to include the specific value
|
8
|
+
# which was invalid.
|
9
|
+
#
|
10
|
+
module EnumerableBehavior
|
11
|
+
|
12
|
+
def validate_each(record, attribute, value)
|
13
|
+
if value.respond_to?(:each)
|
14
|
+
value.each do |v|
|
15
|
+
prev = record.errors[attribute].size rescue 0
|
16
|
+
super(record, attribute, v)
|
17
|
+
messages = record.errors[attribute]
|
18
|
+
if messages && messages.size > prev
|
19
|
+
record.errors.add(attribute, fixed_message(v, messages.pop))
|
20
|
+
end
|
21
|
+
end
|
22
|
+
else
|
23
|
+
super
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def fixed_message(value, message)
|
30
|
+
"value \"#{value}\" #{message}"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'hydra/validations/enumerable_behavior'
|
2
|
+
|
3
|
+
module Hydra
|
4
|
+
module Validations
|
5
|
+
#
|
6
|
+
# FormatValidator - Add EnumerableBehavior to ActiveModel's FormatValidator
|
7
|
+
#
|
8
|
+
# See ActiveModel::Validations::FormatValidator for usage and options.
|
9
|
+
#
|
10
|
+
class FormatValidator < ActiveModel::Validations::FormatValidator
|
11
|
+
include EnumerableBehavior
|
12
|
+
end
|
13
|
+
|
14
|
+
module HelperMethods
|
15
|
+
def validates_format_of *attr_names
|
16
|
+
validates_with FormatValidator, _merge_attributes(attr_names)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'hydra/validations/enumerable_behavior'
|
2
|
+
|
3
|
+
module Hydra
|
4
|
+
module Validations
|
5
|
+
#
|
6
|
+
# InclusionValidation - Adds EnumerableBehavior to ActiveModel's InclusionValidator
|
7
|
+
#
|
8
|
+
# See ActiveModel::Validations::InclusionValidator for usage and options
|
9
|
+
#
|
10
|
+
class InclusionValidator < ActiveModel::Validations::InclusionValidator
|
11
|
+
include EnumerableBehavior
|
12
|
+
end
|
13
|
+
|
14
|
+
module HelperMethods
|
15
|
+
def validates_inclusion_of *attr_names
|
16
|
+
validates_with InclusionValidator, _merge_attributes(attr_names)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'hydra/validations/cardinality'
|
2
|
+
|
3
|
+
module Hydra
|
4
|
+
module Validations
|
5
|
+
#
|
6
|
+
# SingleCardinalityValidator - validates that an enumerator value has size 0 or 1
|
7
|
+
#
|
8
|
+
# validates :myattr, single_cardinality: true
|
9
|
+
# validates_single_cardinality_of :myattr
|
10
|
+
#
|
11
|
+
# Blank and nil values are considered valid (even without :allow_blank or :allow_nil
|
12
|
+
# validator options).
|
13
|
+
#
|
14
|
+
class SingleCardinalityValidator < ActiveModel::EachValidator
|
15
|
+
|
16
|
+
include Cardinality
|
17
|
+
|
18
|
+
def validate_each(record, attribute, value)
|
19
|
+
validate_cardinality(:single, record, attribute, value)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
module HelperMethods
|
25
|
+
def validates_single_cardinality_of *attr_names
|
26
|
+
validates_with SingleCardinalityValidator, _merge_attributes(attr_names)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'hydra/validations'
|
2
|
-
require 'hydra/validations/
|
2
|
+
require 'hydra/validations/cardinality'
|
3
3
|
|
4
4
|
module Hydra
|
5
5
|
module Validations
|
@@ -16,29 +16,31 @@ module Hydra
|
|
16
16
|
# - Accepts only one attribute (can have more than one UniquenessValidator on a model, however)
|
17
17
|
# - :solr_name option must be present
|
18
18
|
# - Can be used on enumerable values (attribute defined with :multiple=>true option), but
|
19
|
-
# validator
|
19
|
+
# validator also validates single cardinality, so will not pass validation if enumerable
|
20
20
|
# has more than one member.
|
21
21
|
#
|
22
22
|
# CAVEAT: The determination of uniqueness depends on a Solr query.
|
23
23
|
# False negatives (record invalid) may result if, for example,
|
24
24
|
# querying a Solr field of type "text".
|
25
25
|
#
|
26
|
-
class UniquenessValidator <
|
26
|
+
class UniquenessValidator < ActiveModel::EachValidator
|
27
|
+
|
28
|
+
include Cardinality
|
27
29
|
|
28
30
|
def check_validity!
|
29
|
-
super
|
30
31
|
raise ArgumentError, "UniquenessValidator accepts only a single attribute: #{attribues}" if attributes.length > 1
|
31
32
|
raise ArgumentError, "UniquenessValidator requires the :solr_name option be present." unless options[:solr_name].present?
|
32
33
|
end
|
33
34
|
|
34
35
|
def validate_each(record, attribute, value)
|
35
|
-
|
36
|
-
|
36
|
+
# TODO: i18n messages
|
37
|
+
validate_cardinality(:single, record, attribute, value)
|
38
|
+
# Validate uniqueness proper only if value is of single cardinality
|
39
|
+
return if record.errors.added?(attribute, "can't have more than one value")
|
40
|
+
value = value.first if value.respond_to?(:each)
|
37
41
|
conditions = {options[:solr_name] => value}
|
38
42
|
conditions.merge!("-id" => record.id) if record.persisted?
|
39
|
-
if record.class.exists?
|
40
|
-
record.errors.add attribute, "has already been taken"
|
41
|
-
end
|
43
|
+
record.errors.add attribute, "has already been taken" if record.class.exists?(conditions)
|
42
44
|
end
|
43
45
|
|
44
46
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples "it validates the format of each member of the attribute value" do
|
4
|
+
context "all attribute value members are valid" do
|
5
|
+
before { subject.field = ["foo", "bar"] }
|
6
|
+
it "should be valid" do
|
7
|
+
expect(subject).to be_valid
|
8
|
+
end
|
9
|
+
end
|
10
|
+
context "one of the attribute value members is invalid" do
|
11
|
+
before { subject.field = ["foo1", "bar"] }
|
12
|
+
it "should be invalid" do
|
13
|
+
expect(subject).to be_invalid
|
14
|
+
end
|
15
|
+
it "should 'fix' the error message to include the value" do
|
16
|
+
subject.valid?
|
17
|
+
expect(subject.errors[:field]).to eq ["value \"foo1\" is invalid"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Hydra::Validations::FormatValidator do
|
23
|
+
before(:all) do
|
24
|
+
class Validatable
|
25
|
+
include ActiveModel::Validations
|
26
|
+
include Hydra::Validations
|
27
|
+
attr_accessor :field
|
28
|
+
end
|
29
|
+
end
|
30
|
+
before(:each) { Validatable.clear_validators! }
|
31
|
+
after(:all) { Object.send(:remove_const, :Validatable) }
|
32
|
+
subject { Validatable.new }
|
33
|
+
describe ".validates" do
|
34
|
+
before do
|
35
|
+
Validatable.clear_validators!
|
36
|
+
Validatable.validates :field, format: { with: /\A[[:alpha:]]+\Z/ }
|
37
|
+
end
|
38
|
+
it_behaves_like "it validates the format of each member of the attribute value"
|
39
|
+
end
|
40
|
+
describe ".validates_format_of" do
|
41
|
+
before do
|
42
|
+
Validatable.clear_validators!
|
43
|
+
Validatable.validates_format_of :field, with: /\A[[:alpha:]]+\Z/
|
44
|
+
end
|
45
|
+
it_behaves_like "it validates the format of each member of the attribute value"
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
shared_examples "it validates the inclusion of each member of the attribute value" do
|
4
|
+
context "all attribute value members are valid" do
|
5
|
+
before { subject.field = ["foo", "bar"] }
|
6
|
+
it "should be valid" do
|
7
|
+
expect(subject).to be_valid
|
8
|
+
end
|
9
|
+
end
|
10
|
+
context "one of the attribute value members is invalid" do
|
11
|
+
before { subject.field = ["foo1", "bar"] }
|
12
|
+
it "should be invalid" do
|
13
|
+
expect(subject).to be_invalid
|
14
|
+
end
|
15
|
+
it "should 'fix' the error message to include the value" do
|
16
|
+
subject.valid?
|
17
|
+
expect(subject.errors[:field]).to eq ["value \"foo1\" is not included in the list"]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe Hydra::Validations::InclusionValidator do
|
23
|
+
before(:all) do
|
24
|
+
class Validatable
|
25
|
+
include ActiveModel::Validations
|
26
|
+
include Hydra::Validations
|
27
|
+
attr_accessor :field
|
28
|
+
end
|
29
|
+
end
|
30
|
+
before(:each) { Validatable.clear_validators! }
|
31
|
+
after(:all) { Object.send(:remove_const, :Validatable) }
|
32
|
+
subject { Validatable.new }
|
33
|
+
let(:valid_values) { ["foo", "bar", "baz"] }
|
34
|
+
describe ".validates" do
|
35
|
+
before do
|
36
|
+
Validatable.clear_validators!
|
37
|
+
Validatable.validates :field, inclusion: { in: valid_values }
|
38
|
+
end
|
39
|
+
it_behaves_like "it validates the inclusion of each member of the attribute value"
|
40
|
+
end
|
41
|
+
describe ".validates_inclusion_of" do
|
42
|
+
before do
|
43
|
+
Validatable.clear_validators!
|
44
|
+
Validatable.validates_inclusion_of :field, in: valid_values
|
45
|
+
end
|
46
|
+
it_behaves_like "it validates the inclusion of each member of the attribute value"
|
47
|
+
end
|
48
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hydra-validations
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dchandekstark
|
@@ -98,11 +98,17 @@ files:
|
|
98
98
|
- Rakefile
|
99
99
|
- hydra-validations.gemspec
|
100
100
|
- lib/hydra/validations.rb
|
101
|
-
- lib/hydra/validations/
|
102
|
-
- lib/hydra/validations/
|
101
|
+
- lib/hydra/validations/cardinality.rb
|
102
|
+
- lib/hydra/validations/enumerable_behavior.rb
|
103
|
+
- lib/hydra/validations/format.rb
|
104
|
+
- lib/hydra/validations/inclusion.rb
|
105
|
+
- lib/hydra/validations/single_cardinality.rb
|
106
|
+
- lib/hydra/validations/uniqueness.rb
|
103
107
|
- lib/hydra/validations/version.rb
|
104
108
|
- spec/spec_helper.rb
|
105
109
|
- spec/support/shared_examples_for_validators.rb
|
110
|
+
- spec/validators/format_validator_spec.rb
|
111
|
+
- spec/validators/inclusion_validator_spec.rb
|
106
112
|
- spec/validators/single_cardinality_validator_spec.rb
|
107
113
|
- spec/validators/uniqueness_validator_spec.rb
|
108
114
|
homepage: https://github.com/duke-libraries/hydra-validations
|
@@ -133,5 +139,7 @@ summary: Validations for Hydra applications, based on ActiveModel::Validations
|
|
133
139
|
test_files:
|
134
140
|
- spec/spec_helper.rb
|
135
141
|
- spec/support/shared_examples_for_validators.rb
|
142
|
+
- spec/validators/format_validator_spec.rb
|
143
|
+
- spec/validators/inclusion_validator_spec.rb
|
136
144
|
- spec/validators/single_cardinality_validator_spec.rb
|
137
145
|
- spec/validators/uniqueness_validator_spec.rb
|
@@ -1,29 +0,0 @@
|
|
1
|
-
#
|
2
|
-
# SingleCardinalityValidator - validates that an enumerator value has size 0 or 1
|
3
|
-
#
|
4
|
-
# validates :myattr, single_cardinality: true
|
5
|
-
# validates_single_cardinality_of :myattr
|
6
|
-
#
|
7
|
-
# Blank and nil values are considered valid (even without :allow_blank or :allow_nil
|
8
|
-
# validator options).
|
9
|
-
#
|
10
|
-
module Hydra
|
11
|
-
module Validations
|
12
|
-
|
13
|
-
class SingleCardinalityValidator < ActiveModel::EachValidator
|
14
|
-
def validate_each(record, attribute, value)
|
15
|
-
if value.respond_to?(:each)
|
16
|
-
record.errors.add(attribute, "can't have more than one value") if value.size > 1
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
module HelperMethods
|
22
|
-
def validates_single_cardinality_of *attr_names
|
23
|
-
validates_with SingleCardinalityValidator, _merge_attributes(attr_names)
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|