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 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