validation_delegation 0.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 +15 -0
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +175 -0
- data/Rakefile +1 -0
- data/lib/validation_delegation/version.rb +3 -0
- data/lib/validation_delegation.rb +82 -0
- data/spec/validation_delegation_spec.rb +147 -0
- data/validation_delegation.gemspec +28 -0
- metadata +126 -0
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZmMyYTIyMzkzMDI5ZDU0MDQ4OWEwNGI5MzNhNzdlMGExOWE1MGJkZg==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
ZTZkZjMzZjFmMjIwM2M1NDc0OTAwYjliNThiZWQ2Y2YzYmQ3NjBkYw==
|
7
|
+
!binary "U0hBNTEy":
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
YjFkYTc0Yzk3OWVhYjIwOGQ1MDVkZjRiMGM5OGJiYmM2ZjNjNTk5MGZjNTNi
|
10
|
+
Mzc2YjMxN2UwMjQ3NDY2N2E5OWZlNGJkYjQ2ZmUxMjU5M2NiYTM3ZDlhYTIx
|
11
|
+
M2Q4MjFiZTlkMzE0NmU5NWNmOGNjM2FjYzRjNGI1YTIwYTZiYzY=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
NDE4ZjRjNGYwNWQ2ODk1NDFmOTc2Y2QxY2E1Y2IyZDc2OGVlYzQ3MTRjYWEy
|
14
|
+
ZDM5NTQxYTBmOGM3ZTBhZDljZDlhMGRmMjNhYjMyMTcyNjliMzUyZTBmZTU0
|
15
|
+
MWJiOTM3MjdjODA2MGZjY2I5NDY5MjMxMjI1OGNiN2QyYmIxYzE=
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2014 Ben Eddy
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
# Validation Delegation
|
2
|
+
|
3
|
+
Validation delegation allows an object to proxy validations to other objects. This facilitates [composition](http://en.wikipedia.org/wiki/Object_composition) and prevents the duplication of validation logic.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'validation_delegation'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install validation_delegation
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
An example use case for validation delegation is a `SignUp` object which simultaneously creates a `User` and an `Organization`. The `SignUp` object is only valid if both the user and organization are valid.
|
22
|
+
|
23
|
+
```Ruby
|
24
|
+
class User < ActiveRecord::Base
|
25
|
+
validates :email, presence: true
|
26
|
+
end
|
27
|
+
|
28
|
+
class Organization < ActiveRecord::Base
|
29
|
+
validates :name, presence: true
|
30
|
+
end
|
31
|
+
|
32
|
+
class SignUp
|
33
|
+
include ActiveModel::Validations
|
34
|
+
|
35
|
+
# delegate validation to the user
|
36
|
+
delegate_validation to: :user
|
37
|
+
|
38
|
+
# and also delegate validation to the organization
|
39
|
+
delegate_validation to: :organization
|
40
|
+
|
41
|
+
attr_reader :user, :organization
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
@user = user
|
45
|
+
@organization = organization
|
46
|
+
end
|
47
|
+
|
48
|
+
def email=(email)
|
49
|
+
@user.email = email
|
50
|
+
end
|
51
|
+
|
52
|
+
def name=(name)
|
53
|
+
@organization.name = name
|
54
|
+
end
|
55
|
+
end
|
56
|
+
```
|
57
|
+
|
58
|
+
Assigning invalid user and organization attributes, which are in turn assigned to the `@user` and `@organization` instance variables, invalidates the `SignUp`, and faithfully copies the user and organization errors.
|
59
|
+
|
60
|
+
```Ruby
|
61
|
+
signup = SignUp.new
|
62
|
+
signup.email = ""
|
63
|
+
signup.name = ""
|
64
|
+
|
65
|
+
signup.valid?
|
66
|
+
# => false
|
67
|
+
|
68
|
+
signup.errors.full_messages
|
69
|
+
# => ["email can't be blank", "name can't be blank"]
|
70
|
+
|
71
|
+
```
|
72
|
+
|
73
|
+
```Ruby
|
74
|
+
signup.email = "email@example.com"
|
75
|
+
signup.name = "My Organization"
|
76
|
+
|
77
|
+
signup.valid?
|
78
|
+
|
79
|
+
```
|
80
|
+
|
81
|
+
If you do not want to copy errors directly onto the composing object, you can specify to which attribute the errors should apply. In this case, we copy errors onto the "organization" attribute. This is useful for nesting forms via `fields_for`.
|
82
|
+
|
83
|
+
```Ruby
|
84
|
+
class SignUp
|
85
|
+
include ActiveModel::Model
|
86
|
+
|
87
|
+
delegate_validation :organization, to: :organization
|
88
|
+
|
89
|
+
attr_reader :organization
|
90
|
+
|
91
|
+
def initialize
|
92
|
+
@organization = Organization.new
|
93
|
+
end
|
94
|
+
|
95
|
+
def name=(name)
|
96
|
+
@organization.name = name
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
signup = SignUp.new
|
101
|
+
signup.name = ""
|
102
|
+
signup.valid?
|
103
|
+
# => false
|
104
|
+
|
105
|
+
signup.errors.full_messages
|
106
|
+
# => ["organization name can't be blank"]
|
107
|
+
```
|
108
|
+
|
109
|
+
### Options
|
110
|
+
|
111
|
+
`delegate_validation` accepts several options.
|
112
|
+
|
113
|
+
- `:if` - errors are only copied if the method specified by the `:if` option returns true
|
114
|
+
|
115
|
+
```Ruby
|
116
|
+
class SignUp
|
117
|
+
delegate_validation to: :user, if: :validate_user?
|
118
|
+
|
119
|
+
def validate_user?
|
120
|
+
# logic
|
121
|
+
end
|
122
|
+
end
|
123
|
+
```
|
124
|
+
|
125
|
+
- `:unless` - errors are only copied if the method specified by the `:unless` option returns false
|
126
|
+
|
127
|
+
```Ruby
|
128
|
+
class SignUp
|
129
|
+
delegate_validation to: :user, unless: :skip_validation?
|
130
|
+
|
131
|
+
def skip_validation?
|
132
|
+
# logic
|
133
|
+
end
|
134
|
+
end
|
135
|
+
```
|
136
|
+
|
137
|
+
- `:only` - a whitelist of errors to be copied
|
138
|
+
|
139
|
+
```Ruby
|
140
|
+
class SignUp
|
141
|
+
delegate_validation to: :user, only: :email
|
142
|
+
end
|
143
|
+
|
144
|
+
signup = SignUp.new
|
145
|
+
signup.user.errors.add(:email, :required)
|
146
|
+
signup.user.errors.add(:phone_number, :required)
|
147
|
+
|
148
|
+
signup.valid?
|
149
|
+
signup.errors.full_messages
|
150
|
+
# => ["email can't be blank"]
|
151
|
+
```
|
152
|
+
|
153
|
+
- `:except` - a blacklist of errors to be copied
|
154
|
+
|
155
|
+
```Ruby
|
156
|
+
class SignUp
|
157
|
+
delegate_validation to: :user, except: :email
|
158
|
+
end
|
159
|
+
|
160
|
+
signup = SignUp.new
|
161
|
+
signup.user.errors.add(:email, :required)
|
162
|
+
signup.user.errors.add(:phone_number, :required)
|
163
|
+
|
164
|
+
signup.valid?
|
165
|
+
signup.errors.full_messages
|
166
|
+
# => ["phone number can't be blank"]
|
167
|
+
```
|
168
|
+
|
169
|
+
## Contributing
|
170
|
+
|
171
|
+
1. Fork it
|
172
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
173
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
174
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
175
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require "validation_delegation/version"
|
2
|
+
require "active_support"
|
3
|
+
require "active_support/core_ext"
|
4
|
+
|
5
|
+
module ValidationDelegation
|
6
|
+
def self.included(base)
|
7
|
+
base.send(:extend, ClassMethods)
|
8
|
+
end
|
9
|
+
|
10
|
+
def receive_errors(attribute, object_attribute, errors)
|
11
|
+
Array.wrap(errors).each{ |error| receive_error attribute, object_attribute, error }
|
12
|
+
end
|
13
|
+
|
14
|
+
def receive_error(attribute, object_attribute, error)
|
15
|
+
attribute ? receive_error_on_attribute(attribute, object_attribute, error) : receive_error_on_self(object_attribute, error)
|
16
|
+
end
|
17
|
+
|
18
|
+
def receive_error_on_attribute(attribute, prefix, error)
|
19
|
+
errors[attribute] << [format_attribute(prefix), error].join(" ")
|
20
|
+
end
|
21
|
+
|
22
|
+
def receive_error_on_self(attribute, error)
|
23
|
+
errors[attribute] << error
|
24
|
+
end
|
25
|
+
|
26
|
+
def format_attribute(attribute_name)
|
27
|
+
attribute_name.to_s.humanize.downcase.gsub(/\./, " ")
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
def delegate_validation(*args)
|
32
|
+
if args.first.is_a?(Hash)
|
33
|
+
transplant_errors(args.first)
|
34
|
+
else
|
35
|
+
transplant_errors(args.last.merge(attribute: args.first))
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def transplant_errors(options)
|
40
|
+
validate do
|
41
|
+
return unless send(options[:if]) if options[:if]
|
42
|
+
return if send(options[:unless]) if options[:unless]
|
43
|
+
|
44
|
+
object = send(options[:to])
|
45
|
+
ErrorTransplanter.new(self, object, options).transplant unless object.valid?
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
class ErrorTransplanter
|
51
|
+
delegate :errors, to: :donor
|
52
|
+
delegate :receive_errors, to: :recipient
|
53
|
+
|
54
|
+
attr_accessor :recipient, :donor, :options
|
55
|
+
|
56
|
+
def initialize(recipient, donor, options)
|
57
|
+
self.recipient = recipient
|
58
|
+
self.donor = donor
|
59
|
+
self.options = options
|
60
|
+
end
|
61
|
+
|
62
|
+
def transplant
|
63
|
+
errors.each do |object_attribute, object_errors|
|
64
|
+
next if ignore_attribute? object_attribute
|
65
|
+
receive_errors options[:attribute], object_attribute, object_errors
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def ignore_attribute?(attribute)
|
70
|
+
excepted_attribute?(attribute) || !specified_attribute?(attribute)
|
71
|
+
end
|
72
|
+
|
73
|
+
def excepted_attribute?(attribute)
|
74
|
+
Array.wrap(options[:except]).include?(attribute.to_sym)
|
75
|
+
end
|
76
|
+
|
77
|
+
def specified_attribute?(attribute)
|
78
|
+
return true unless options[:only]
|
79
|
+
Array.wrap(options[:only]).include?(attribute.to_sym)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,147 @@
|
|
1
|
+
require "active_model"
|
2
|
+
require "validation_delegation"
|
3
|
+
|
4
|
+
class TestClass ; end
|
5
|
+
|
6
|
+
class Validator
|
7
|
+
include ActiveModel::Validations
|
8
|
+
end
|
9
|
+
|
10
|
+
RSpec::Matchers.define :have_error do |message|
|
11
|
+
match do |actual|
|
12
|
+
actual.errors[@attribute].include?(message)
|
13
|
+
end
|
14
|
+
|
15
|
+
chain :on do |attribute|
|
16
|
+
@attribute = attribute
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe ValidationDelegation do
|
21
|
+
let(:validator) { Validator.new }
|
22
|
+
let(:test) { TestClass.new }
|
23
|
+
|
24
|
+
before do
|
25
|
+
Object.send(:remove_const, "TestClass")
|
26
|
+
|
27
|
+
class TestClass
|
28
|
+
include ActiveModel::Validations
|
29
|
+
include ValidationDelegation
|
30
|
+
end
|
31
|
+
|
32
|
+
allow(validator).to receive(:valid?).and_return(false)
|
33
|
+
validator.errors[:attr] << "is invalid"
|
34
|
+
allow(test).to receive(:validator).and_return(validator)
|
35
|
+
end
|
36
|
+
|
37
|
+
subject { test.tap(&:valid?) }
|
38
|
+
|
39
|
+
it "copies errors from the validator to itself" do
|
40
|
+
TestClass.delegate_validation to: :validator
|
41
|
+
expect(subject).to have_error("is invalid").on(:attr)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "copies all errors" do
|
45
|
+
validator.errors[:attr] << "is bananas"
|
46
|
+
TestClass.delegate_validation to: :validator
|
47
|
+
|
48
|
+
expect(subject).to have_error("is invalid").on(:attr)
|
49
|
+
expect(subject).to have_error("is bananas").on(:attr)
|
50
|
+
end
|
51
|
+
|
52
|
+
it "copies errors if the :if option is true" do
|
53
|
+
allow(test).to receive(:validate?).and_return(true)
|
54
|
+
TestClass.delegate_validation to: :validator, if: :validate?
|
55
|
+
expect(subject).to have_error("is invalid").on(:attr)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "does not copy errors if the :if option is false" do
|
59
|
+
allow(test).to receive(:validate?).and_return(false)
|
60
|
+
TestClass.delegate_validation to: :validator, if: :validate?
|
61
|
+
expect(subject).to_not have_error("is invalid").on(:attr)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "copies errors if the :unless option is false" do
|
65
|
+
allow(test).to receive(:validate?).and_return(false)
|
66
|
+
TestClass.delegate_validation to: :validator, unless: :validate?
|
67
|
+
expect(subject).to have_error("is invalid").on(:attr)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "does not copy errors if the :unless option is true" do
|
71
|
+
allow(test).to receive(:validate?).and_return(true)
|
72
|
+
TestClass.delegate_validation to: :validator, unless: :validate?
|
73
|
+
expect(subject).to_not have_error("is invalid").on(:attr)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "does not copy errors for excluded attributes" do
|
77
|
+
allow(test).to receive(:validate?).and_return(true)
|
78
|
+
TestClass.delegate_validation to: :validator, except: :attr
|
79
|
+
expect(subject).to_not have_error("is invalid").on(:attr)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "only copies errors for specified attributes" do
|
83
|
+
allow(test).to receive(:validate?).and_return(true)
|
84
|
+
TestClass.delegate_validation to: :validator, only: :attr
|
85
|
+
expect(subject).to have_error("is invalid").on(:attr)
|
86
|
+
end
|
87
|
+
|
88
|
+
context "an method is supplied" do
|
89
|
+
it "copies errors to the specified method and prefixes the attribute name" do
|
90
|
+
TestClass.delegate_validation :my_method, to: :validator
|
91
|
+
expect(subject).to have_error("attr is invalid").on(:my_method)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "copies all errors" do
|
95
|
+
allow(validator).to receive(:errors).and_return({attr: ["is invalid", "is bananas"]})
|
96
|
+
TestClass.delegate_validation :my_method, to: :validator
|
97
|
+
|
98
|
+
expect(subject).to have_error("attr is invalid").on(:my_method)
|
99
|
+
expect(subject).to have_error("attr is bananas").on(:my_method)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "reformats nested attribute errors" do
|
103
|
+
TestClass.delegate_validation :my_method, to: :validator
|
104
|
+
validator.errors[:"associated_class.attribute"] << "is bananas"
|
105
|
+
|
106
|
+
expect(subject).to have_error("associated class attribute is bananas").on(:my_method)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "copies errors if the :if option is true" do
|
110
|
+
allow(test).to receive(:validate?).and_return(true)
|
111
|
+
TestClass.delegate_validation :my_method, to: :validator, if: :validate?
|
112
|
+
|
113
|
+
expect(subject).to have_error("attr is invalid").on(:my_method)
|
114
|
+
end
|
115
|
+
|
116
|
+
it "does not copy errors if the :if option is false" do
|
117
|
+
allow(test).to receive(:validate?).and_return(false)
|
118
|
+
TestClass.delegate_validation :my_method, to: :validator, if: :validate?
|
119
|
+
expect(subject).to_not have_error("attr is invalid").on(:my_method)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "copies errors if the :unless option is false" do
|
123
|
+
allow(test).to receive(:validate?).and_return(false)
|
124
|
+
TestClass.delegate_validation :my_method, to: :validator, unless: :validate?
|
125
|
+
expect(subject).to have_error("attr is invalid").on(:my_method)
|
126
|
+
end
|
127
|
+
|
128
|
+
it "does not copy errors if the :unless option is true" do
|
129
|
+
allow(test).to receive(:validate?).and_return(true)
|
130
|
+
TestClass.delegate_validation :my_method, to: :validator, unless: :validate?
|
131
|
+
expect(subject).to_not have_error("attr is invalid").on(:my_method)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "does not copy errors for excluded attributes" do
|
135
|
+
allow(test).to receive(:validate?).and_return(true)
|
136
|
+
TestClass.delegate_validation :my_method, to: :validator, except: :attr
|
137
|
+
expect(subject).to_not have_error("attr is invalid").on(:my_method)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "only copies errors for specified attributes" do
|
141
|
+
allow(test).to receive(:validate?).and_return(true)
|
142
|
+
TestClass.delegate_validation :my_method, to: :validator, only: :attr
|
143
|
+
expect(subject).to have_error("attr is invalid").on(:my_method)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
|
5
|
+
require "validation_delegation/version"
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "validation_delegation"
|
9
|
+
spec.version = ValidationDelegation::VERSION
|
10
|
+
spec.authors = ["Ben Eddy"]
|
11
|
+
spec.email = ["bae@foraker.com"]
|
12
|
+
spec.description = %q{Delegates validation between objects}
|
13
|
+
spec.summary = %q{Validation delegation allows an object to proxy validations to other objects. This facilitates composition and prevents the duplication of validation logic.}
|
14
|
+
spec.homepage = "https://github.com/foraker/validation_delegation"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "activesupport", "~> 3.1"
|
23
|
+
spec.add_dependency "activemodel", "~> 3.1"
|
24
|
+
|
25
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
26
|
+
spec.add_development_dependency "rake"
|
27
|
+
spec.add_development_dependency "rspec"
|
28
|
+
end
|
metadata
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: validation_delegation
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Eddy
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-10-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.1'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.1'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activemodel
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.1'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ! '>='
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ! '>='
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ! '>='
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
description: Delegates validation between objects
|
84
|
+
email:
|
85
|
+
- bae@foraker.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- .gitignore
|
91
|
+
- Gemfile
|
92
|
+
- LICENSE.txt
|
93
|
+
- README.md
|
94
|
+
- Rakefile
|
95
|
+
- lib/validation_delegation.rb
|
96
|
+
- lib/validation_delegation/version.rb
|
97
|
+
- spec/validation_delegation_spec.rb
|
98
|
+
- validation_delegation.gemspec
|
99
|
+
homepage: https://github.com/foraker/validation_delegation
|
100
|
+
licenses:
|
101
|
+
- MIT
|
102
|
+
metadata: {}
|
103
|
+
post_install_message:
|
104
|
+
rdoc_options: []
|
105
|
+
require_paths:
|
106
|
+
- lib
|
107
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ! '>='
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ! '>='
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: '0'
|
117
|
+
requirements: []
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.0.3
|
120
|
+
signing_key:
|
121
|
+
specification_version: 4
|
122
|
+
summary: Validation delegation allows an object to proxy validations to other objects.
|
123
|
+
This facilitates composition and prevents the duplication of validation logic.
|
124
|
+
test_files:
|
125
|
+
- spec/validation_delegation_spec.rb
|
126
|
+
has_rdoc:
|