attestor 0.2.0 → 0.3.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: dbf1e027054a7c3baeeaa39f6e66f515e1b3fa2e
4
- data.tar.gz: 546765bd0a8dfee528fa5ed45f3fe7a3b07047cf
3
+ metadata.gz: b4755994f9e2305a2cd5ee6e243fc47fe5f5b404
4
+ data.tar.gz: 149e89d4ed18c39bf51df1d75933b5e06fe4c5f0
5
5
  SHA512:
6
- metadata.gz: bfa470608fa7882248c256abd5e594a7ed4d50cef97fbc230425a89703b1cd6c652586b57a760a76b78b9611a76ad41f0f58eb2573e2e3f50c88f2aabfd903df
7
- data.tar.gz: 5694b759f83f0b281fc102753dce9537512510157e79a22941fd312d5ed141b7e62e7b1b6072d54035b43995e735b74ce746109acc43c9c5a6197b4553d2ea3c
6
+ metadata.gz: 0daa45d47fef84269ac1f27a62f985ab6c585cef0c73d2be5de736a3ecfb9357f2632b1557f28dfdfd93caf75b222bc9a032e2370154d2c20ae1026a941d853f
7
+ data.tar.gz: 0107fd28176f7b61ff7c6240eac3ab2c6b781c1ccbda0091507f0d6b8190ebc04fe0fee7bf8e63aadfed30f17c2f454b4865b05dbede51fac771387791d9023c
data/README.md CHANGED
@@ -101,6 +101,15 @@ en:
101
101
  inconsistent: "Credit differs from debet by %{fraud}"
102
102
  ```
103
103
 
104
+ Alternatively, you can describe validation in the block (called in the scope of instance):
105
+
106
+ ```ruby
107
+ class Transfer
108
+ # ...
109
+ validate(:consistent) { invalid :inconsistent if credit.sum != debet.sum }
110
+ end
111
+ ```
112
+
104
113
  To run validations use the `#validate` instance method:
105
114
 
106
115
  ```ruby
@@ -202,6 +211,17 @@ en:
202
211
  consistency: "The transfer is inconsistent"
203
212
  ```
204
213
 
214
+ Alternatively, you can describe a policy in the block (called in the scope of instance):
215
+
216
+ ```ruby
217
+ class Transfer
218
+ # ...
219
+ follow_policy :consistency, only: :fair_trade do
220
+ ConsistencyPolicy.new(debet.sum, credit.sum)
221
+ end
222
+ end
223
+ ```
224
+
205
225
  Complex Policies
206
226
  ----------------
207
227
 
@@ -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/follower"
11
12
  require_relative "attestor/validations/validators"
12
13
  require_relative "attestor/validations/message"
13
14
 
@@ -6,24 +6,20 @@ module Attestor
6
6
  class InvalidError < RuntimeError
7
7
 
8
8
  # @!scope class
9
- # @!method new(object, validations: nil, messages: [], context: :all)
9
+ # @!method new(object, messages = nil)
10
10
  # Creates an exception for given object
11
11
  #
12
12
  # @param [Object] object
13
13
  # The invalid object
14
- # @option [Array<String>] :messages
14
+ # @param [String, Array<String>] messages
15
15
  # The list of validation error messages
16
- # @option [Symbol] :context
17
- # The list of context for validation
18
- # @option [Array<Symbol>] :validations
19
- # The list of all validations that was checked out
20
16
  #
21
17
  # @return [Attestor::InvalidError]
22
18
 
23
19
  # @private
24
- def initialize(object, messages = [])
20
+ def initialize(object, messages = nil)
25
21
  @object = object
26
- @messages = messages.dup.freeze
22
+ @messages = Array(messages)
27
23
  freeze
28
24
  end
29
25
 
@@ -16,20 +16,19 @@ module Attestor
16
16
  end
17
17
  end
18
18
 
19
- # Builds the policy class
19
+ # Builds a policy class with given attributes
20
20
  #
21
21
  # @example
22
22
  # MyPolicy = Attestor::Policy.new(:foo, :bar) do
23
23
  # attr_reader :baz
24
24
  # end
25
25
  #
26
- # @attribute [Array<#to_sym>] attributes
27
- # the list of attributes
28
- # @attribute [Proc] block
26
+ # @param [Array<#to_sym>] attributes
27
+ # @param [Proc] block
29
28
  #
30
29
  # @yield the block in the scope of created class
31
30
  #
32
- # @return [Class]
31
+ # @return [Class] the policy class, based on Struct
33
32
  def self.new(*attributes, &block)
34
33
  Struct.new(*attributes) do
35
34
  include Attestor::Policy
@@ -36,7 +36,7 @@ module Attestor
36
36
  # the name converted to string
37
37
  def invalid(name, options = {})
38
38
  message = Message.new(name, self, options)
39
- fail InvalidError.new self, [message]
39
+ fail InvalidError.new self, message
40
40
  end
41
41
 
42
42
  # @private
@@ -51,6 +51,7 @@ module Attestor
51
51
  @validators ||= Validators.new
52
52
  end
53
53
 
54
+ # @!method follow_validator(name, except: nil, only: nil)
54
55
  # Registers a validator
55
56
  #
56
57
  # Mutates the class by changing its {#validators} attribute!
@@ -63,24 +64,24 @@ module Attestor
63
64
  # the white list of contexts for validation
64
65
  #
65
66
  # @return [Attestor::Validators] the updated collection
66
- def validate(name, options = {})
67
- @validators = validators.add(name, options)
67
+ def validate(*args)
68
+ @validators = validators.add_validator(*args)
68
69
  end
69
70
 
71
+ # @!method follow_policy(name, except: nil, only: nil)
70
72
  # Registers a followed policy
71
73
  #
72
74
  # Mutates the class by changing its {#validators} attribute!
73
75
  #
74
76
  # @param [#to_sym] name
75
- # @param [Hash] options
76
- # @option options [#to_sym, Array<#to_sym>] :except
77
+ # @option [#to_sym, Array<#to_sym>] :except
77
78
  # the black list of contexts for validation
78
- # @option options [#to_sym, Array<#to_sym>] :only
79
+ # @option [#to_sym, Array<#to_sym>] :only
79
80
  # the white list of contexts for validation
80
81
  #
81
82
  # @return [Attestor::Collection] the updated collection
82
- def follow_policy(name, options = {})
83
- @validators = validators.add(name, options.merge(policy: true))
83
+ def follow_policy(*args)
84
+ @validators = validators.add_follower(*args)
84
85
  end
85
86
 
86
87
  end # module ClassMethods
@@ -0,0 +1,35 @@
1
+ # encoding: utf-8
2
+
3
+ module Attestor
4
+
5
+ module Validations
6
+
7
+ # Describe a policy follower for class instances
8
+ #
9
+ # The follower not only calls an instance method (as validator does),
10
+ # but checks whether the result is valid and raises an exception otherwise.
11
+ #
12
+ # @example
13
+ # follower = Validator.new(:foo, only: :baz) { FooPolicy.new(foo) }
14
+ #
15
+ # @api private
16
+ class Follower < Validator
17
+
18
+ # Validates a policy
19
+ #
20
+ # @param [Object] object
21
+ #
22
+ # @raise [Attestor::InvalidError] if a policy isn't valid
23
+ #
24
+ # @return [undefined]
25
+ def validate(object)
26
+ policy = super(object)
27
+ return if policy.valid?
28
+ object.__send__ :invalid, name
29
+ end
30
+
31
+ end # class Follower
32
+
33
+ end # module Validations
34
+
35
+ end # module Attestor
@@ -7,7 +7,7 @@ module Attestor
7
7
  # Describe a validator for class instances
8
8
  #
9
9
  # @example
10
- # validator = Validator.new(:foo, policy: :bar, only: :baz)
10
+ # validator = Validator.new(:foo, only: :baz)
11
11
  #
12
12
  # validator.used_in_context? :baz # => true
13
13
  # validator.validate object
@@ -26,11 +26,11 @@ module Attestor
26
26
  # @return [Attestor::Validations::Validator]
27
27
 
28
28
  # @private
29
- def initialize(name, except: nil, only: nil, policy: nil)
29
+ def initialize(name, except: nil, only: nil, &block)
30
30
  @name = name.to_sym
31
- @policy = policy
32
31
  @whitelist = normalize(only)
33
32
  @blacklist = normalize(except)
33
+ @block = block
34
34
  generate_id
35
35
  freeze
36
36
  end
@@ -41,14 +41,6 @@ module Attestor
41
41
  # @return [Symbol]
42
42
  attr_reader :name
43
43
 
44
- # @!method policy?
45
- # Whether the validator uses a policy
46
- #
47
- # @return [Boolean]
48
- def policy?
49
- @policy ? true : false
50
- end
51
-
52
44
  # Compares an item to another one
53
45
  #
54
46
  # @param [Object] other
@@ -77,8 +69,7 @@ module Attestor
77
69
  #
78
70
  # @return [undefined]
79
71
  def validate(object)
80
- result = object.__send__(name)
81
- object.__send__(:invalid, name) if policy? && result.invalid?
72
+ block ? object.instance_eval(&block) : object.__send__(name)
82
73
  end
83
74
 
84
75
  protected
@@ -91,7 +82,7 @@ module Attestor
91
82
 
92
83
  private
93
84
 
94
- attr_reader :whitelist, :blacklist
85
+ attr_reader :whitelist, :blacklist, :block
95
86
 
96
87
  def whitelisted?(symbol)
97
88
  whitelist.empty? || whitelist.include?(symbol)
@@ -19,8 +19,8 @@ module Attestor
19
19
  # @return [Attestor::Validators]
20
20
 
21
21
  # @private
22
- def initialize(items = [])
23
- @items = items
22
+ def initialize(*items)
23
+ @items = items.flatten
24
24
  freeze
25
25
  end
26
26
 
@@ -32,40 +32,46 @@ module Attestor
32
32
  #
33
33
  # @return [Enumerator]
34
34
  def each
35
- block_given? ? @items.each { |item| yield(item) } : to_enum
35
+ block_given? ? items.each { |item| yield(item) } : to_enum
36
36
  end
37
37
 
38
- # Returns validators updated by new item
38
+ # Returns validators used in given context
39
39
  #
40
- # @param [#to_sym] name
41
- # @param [Hash] options
42
- # @option options [Array<#to_sym>] :except
43
- # @option options [Array<#to_sym>] :only
44
- # @option options [Symbol, nil] :policy
40
+ # @param [#to_sym] context
45
41
  #
46
42
  # @return [Attestor::Validators]
47
- def add(name, options = {})
48
- item = Validator.new(name, options)
49
- return self if include? item
50
-
51
- self.class.new(@items + [item])
43
+ def set(context)
44
+ validators = select { |item| item.used_in_context? context }
45
+ (validators == items) ? self : self.class.new(validators)
52
46
  end
53
47
 
54
- # Returns validators used in given context
48
+ # Returns validators updated by a new validator with given args
55
49
  #
56
- # @param [#to_sym] context
50
+ # @param [Array] args
57
51
  #
58
52
  # @return [Attestor::Validators]
59
- def set(context)
60
- validators = select { |item| item.used_in_context? context }
53
+ def add_validator(*args)
54
+ add_item Validator, *args
55
+ end
61
56
 
62
- self.class.new(validators)
57
+ # Returns validators updated by a new follower with given args
58
+ #
59
+ # @param [Array] args
60
+ #
61
+ # @return [Attestor::Validators]
62
+ def add_follower(*args)
63
+ add_item Follower, *args
63
64
  end
64
65
 
65
66
  private
66
67
 
67
68
  attr_reader :items
68
69
 
70
+ def add_item(type, *args)
71
+ item = type.new(*args)
72
+ include?(item) ? self : self.class.new(items, item)
73
+ end
74
+
69
75
  end # class Validators
70
76
 
71
77
  end # module Validations
@@ -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.2.0".freeze
7
+ VERSION = "0.3.0".freeze
8
8
 
9
9
  end # module Attestor
@@ -48,10 +48,6 @@ describe Attestor::InvalidError do
48
48
  expect(subject.messages).to eq %w(cad cam)
49
49
  end
50
50
 
51
- it "is immutable" do
52
- expect(subject.messages).to be_frozen
53
- end
54
-
55
51
  end # describe #messages
56
52
 
57
53
  end # describe Attestor::ValidError
@@ -0,0 +1,44 @@
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
@@ -38,10 +38,6 @@ describe Attestor::Validations::Validator do
38
38
  .to eq(described_class.new "foo", only: %i(bar))
39
39
  end
40
40
 
41
- it "accepts array option :policy" do
42
- expect { described_class.new "foo", policy: :bar }.not_to raise_error
43
- end
44
-
45
41
  end # describe .new
46
42
 
47
43
  describe "#name" do
@@ -52,19 +48,6 @@ describe Attestor::Validations::Validator do
52
48
 
53
49
  end # describe .name
54
50
 
55
- describe "#policy?" do
56
-
57
- it "is set to false by default" do
58
- expect(subject.policy?).to eq false
59
- end
60
-
61
- it "can be initialized" do
62
- subject = described_class.new "foo", policy: 1
63
- expect(subject.policy?).to eq true
64
- end
65
-
66
- end # describe #policy?
67
-
68
51
  describe "#==" do
69
52
 
70
53
  subject { described_class.new :foo, except: [:foo], only: %i(bar) }
@@ -171,11 +154,11 @@ describe Attestor::Validations::Validator do
171
154
 
172
155
  describe "#validate" do
173
156
 
157
+ let(:object) { double foo: nil }
174
158
  after { subject.validate object }
175
159
 
176
- context "when a #policy isn't set" do
160
+ context "when no block initialized" do
177
161
 
178
- let(:object) { double foo: nil }
179
162
  subject { described_class.new :foo }
180
163
 
181
164
  it "calls validation method" do
@@ -184,32 +167,12 @@ describe Attestor::Validations::Validator do
184
167
 
185
168
  end # context
186
169
 
187
- context "when a #policy is set to valid policy" do
170
+ context "when block initialized" do
188
171
 
189
- let(:object) { double foo: valid_policy }
190
- subject { described_class.new :foo, policy: true }
191
-
192
- it "calls policy method" do
193
- expect(object).to receive(:foo)
194
- end
172
+ subject { described_class.new(:baz) { foo } }
195
173
 
196
- it "doesn't call #invalid" do
197
- expect(object).not_to receive(:invalid)
198
- end
199
-
200
- end # context
201
-
202
- context "when a #policy is set to valid policy" do
203
-
204
- let(:object) { double foo: invalid_policy, invalid: nil }
205
- subject { described_class.new :foo, policy: true }
206
-
207
- it "calls policy method" do
208
- expect(object).to receive(:foo)
209
- end
210
-
211
- it "calls #invalid with name" do
212
- expect(object).to receive(:invalid).with(:foo)
174
+ it "calls a block" do
175
+ expect(object).to receive :foo
213
176
  end
214
177
 
215
178
  end # context
@@ -3,6 +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
7
 
7
8
  describe ".new" do
8
9
 
@@ -31,30 +32,88 @@ describe Attestor::Validations::Validators do
31
32
 
32
33
  end # describe #each
33
34
 
34
- describe "#add" do
35
+ describe "#add_validator" do
35
36
 
36
- context "without options" do
37
+ context "without contexts" do
37
38
 
38
- let(:result) { subject.add("foo") }
39
+ let(:result) { subject.add_validator "foo" }
39
40
 
40
41
  it "returns validators" do
41
42
  expect(result).to be_kind_of described_class
42
43
  end
43
44
 
45
+ it "adds validator (not a follower)" do
46
+ item = result.first
47
+ expect(item).to be_kind_of validator_class
48
+ expect(item).not_to be_kind_of follower_class
49
+ end
50
+
51
+ it "assigns a name" do
52
+ item = result.first
53
+ expect(item.name).to eq :foo
54
+ end
55
+
56
+ it "preserves existing items" do
57
+ expect(result.add_validator(:bar).map(&:name))
58
+ .to contain_exactly :foo, :bar
59
+ end
60
+
61
+ end # context
62
+
63
+ context "with contexts" do
64
+
65
+ let(:result) { subject.add_validator "foo", only: [:foo] }
66
+
44
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 []
71
+ end
72
+
73
+ end # context
74
+
75
+ context "existing validator" do
76
+
77
+ subject { described_class.new.add_validator "foo" }
78
+
79
+ it "returns itself" do
80
+ expect(subject.add_validator "foo").to eq subject
81
+ end
82
+
83
+ end # context
84
+
85
+ end # describe #add_validator
86
+
87
+ describe "#add_follower" do
88
+
89
+ context "without contexts" do
90
+
91
+ let(:result) { subject.add_follower "foo" }
92
+
93
+ it "returns validators" do
94
+ expect(result).to be_kind_of described_class
95
+ end
96
+
97
+ it "adds a follower" do
98
+ item = result.first
99
+ expect(item).to be_kind_of follower_class
100
+ end
101
+
102
+ it "assigns a name" do
45
103
  item = result.first
46
104
  expect(item.name).to eq :foo
47
105
  end
48
106
 
49
107
  it "preserves existing items" do
50
- expect(result.add(:bar).map(&:name)).to contain_exactly :foo, :bar
108
+ expect(result.add_follower(:bar).map(&:name))
109
+ .to contain_exactly :foo, :bar
51
110
  end
52
111
 
53
112
  end # context
54
113
 
55
- context "with options" do
114
+ context "with contexts" do
56
115
 
57
- let(:result) { subject.add "foo", only: [:foo] }
116
+ let(:result) { subject.add_follower "foo", only: [:foo] }
58
117
 
59
118
  it "adds item to validators" do
60
119
  expect(result.map(&:name)).to eq [:foo]
@@ -66,23 +125,23 @@ describe Attestor::Validations::Validators do
66
125
 
67
126
  context "existing validator" do
68
127
 
69
- subject { described_class.new.add "foo" }
128
+ subject { described_class.new.add_follower "foo" }
70
129
 
71
130
  it "returns itself" do
72
- expect(subject.add "foo").to eq subject
131
+ expect(subject.add_follower "foo").to eq subject
73
132
  end
74
133
 
75
134
  end # context
76
135
 
77
- end # describe #add
136
+ end # describe #add_follower
78
137
 
79
- describe "#context" do
138
+ describe "#set" do
80
139
 
81
140
  subject do
82
141
  described_class.new
83
- .add("foo", only: %w(cad cam))
84
- .add("bar", except: %w(cad))
85
- .add("baz", except: %w(cam))
142
+ .add_validator("foo", only: %w(cad cam))
143
+ .add_validator("bar", except: %w(cad))
144
+ .add_validator("baz", except: %w(cam))
86
145
  end
87
146
 
88
147
  it "returns a collection" do
@@ -95,6 +154,6 @@ describe Attestor::Validations::Validators do
95
154
  expect(subject.set("all").map(&:name)).to contain_exactly :bar, :baz
96
155
  end
97
156
 
98
- end # describe #context
157
+ end # describe #set
99
158
 
100
159
  end # describe Attestor::Validators
@@ -5,14 +5,15 @@ require "support/policies" # for #valid_policy and #invalid_policy definitions
5
5
  describe Attestor::Validations do
6
6
 
7
7
  let(:validators_class) { Attestor::Validations::Validators }
8
- let(:validator_class) { Attestor::Validations::Validator }
8
+ let(:validator_class) { Attestor::Validations::Validator }
9
+ let(:follower_class) { Attestor::Validations::Follower }
9
10
  let(:collection_class) { Attestor::Validations::Validators }
10
- let(:item_class) { Attestor::Validations::Item }
11
- let(:message_class) { Attestor::Validations::Message }
12
- let(:invalid_error) { Attestor::InvalidError }
13
- let(:test_class) { Class.new.send(:include, described_class) }
11
+ let(:item_class) { Attestor::Validations::Item }
12
+ let(:message_class) { Attestor::Validations::Message }
13
+ let(:invalid_error) { Attestor::InvalidError }
14
14
 
15
- before { Test = test_class }
15
+ let(:test_class) { Class.new.send(:include, described_class) }
16
+ before { Test = test_class }
16
17
  after { Object.send :remove_const, :Test }
17
18
 
18
19
  subject { test_class.new }
@@ -37,10 +38,7 @@ describe Attestor::Validations do
37
38
 
38
39
  it "registers a validator" do
39
40
  expect(test_class.validators.map(&:name)).to eq [:foo]
40
- end
41
-
42
- it "sets a validator's policy to false" do
43
- expect(test_class.validators.first).not_to be_policy
41
+ expect(test_class.validators.first).not_to be_kind_of follower_class
44
42
  end
45
43
 
46
44
  end # context
@@ -65,12 +63,9 @@ describe Attestor::Validations do
65
63
 
66
64
  before { test_class.follow_policy :foo }
67
65
 
68
- it "registers a validator" do
66
+ it "registers a follower" do
69
67
  expect(test_class.validators.map(&:name)).to eq [:foo]
70
- end
71
-
72
- it "sets a validator's policy to true" do
73
- expect(test_class.validators.first).to be_policy
68
+ expect(test_class.validators.first).to be_kind_of follower_class
74
69
  end
75
70
 
76
71
  end # context
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: attestor
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Kozin
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-03-27 00:00:00.000000000 Z
11
+ date: 2015-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: extlib
@@ -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/follower.rb
84
85
  - lib/attestor/validations/message.rb
85
86
  - lib/attestor/validations/validator.rb
86
87
  - lib/attestor/validations/validators.rb
@@ -97,6 +98,7 @@ files:
97
98
  - spec/tests/policy/or_spec.rb
98
99
  - spec/tests/policy/xor_spec.rb
99
100
  - spec/tests/policy_spec.rb
101
+ - spec/tests/validations/follower_spec.rb
100
102
  - spec/tests/validations/message_spec.rb
101
103
  - spec/tests/validations/validator_spec.rb
102
104
  - spec/tests/validations/validators_spec.rb
@@ -131,6 +133,7 @@ test_files:
131
133
  - spec/tests/invalid_error_spec.rb
132
134
  - spec/tests/validations_spec.rb
133
135
  - spec/tests/validations/message_spec.rb
136
+ - spec/tests/validations/follower_spec.rb
134
137
  - spec/tests/validations/validator_spec.rb
135
138
  - spec/tests/validations/validators_spec.rb
136
139
  - spec/tests/policy/or_spec.rb