attestor 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|