attestor 1.0.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/README.md +69 -55
- data/config/metrics/rubocop.yml +4 -0
- data/lib/attestor/invalid_error.rb +1 -12
- data/lib/attestor/policy/and.rb +2 -19
- data/lib/attestor/policy/negator.rb +2 -29
- data/lib/attestor/policy/node.rb +7 -33
- data/lib/attestor/policy/not.rb +2 -27
- data/lib/attestor/policy/or.rb +2 -19
- data/lib/attestor/policy/xor.rb +2 -19
- data/lib/attestor/policy.rb +0 -18
- data/lib/attestor/report.rb +51 -0
- data/lib/attestor/validations/delegator.rb +3 -18
- data/lib/attestor/validations/message.rb +1 -16
- data/lib/attestor/validations/reporter.rb +21 -0
- data/lib/attestor/validations/validator.rb +4 -63
- data/lib/attestor/validations/validators.rb +13 -41
- data/lib/attestor/validations.rb +12 -1
- data/lib/attestor/version.rb +1 -1
- data/lib/attestor.rb +2 -0
- data/spec/features/example_spec.rb +5 -5
- data/spec/support/policies.rb +5 -5
- data/spec/tests/policy/and_spec.rb +2 -2
- data/spec/tests/policy/node_spec.rb +9 -9
- data/spec/tests/policy/not_spec.rb +2 -2
- data/spec/tests/policy/or_spec.rb +2 -2
- data/spec/tests/policy/xor_spec.rb +2 -2
- data/spec/tests/policy_spec.rb +0 -48
- data/spec/tests/report_spec.rb +106 -0
- data/spec/tests/validations/delegator_spec.rb +6 -6
- data/spec/tests/validations/message_spec.rb +1 -1
- data/spec/tests/validations/reporter_spec.rb +47 -0
- data/spec/tests/validations/validator_spec.rb +56 -74
- data/spec/tests/validations/validators_spec.rb +81 -4
- data/spec/tests/validations_spec.rb +98 -10
- metadata +9 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1b4d9f6dfa1931f69062623223fafaf32ec4d158
|
4
|
+
data.tar.gz: a18709a18446af9c58a71287eb9b3d923c125aed
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fadf072439c8efa450e86ff37f7dd5778c67ce7a087eaea4e012e0267d9dce2b877283b76c04b1434b1ab0d17b7a00a48317ddeee766304d7ff08ebb02c66109
|
7
|
+
data.tar.gz: 0c5fccf30fe0cfc574d71b3235da77acc904c3f537f4d9ffb4887184925d42c57d82736f99d0af0954fe000c0bc141cc1793bd15911275485bfcfc648bb235c6
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -37,7 +37,12 @@ To solve the problem, the `attestor` gem:
|
|
37
37
|
Approach
|
38
38
|
--------
|
39
39
|
|
40
|
-
Instead of collecting errors inside the object, the module
|
40
|
+
Instead of collecting errors inside the object, the module defines two instance methods:
|
41
|
+
|
42
|
+
* `validate!` raises an exception (`Attestor::InvalidError`), that carries errors outside of the object.
|
43
|
+
* `validate` - the safe version of `validate!`. It rescues an exception and returns special result object, that carries error info outside of the object.
|
44
|
+
|
45
|
+
The object stays untouched (and can be made immutable).
|
41
46
|
|
42
47
|
Installation
|
43
48
|
------------
|
@@ -67,18 +72,10 @@ Basic Use
|
|
67
72
|
Declare validation in the same way as ActiveModel's `.validate` method does:
|
68
73
|
|
69
74
|
```ruby
|
70
|
-
|
75
|
+
Transfer = Struct.new(:debet, :credit) do
|
71
76
|
include Attestor::Validations
|
72
77
|
|
73
78
|
validate :consistent
|
74
|
-
end
|
75
|
-
```
|
76
|
-
|
77
|
-
You have to define an instance validator method (that can be private):
|
78
|
-
|
79
|
-
```ruby
|
80
|
-
class Transfer < Struct.new(:debet, :credit)
|
81
|
-
# ...
|
82
79
|
|
83
80
|
private
|
84
81
|
|
@@ -89,7 +86,16 @@ class Transfer < Struct.new(:debet, :credit)
|
|
89
86
|
end
|
90
87
|
```
|
91
88
|
|
92
|
-
|
89
|
+
Alternatively, you can describe validation in the block (called in the scope of instance):
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
class Transfer
|
93
|
+
# ...
|
94
|
+
validate { invalid :inconsistent if credit.sum != debet.sum }
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
The `#invalid` method translates its argument in a current class scope and raises an exception with that method.
|
93
99
|
|
94
100
|
```yaml
|
95
101
|
# config/locales/en.yml
|
@@ -101,16 +107,7 @@ en:
|
|
101
107
|
inconsistent: "Credit differs from debet by %{fraud}"
|
102
108
|
```
|
103
109
|
|
104
|
-
|
105
|
-
|
106
|
-
```ruby
|
107
|
-
class Transfer
|
108
|
-
# ...
|
109
|
-
validate { invalid :inconsistent if credit.sum != debet.sum }
|
110
|
-
end
|
111
|
-
```
|
112
|
-
|
113
|
-
To run validations use the `#validate` instance method:
|
110
|
+
To run validations use the `#validate!` instance method:
|
114
111
|
|
115
112
|
```ruby
|
116
113
|
debet = OpenStruct.new(sum: 100)
|
@@ -118,14 +115,25 @@ credit = OpenStruct.new(sum: 90)
|
|
118
115
|
fraud_transfer = Transfer.new(debet, credit)
|
119
116
|
|
120
117
|
begin
|
121
|
-
transfer.validate
|
122
|
-
rescue => error
|
118
|
+
transfer.validate! # with the bang
|
119
|
+
rescue Attestor::InvalidError => error
|
123
120
|
error.object == transfer # => true
|
124
|
-
error.messages
|
125
|
-
# => ["Credit differs from debet by 10"]
|
121
|
+
error.messages # => ["Credit differs from debet by 10"]
|
126
122
|
end
|
127
123
|
```
|
128
124
|
|
125
|
+
Another option is to use the safe version `#validate`. It rescues from the exception and returns results in a separate report object:
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
report = transfer.validate # without the bang
|
129
|
+
|
130
|
+
report.valid? # => false
|
131
|
+
report.invalid? # => true
|
132
|
+
report.object == transfer # => true
|
133
|
+
report.messages # => ["Credit differs from debet by 10"]
|
134
|
+
report.error # => <Attestor::InvalidError ...>
|
135
|
+
```
|
136
|
+
|
129
137
|
Use of Contexts
|
130
138
|
---------------
|
131
139
|
|
@@ -134,43 +142,42 @@ Sometimes you need to validate the object agaist the subset of validations, not
|
|
134
142
|
To do this use `:except` and `:only` options of the `.validate` class method.
|
135
143
|
|
136
144
|
```ruby
|
137
|
-
class Transfer
|
138
|
-
|
139
|
-
|
145
|
+
class Transfer
|
146
|
+
# ...
|
140
147
|
validate :consistent, except: :steal_of_money
|
141
148
|
end
|
142
149
|
```
|
143
150
|
|
144
|
-
Then call a validate
|
151
|
+
Then call a `#validate!`/`#validate` methods with that context:
|
145
152
|
|
146
153
|
```ruby
|
147
|
-
fraud_transfer.validate # => InvalidError
|
148
|
-
fraud_transfer.validate :steal_of_money # => PASSES!
|
154
|
+
fraud_transfer.validate! # => InvalidError
|
155
|
+
fraud_transfer.validate! :steal_of_money # => PASSES!
|
149
156
|
```
|
150
157
|
|
151
|
-
You can use the same validator several times with different contexts.
|
158
|
+
You can use the same validator several times with different contexts.
|
152
159
|
|
153
160
|
```ruby
|
154
161
|
class Transfer
|
155
162
|
# ...
|
163
|
+
|
164
|
+
# validate :consistent, only: [:fair_trade, :legal]
|
156
165
|
validate :consistent, only: :fair_trade
|
157
166
|
validate :consistent, only: :legal
|
158
167
|
|
159
|
-
# This is the same as:
|
160
|
-
# validate :consistent, only: [:fair_trade, :legal]
|
161
168
|
end
|
162
169
|
```
|
163
170
|
|
164
171
|
Delegation
|
165
172
|
----------
|
166
173
|
|
167
|
-
Extract validator to
|
174
|
+
Extract validator to an external object (policy), that responds to `validate!`.
|
168
175
|
|
169
176
|
```ruby
|
170
|
-
|
177
|
+
ConsistentTransfer = Struct.new(:debet, :credit) do
|
171
178
|
include Attestor::Validations
|
172
179
|
|
173
|
-
def validate
|
180
|
+
def validate!
|
174
181
|
invalid :inconsistent unless debet.sum == credit.sum
|
175
182
|
end
|
176
183
|
end
|
@@ -197,36 +204,36 @@ class Transfer
|
|
197
204
|
end
|
198
205
|
```
|
199
206
|
|
200
|
-
The
|
201
|
-
*
|
202
|
-
*
|
207
|
+
The difference between `.validate :something` and `.validates :something` class methods is that:
|
208
|
+
* `.validate` expects `#something` to make checks and raise error by itself
|
209
|
+
* `.validates` expects `#something` to respond to `#validate!`
|
203
210
|
|
204
211
|
Policy Objects
|
205
212
|
--------------
|
206
213
|
|
207
|
-
Basically the policy includes `Attestor::Validations` with additional methods to allow
|
214
|
+
Basically the policy includes `Attestor::Validations` with additional methods to allow logical compositions.
|
208
215
|
|
209
|
-
To create a policy as a `Struct` use the builder
|
216
|
+
To create a policy as a `Struct` use the builder:
|
210
217
|
|
211
218
|
```ruby
|
212
219
|
ConsistencyPolicy = Attestor::Policy.new(:debet, :credit) do
|
213
|
-
def validate
|
220
|
+
def validate!
|
214
221
|
fraud = credit - debet
|
215
222
|
invalid :inconsistent, fraud: fraud if fraud != 0
|
216
223
|
end
|
217
224
|
end
|
218
225
|
```
|
219
226
|
|
220
|
-
If you doesn't need Struct
|
227
|
+
If you doesn't need `Struct`, include `Attestor::Policy` to the class and initialize its arguments somehow else:
|
221
228
|
|
222
229
|
```ruby
|
223
|
-
class ConsistencyPolicy
|
230
|
+
class ConsistencyPolicy
|
224
231
|
include Attestor::Policy
|
225
232
|
# ...
|
226
233
|
end
|
227
234
|
```
|
228
235
|
|
229
|
-
Policy objects can be used by `validates` method like other
|
236
|
+
Policy objects can be used by `validates` method like other objects that respond to `#validate!`:
|
230
237
|
|
231
238
|
```ruby
|
232
239
|
class Transfer
|
@@ -235,8 +242,6 @@ class Transfer
|
|
235
242
|
end
|
236
243
|
```
|
237
244
|
|
238
|
-
They also respond to `valid?` and `invalid?` methods (that just rescues from `vaidate` missing any error messages).
|
239
|
-
|
240
245
|
Complex Policies
|
241
246
|
----------------
|
242
247
|
|
@@ -245,27 +250,27 @@ Policies (assertions) can be combined by logical methods.
|
|
245
250
|
Suppose we have two policy objects:
|
246
251
|
|
247
252
|
```ruby
|
248
|
-
valid_policy.valid? # => true
|
249
|
-
invalid_policy.valid? # => false
|
253
|
+
valid_policy.validate.valid? # => true
|
254
|
+
invalid_policy.validate.valid? # => false
|
250
255
|
```
|
251
256
|
|
252
257
|
Use factory methods to provide compositions:
|
253
258
|
|
254
259
|
```ruby
|
255
260
|
complex_policy = valid_policy.not
|
256
|
-
complex_policy.validate # => fails
|
261
|
+
complex_policy.validate! # => fails
|
257
262
|
|
258
263
|
complex_policy = valid_policy.and(valid_policy, invalid_policy)
|
259
|
-
complex_policy.validate # => fails
|
264
|
+
complex_policy.validate! # => fails
|
260
265
|
|
261
266
|
complex_policy = invalid_policy.or(invalid_policy, valid_policy)
|
262
|
-
complex_policy.validate # => passes
|
267
|
+
complex_policy.validate! # => passes
|
263
268
|
|
264
269
|
complex_policy = valid_policy.xor(valid_poicy, valid_policy)
|
265
|
-
complex_policy.validate # => fails
|
270
|
+
complex_policy.validate! # => fails
|
266
271
|
|
267
272
|
complex_policy = valid_policy.xor(valid_poicy, invalid_policy)
|
268
|
-
complex_policy.validate # => passes
|
273
|
+
complex_policy.validate! # => passes
|
269
274
|
```
|
270
275
|
|
271
276
|
The `or`, `and` and `xor` methods called without argument(s) don't provide a policy object. They return lazy composer, expecting `#not` method.
|
@@ -294,6 +299,15 @@ Policy.not(valid_policy)
|
|
294
299
|
|
295
300
|
As before, you can use any number of policies (except for negation of a single policy) at any number of nesting.
|
296
301
|
|
302
|
+
Latest changes
|
303
|
+
--------------
|
304
|
+
|
305
|
+
### Version 2.0.0
|
306
|
+
|
307
|
+
1. The method `#validate` doesn't raise an error. It returns a validation results report. To raise an exception use the unsafe `#validate!` method (see [Basic Use](#basic-use) for details).
|
308
|
+
|
309
|
+
2. Policies doesn't have `#valid?` and `#invalid?` methods any longer. Both the methods are removed to `#validate` report.
|
310
|
+
|
297
311
|
Compatibility
|
298
312
|
-------------
|
299
313
|
|
data/config/metrics/rubocop.yml
CHANGED
@@ -2,20 +2,9 @@
|
|
2
2
|
|
3
3
|
module Attestor
|
4
4
|
|
5
|
-
# The exception to be raised when
|
5
|
+
# The exception to be raised when an unsafe validation fails
|
6
6
|
class InvalidError < RuntimeError
|
7
7
|
|
8
|
-
# @!scope class
|
9
|
-
# @!method new(object, messages = nil)
|
10
|
-
# Creates an exception for given object
|
11
|
-
#
|
12
|
-
# @param [Object] object
|
13
|
-
# The invalid object
|
14
|
-
# @param [String, Array<String>] messages
|
15
|
-
# The list of validation error messages
|
16
|
-
#
|
17
|
-
# @return [Attestor::InvalidError]
|
18
|
-
|
19
8
|
# @private
|
20
9
|
def initialize(object, messages = nil)
|
21
10
|
@object = object
|
data/lib/attestor/policy/and.rb
CHANGED
@@ -4,27 +4,10 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# The policy is valid if all its branches are valid.
|
10
|
-
#
|
11
|
-
# @example (see #validate)
|
12
|
-
#
|
13
|
-
# @api private
|
7
|
+
# @private
|
14
8
|
class And < Node
|
15
9
|
|
16
|
-
|
17
|
-
#
|
18
|
-
# @example
|
19
|
-
# first.valid? # => true
|
20
|
-
# second.valid? # => false
|
21
|
-
#
|
22
|
-
# composition = Attestor::Policy::And.new(first, second)
|
23
|
-
# composition.validate
|
24
|
-
# # => Policy::InvalidError
|
25
|
-
#
|
26
|
-
# @return [undefined]
|
27
|
-
def validate
|
10
|
+
def validate!
|
28
11
|
return unless detect(&:invalid?)
|
29
12
|
super
|
30
13
|
end
|
@@ -4,47 +4,20 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# @api private
|
7
|
+
# @private
|
10
8
|
class Negator
|
11
9
|
|
12
|
-
# @!scope class
|
13
|
-
# @!method new(policy, composer)
|
14
|
-
# Creates the negator object, expecting {#not} method call
|
15
|
-
#
|
16
|
-
# @param [Policy::Base] policy
|
17
|
-
# the policy to be composed with negations of other policies
|
18
|
-
# @param [Class] composer
|
19
|
-
# the composer for policies
|
20
|
-
#
|
21
|
-
# @return [Policy::Base::Negator]
|
22
10
|
def initialize(composer, policy)
|
23
11
|
@policy = policy
|
24
12
|
@composer = composer
|
25
13
|
freeze
|
26
14
|
end
|
27
15
|
|
28
|
-
# Returns a composition of the {#policy} with negations of other policies
|
29
|
-
#
|
30
|
-
# @param [Policy::Base, Array<Policy::Base>] policies
|
31
|
-
#
|
32
|
-
# @return [Policy::Base]
|
33
16
|
def not(*policies)
|
34
17
|
composer.new policy, policies.flat_map(&Not.method(:new))
|
35
18
|
end
|
36
19
|
|
37
|
-
|
38
|
-
# The the policy to be composed with negations of other policies
|
39
|
-
#
|
40
|
-
# @return [Policy::Base]
|
41
|
-
attr_reader :policy
|
42
|
-
|
43
|
-
# @!attribute [r] composer
|
44
|
-
# The the composer for policies
|
45
|
-
#
|
46
|
-
# @return [Class]
|
47
|
-
attr_reader :composer
|
20
|
+
attr_reader :policy, :composer
|
48
21
|
|
49
22
|
end # class Negator
|
50
23
|
|
data/lib/attestor/policy/node.rb
CHANGED
@@ -4,49 +4,23 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# @api private
|
7
|
+
# @private
|
10
8
|
class Node
|
11
|
-
include Attestor::Policy
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
# @!method new(*branches)
|
16
|
-
# Creates the node with branches
|
17
|
-
#
|
18
|
-
# @param [<Attestor::Policy>, Array<Attestor::Policy>] branches
|
19
|
-
#
|
20
|
-
# @return [Policy::Base::Node]
|
21
|
-
|
22
|
-
# @private
|
9
|
+
include Attestor::Policy, Enumerable
|
10
|
+
|
11
|
+
attr_reader :branches
|
12
|
+
|
23
13
|
def initialize(*branches)
|
24
14
|
@branches = branches.flatten
|
25
15
|
freeze
|
26
16
|
end
|
27
17
|
|
28
|
-
|
29
|
-
# The branches of the node
|
30
|
-
#
|
31
|
-
# @return [Array<Policy::Base>]
|
32
|
-
attr_reader :branches
|
33
|
-
|
34
|
-
# Validates the policy as invalid
|
35
|
-
#
|
36
|
-
# To be reloaded by subclasses (And, Or, Xor, Not)
|
37
|
-
#
|
38
|
-
# @raise [Policy::InvalidError]
|
39
|
-
#
|
40
|
-
# @return [undefined]
|
41
|
-
def validate
|
18
|
+
def validate!
|
42
19
|
invalid :base
|
43
20
|
end
|
44
21
|
|
45
|
-
# Iterates throught branches
|
46
|
-
#
|
47
|
-
# @return [Enumerator]
|
48
22
|
def each
|
49
|
-
block_given? ? branches.each { |item| yield(item) } : to_enum
|
23
|
+
block_given? ? branches.each { |item| yield(item.validate) } : to_enum
|
50
24
|
end
|
51
25
|
|
52
26
|
end # class Node
|
data/lib/attestor/policy/not.rb
CHANGED
@@ -4,39 +4,14 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# The policy is valid if its only branch is invalid
|
10
|
-
#
|
11
|
-
# @example (see #validate)
|
12
|
-
#
|
13
|
-
# @api private
|
7
|
+
# @private
|
14
8
|
class Not < Node
|
15
9
|
|
16
|
-
# @!scope class
|
17
|
-
# @!method new(policy)
|
18
|
-
# Creates the policy negation
|
19
|
-
#
|
20
|
-
# @param [Array<Policy::Base>] policy
|
21
|
-
#
|
22
|
-
# @return [Policy::Base::Node]
|
23
|
-
|
24
|
-
# @private
|
25
10
|
def initialize(_)
|
26
11
|
super
|
27
12
|
end
|
28
13
|
|
29
|
-
|
30
|
-
#
|
31
|
-
# @example
|
32
|
-
# policy.valid? # => true
|
33
|
-
#
|
34
|
-
# composition = Attestor::Policy::Not.new(policy)
|
35
|
-
# composition.validate
|
36
|
-
# # => Policy::InvalidError
|
37
|
-
#
|
38
|
-
# @return [undefined]
|
39
|
-
def validate
|
14
|
+
def validate!
|
40
15
|
return unless detect(&:valid?)
|
41
16
|
super
|
42
17
|
end
|
data/lib/attestor/policy/or.rb
CHANGED
@@ -4,27 +4,10 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# The policy is valid unless all its branches are invalid.
|
10
|
-
#
|
11
|
-
# @example (see #validate)
|
12
|
-
#
|
13
|
-
# @api private
|
7
|
+
# @private
|
14
8
|
class Or < Node
|
15
9
|
|
16
|
-
|
17
|
-
#
|
18
|
-
# @example
|
19
|
-
# first.valid? # => false
|
20
|
-
# second.valid? # => false
|
21
|
-
#
|
22
|
-
# composition = Attestor::Policy::Or.new(first, second)
|
23
|
-
# composition.validate
|
24
|
-
# # => Policy::InvalidError
|
25
|
-
#
|
26
|
-
# @return [undefined]
|
27
|
-
def validate
|
10
|
+
def validate!
|
28
11
|
return if detect(&:valid?)
|
29
12
|
super
|
30
13
|
end
|
data/lib/attestor/policy/xor.rb
CHANGED
@@ -4,27 +4,10 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Policy
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# The policy is valid when it has both valid and invalid branches.
|
10
|
-
#
|
11
|
-
# @example (see #validate)
|
12
|
-
#
|
13
|
-
# @api private
|
7
|
+
# @private
|
14
8
|
class Xor < Node
|
15
9
|
|
16
|
-
|
17
|
-
#
|
18
|
-
# @example
|
19
|
-
# first.valid? # => true
|
20
|
-
# second.valid? # => true
|
21
|
-
#
|
22
|
-
# composition = Attestor::Policy::Xor.new(first, second)
|
23
|
-
# composition.validate
|
24
|
-
# # => Policy::InvalidError
|
25
|
-
#
|
26
|
-
# @return [undefined]
|
27
|
-
def validate
|
10
|
+
def validate!
|
28
11
|
return if detect(&:valid?) && detect(&:invalid?)
|
29
12
|
super
|
30
13
|
end
|
data/lib/attestor/policy.rb
CHANGED
@@ -36,24 +36,6 @@ module Attestor
|
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
39
|
-
# Checks whether the policy is valid
|
40
|
-
#
|
41
|
-
# @return [Boolean]
|
42
|
-
def valid?
|
43
|
-
validate
|
44
|
-
rescue InvalidError
|
45
|
-
false
|
46
|
-
else
|
47
|
-
true
|
48
|
-
end
|
49
|
-
|
50
|
-
# Checks whether the policy is invalid
|
51
|
-
#
|
52
|
-
# @return [Boolean]
|
53
|
-
def invalid?
|
54
|
-
!valid?
|
55
|
-
end
|
56
|
-
|
57
39
|
# Negates the current policy
|
58
40
|
#
|
59
41
|
# @return [Attestor::Policy::Not]
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Attestor
|
4
|
+
|
5
|
+
# Describes the result, returned by safe validation
|
6
|
+
class Report
|
7
|
+
|
8
|
+
# @private
|
9
|
+
def initialize(object, error = nil)
|
10
|
+
@object = object
|
11
|
+
@error = error
|
12
|
+
freeze
|
13
|
+
end
|
14
|
+
|
15
|
+
# @!attribute [r] object
|
16
|
+
# The object being validated
|
17
|
+
#
|
18
|
+
# @return [Object]
|
19
|
+
attr_reader :object
|
20
|
+
|
21
|
+
# @!attribute [r] error
|
22
|
+
# The exception raised by validation
|
23
|
+
#
|
24
|
+
# @return [Attestor::InvalidError] if validation fails
|
25
|
+
# @return [nil] if validation passes
|
26
|
+
attr_reader :error
|
27
|
+
|
28
|
+
# Checks whether validation passes
|
29
|
+
#
|
30
|
+
# @return [Boolean]
|
31
|
+
def valid?
|
32
|
+
error.blank?
|
33
|
+
end
|
34
|
+
|
35
|
+
# Checks whether validation fails
|
36
|
+
#
|
37
|
+
# @return [Boolean]
|
38
|
+
def invalid?
|
39
|
+
!valid?
|
40
|
+
end
|
41
|
+
|
42
|
+
# Returns the list of error messages
|
43
|
+
#
|
44
|
+
# @return [Array<String>]
|
45
|
+
def messages
|
46
|
+
error ? error.messages : []
|
47
|
+
end
|
48
|
+
|
49
|
+
end # class Report
|
50
|
+
|
51
|
+
end # module Attestor
|
@@ -4,26 +4,11 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Validations
|
6
6
|
|
7
|
-
#
|
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
|
7
|
+
# @private
|
16
8
|
class Delegator < Validator
|
17
9
|
|
18
|
-
|
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
|
10
|
+
def validate!(_)
|
11
|
+
super.validate!
|
27
12
|
end
|
28
13
|
|
29
14
|
end # class Follower
|
@@ -4,24 +4,9 @@ module Attestor
|
|
4
4
|
|
5
5
|
module Validations
|
6
6
|
|
7
|
-
#
|
8
|
-
#
|
9
|
-
# @api private
|
7
|
+
# @private
|
10
8
|
class Message < String
|
11
9
|
|
12
|
-
# @!scope class
|
13
|
-
# @!method new(value, object, options = {})
|
14
|
-
# Builds a string from value
|
15
|
-
#
|
16
|
-
# @param [#to_s] value
|
17
|
-
# @param [Object] object
|
18
|
-
# @param [Hash] options
|
19
|
-
# options for translating symbolic value
|
20
|
-
#
|
21
|
-
# @return [String]
|
22
|
-
# either translation of symbolic value or stringified value argument
|
23
|
-
|
24
|
-
# @private
|
25
10
|
def initialize(value, object, options = {})
|
26
11
|
@value = value
|
27
12
|
@object = object
|