hydra-validations 0.2.1 → 0.3.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 +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
|
-
|