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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4755994f9e2305a2cd5ee6e243fc47fe5f5b404
4
- data.tar.gz: 149e89d4ed18c39bf51df1d75933b5e06fe4c5f0
3
+ metadata.gz: 7889c90de0f2f5e7a65ac09a622200903219fecf
4
+ data.tar.gz: da24f1d17b8705a96f505e28063b44d38051c222
5
5
  SHA512:
6
- metadata.gz: 0daa45d47fef84269ac1f27a62f985ab6c585cef0c73d2be5de736a3ecfb9357f2632b1557f28dfdfd93caf75b222bc9a032e2370154d2c20ae1026a941d853f
7
- data.tar.gz: 0107fd28176f7b61ff7c6240eac3ab2c6b781c1ccbda0091507f0d6b8190ebc04fe0fee7bf8e63aadfed30f17c2f454b4865b05dbede51fac771387791d9023c
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(:consistent) { invalid :inconsistent if credit.sum != debet.sum }
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
- Policy Objects
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
- To create a policy as a `Struct` use the builder method:
167
+ Extract validator to the external object (policy), that responds to `validate`.
170
168
 
171
169
  ```ruby
172
- ConsistencyPolicy = Attestor::Policy.new(:debet, :credit) do
170
+ class ConsistentTransfer.new(:debet, :credit)
171
+ include Attestor::Validations
172
+
173
173
  def validate
174
- fraud = credit - debet
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
- This looks mainly the same as before. But the policy's debet and credit are numbers, not the transactions. **The policy knows nothing about the nature of its attributes** - whether they are sums of transactions, or anything else.
179
+ Then use `validates` helper:
181
180
 
182
- This is the core part of the [Policy Object design pattern] - it isolates the rule from unsignificant details of the target.
181
+ ```ruby
182
+ class Transfer
183
+ # ...
184
+ validates { ConsistentTransfer.new(:debet, :credit) }
185
+ end
186
+ ```
183
187
 
184
- When you have a policy to follow, use the `follow_policy` method:
188
+ or by method name:
185
189
 
186
190
  ```ruby
187
- class Transfer < Struct.new(:debet, :credit)
188
- include Attestor::Validations
191
+ class Transfer
192
+ # ...
193
+ validates :consistent_transfer
189
194
 
190
- follow_policy :consistency, only: :fair_trade
195
+ def consistent_transfer
196
+ ConsistentTransfer.new(:debet, :credit)
197
+ end
198
+ ```
191
199
 
192
- private
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
- def consistency # should respond to #valid? and #invalid?
195
- ConsistencyPolicy.new(debet.sum, credit.sum)
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
- In case the policy object is invalid, validation raises an exception.
220
+ If you doesn't need Struct, include `Attestor::Policy` to the class and initialize its arguments somehow else:
201
221
 
202
- The name of the method (`consistency`) will be used for the error message:
203
-
204
- ```yaml
205
- # config/locales/en.yml
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
- Alternatively, you can describe a policy in the block (called in the scope of instance):
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
- follow_policy :consistency, only: :fair_trade do
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
- Now that policies are isolated from their targets, we can provide complex policies from simpler ones.
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"
@@ -31,7 +31,7 @@ module Attestor
31
31
  # @return [Class] the policy class, based on Struct
32
32
  def self.new(*attributes, &block)
33
33
  Struct.new(*attributes) do
34
- include Attestor::Policy
34
+ include Policy
35
35
  instance_eval(&block) if block_given?
36
36
  end
37
37
  end
@@ -25,7 +25,7 @@ module Attestor
25
25
  #
26
26
  # @return [undefined]
27
27
  def validate
28
- return unless any_invalid?
28
+ return unless detect(&:invalid?)
29
29
  super
30
30
  end
31
31
 
@@ -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
- private
45
-
46
- def any_valid?
47
- branches.detect(&:valid?)
48
- end
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
@@ -37,7 +37,7 @@ module Attestor
37
37
  #
38
38
  # @return [undefined]
39
39
  def validate
40
- return unless any_valid?
40
+ return unless detect(&:valid?)
41
41
  super
42
42
  end
43
43
 
@@ -25,7 +25,7 @@ module Attestor
25
25
  #
26
26
  # @return [undefined]
27
27
  def validate
28
- return if any_valid?
28
+ return if detect(&:valid?)
29
29
  super
30
30
  end
31
31
 
@@ -25,7 +25,7 @@ module Attestor
25
25
  #
26
26
  # @return [undefined]
27
27
  def validate
28
- return if any_valid? && any_invalid?
28
+ return if detect(&:valid?) && detect(&:invalid?)
29
29
  super
30
30
  end
31
31
 
@@ -51,21 +51,53 @@ module Attestor
51
51
  @validators ||= Validators.new
52
52
  end
53
53
 
54
- # @!method follow_validator(name, except: nil, only: nil)
55
- # Registers a validator
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
- # @return [Attestor::Validators] the updated collection
67
- def validate(*args)
68
- @validators = validators.add_validator(*args)
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
- (validators == items) ? self : self.class.new(validators)
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 follower with given args
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
 
@@ -4,6 +4,6 @@ module Attestor
4
4
 
5
5
  # The semantic version of the module.
6
6
  # @see http://semver.org/ Semantic versioning 2.0
7
- VERSION = "0.3.0".freeze
7
+ VERSION = "0.4.0".freeze
8
8
 
9
9
  end # module Attestor
@@ -53,16 +53,14 @@ describe "Base example" do
53
53
  class Transfer
54
54
  include Attestor::Validations
55
55
 
56
- follow_policy :consistent
57
- follow_policy :limited, except: :blocked
58
- follow_policy :internal, only: :blocked
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
@@ -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
@@ -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
- it "is a factory" do
16
- expect(test_class).to be_kind_of factory
17
- end
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
- let(:build) { described_class.new(:foo) { attr_reader :bar } }
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
- expect(subject).to respond_to :bar
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) { double foo: nil }
158
- after { subject.validate object }
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(:follower_class) { Attestor::Validations::Follower }
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 "without contexts" do
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 follower)" do
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 follower_class
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).map(&:name))
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 contexts" do
62
+ context "with a block" do
64
63
 
65
- let(:result) { subject.add_validator "foo", only: [:foo] }
64
+ let(:result) { subject.add_validator { foo } }
66
65
 
67
- it "adds item to validators" do
68
- expect(result.map(&:name)).to eq [:foo]
69
- expect(result.set(:foo).map(&:name)).to eq [:foo]
70
- expect(result.set(:all).map(&:name)).to eq []
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 "existing validator" do
78
+ context "with contexts" do
76
79
 
77
- subject { described_class.new.add_validator "foo" }
80
+ let(:result) { subject.add_validator "foo", only: [:foo] }
78
81
 
79
- it "returns itself" do
80
- expect(subject.add_validator "foo").to eq subject
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 "#add_follower" do
92
+ describe "#add_delegator" do
88
93
 
89
- context "without contexts" do
94
+ context "with a name" do
90
95
 
91
- let(:result) { subject.add_follower "foo" }
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 follower" do
102
+ it "adds a delegator" do
98
103
  item = result.first
99
- expect(item).to be_kind_of follower_class
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.add_follower(:bar).map(&:name))
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 contexts" do
118
+ context "with a block" do
115
119
 
116
- let(:result) { subject.add_follower "foo", only: [:foo] }
120
+ let(:result) { subject.add_delegator { foo } }
117
121
 
118
- it "adds item to validators" do
119
- expect(result.map(&:name)).to eq [:foo]
120
- expect(result.set(:foo).map(&:name)).to eq [:foo]
121
- expect(result.set(:all).map(&:name)).to eq []
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 "existing validator" do
133
+ context "with contexts" do
127
134
 
128
- subject { described_class.new.add_follower "foo" }
135
+ let(:result) { subject.add_delegator "foo", only: [:foo] }
129
136
 
130
- it "returns itself" do
131
- expect(subject.add_follower "foo").to eq subject
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 #add_follower
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", only: %w(cad cam))
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(:follower_class) { Attestor::Validations::Follower }
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 { Test = test_class }
17
- after { Object.send :remove_const, :Test }
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 follower_class
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 ".follow_policy" do
59
+ describe ".validates" do
61
60
 
62
61
  context "without options" do
63
62
 
64
- before { test_class.follow_policy :foo }
63
+ before { test_class.validates :foo }
65
64
 
66
- it "registers a follower" do
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 follower_class
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.follow_policy :foo, only: %w(bar baz), except: "bar" }
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 .follow_policy
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 :foo
130
- test_class.validate :bar, only: :all
131
- test_class.follow_policy :baz, only: :foo
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.3.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/follower_spec.rb
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