attestor 0.2.0 → 0.3.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: 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