assertion 0.2.0 → 0.2.1
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 +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
|