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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: cae38f3407ca9c3bc9b8f23b3e48c058fdda29a7
4
- data.tar.gz: 6f8425826a0e664be440b6508bf9f0deb7a7ecbf
3
+ metadata.gz: f00975706cfd4a91b57c5a09f1213dd3c70d7f94
4
+ data.tar.gz: 5cd13aed9137be4e5b7a1d5a2613e480714c769e
5
5
  SHA512:
6
- metadata.gz: f1e72b4e763c1279f7a1bd16e8d9f2ef5ff730f85cccbbcbb52e210336f5ee748bb7acac8d7f6d8858f666bac9e99af4d039066d2bc912de804049a74c502625
7
- data.tar.gz: 08ea622a521af583cc2122ad7f639cf9a45b3c09ae2549fe49ecf5f9e3af8648f30f72b00f2359472cb6325fe0aed22e04c7291bf6c9b1dd3b836c9cece959e7
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 andn spec tests.
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 Validatable < ActiveFedora::Base
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
- # validates_uniqueness_of helper method
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 (Can be used with POROs)
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/single_cardinality_validator'
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 subclasses SingleCardinalityValidator, so will not pass validation if enumerable
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 < SingleCardinalityValidator
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
- super
36
- value = value.first if record.class.multiple?(attribute)
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? conditions
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
@@ -1,5 +1,5 @@
1
1
  module Hydra
2
2
  module Validations
3
- VERSION = "0.2.1"
3
+ VERSION = "0.3.0"
4
4
  end
5
5
  end
data/spec/spec_helper.rb CHANGED
@@ -57,4 +57,6 @@ RSpec.configure do |config|
57
57
  # a real object. This is generally recommended.
58
58
  mocks.verify_partial_doubles = true
59
59
  end
60
+
61
+ I18n.enforce_available_locales = false
60
62
  end
@@ -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.2.1
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/single_cardinality_validator.rb
102
- - lib/hydra/validations/uniqueness_validator.rb
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
-