assertion 0.2.0 → 0.2.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +16 -0
- data/README.md +1 -1
- data/lib/assertion.rb +8 -4
- data/lib/assertion/base.rb +5 -3
- data/lib/assertion/dsl/attribute.rb +44 -0
- data/lib/assertion/dsl/attributes.rb +54 -0
- data/lib/assertion/dsl/builder.rb +81 -0
- data/lib/assertion/dsl/caller.rb +26 -0
- data/lib/assertion/dsl/inversion.rb +36 -0
- data/lib/assertion/guard.rb +2 -7
- data/lib/assertion/inverter.rb +2 -10
- data/lib/assertion/translator.rb +1 -1
- data/lib/assertion/version.rb +1 -1
- data/spec/unit/assertion/base_spec.rb +30 -137
- data/spec/unit/assertion/dsl/attribute_spec.rb +53 -0
- data/spec/unit/assertion/dsl/attributes_spec.rb +89 -0
- data/spec/unit/assertion/dsl/builder_spec.rb +123 -0
- data/spec/unit/assertion/dsl/caller_spec.rb +23 -0
- data/spec/unit/assertion/dsl/inversion_spec.rb +18 -0
- data/spec/unit/assertion/guard_spec.rb +10 -49
- data/spec/unit/assertion/inverter_spec.rb +4 -26
- data/spec/unit/assertion/translator_spec.rb +2 -0
- data/spec/unit/assertion_spec.rb +3 -116
- metadata +17 -5
- data/lib/assertion/base_dsl.rb +0 -75
- data/lib/assertion/dsl.rb +0 -77
- data/lib/assertion/guard_dsl.rb +0 -39
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e02fce1546e9b7523fbff83894476957ca0b335d
|
4
|
+
data.tar.gz: 49d6ede0ddd7a992b8bd688cc55ef06b0b7a66bd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d4db34e23434e46569f8fa530d41bec8a0d8b920e7d13344ed6a0a864a0c416398f4835faa1e1e77b35b8d63025416b1fc32b2e9f17ceb3c85b42678fda9e75e
|
7
|
+
data.tar.gz: d9d16dd22f86a0da3e37b6e23f68b0c049bc6832dfec864c94fbfe41f6dd6e2e71b8f0f677f35757fddd012b69116853a59bb1db2d3960db9b73d08c3f059a87
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,19 @@
|
|
1
|
+
## v0.2.1 2015-06-23
|
2
|
+
|
3
|
+
### Bugs Fixed
|
4
|
+
|
5
|
+
* Support any values returned by `Base#check` method, not only boolean ones (nepalez)
|
6
|
+
|
7
|
+
### Internal
|
8
|
+
|
9
|
+
* `[]` caller method is extracted from `BaseDSL`, `Inverter`, and `GuardDSL` to `DSL::Caller` (nepalez)
|
10
|
+
* `GuardDSL` is splitted to `DSL::Caller` and `DSL::Attribute` (nepalez)
|
11
|
+
* `.attribute`, `.attributes` and `#attributes` extracted from `BaseDSL` to `DSL::Attributes` (nepalez)
|
12
|
+
* `BaseDSL` is splitted to `DSL::Attributes`, `DSL::Caller` and `DSL::Inversion` (nepalez)
|
13
|
+
* `DSL` is renamed to `DSL::Builder` to follow the convention. `DSL` is reserved for collection of DSLs (nepalez)
|
14
|
+
|
15
|
+
[Compare v0.2.0...v0.2.1](https://github.com/nepalez/assertion/compare/v0.2.0...v0.2.1)
|
16
|
+
|
1
17
|
## v0.2.0 2015-06-22
|
2
18
|
|
3
19
|
### Changed (backward-incompatible!)
|
data/README.md
CHANGED
@@ -29,7 +29,7 @@ No `ActiveSupport`, no mutation of any instances.
|
|
29
29
|
### Basic Usage
|
30
30
|
|
31
31
|
Define an assertion by inheriting it from the `Assertion::Base` class with attributes to which it should be applied.
|
32
|
-
Then implement the method `check`
|
32
|
+
Then implement the method `check` to describe if the assertion is truthy or falsey.
|
33
33
|
|
34
34
|
You can do it either in the classic style:
|
35
35
|
|
data/lib/assertion.rb
CHANGED
@@ -4,15 +4,19 @@ require "transproc"
|
|
4
4
|
|
5
5
|
require_relative "assertion/inflector"
|
6
6
|
require_relative "assertion/invalid_error"
|
7
|
+
|
8
|
+
require_relative "assertion/dsl/caller"
|
9
|
+
require_relative "assertion/dsl/attribute"
|
10
|
+
require_relative "assertion/dsl/attributes"
|
11
|
+
require_relative "assertion/dsl/inversion"
|
12
|
+
require_relative "assertion/dsl/builder"
|
13
|
+
|
7
14
|
require_relative "assertion/translator"
|
8
15
|
require_relative "assertion/state"
|
9
|
-
require_relative "assertion/base_dsl"
|
10
16
|
require_relative "assertion/base"
|
11
17
|
require_relative "assertion/inversion"
|
12
18
|
require_relative "assertion/inverter"
|
13
|
-
require_relative "assertion/guard_dsl"
|
14
19
|
require_relative "assertion/guard"
|
15
|
-
require_relative "assertion/dsl"
|
16
20
|
|
17
21
|
# The module declares:
|
18
22
|
#
|
@@ -54,6 +58,6 @@ require_relative "assertion/dsl"
|
|
54
58
|
#
|
55
59
|
module Assertion
|
56
60
|
|
57
|
-
extend DSL
|
61
|
+
extend DSL::Builder
|
58
62
|
|
59
63
|
end # module Assertion
|
data/lib/assertion/base.rb
CHANGED
@@ -35,7 +35,9 @@ module Assertion
|
|
35
35
|
#
|
36
36
|
class Base
|
37
37
|
|
38
|
-
extend
|
38
|
+
extend DSL::Attributes
|
39
|
+
extend DSL::Inversion
|
40
|
+
extend DSL::Caller
|
39
41
|
|
40
42
|
# The translator of states for the current class
|
41
43
|
#
|
@@ -81,7 +83,7 @@ module Assertion
|
|
81
83
|
#
|
82
84
|
# @return [String]
|
83
85
|
#
|
84
|
-
def message(state)
|
86
|
+
def message(state = nil)
|
85
87
|
self.class.translator.call(state, attributes)
|
86
88
|
end
|
87
89
|
|
@@ -94,7 +96,7 @@ module Assertion
|
|
94
96
|
# The state of the assertion being applied to its attributes
|
95
97
|
#
|
96
98
|
def call
|
97
|
-
State.new check, message
|
99
|
+
State.new check, message
|
98
100
|
end
|
99
101
|
|
100
102
|
end # class Base
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Assertion
|
4
|
+
|
5
|
+
# Collection of DSLs for various modules and classes
|
6
|
+
#
|
7
|
+
module DSL
|
8
|
+
|
9
|
+
# Allows adding aliases to `#object` method.
|
10
|
+
#
|
11
|
+
module Attribute
|
12
|
+
|
13
|
+
# Adds alias to the [#object] method
|
14
|
+
#
|
15
|
+
# @param [#to_sym] name
|
16
|
+
#
|
17
|
+
# @return [undefined]
|
18
|
+
#
|
19
|
+
# @raise [NameError]
|
20
|
+
# When a given name is either used by instance methods,
|
21
|
+
# or reserved by the `#state` method to be implemented later.
|
22
|
+
#
|
23
|
+
def attribute(name)
|
24
|
+
__check_attribute__(name)
|
25
|
+
alias_method name, :object
|
26
|
+
end
|
27
|
+
|
28
|
+
# @private
|
29
|
+
def self.extended(klass)
|
30
|
+
klass.__send__ :attr_reader, :object
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def __check_attribute__(key)
|
36
|
+
return unless (instance_methods << :state).include? key.to_sym
|
37
|
+
fail NameError.new "#{self}##{key} is already defined"
|
38
|
+
end
|
39
|
+
|
40
|
+
end # module Attribute
|
41
|
+
|
42
|
+
end # module DSL
|
43
|
+
|
44
|
+
end # module Assertion
|
@@ -0,0 +1,54 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Assertion
|
4
|
+
|
5
|
+
module DSL
|
6
|
+
|
7
|
+
# Allows adding aliases to values of the `#attributes` hash.
|
8
|
+
#
|
9
|
+
module Attributes
|
10
|
+
|
11
|
+
# List of declared attributes
|
12
|
+
#
|
13
|
+
# @return [Array<Symbol>]
|
14
|
+
#
|
15
|
+
def attributes
|
16
|
+
@attributes ||= []
|
17
|
+
end
|
18
|
+
|
19
|
+
# Declares new attribute(s) by name(s)
|
20
|
+
#
|
21
|
+
# @param [#to_sym, Array<#to_sym>] names
|
22
|
+
#
|
23
|
+
# @return [undefined]
|
24
|
+
#
|
25
|
+
# @raise [NameError]
|
26
|
+
# When a given name is either used by instance methods,
|
27
|
+
# or reserved by the `#check` method to be implemented later.
|
28
|
+
#
|
29
|
+
def attribute(*names)
|
30
|
+
names.flatten.map(&:to_sym).each(&method(:__add_attribute__))
|
31
|
+
end
|
32
|
+
|
33
|
+
# @private
|
34
|
+
def self.extended(klass)
|
35
|
+
klass.__send__(:define_method, :attributes) { @attributes ||= {} }
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def __add_attribute__(name)
|
41
|
+
__check_attribute__(name)
|
42
|
+
attributes << define_method(name) { attributes[name] }
|
43
|
+
end
|
44
|
+
|
45
|
+
def __check_attribute__(name)
|
46
|
+
return unless (instance_methods << :check).include? name
|
47
|
+
fail NameError.new "#{self}##{name} is already defined"
|
48
|
+
end
|
49
|
+
|
50
|
+
end # module Attributes
|
51
|
+
|
52
|
+
end # module DSL
|
53
|
+
|
54
|
+
end # module Assertion
|
@@ -0,0 +1,81 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Assertion
|
4
|
+
|
5
|
+
module DSL
|
6
|
+
|
7
|
+
# Provides methods to build assertions and guards
|
8
|
+
#
|
9
|
+
module Builder
|
10
|
+
|
11
|
+
# Builds the subclass of `Assertion::Base` with predefined `attributes`
|
12
|
+
# and implementation of the `#check` method.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# IsMan = Assertion.about :age, :gender do
|
16
|
+
# (age >= 18) && (gender == :male)
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
# # This is the same as:
|
20
|
+
# class IsMan < Assertion::Base
|
21
|
+
# attribute :age, :gender
|
22
|
+
#
|
23
|
+
# def check
|
24
|
+
# (age >= 18) && (gender == :male)
|
25
|
+
# end
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
# @param [Symbol, Array<Symbol>] attributes
|
29
|
+
# The list of attributes for the new assertion
|
30
|
+
# @param [Proc] block
|
31
|
+
# The content for the `check` method
|
32
|
+
#
|
33
|
+
# @return [Class] The specific assertion class
|
34
|
+
#
|
35
|
+
def about(*attributes, &block)
|
36
|
+
__build__(Base, attributes, :check, &block)
|
37
|
+
end
|
38
|
+
|
39
|
+
# Builds the subclass of `Assertion::Guard` with given attribute
|
40
|
+
# (alias for the `object`) and implementation of the `#state` method.
|
41
|
+
#
|
42
|
+
# @example
|
43
|
+
# VoterOnly = Assertion.guards :user do
|
44
|
+
# IsAdult[user.attributes] & IsCitizen[user.attributes]
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# # This is the same as:
|
48
|
+
# class VoterOnly < Assertion::Guard
|
49
|
+
# alias_method :user, :object
|
50
|
+
#
|
51
|
+
# def state
|
52
|
+
# IsAdult[user.attributes] & IsCitizen[user.attributes]
|
53
|
+
# end
|
54
|
+
# end
|
55
|
+
#
|
56
|
+
# @param [Symbol] attribute
|
57
|
+
# The alias for the `object` attribute
|
58
|
+
# @param [Proc] block
|
59
|
+
# The content for the `state` method
|
60
|
+
#
|
61
|
+
# @return [Class] The specific guard class
|
62
|
+
#
|
63
|
+
def guards(attribute = nil, &block)
|
64
|
+
__build__(Guard, attribute, :state, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
def __build__(type, attributes, name, &block)
|
70
|
+
klass = Class.new(type)
|
71
|
+
klass.public_send(:attribute, attributes) if attributes
|
72
|
+
klass.__send__(:define_method, name, &block) if block_given?
|
73
|
+
|
74
|
+
klass
|
75
|
+
end
|
76
|
+
|
77
|
+
end # module Builder
|
78
|
+
|
79
|
+
end # module DSL
|
80
|
+
|
81
|
+
end # module Assertion
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Assertion
|
4
|
+
|
5
|
+
module DSL
|
6
|
+
|
7
|
+
# Allows to initialize and call objects at once
|
8
|
+
#
|
9
|
+
module Caller
|
10
|
+
|
11
|
+
# Initializes and immediately calls the instance of the class
|
12
|
+
#
|
13
|
+
# @param [Object, Array<Object>] args
|
14
|
+
# The <list of> arguments to initialize the instance with
|
15
|
+
#
|
16
|
+
# @return [Object] the result of #call method
|
17
|
+
#
|
18
|
+
def [](*args)
|
19
|
+
new(*args).call
|
20
|
+
end
|
21
|
+
|
22
|
+
end # module Caller
|
23
|
+
|
24
|
+
end # module DSL
|
25
|
+
|
26
|
+
end # module Assertion
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
module Assertion
|
4
|
+
|
5
|
+
module DSL
|
6
|
+
|
7
|
+
# Allows to provide inverter for objects of the current class
|
8
|
+
#
|
9
|
+
module Inversion
|
10
|
+
|
11
|
+
# Initializes the intermediate inverter with `new` and `[]` methods
|
12
|
+
#
|
13
|
+
# The inverter can be used to initialize the assertion, that describes
|
14
|
+
# just the opposite statement to the current one
|
15
|
+
#
|
16
|
+
# @example
|
17
|
+
# IsAdult = Assertion.about :name, :age do
|
18
|
+
# age >= 18
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# joe = { name: 'Joe', age: 19 }
|
22
|
+
#
|
23
|
+
# IsAdult[joe].valid? # => true
|
24
|
+
# IsAdult.not[joe].valid? # => false
|
25
|
+
#
|
26
|
+
# @return [Assertion::Inverter]
|
27
|
+
#
|
28
|
+
def not
|
29
|
+
Inverter.new(self)
|
30
|
+
end
|
31
|
+
|
32
|
+
end # module Inversion
|
33
|
+
|
34
|
+
end # module DSL
|
35
|
+
|
36
|
+
end # module Assertion
|
data/lib/assertion/guard.rb
CHANGED
@@ -32,13 +32,8 @@ module Assertion
|
|
32
32
|
#
|
33
33
|
class Guard
|
34
34
|
|
35
|
-
extend
|
36
|
-
|
37
|
-
# @!attribute [r] object
|
38
|
-
#
|
39
|
-
# @return [Object] The object whose state should be tested
|
40
|
-
#
|
41
|
-
attr_reader :object
|
35
|
+
extend DSL::Attribute
|
36
|
+
extend DSL::Caller
|
42
37
|
|
43
38
|
# @!scope class
|
44
39
|
# @!method new(object)
|
data/lib/assertion/inverter.rb
CHANGED
@@ -17,6 +17,8 @@ module Assertion
|
|
17
17
|
#
|
18
18
|
class Inverter
|
19
19
|
|
20
|
+
include DSL::Caller
|
21
|
+
|
20
22
|
# @!attribute [r] source
|
21
23
|
#
|
22
24
|
# @return [Class] The `Assertion::Base` sublcass to build negators for
|
@@ -47,16 +49,6 @@ module Assertion
|
|
47
49
|
Inversion.new source.new(hash)
|
48
50
|
end
|
49
51
|
|
50
|
-
# Initializes an assertion, builds its inversion, and applies it to the data
|
51
|
-
#
|
52
|
-
# @param (see #new)
|
53
|
-
#
|
54
|
-
# @return (see Assertion::Base#call)
|
55
|
-
#
|
56
|
-
def [](hash = {})
|
57
|
-
new(hash).call
|
58
|
-
end
|
59
|
-
|
60
52
|
end # class Inverter
|
61
53
|
|
62
54
|
end # module Assertion
|
data/lib/assertion/translator.rb
CHANGED
@@ -87,7 +87,7 @@ module Assertion
|
|
87
87
|
# @return [String] The translation
|
88
88
|
#
|
89
89
|
def call(state, args = {})
|
90
|
-
I18n.translate DICTIONARY[state], args.merge(scope: scope)
|
90
|
+
I18n.translate DICTIONARY[state ? true : false], args.merge(scope: scope)
|
91
91
|
end
|
92
92
|
|
93
93
|
end # class Translator
|
data/lib/assertion/version.rb
CHANGED
@@ -5,6 +5,18 @@ describe Assertion::Base do
|
|
5
5
|
let(:klass) { Class.new(described_class) }
|
6
6
|
before { allow(klass).to receive(:name) { "Test" } }
|
7
7
|
|
8
|
+
it "implements DSL::Caller" do
|
9
|
+
expect(klass).to be_kind_of Assertion::DSL::Caller
|
10
|
+
end
|
11
|
+
|
12
|
+
it "implements DSL::Attributes" do
|
13
|
+
expect(klass).to be_kind_of Assertion::DSL::Attributes
|
14
|
+
end
|
15
|
+
|
16
|
+
it "implements DSL::Inversion" do
|
17
|
+
expect(klass).to be_kind_of Assertion::DSL::Inversion
|
18
|
+
end
|
19
|
+
|
8
20
|
describe ".new" do
|
9
21
|
|
10
22
|
let(:klass) { Class.new(described_class) { attribute :foo, :bar } }
|
@@ -37,158 +49,39 @@ describe Assertion::Base do
|
|
37
49
|
|
38
50
|
end # describe .new
|
39
51
|
|
40
|
-
describe "
|
41
|
-
|
42
|
-
subject { klass.attributes }
|
43
|
-
it { is_expected.to eql [] }
|
44
|
-
|
45
|
-
end # describe .attributes
|
52
|
+
describe "#message" do
|
46
53
|
|
47
|
-
|
54
|
+
let(:klass) { Class.new(described_class) { attribute :foo } }
|
55
|
+
let(:assertion) { klass.new(foo: :FOO) }
|
48
56
|
|
49
|
-
shared_examples "
|
57
|
+
shared_examples "translating" do |as: nil|
|
50
58
|
|
51
|
-
|
52
|
-
|
53
|
-
end
|
59
|
+
let(:translator) { Assertion::Translator.new(klass) }
|
60
|
+
let(:attributes) { assertion.attributes }
|
54
61
|
|
55
|
-
it "
|
62
|
+
it "uses attributes in a translation" do
|
63
|
+
expect(I18n).to receive :translate do |_, args|
|
64
|
+
expect(args.merge(attributes)).to eql args
|
65
|
+
end
|
56
66
|
subject
|
57
|
-
assertion = klass.new(foo: :FOO, bar: :BAR, baz: :BAZ)
|
58
|
-
expect(assertion.attributes).to eql(foo: :FOO, bar: :BAR)
|
59
|
-
expect(assertion.foo).to eql :FOO
|
60
|
-
expect(assertion.bar).to eql :BAR
|
61
67
|
end
|
62
68
|
|
63
|
-
|
64
|
-
|
65
|
-
shared_examples "raising NameError" do |with: nil|
|
66
|
-
|
67
|
-
it "fails" do
|
68
|
-
expect { subject }.to raise_error do |exception|
|
69
|
-
expect(exception).to be_kind_of NameError
|
70
|
-
expect(exception.message).to eql "#{klass}##{with} is already defined"
|
71
|
-
end
|
69
|
+
it "returns a translation" do
|
70
|
+
expect(subject).to eql translator.call(as, attributes)
|
72
71
|
end
|
73
72
|
|
74
73
|
end # shared examples
|
75
74
|
|
76
|
-
|
77
|
-
|
78
|
-
subject do
|
79
|
-
klass.attribute :foo
|
80
|
-
klass.attribute "bar"
|
81
|
-
end
|
82
|
-
it_behaves_like "defining attributes"
|
83
|
-
|
84
|
-
end # context
|
85
|
-
|
86
|
-
context "with a list of names" do
|
87
|
-
|
88
|
-
subject { klass.attribute :foo, :bar }
|
89
|
-
it_behaves_like "defining attributes"
|
90
|
-
|
91
|
-
end # context
|
92
|
-
|
93
|
-
context "with an array of names" do
|
94
|
-
|
95
|
-
subject { klass.attribute %w(foo bar) }
|
96
|
-
it_behaves_like "defining attributes"
|
97
|
-
|
98
|
-
end # context
|
99
|
-
|
100
|
-
context ":check" do
|
101
|
-
|
102
|
-
subject { klass.attribute :check }
|
103
|
-
it_behaves_like "raising NameError", with: :check
|
104
|
-
|
105
|
-
end # context
|
106
|
-
|
107
|
-
context ":call" do
|
108
|
-
|
109
|
-
subject { klass.attribute :call }
|
110
|
-
it_behaves_like "raising NameError", with: :call
|
111
|
-
|
112
|
-
end # context
|
113
|
-
|
114
|
-
end # describe .attribute
|
115
|
-
|
116
|
-
describe ".not" do
|
117
|
-
|
118
|
-
subject { klass.not }
|
119
|
-
|
120
|
-
it "creates the iverter for the current class" do
|
121
|
-
expect(subject).to be_kind_of Assertion::Inverter
|
122
|
-
expect(subject.source).to eql klass
|
75
|
+
it_behaves_like "translating", as: true do
|
76
|
+
subject { assertion.message(true) }
|
123
77
|
end
|
124
78
|
|
125
|
-
|
126
|
-
|
127
|
-
describe ".[]" do
|
128
|
-
|
129
|
-
let(:params) { { foo: :FOO } }
|
130
|
-
let(:state) { double }
|
131
|
-
let(:assertion) { double call: state }
|
132
|
-
|
133
|
-
context "with params" do
|
134
|
-
|
135
|
-
subject { klass[params] }
|
136
|
-
|
137
|
-
it "checks the assertion for given attributes" do
|
138
|
-
allow(klass).to receive(:new).with(params) { assertion }
|
139
|
-
expect(subject).to eql state
|
140
|
-
end
|
141
|
-
|
142
|
-
end # context
|
143
|
-
|
144
|
-
context "without params" do
|
145
|
-
|
146
|
-
subject { klass[] }
|
147
|
-
|
148
|
-
it "checks the assertion" do
|
149
|
-
allow(klass).to receive(:new) { assertion }
|
150
|
-
expect(subject).to eql state
|
151
|
-
end
|
152
|
-
|
153
|
-
end # context
|
154
|
-
|
155
|
-
end # describe .[]
|
156
|
-
|
157
|
-
describe ".translator" do
|
158
|
-
|
159
|
-
subject { klass.translator }
|
160
|
-
|
161
|
-
it { is_expected.to be_kind_of Assertion::Translator }
|
162
|
-
|
163
|
-
it "refers to the current class" do
|
164
|
-
expect(subject.assertion).to eql klass
|
79
|
+
it_behaves_like "translating", as: false do
|
80
|
+
subject { assertion.message(false) }
|
165
81
|
end
|
166
82
|
|
167
|
-
|
168
|
-
|
169
|
-
describe "#attributes" do
|
170
|
-
|
171
|
-
let(:attrs) { { foo: :FOO, bar: :BAR } }
|
172
|
-
let(:klass) { Class.new(described_class) { attribute :foo, :bar } }
|
173
|
-
let(:assertion) { klass.new attrs }
|
174
|
-
|
175
|
-
subject { assertion.attributes }
|
176
|
-
it { is_expected.to eql attrs }
|
177
|
-
|
178
|
-
end # describe #attributes
|
179
|
-
|
180
|
-
describe "#message" do
|
181
|
-
|
182
|
-
let(:state) { double }
|
183
|
-
let(:attrs) { { foo: :FOO, bar: :BAR } }
|
184
|
-
let(:klass) { Class.new(described_class) { attribute :foo, :bar } }
|
185
|
-
let(:assertion) { klass.new attrs }
|
186
|
-
let(:translator) { double call: nil }
|
187
|
-
|
188
|
-
it "calls a translator with state and attributes" do
|
189
|
-
allow(klass).to receive(:translator) { translator }
|
190
|
-
expect(translator).to receive(:call).with(state, attrs)
|
191
|
-
assertion.message(state)
|
83
|
+
it_behaves_like "translating", as: false do
|
84
|
+
subject { assertion.message }
|
192
85
|
end
|
193
86
|
|
194
87
|
end # describe #message
|