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 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
-