nested_validator 1.0.0 → 1.0.1
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 +8 -8
- data/.gitignore +4 -0
- data/Gemfile.lock +1 -1
- data/README.md +4 -4
- data/lib/nested_validator/nested_validator.rb +49 -2
- data/lib/nested_validator/validate_nested_matcher.rb +12 -10
- data/lib/nested_validator/version.rb +1 -1
- data/spec/lib/nested_validator/nested_validator_spec.rb +8 -2
- data/spec/lib/nested_validator/validate_nested_matcher_spec.rb +21 -14
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YWYzM2NmNDIzYTkxOTM5NDc1ZGMyNGFlODA4Y2M2NGI2NGQxNTRiMw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ODRmZTNjYTcyY2VhODI5ODY3YjlmOTMwMzk5M2VmODY2MmNhNDk5Yw==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTRhMjg2NTgyMGQ2MDEyMjY4NzM3NjQ0NjdkYzIxOTlmOTk5M2JmNGRiNjhk
|
10
|
+
NTgwYmU1NDg5M2M1YzczNGE3MTcwODZjZjYzOWU0MzA5ZDkyNDEyYzkzNmFh
|
11
|
+
ZjlkZTZjMjAyMWUxMWQ1ZThkM2IzM2ExMWVlYTBiOTRhNDM4MmM=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NGM2YzJhN2I5MmM2NmNmMjkwZmU1NDg3NzBhOWYyZWZlMWY3NzE2MjAzOTg0
|
14
|
+
Y2QxYTlkMGM2YzRmMTUxNzZlNWM3YzNhZjBlZmFmNTUzY2QzODVjMGM2YzYz
|
15
|
+
YzY0NjE1MWY5ZmI1ZWNmYjFiNjI5ODhkZTgxZTM0ODU5M2EzM2E=
|
data/.gitignore
CHANGED
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
[](https://badge.fury.io/rb/nested_validator.png)
|
2
|
+
[](https://travis-ci.org/dwhelan/nested_validator)
|
3
|
+
[](https://codeclimate.com/github/dwhelan/nested_validator)
|
4
|
+
[](https://coveralls.io/r/dwhelan/nested_validator)
|
5
5
|
|
6
6
|
# Nested Validator
|
7
7
|
|
@@ -3,6 +3,7 @@ require 'active_support/core_ext/array'
|
|
3
3
|
|
4
4
|
module ActiveModel
|
5
5
|
module Validations
|
6
|
+
|
6
7
|
class NestedValidator < EachValidator
|
7
8
|
|
8
9
|
private
|
@@ -63,8 +64,54 @@ module ActiveModel
|
|
63
64
|
end
|
64
65
|
|
65
66
|
module HelperMethods
|
66
|
-
|
67
|
-
|
67
|
+
# Bases an object's validity on nested attr_names.
|
68
|
+
#
|
69
|
+
# class Parent < ActiveRecord::Base
|
70
|
+
# has_one :child
|
71
|
+
#
|
72
|
+
# validates_nested :child
|
73
|
+
# end
|
74
|
+
#
|
75
|
+
# class Child < ActiveRecord::Base
|
76
|
+
# has_one :child
|
77
|
+
#
|
78
|
+
# validates_presence_of :attribute
|
79
|
+
# end
|
80
|
+
#
|
81
|
+
# Any errors in the child will be copied to the parent using the child's name as
|
82
|
+
# a prefix for the error:
|
83
|
+
#
|
84
|
+
# puts parent.errors.messages #=> { :'child attribute' => ["can't be blank"] }
|
85
|
+
#
|
86
|
+
# @param attr_names attribute names followed with options
|
87
|
+
#
|
88
|
+
# @option attr_names [String] :prefix The prefix to use instead of the attribute name
|
89
|
+
#
|
90
|
+
# @option attr_names [String, Array] :only The name(s) of attr_names to include
|
91
|
+
# when validating. Default is <tt>all</tt>
|
92
|
+
#
|
93
|
+
# @option attr_names [String, Array] :except The name(s) of attr_names to exclude
|
94
|
+
# when validating. Default is <tt>none</tt>
|
95
|
+
#
|
96
|
+
# @option attr_names [Symbol] :on Specifies when this validation is active. Runs in all
|
97
|
+
# validation contexts by default (+nil+), other options are <tt>:create</tt>
|
98
|
+
# and <tt>:update</tt>.
|
99
|
+
#
|
100
|
+
# @option attr_names [Symbol, String or Proc] :if a method, proc or string to call to determine
|
101
|
+
# if the validation should occur (e.g. <tt>if: :allow_validation</tt>,
|
102
|
+
# or <tt>if: Proc.new { |user| user.signup_step > 2 }</tt>). The method,
|
103
|
+
# proc or string should return or evaluate to a true or false value.
|
104
|
+
#
|
105
|
+
# @option attr_names [[Symbol, String or Proc]] :unless a method, proc or string to call to determine
|
106
|
+
# if the validation should not occur (e.g. <tt>unless: :skip_validation</tt>,
|
107
|
+
# or <tt>unless: Proc.new { |user| user.signup_step <= 2 }</tt>). The method,
|
108
|
+
# proc or string should return or evaluate to a true or false value.
|
109
|
+
#
|
110
|
+
# @option attr_names [boolean] :strict Specifies whether validation should be strict.
|
111
|
+
# See <tt>ActiveModel::Validation#validates!</tt> for more information.
|
112
|
+
#
|
113
|
+
def validates_nested(*attr_names)
|
114
|
+
validates_with NestedValidator, _merge_attributes(attr_names)
|
68
115
|
end
|
69
116
|
end
|
70
117
|
end
|
@@ -28,8 +28,9 @@ RSpec::Matchers.define :validate_nested do |child_name|
|
|
28
28
|
self.parent = parent
|
29
29
|
|
30
30
|
return false unless parent.respond_to? child_name
|
31
|
-
|
32
31
|
self.actual_keys = (error_keys_when_child_validity_is(false) - error_keys_when_child_validity_is(true))
|
32
|
+
return false if invalid_child_keys.present?
|
33
|
+
|
33
34
|
|
34
35
|
actual_keys == expected_keys
|
35
36
|
end
|
@@ -89,10 +90,8 @@ RSpec::Matchers.define :validate_nested do |child_name|
|
|
89
90
|
|
90
91
|
failure_message do
|
91
92
|
case
|
92
|
-
when
|
93
|
-
|
94
|
-
when invalid_child_keys.present?
|
95
|
-
"#{child_name} doesn't respond to #{show invalid_child_keys}"
|
93
|
+
when common_failure_message
|
94
|
+
common_failure_message
|
96
95
|
when (missing_child_keys = expected_child_keys - actual_child_keys - invalid_child_keys - [TEST_KEY]).present?
|
97
96
|
"#{parent} doesn't nest validations for: #{show missing_child_keys}"
|
98
97
|
when actual_keys.empty?
|
@@ -110,12 +109,10 @@ RSpec::Matchers.define :validate_nested do |child_name|
|
|
110
109
|
|
111
110
|
failure_message_when_negated do
|
112
111
|
case
|
113
|
-
when
|
114
|
-
|
112
|
+
when common_failure_message
|
113
|
+
common_failure_message
|
115
114
|
when (extras = only_keys & actual_child_keys).present?
|
116
|
-
|
117
|
-
when invalid_child_keys.present?
|
118
|
-
"#{child_name} doesn't respond to #{show invalid_child_keys}"
|
115
|
+
"#{parent} does nest #{show child_name} validations for: #{show extras}"
|
119
116
|
when except_keys.present?
|
120
117
|
"#{parent} doesn't nest #{show child_name} validations for: #{show except_keys - actual_child_keys}"
|
121
118
|
when prefix.present?
|
@@ -125,6 +122,11 @@ RSpec::Matchers.define :validate_nested do |child_name|
|
|
125
122
|
end
|
126
123
|
end
|
127
124
|
|
125
|
+
def common_failure_message
|
126
|
+
return "#{parent} doesn't respond to #{show child_name}" unless parent.respond_to?(child_name)
|
127
|
+
"#{child_name} doesn't respond to #{show invalid_child_keys}" if invalid_child_keys.present?
|
128
|
+
end
|
129
|
+
|
128
130
|
def show(value)
|
129
131
|
Array.wrap(value).map{|key| key.is_a?(Symbol) ? ":#{key}" : key.to_s}.join(', ')
|
130
132
|
end
|
@@ -86,10 +86,16 @@ describe NestedValidator do
|
|
86
86
|
its('errors.messages') { should eq :'child1 attribute1' => ["can't be blank"] }
|
87
87
|
end
|
88
88
|
|
89
|
-
describe 'with "prefix: "OMG"
|
89
|
+
describe 'with "prefix: "OMG"', :focus do
|
90
90
|
subject { with_nested_options prefix: 'OMG' }
|
91
91
|
|
92
|
-
its('errors.messages') { should eq :'OMG attribute1' => ["can't be blank"] }
|
92
|
+
its('errors.messages') { puts subject.errors.messages; should eq :'OMG attribute1' => ["can't be blank"] }
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'with "prefix: ""' do
|
96
|
+
subject { with_nested_options prefix: '' }
|
97
|
+
|
98
|
+
its('errors.messages') { should eq :'attribute1' => ["can't be blank"] }
|
93
99
|
end
|
94
100
|
end
|
95
101
|
|
@@ -38,8 +38,9 @@ describe 'validates_nested with [parent class with "validates, child1]"' do
|
|
38
38
|
}
|
39
39
|
end
|
40
40
|
|
41
|
-
let(:parent)
|
42
|
-
let(:options)
|
41
|
+
let(:parent) { parent_class.new child_class.new, child_class.new }
|
42
|
+
let(:options) { { nested: true } }
|
43
|
+
let(:validator) { instance_eval self.class.description }
|
43
44
|
|
44
45
|
before { parent_class.class_eval "validates :child1, #{options}" }
|
45
46
|
|
@@ -57,7 +58,6 @@ describe 'validates_nested with [parent class with "validates, child1]"' do
|
|
57
58
|
end
|
58
59
|
|
59
60
|
context 'nested: {prefix: "OMG"}' do
|
60
|
-
|
61
61
|
it { should validate_nested(:child1).with_prefix('OMG') }
|
62
62
|
it { should validate_nested(:child1).with_prefix(:OMG) }
|
63
63
|
|
@@ -99,8 +99,6 @@ describe 'validates_nested with [parent class with "validates, child1]"' do
|
|
99
99
|
end
|
100
100
|
|
101
101
|
describe 'its description for:' do
|
102
|
-
let(:validator) { instance_eval self.class.description }
|
103
|
-
|
104
102
|
subject { validator.description }
|
105
103
|
|
106
104
|
context('validate_nested(:child1)') { it { should eq 'validate nested :child1' } }
|
@@ -110,17 +108,28 @@ describe 'validates_nested with [parent class with "validates, child1]"' do
|
|
110
108
|
end
|
111
109
|
|
112
110
|
describe 'its error messages:' do
|
113
|
-
let(:options)
|
114
|
-
let(:
|
111
|
+
let(:options) { self.class.parent.description }
|
112
|
+
let(:expect_match) { false }
|
115
113
|
|
116
|
-
|
117
|
-
|
114
|
+
before { expect(validator.matches? parent).to be expect_match }
|
115
|
+
|
116
|
+
describe 'failures for should and should_not' do
|
117
|
+
[:failure_message, :failure_message_when_negated].each do |message|
|
118
|
+
subject { validator.send message }
|
118
119
|
|
120
|
+
context 'nested: true' do
|
121
|
+
describe('validate_nested(:invalid_child_name)') { it { should eq "parent doesn't respond to :invalid_child_name" } }
|
122
|
+
describe('validate_nested(:child1).only(:invalid_attribute_name)') { it { should eq "child1 doesn't respond to :invalid_attribute_name" } }
|
123
|
+
describe('validate_nested(:child1).except(:invalid_attribute_name)') { it { should eq "child1 doesn't respond to :invalid_attribute_name" } }
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe 'should failure messages for' do
|
119
129
|
subject { validator.failure_message }
|
120
130
|
|
121
131
|
context 'nested: true' do
|
122
|
-
describe('validate_nested(:child2)')
|
123
|
-
describe('validate_nested(:invalid_child_name)') { it { should eq "parent doesn't respond to :invalid_child_name" } }
|
132
|
+
describe('validate_nested(:child2)') { it { should eq "parent doesn't nest validations for :child2" } }
|
124
133
|
end
|
125
134
|
|
126
135
|
context 'nested: {prefix: :OMG}' do
|
@@ -129,20 +138,18 @@ describe 'validates_nested with [parent class with "validates, child1]"' do
|
|
129
138
|
end
|
130
139
|
|
131
140
|
context 'nested: {only: :attribute1}' do
|
132
|
-
describe('validate_nested(:child1).only(:invalid_attribute_name)') { it { should eq "child1 doesn't respond to :invalid_attribute_name" } }
|
133
141
|
describe('validate_nested(:child1).only(:attribute2)') { it { should eq "parent doesn't nest validations for: :attribute2" } }
|
134
142
|
describe('validate_nested(:child1).only(:attribute1, :attribute2)') { it { should eq "parent doesn't nest validations for: :attribute2" } }
|
135
143
|
end
|
136
144
|
|
137
145
|
context 'nested: {except: :attribute1}' do
|
138
|
-
describe('validate_nested(:child1).except(:invalid_attribute_name)') { it { should eq "child1 doesn't respond to :invalid_attribute_name" } }
|
139
146
|
describe('validate_nested(:child1).except(:attribute2)') { it { should eq 'parent does nest validations for: :attribute2' } }
|
140
147
|
describe('validate_nested(:child1).except(:attribute1, :attribute2)') { it { should eq 'parent does nest validations for: :attribute2' } }
|
141
148
|
end
|
142
149
|
end
|
143
150
|
|
144
151
|
describe 'should_not failure messages for' do
|
145
|
-
|
152
|
+
let(:expect_match) { true }
|
146
153
|
|
147
154
|
subject { validator.failure_message_when_negated }
|
148
155
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nested_validator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Declan Whelan
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-12-
|
11
|
+
date: 2014-12-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|