attestor 0.3.0 → 0.4.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 +49 -34
- data/lib/attestor.rb +1 -0
- data/lib/attestor/policy.rb +1 -1
- data/lib/attestor/policy/and.rb +1 -1
- data/lib/attestor/policy/node.rb +6 -8
- data/lib/attestor/policy/not.rb +1 -1
- data/lib/attestor/policy/or.rb +1 -1
- data/lib/attestor/policy/xor.rb +1 -1
- data/lib/attestor/validations.rb +39 -7
- data/lib/attestor/validations/delegator.rb +33 -0
- data/lib/attestor/validations/validator.rb +1 -1
- data/lib/attestor/validations/validators.rb +14 -6
- data/lib/attestor/version.rb +1 -1
- data/spec/features/example_spec.rb +5 -7
- data/spec/support/policies.rb +2 -2
- data/spec/tests/policy/node_spec.rb +29 -0
- data/spec/tests/policy_spec.rb +14 -10
- data/spec/tests/validations/delegator_spec.rb +44 -0
- data/spec/tests/validations/validator_spec.rb +6 -2
- data/spec/tests/validations/validators_spec.rb +45 -36
- data/spec/tests/validations_spec.rb +13 -14
- metadata +4 -3
- data/spec/tests/validations/follower_spec.rb +0 -44
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7889c90de0f2f5e7a65ac09a622200903219fecf
|
4
|
+
data.tar.gz: da24f1d17b8705a96f505e28063b44d38051c222
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: dd38ec23f72df933af48dfbdc3cbf26ec10845f4c6b6ec56796537c20c42b09d93113929efe89292835adcc1cf378894209dc87773b8f1870247e1a79ceda67c
|
7
|
+
data.tar.gz: ef469dd31b6df6f9f3176e5ebc74bff358e271b3c42974e6a70a07595369d66818585aea3aa660a3e54c2c646a959f6c26df8b18fff8c05502bdd2e3b08d260a
|
data/README.md
CHANGED
@@ -106,7 +106,7 @@ Alternatively, you can describe validation in the block (called in the scope of
|
|
106
106
|
```ruby
|
107
107
|
class Transfer
|
108
108
|
# ...
|
109
|
-
validate
|
109
|
+
validate { invalid :inconsistent if credit.sum != debet.sum }
|
110
110
|
end
|
111
111
|
```
|
112
112
|
|
@@ -161,71 +161,86 @@ class Transfer
|
|
161
161
|
end
|
162
162
|
```
|
163
163
|
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
Extract a validator to the separate object (policy). Basically the policy includes `Attestor::Validations` with additional methods.
|
164
|
+
Delegation
|
165
|
+
----------
|
168
166
|
|
169
|
-
|
167
|
+
Extract validator to the external object (policy), that responds to `validate`.
|
170
168
|
|
171
169
|
```ruby
|
172
|
-
|
170
|
+
class ConsistentTransfer.new(:debet, :credit)
|
171
|
+
include Attestor::Validations
|
172
|
+
|
173
173
|
def validate
|
174
|
-
|
175
|
-
invalid :inconsistent, fraud: fraud if fraud != 0
|
174
|
+
invalid :inconsistent unless debet.sum == credit.sum
|
176
175
|
end
|
177
176
|
end
|
178
177
|
```
|
179
178
|
|
180
|
-
|
179
|
+
Then use `validates` helper:
|
181
180
|
|
182
|
-
|
181
|
+
```ruby
|
182
|
+
class Transfer
|
183
|
+
# ...
|
184
|
+
validates { ConsistentTransfer.new(:debet, :credit) }
|
185
|
+
end
|
186
|
+
```
|
183
187
|
|
184
|
-
|
188
|
+
or by method name:
|
185
189
|
|
186
190
|
```ruby
|
187
|
-
class Transfer
|
188
|
-
|
191
|
+
class Transfer
|
192
|
+
# ...
|
193
|
+
validates :consistent_transfer
|
189
194
|
|
190
|
-
|
195
|
+
def consistent_transfer
|
196
|
+
ConsistentTransfer.new(:debet, :credit)
|
197
|
+
end
|
198
|
+
```
|
191
199
|
|
192
|
-
|
200
|
+
The change between `validate :something` and `validates :something` is that:
|
201
|
+
* `validate` expects `#something` to make checks and raise error by itself
|
202
|
+
* `validates` expects `#something` to respond to `#validate`
|
193
203
|
|
194
|
-
|
195
|
-
|
204
|
+
Policy Objects
|
205
|
+
--------------
|
206
|
+
|
207
|
+
Basically the policy includes `Attestor::Validations` with additional methods to allow chaining policies by logical methods.
|
208
|
+
|
209
|
+
To create a policy as a `Struct` use the builder method:
|
210
|
+
|
211
|
+
```ruby
|
212
|
+
ConsistencyPolicy = Attestor::Policy.new(:debet, :credit) do
|
213
|
+
def validate
|
214
|
+
fraud = credit - debet
|
215
|
+
invalid :inconsistent, fraud: fraud if fraud != 0
|
196
216
|
end
|
197
217
|
end
|
198
218
|
```
|
199
219
|
|
200
|
-
|
220
|
+
If you doesn't need Struct, include `Attestor::Policy` to the class and initialize its arguments somehow else:
|
201
221
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
#
|
206
|
-
|
207
|
-
en:
|
208
|
-
attestor:
|
209
|
-
errors:
|
210
|
-
transfer:
|
211
|
-
consistency: "The transfer is inconsistent"
|
222
|
+
```ruby
|
223
|
+
class ConsistencyPolicy < OpenStruct
|
224
|
+
include Attestor::Policy
|
225
|
+
# ...
|
226
|
+
end
|
212
227
|
```
|
213
228
|
|
214
|
-
|
229
|
+
Policy objects can be used by `validates` method like other validatable objects:
|
215
230
|
|
216
231
|
```ruby
|
217
232
|
class Transfer
|
218
233
|
# ...
|
219
|
-
|
220
|
-
ConsistencyPolicy.new(debet.sum, credit.sum)
|
221
|
-
end
|
234
|
+
validates { ConsistencyPolicy.new(debet, credit) }
|
222
235
|
end
|
223
236
|
```
|
224
237
|
|
238
|
+
They also respond to `valid?` and `invalid?` methods (that just rescues from `vaidate` missing any error messages).
|
239
|
+
|
225
240
|
Complex Policies
|
226
241
|
----------------
|
227
242
|
|
228
|
-
|
243
|
+
Policies (assertions) can be combined by logical methods.
|
229
244
|
|
230
245
|
Suppose we have two policy objects:
|
231
246
|
|
data/lib/attestor.rb
CHANGED
@@ -8,6 +8,7 @@ require_relative "attestor/invalid_error"
|
|
8
8
|
|
9
9
|
require_relative "attestor/validations"
|
10
10
|
require_relative "attestor/validations/validator"
|
11
|
+
require_relative "attestor/validations/delegator"
|
11
12
|
require_relative "attestor/validations/follower"
|
12
13
|
require_relative "attestor/validations/validators"
|
13
14
|
require_relative "attestor/validations/message"
|
data/lib/attestor/policy.rb
CHANGED
data/lib/attestor/policy/and.rb
CHANGED
data/lib/attestor/policy/node.rb
CHANGED
@@ -9,6 +9,7 @@ module Attestor
|
|
9
9
|
# @api private
|
10
10
|
class Node
|
11
11
|
include Attestor::Policy
|
12
|
+
include Enumerable
|
12
13
|
|
13
14
|
# @!scope class
|
14
15
|
# @!method new(*branches)
|
@@ -41,14 +42,11 @@ module Attestor
|
|
41
42
|
invalid :base
|
42
43
|
end
|
43
44
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
def any_invalid?
|
51
|
-
branches.detect(&:invalid?)
|
45
|
+
# Iterates throught branches
|
46
|
+
#
|
47
|
+
# @return [Enumerator]
|
48
|
+
def each
|
49
|
+
block_given? ? branches.each { |item| yield(item) } : to_enum
|
52
50
|
end
|
53
51
|
|
54
52
|
end # class Node
|
data/lib/attestor/policy/not.rb
CHANGED
data/lib/attestor/policy/or.rb
CHANGED
data/lib/attestor/policy/xor.rb
CHANGED
data/lib/attestor/validations.rb
CHANGED
@@ -51,21 +51,53 @@ module Attestor
|
|
51
51
|
@validators ||= Validators.new
|
52
52
|
end
|
53
53
|
|
54
|
-
# @!method
|
55
|
-
#
|
54
|
+
# @!method validate(name = nil, except: nil, only: nil, &block)
|
55
|
+
# Uses an instance method or block for validation
|
56
56
|
#
|
57
57
|
# Mutates the class by changing its {#validators} attribute!
|
58
58
|
#
|
59
|
-
# @param [#to_sym] name
|
60
|
-
# @param [Hash] options
|
61
59
|
# @option options [#to_sym, Array<#to_sym>] :except
|
62
60
|
# the black list of contexts for validation
|
63
61
|
# @option options [#to_sym, Array<#to_sym>] :only
|
64
62
|
# the white list of contexts for validation
|
65
63
|
#
|
66
|
-
# @
|
67
|
-
|
68
|
-
|
64
|
+
# @overload validate(name, except: nil, only: nil)
|
65
|
+
# Uses the instance method for validation
|
66
|
+
#
|
67
|
+
# @param [#to_sym] name The name of the instance method
|
68
|
+
#
|
69
|
+
# @overload validate(except: nil, only: nil, &block)
|
70
|
+
# Uses the block (in the scope of the instance) for validation
|
71
|
+
#
|
72
|
+
# @param [Proc] block
|
73
|
+
#
|
74
|
+
# @return [Attestor::Validators] the updated list of validators
|
75
|
+
def validate(*args, &block)
|
76
|
+
@validators = validators.add_validator(*args, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
# @!method validates(name = nil, except: nil, only: nil, &block)
|
80
|
+
# Delegates a validation to instance method or block
|
81
|
+
#
|
82
|
+
# Mutates the class by changing its {#validators} attribute!
|
83
|
+
#
|
84
|
+
# @option (see #validate)
|
85
|
+
#
|
86
|
+
# @overload validates(name, except: nil, only: nil)
|
87
|
+
# Delegates a validation to instance method
|
88
|
+
#
|
89
|
+
# @param [#to_sym] name
|
90
|
+
# The name of the instance method that should respond to #validate
|
91
|
+
#
|
92
|
+
# @overload validates(except: nil, only: nil, &block)
|
93
|
+
# Uses the block (in the scope of the instance) for validation
|
94
|
+
#
|
95
|
+
# @param [Proc] block
|
96
|
+
# The block that should respond to #validate
|
97
|
+
#
|
98
|
+
# @return (see #validate)
|
99
|
+
def validates(*args, &block)
|
100
|
+
@validators = validators.add_delegator(*args, &block)
|
69
101
|
end
|
70
102
|
|
71
103
|
# @!method follow_policy(name, except: nil, only: nil)
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Attestor
|
4
|
+
|
5
|
+
module Validations
|
6
|
+
|
7
|
+
# Describe a validator that delegates validation to instance method or block
|
8
|
+
#
|
9
|
+
# The follower not only calls an instance method (block) as validator does,
|
10
|
+
# but calls #validate method of the result.
|
11
|
+
#
|
12
|
+
# @example
|
13
|
+
# follower = Validator.new(:foo, only: :baz) { FooPolicy.new(foo) }
|
14
|
+
#
|
15
|
+
# @api private
|
16
|
+
class Delegator < Validator
|
17
|
+
|
18
|
+
# Validates an object by delegation
|
19
|
+
#
|
20
|
+
# @param [Object] object
|
21
|
+
#
|
22
|
+
# @raise [Attestor::InvalidError] if a policy isn't valid
|
23
|
+
#
|
24
|
+
# @return [undefined]
|
25
|
+
def validate(_)
|
26
|
+
super.validate
|
27
|
+
end
|
28
|
+
|
29
|
+
end # class Follower
|
30
|
+
|
31
|
+
end # module Validations
|
32
|
+
|
33
|
+
end # module Attestor
|
@@ -26,7 +26,7 @@ module Attestor
|
|
26
26
|
# @return [Attestor::Validations::Validator]
|
27
27
|
|
28
28
|
# @private
|
29
|
-
def initialize(name, except: nil, only: nil, &block)
|
29
|
+
def initialize(name = :invalid, except: nil, only: nil, &block)
|
30
30
|
@name = name.to_sym
|
31
31
|
@whitelist = normalize(only)
|
32
32
|
@blacklist = normalize(except)
|
@@ -42,7 +42,8 @@ module Attestor
|
|
42
42
|
# @return [Attestor::Validators]
|
43
43
|
def set(context)
|
44
44
|
validators = select { |item| item.used_in_context? context }
|
45
|
-
|
45
|
+
|
46
|
+
self.class.new(validators)
|
46
47
|
end
|
47
48
|
|
48
49
|
# Returns validators updated by a new validator with given args
|
@@ -50,16 +51,23 @@ module Attestor
|
|
50
51
|
# @param [Array] args
|
51
52
|
#
|
52
53
|
# @return [Attestor::Validators]
|
53
|
-
def add_validator(*args)
|
54
|
-
add_item Validator, *args
|
54
|
+
def add_validator(*args, &block)
|
55
|
+
add_item Validator, *args, &block
|
55
56
|
end
|
56
57
|
|
57
|
-
# Returns validators updated by a new
|
58
|
+
# Returns validators updated by a new validator with given args
|
58
59
|
#
|
59
60
|
# @param [Array] args
|
60
61
|
#
|
61
62
|
# @return [Attestor::Validators]
|
63
|
+
def add_delegator(*args, &block)
|
64
|
+
add_item Delegator, *args, &block
|
65
|
+
end
|
66
|
+
|
67
|
+
# @deprecated
|
62
68
|
def add_follower(*args)
|
69
|
+
warn "[DEPRECATED] .add_follower is deprecated since v1.0.0" \
|
70
|
+
" Use .validates method instead."
|
63
71
|
add_item Follower, *args
|
64
72
|
end
|
65
73
|
|
@@ -67,8 +75,8 @@ module Attestor
|
|
67
75
|
|
68
76
|
attr_reader :items
|
69
77
|
|
70
|
-
def add_item(type, *args)
|
71
|
-
item = type.new(*args)
|
78
|
+
def add_item(type, *args, &block)
|
79
|
+
item = type.new(*args, &block)
|
72
80
|
include?(item) ? self : self.class.new(items, item)
|
73
81
|
end
|
74
82
|
|
data/lib/attestor/version.rb
CHANGED
@@ -53,16 +53,14 @@ describe "Base example" do
|
|
53
53
|
class Transfer
|
54
54
|
include Attestor::Validations
|
55
55
|
|
56
|
-
|
57
|
-
|
58
|
-
|
56
|
+
validates { ConsistencyPolicy.new(debet, credit) }
|
57
|
+
validates :limited, except: :blocked
|
58
|
+
validate only: :blocked do
|
59
|
+
internal.validate
|
60
|
+
end
|
59
61
|
|
60
62
|
private
|
61
63
|
|
62
|
-
def consistent
|
63
|
-
ConsistencyPolicy.new(debet, credit)
|
64
|
-
end
|
65
|
-
|
66
64
|
def limited
|
67
65
|
LimitPolicy.new(debet).or internal
|
68
66
|
end
|
data/spec/support/policies.rb
CHANGED
@@ -3,11 +3,11 @@
|
|
3
3
|
# Definitions for testing compound policies
|
4
4
|
|
5
5
|
def valid_policy
|
6
|
-
double valid?: true, invalid?: false
|
6
|
+
double valid?: true, invalid?: false, validate: nil
|
7
7
|
end
|
8
8
|
|
9
9
|
def invalid_policy
|
10
|
-
double valid?: false, invalid?: true
|
10
|
+
double valid?: false, invalid?: true, validate: nil
|
11
11
|
end
|
12
12
|
|
13
13
|
shared_examples "creating a node" do
|
@@ -11,6 +11,10 @@ describe Attestor::Policy::Node do
|
|
11
11
|
expect(subject).to be_kind_of policy_class
|
12
12
|
end
|
13
13
|
|
14
|
+
it "creates a collection" do
|
15
|
+
expect(subject).to be_kind_of Enumerable
|
16
|
+
end
|
17
|
+
|
14
18
|
it "creates immutable object" do
|
15
19
|
expect(subject).to be_frozen
|
16
20
|
end
|
@@ -33,12 +37,37 @@ describe Attestor::Policy::Node do
|
|
33
37
|
|
34
38
|
end # describe #branches
|
35
39
|
|
40
|
+
describe "#each" do
|
41
|
+
|
42
|
+
let(:branches) { 3.times.map { double } }
|
43
|
+
|
44
|
+
it "returns an enumerator" do
|
45
|
+
expect(subject.each).to be_kind_of Enumerator
|
46
|
+
end
|
47
|
+
|
48
|
+
it "iterates through brances" do
|
49
|
+
subject = described_class.new(branches)
|
50
|
+
expect(subject.to_a).to eq branches
|
51
|
+
end
|
52
|
+
|
53
|
+
end # each
|
54
|
+
|
36
55
|
describe "#validate" do
|
37
56
|
|
57
|
+
let(:message) { Attestor::Validations::Message.new :base, subject }
|
58
|
+
|
38
59
|
it "raises InvalidError" do
|
39
60
|
expect { subject.validate }.to raise_error invalid_error
|
40
61
|
end
|
41
62
|
|
63
|
+
it "adds the :invalid message" do
|
64
|
+
begin
|
65
|
+
subject.validate
|
66
|
+
rescue => error
|
67
|
+
expect(error.messages).to contain_exactly message
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
42
71
|
end # describe #validate
|
43
72
|
|
44
73
|
end # describe Attestor::Policy::Node
|
data/spec/tests/policy_spec.rb
CHANGED
@@ -12,32 +12,36 @@ describe Attestor::Policy do
|
|
12
12
|
after { Object.send :remove_const, :Test }
|
13
13
|
subject { test_class.new }
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
15
|
+
describe ".included" do
|
16
|
+
|
17
|
+
it "is a factory" do
|
18
|
+
expect(test_class).to be_kind_of factory
|
19
|
+
end
|
20
|
+
|
21
|
+
end # describe .included
|
18
22
|
|
19
23
|
describe ".new" do
|
20
24
|
|
21
|
-
|
22
|
-
subject { build.new(:baz) }
|
25
|
+
subject { described_class.new(:foo) }
|
23
26
|
|
24
27
|
it "builds the struct" do
|
25
|
-
expect(subject).to be_kind_of Struct
|
28
|
+
expect(subject.new(:baz)).to be_kind_of Struct
|
26
29
|
end
|
27
30
|
|
28
31
|
it "adds given attributes" do
|
29
|
-
expect(subject.foo).to eq :baz
|
32
|
+
expect(subject.new(:baz).foo).to eq :baz
|
30
33
|
end
|
31
34
|
|
32
35
|
it "builds the policy" do
|
33
|
-
expect(subject).to be_kind_of described_class
|
36
|
+
expect(subject.new(:baz)).to be_kind_of described_class
|
34
37
|
end
|
35
38
|
|
36
39
|
it "yields the block in class scope" do
|
37
|
-
|
40
|
+
subject = described_class.new(:foo) { attr_reader :bar }
|
41
|
+
expect(subject.new(:baz)).to respond_to :bar
|
38
42
|
end
|
39
43
|
|
40
|
-
end
|
44
|
+
end # describe .new
|
41
45
|
|
42
46
|
describe ".included" do
|
43
47
|
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require "support/policies"
|
4
|
+
|
5
|
+
describe Attestor::Validations::Delegator do
|
6
|
+
|
7
|
+
let(:validator) { Attestor::Validations::Validator }
|
8
|
+
|
9
|
+
describe ".new" do
|
10
|
+
|
11
|
+
subject { described_class.new "foo" }
|
12
|
+
it { is_expected.to be_kind_of validator }
|
13
|
+
|
14
|
+
end # describe .new
|
15
|
+
|
16
|
+
describe "#validate" do
|
17
|
+
|
18
|
+
let(:object) { double foo: valid_policy }
|
19
|
+
|
20
|
+
context "when initialized without a block" do
|
21
|
+
|
22
|
+
subject { described_class.new "foo" }
|
23
|
+
after { subject.validate object }
|
24
|
+
|
25
|
+
it "delegates validation to named method" do
|
26
|
+
expect(object).to receive_message_chain(:foo, :validate)
|
27
|
+
end
|
28
|
+
|
29
|
+
end # context
|
30
|
+
|
31
|
+
context "when initialized with a block" do
|
32
|
+
|
33
|
+
subject { described_class.new { foo } }
|
34
|
+
after { subject.validate object }
|
35
|
+
|
36
|
+
it "delegates validation to block" do
|
37
|
+
expect(object).to receive_message_chain(:foo, :validate)
|
38
|
+
end
|
39
|
+
|
40
|
+
end # context
|
41
|
+
|
42
|
+
end # describe #validate
|
43
|
+
|
44
|
+
end # describe Attestor::Validations::Delegator
|
@@ -46,6 +46,10 @@ describe Attestor::Validations::Validator do
|
|
46
46
|
expect(subject.name).to eq :foo
|
47
47
|
end
|
48
48
|
|
49
|
+
it "is initialized by default as :invalid" do
|
50
|
+
expect(described_class.new.name).to eq :invalid
|
51
|
+
end
|
52
|
+
|
49
53
|
end # describe .name
|
50
54
|
|
51
55
|
describe "#==" do
|
@@ -154,8 +158,8 @@ describe Attestor::Validations::Validator do
|
|
154
158
|
|
155
159
|
describe "#validate" do
|
156
160
|
|
157
|
-
let(:object) {
|
158
|
-
after
|
161
|
+
let(:object) { Class.new { private def foo; end }.new }
|
162
|
+
after { subject.validate object }
|
159
163
|
|
160
164
|
context "when no block initialized" do
|
161
165
|
|
@@ -3,7 +3,7 @@
|
|
3
3
|
describe Attestor::Validations::Validators do
|
4
4
|
|
5
5
|
let(:validator_class) { Attestor::Validations::Validator }
|
6
|
-
let(:
|
6
|
+
let(:delegator_class) { Attestor::Validations::Delegator }
|
7
7
|
|
8
8
|
describe ".new" do
|
9
9
|
|
@@ -34,7 +34,7 @@ describe Attestor::Validations::Validators do
|
|
34
34
|
|
35
35
|
describe "#add_validator" do
|
36
36
|
|
37
|
-
context "
|
37
|
+
context "with a name" do
|
38
38
|
|
39
39
|
let(:result) { subject.add_validator "foo" }
|
40
40
|
|
@@ -42,10 +42,10 @@ describe Attestor::Validations::Validators do
|
|
42
42
|
expect(result).to be_kind_of described_class
|
43
43
|
end
|
44
44
|
|
45
|
-
it "adds validator (not a
|
45
|
+
it "adds validator (not a delegator)" do
|
46
46
|
item = result.first
|
47
47
|
expect(item).to be_kind_of validator_class
|
48
|
-
expect(item).not_to be_kind_of
|
48
|
+
expect(item).not_to be_kind_of delegator_class
|
49
49
|
end
|
50
50
|
|
51
51
|
it "assigns a name" do
|
@@ -54,49 +54,54 @@ describe Attestor::Validations::Validators do
|
|
54
54
|
end
|
55
55
|
|
56
56
|
it "preserves existing items" do
|
57
|
-
expect(result.add_validator(:bar).
|
58
|
-
.to contain_exactly :foo, :bar
|
57
|
+
expect(result.add_validator(:bar).count).to be 2
|
59
58
|
end
|
60
59
|
|
61
60
|
end # context
|
62
61
|
|
63
|
-
context "with
|
62
|
+
context "with a block" do
|
64
63
|
|
65
|
-
let(:result) { subject.add_validator
|
64
|
+
let(:result) { subject.add_validator { foo } }
|
66
65
|
|
67
|
-
it "
|
68
|
-
expect(result
|
69
|
-
|
70
|
-
|
66
|
+
it "returns validators" do
|
67
|
+
expect(result).to be_kind_of described_class
|
68
|
+
end
|
69
|
+
|
70
|
+
it "adds validator (not a delegator)" do
|
71
|
+
item = result.first
|
72
|
+
expect(item).to be_kind_of validator_class
|
73
|
+
expect(item).not_to be_kind_of delegator_class
|
71
74
|
end
|
72
75
|
|
73
76
|
end # context
|
74
77
|
|
75
|
-
context "
|
78
|
+
context "with contexts" do
|
76
79
|
|
77
|
-
|
80
|
+
let(:result) { subject.add_validator "foo", only: [:foo] }
|
78
81
|
|
79
|
-
it "
|
80
|
-
expect(
|
82
|
+
it "adds item to validators" do
|
83
|
+
expect(result.map(&:name)).to eq [:foo]
|
84
|
+
expect(result.set(:foo).map(&:name)).to eq [:foo]
|
85
|
+
expect(result.set(:all).map(&:name)).to eq []
|
81
86
|
end
|
82
87
|
|
83
88
|
end # context
|
84
89
|
|
85
90
|
end # describe #add_validator
|
86
91
|
|
87
|
-
describe "#
|
92
|
+
describe "#add_delegator" do
|
88
93
|
|
89
|
-
context "
|
94
|
+
context "with a name" do
|
90
95
|
|
91
|
-
let(:result) { subject.
|
96
|
+
let(:result) { subject.add_delegator "foo" }
|
92
97
|
|
93
98
|
it "returns validators" do
|
94
99
|
expect(result).to be_kind_of described_class
|
95
100
|
end
|
96
101
|
|
97
|
-
it "adds a
|
102
|
+
it "adds a delegator" do
|
98
103
|
item = result.first
|
99
|
-
expect(item).to be_kind_of
|
104
|
+
expect(item).to be_kind_of delegator_class
|
100
105
|
end
|
101
106
|
|
102
107
|
it "assigns a name" do
|
@@ -105,41 +110,45 @@ describe Attestor::Validations::Validators do
|
|
105
110
|
end
|
106
111
|
|
107
112
|
it "preserves existing items" do
|
108
|
-
expect(result.
|
109
|
-
.to contain_exactly :foo, :bar
|
113
|
+
expect(result.add_delegator(:bar).count).to eq 2
|
110
114
|
end
|
111
115
|
|
112
116
|
end # context
|
113
117
|
|
114
|
-
context "with
|
118
|
+
context "with a block" do
|
115
119
|
|
116
|
-
let(:result) { subject.
|
120
|
+
let(:result) { subject.add_delegator { foo } }
|
117
121
|
|
118
|
-
it "
|
119
|
-
expect(result
|
120
|
-
|
121
|
-
|
122
|
+
it "returns validators" do
|
123
|
+
expect(result).to be_kind_of described_class
|
124
|
+
end
|
125
|
+
|
126
|
+
it "adds a delegator" do
|
127
|
+
item = result.first
|
128
|
+
expect(item).to be_kind_of delegator_class
|
122
129
|
end
|
123
130
|
|
124
131
|
end # context
|
125
132
|
|
126
|
-
context "
|
133
|
+
context "with contexts" do
|
127
134
|
|
128
|
-
|
135
|
+
let(:result) { subject.add_delegator "foo", only: [:foo] }
|
129
136
|
|
130
|
-
it "
|
131
|
-
expect(
|
137
|
+
it "adds item to validators" do
|
138
|
+
expect(result.map(&:name)).to eq [:foo]
|
139
|
+
expect(result.set(:foo).map(&:name)).to eq [:foo]
|
140
|
+
expect(result.set(:all).map(&:name)).to eq []
|
132
141
|
end
|
133
142
|
|
134
143
|
end # context
|
135
144
|
|
136
|
-
end # describe #
|
145
|
+
end # describe #add_delegator
|
137
146
|
|
138
147
|
describe "#set" do
|
139
148
|
|
140
149
|
subject do
|
141
150
|
described_class.new
|
142
|
-
.add_validator("foo"
|
151
|
+
.add_validator("foo")
|
143
152
|
.add_validator("bar", except: %w(cad))
|
144
153
|
.add_validator("baz", except: %w(cam))
|
145
154
|
end
|
@@ -151,7 +160,7 @@ describe Attestor::Validations::Validators do
|
|
151
160
|
it "returns a set of items used in given context" do
|
152
161
|
expect(subject.set("cad").map(&:name)).to contain_exactly :foo, :baz
|
153
162
|
expect(subject.set("cam").map(&:name)).to contain_exactly :foo, :bar
|
154
|
-
expect(subject.set("all").map(&:name)).to contain_exactly :bar, :baz
|
163
|
+
expect(subject.set("all").map(&:name)).to contain_exactly :foo, :bar, :baz
|
155
164
|
end
|
156
165
|
|
157
166
|
end # describe #set
|
@@ -6,15 +6,14 @@ describe Attestor::Validations do
|
|
6
6
|
|
7
7
|
let(:validators_class) { Attestor::Validations::Validators }
|
8
8
|
let(:validator_class) { Attestor::Validations::Validator }
|
9
|
-
let(:
|
10
|
-
let(:collection_class) { Attestor::Validations::Validators }
|
9
|
+
let(:delegator_class) { Attestor::Validations::Delegator }
|
11
10
|
let(:item_class) { Attestor::Validations::Item }
|
12
11
|
let(:message_class) { Attestor::Validations::Message }
|
13
12
|
let(:invalid_error) { Attestor::InvalidError }
|
14
13
|
|
15
14
|
let(:test_class) { Class.new.send(:include, described_class) }
|
16
|
-
before
|
17
|
-
after
|
15
|
+
before { Test = test_class }
|
16
|
+
after { Object.send :remove_const, :Test }
|
18
17
|
|
19
18
|
subject { test_class.new }
|
20
19
|
|
@@ -38,7 +37,7 @@ describe Attestor::Validations do
|
|
38
37
|
|
39
38
|
it "registers a validator" do
|
40
39
|
expect(test_class.validators.map(&:name)).to eq [:foo]
|
41
|
-
expect(test_class.validators.first).not_to be_kind_of
|
40
|
+
expect(test_class.validators.first).not_to be_kind_of delegator_class
|
42
41
|
end
|
43
42
|
|
44
43
|
end # context
|
@@ -57,22 +56,22 @@ describe Attestor::Validations do
|
|
57
56
|
|
58
57
|
end # describe .validate
|
59
58
|
|
60
|
-
describe ".
|
59
|
+
describe ".validates" do
|
61
60
|
|
62
61
|
context "without options" do
|
63
62
|
|
64
|
-
before { test_class.
|
63
|
+
before { test_class.validates :foo }
|
65
64
|
|
66
|
-
it "registers a
|
65
|
+
it "registers a delegator" do
|
67
66
|
expect(test_class.validators.map(&:name)).to eq [:foo]
|
68
|
-
expect(test_class.validators.first).to be_kind_of
|
67
|
+
expect(test_class.validators.first).to be_kind_of delegator_class
|
69
68
|
end
|
70
69
|
|
71
70
|
end # context
|
72
71
|
|
73
72
|
context "with restrictions" do
|
74
73
|
|
75
|
-
before { test_class.
|
74
|
+
before { test_class.validates :foo, only: %w(bar baz), except: "bar" }
|
76
75
|
|
77
76
|
it "uses options" do
|
78
77
|
expect(test_class.validators.map(&:name)).to eq [:foo]
|
@@ -82,7 +81,7 @@ describe Attestor::Validations do
|
|
82
81
|
|
83
82
|
end # context
|
84
83
|
|
85
|
-
end # describe .
|
84
|
+
end # describe .validates
|
86
85
|
|
87
86
|
describe "#invalid" do
|
88
87
|
|
@@ -126,9 +125,9 @@ describe Attestor::Validations do
|
|
126
125
|
describe "#validate" do
|
127
126
|
|
128
127
|
before do
|
129
|
-
test_class.validate
|
130
|
-
test_class.validate
|
131
|
-
test_class.
|
128
|
+
test_class.validate :foo
|
129
|
+
test_class.validate :bar, only: :all
|
130
|
+
test_class.validates :baz, only: :foo
|
132
131
|
|
133
132
|
allow(subject).to receive(:foo)
|
134
133
|
allow(subject).to receive(:bar)
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: attestor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Kozin
|
@@ -81,6 +81,7 @@ files:
|
|
81
81
|
- lib/attestor/policy/or.rb
|
82
82
|
- lib/attestor/policy/xor.rb
|
83
83
|
- lib/attestor/validations.rb
|
84
|
+
- lib/attestor/validations/delegator.rb
|
84
85
|
- lib/attestor/validations/follower.rb
|
85
86
|
- lib/attestor/validations/message.rb
|
86
87
|
- lib/attestor/validations/validator.rb
|
@@ -98,7 +99,7 @@ files:
|
|
98
99
|
- spec/tests/policy/or_spec.rb
|
99
100
|
- spec/tests/policy/xor_spec.rb
|
100
101
|
- spec/tests/policy_spec.rb
|
101
|
-
- spec/tests/validations/
|
102
|
+
- spec/tests/validations/delegator_spec.rb
|
102
103
|
- spec/tests/validations/message_spec.rb
|
103
104
|
- spec/tests/validations/validator_spec.rb
|
104
105
|
- spec/tests/validations/validators_spec.rb
|
@@ -133,8 +134,8 @@ test_files:
|
|
133
134
|
- spec/tests/invalid_error_spec.rb
|
134
135
|
- spec/tests/validations_spec.rb
|
135
136
|
- spec/tests/validations/message_spec.rb
|
136
|
-
- spec/tests/validations/follower_spec.rb
|
137
137
|
- spec/tests/validations/validator_spec.rb
|
138
|
+
- spec/tests/validations/delegator_spec.rb
|
138
139
|
- spec/tests/validations/validators_spec.rb
|
139
140
|
- spec/tests/policy/or_spec.rb
|
140
141
|
- spec/tests/policy/factory_spec.rb
|
@@ -1,44 +0,0 @@
|
|
1
|
-
# encoding: utf-8
|
2
|
-
|
3
|
-
require "support/policies"
|
4
|
-
|
5
|
-
describe Attestor::Validations::Follower do
|
6
|
-
|
7
|
-
let(:validator) { Attestor::Validations::Validator }
|
8
|
-
subject { described_class.new "foo" }
|
9
|
-
|
10
|
-
describe ".new" do
|
11
|
-
|
12
|
-
it { is_expected.to be_kind_of validator }
|
13
|
-
|
14
|
-
end # describe .new
|
15
|
-
|
16
|
-
describe "#validate" do
|
17
|
-
|
18
|
-
after { subject.validate object }
|
19
|
-
|
20
|
-
context "when a policy is valid" do
|
21
|
-
|
22
|
-
let(:object) { double foo: valid_policy }
|
23
|
-
|
24
|
-
it "calls policy method and passes" do
|
25
|
-
expect(object).to receive :foo
|
26
|
-
expect(object).not_to receive :invalid
|
27
|
-
end
|
28
|
-
|
29
|
-
end # context
|
30
|
-
|
31
|
-
context "when a policy is invalid" do
|
32
|
-
|
33
|
-
let(:object) { double foo: invalid_policy }
|
34
|
-
|
35
|
-
it "calls policy method and fails" do
|
36
|
-
expect(object).to receive :foo
|
37
|
-
expect(object).to receive(:invalid).with(:foo)
|
38
|
-
end
|
39
|
-
|
40
|
-
end # context
|
41
|
-
|
42
|
-
end # describe #validate
|
43
|
-
|
44
|
-
end # describe Attestor::Validations::Follower
|