interaktor 0.1.5 → 0.2.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 +4 -4
- data/.github/workflows/publish.yml +30 -0
- data/.github/workflows/tests.yml +24 -0
- data/.ruby-version +1 -0
- data/.travis.yml +1 -12
- data/Gemfile +3 -2
- data/Guardfile +42 -0
- data/README.md +87 -132
- data/interaktor.gemspec +1 -1
- data/lib/interaktor.rb +12 -188
- data/lib/interaktor/callable.rb +219 -0
- data/lib/interaktor/context.rb +16 -1
- data/lib/interaktor/error/attribute_error.rb +16 -0
- data/lib/interaktor/error/base.rb +9 -0
- data/lib/interaktor/error/disallowed_attribute_assignment_error.rb +9 -0
- data/lib/interaktor/error/missing_attribute_error.rb +5 -0
- data/lib/interaktor/error/option_error.rb +16 -0
- data/lib/interaktor/error/unknown_attribute_error.rb +5 -0
- data/lib/interaktor/error/unknown_option_error.rb +5 -0
- data/lib/interaktor/organizer.rb +7 -20
- data/spec/integration_spec.rb +18 -15
- data/spec/interactor/organizer_spec.rb +81 -13
- data/spec/spec_helper.rb +8 -3
- data/spec/support/lint.rb +289 -57
- metadata +19 -6
data/lib/interaktor/context.rb
CHANGED
@@ -62,7 +62,7 @@ class Interaktor::Context < OpenStruct
|
|
62
62
|
# @return [void]
|
63
63
|
def success!(context = {})
|
64
64
|
context.each { |key, value| self[key.to_sym] = value }
|
65
|
-
|
65
|
+
early_return!
|
66
66
|
end
|
67
67
|
|
68
68
|
# Roll back the Interaktor::Context. Any interaktors to which this context
|
@@ -98,4 +98,19 @@ class Interaktor::Context < OpenStruct
|
|
98
98
|
def _called
|
99
99
|
@called ||= []
|
100
100
|
end
|
101
|
+
|
102
|
+
# Trigger an early return throw.
|
103
|
+
#
|
104
|
+
# @return [void]
|
105
|
+
def early_return!
|
106
|
+
@early_return = true
|
107
|
+
throw :early_return, self
|
108
|
+
end
|
109
|
+
|
110
|
+
# Whether or not the context has been returned from early.
|
111
|
+
#
|
112
|
+
# @return [Boolean]
|
113
|
+
def early_return?
|
114
|
+
(@early_return == true) || false
|
115
|
+
end
|
101
116
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Interaktor::Error::AttributeError < Interaktor::Error::Base
|
2
|
+
# @return [Array<Symbol>]
|
3
|
+
attr_reader :attributes
|
4
|
+
|
5
|
+
# @param interaktor [Class]
|
6
|
+
# @param attributes [Array<Symbol>]
|
7
|
+
def initialize(interaktor, attributes)
|
8
|
+
super(interaktor)
|
9
|
+
|
10
|
+
@attributes = attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,9 @@
|
|
1
|
+
class Interaktor::Error::DisallowedAttributeAssignmentError < Interaktor::Error::AttributeError
|
2
|
+
def message
|
3
|
+
<<~MESSAGE.strip.tr("\n", "")
|
4
|
+
Attempted a disallowed assignment to the '#{attributes.first}'
|
5
|
+
attribute which was not included when the #{interaktor} interaktor was
|
6
|
+
originally called.
|
7
|
+
MESSAGE
|
8
|
+
end
|
9
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Interaktor::Error::OptionError < Interaktor::Error::Base
|
2
|
+
# @return [Hash{Symbol=>Object}]
|
3
|
+
attr_reader :options
|
4
|
+
|
5
|
+
# @param interaktor [Class]
|
6
|
+
# @param options [Hash{Symbol=>Object}]
|
7
|
+
def initialize(interaktor, options)
|
8
|
+
super(interaktor)
|
9
|
+
|
10
|
+
@options = options
|
11
|
+
end
|
12
|
+
|
13
|
+
def message
|
14
|
+
raise NotImplementedError
|
15
|
+
end
|
16
|
+
end
|
data/lib/interaktor/organizer.rb
CHANGED
@@ -40,28 +40,15 @@ module Interaktor::Organizer
|
|
40
40
|
# @return [void]
|
41
41
|
def call
|
42
42
|
self.class.organized.each do |interaktor|
|
43
|
+
# Take the context that is being passed to each interaktor and remove
|
44
|
+
# any attributes from it that are not required by the interactor.
|
45
|
+
@context.to_h
|
46
|
+
.keys
|
47
|
+
.reject { |attr| interaktor.input_attributes.include?(attr) }
|
48
|
+
.each { |attr| @context.delete_field(attr) }
|
49
|
+
|
43
50
|
catch(:early_return) { interaktor.call!(@context) }
|
44
51
|
end
|
45
52
|
end
|
46
|
-
|
47
|
-
private
|
48
|
-
|
49
|
-
# A list of attributes required to invoke the organized Interaktors.
|
50
|
-
# Obtained by compiling a list of all required attributes of all organized
|
51
|
-
# interaktors. Duplicates are removed.
|
52
|
-
#
|
53
|
-
# @return [Array<Symbol>]
|
54
|
-
def required_attributes
|
55
|
-
self.class.organized.map(&:required_attributes).flatten.uniq
|
56
|
-
end
|
57
|
-
|
58
|
-
# A list of optional attributes allowed to be included when invoking the
|
59
|
-
# organized Interaktors. Obtained by compiling a list of all optional
|
60
|
-
# attributes of all organized interaktors. Duplicates are removed.
|
61
|
-
#
|
62
|
-
# @return [Array<Symbol>]
|
63
|
-
def optional_attributes
|
64
|
-
self.class.organized.map(&:optional_attributes).flatten.uniq
|
65
|
-
end
|
66
53
|
end
|
67
54
|
end
|
data/spec/integration_spec.rb
CHANGED
@@ -5,30 +5,33 @@
|
|
5
5
|
|
6
6
|
describe "Integration" do
|
7
7
|
def build_interaktor(&block)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
Class.new.tap do |interaktor|
|
9
|
+
interaktor.send(:include, Interaktor)
|
10
|
+
interaktor.class_eval(&block) if block
|
11
|
+
interaktor.class_eval do
|
12
|
+
optional :steps
|
12
13
|
|
13
|
-
|
14
|
-
|
14
|
+
def unexpected_error!
|
15
|
+
raise "foo"
|
16
|
+
end
|
15
17
|
end
|
16
18
|
end
|
17
|
-
interaktor
|
18
19
|
end
|
19
20
|
|
20
21
|
def build_organizer(options = {}, &block)
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
22
|
+
Class.new.tap do |organizer|
|
23
|
+
organizer.send(:include, Interaktor::Organizer)
|
24
|
+
|
25
|
+
organizer.organize(options[:organize]) if options[:organize]
|
26
|
+
organizer.class_eval(&block) if block
|
27
|
+
organizer.class_eval do
|
28
|
+
optional :steps
|
26
29
|
|
27
|
-
|
28
|
-
|
30
|
+
def unexpected_error!
|
31
|
+
raise "foo"
|
32
|
+
end
|
29
33
|
end
|
30
34
|
end
|
31
|
-
organizer
|
32
35
|
end
|
33
36
|
|
34
37
|
# rubocop:disable Style/AsciiComments
|
@@ -36,24 +36,92 @@ module Interaktor
|
|
36
36
|
end
|
37
37
|
|
38
38
|
describe "#call" do
|
39
|
-
it "calls each interaktor in order
|
40
|
-
|
41
|
-
|
42
|
-
interaktor2 =
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
it "calls each interaktor in order" do
|
40
|
+
organizer.class_eval { required :foo }
|
41
|
+
|
42
|
+
interaktor2 = Class.new.include(Interaktor)
|
43
|
+
interaktor2.class_eval { required :foo }
|
44
|
+
interaktor2.define_method(:call) { self.foo = "bar" }
|
45
|
+
|
46
|
+
interaktor3 = Class.new.include(Interaktor)
|
47
|
+
interaktor3.class_eval { required :foo }
|
48
|
+
interaktor3.define_method(:call) { self.foo = "baz" }
|
49
|
+
|
50
|
+
interaktor4 = Class.new.include(Interaktor)
|
51
|
+
interaktor4.class_eval { required :foo }
|
52
|
+
interaktor4.define_method(:call) { self.foo = "wadus" }
|
53
|
+
|
48
54
|
allow(organizer).to receive(:organized) {
|
49
55
|
[interaktor2, interaktor3, interaktor4]
|
50
56
|
}
|
51
57
|
|
52
|
-
expect(interaktor2).to receive(:call!).once.
|
53
|
-
expect(interaktor3).to receive(:call!).once.
|
54
|
-
expect(interaktor4).to receive(:call!).once.
|
58
|
+
expect(interaktor2).to receive(:call!).once.ordered.and_call_original
|
59
|
+
expect(interaktor3).to receive(:call!).once.ordered.and_call_original
|
60
|
+
expect(interaktor4).to receive(:call!).once.ordered.and_call_original
|
61
|
+
|
62
|
+
result = organizer.call(foo: "asdf")
|
63
|
+
|
64
|
+
expect(result.foo).to eq "wadus"
|
65
|
+
end
|
66
|
+
|
67
|
+
it "calls each interaktor in order and passes success attributes" do
|
68
|
+
organizer.class_eval { required :foo }
|
69
|
+
|
70
|
+
interaktor2 = Class.new.include(Interaktor)
|
71
|
+
interaktor2.class_eval do
|
72
|
+
required :foo
|
73
|
+
success :bar
|
74
|
+
end
|
75
|
+
interaktor2.define_method(:call) { success!(bar: "baz") }
|
76
|
+
|
77
|
+
interaktor3 = Class.new.include(Interaktor)
|
78
|
+
interaktor3.class_eval { required :bar }
|
79
|
+
interaktor3.define_method(:call) { self.bar = "wadus" }
|
80
|
+
|
81
|
+
allow(organizer).to receive(:organized) {
|
82
|
+
[interaktor2, interaktor3]
|
83
|
+
}
|
84
|
+
|
85
|
+
expect(interaktor2).to receive(:call!).once.ordered.and_call_original
|
86
|
+
expect(interaktor3).to receive(:call!).once.ordered.and_call_original
|
87
|
+
|
88
|
+
result = organizer.call(foo: "asdf")
|
55
89
|
|
56
|
-
|
90
|
+
expect(result.bar).to eq "wadus"
|
91
|
+
end
|
92
|
+
|
93
|
+
it "raises an exception if the organizer attributes do not satisfy the first interaktor" do
|
94
|
+
organizer.class_eval { required :foo }
|
95
|
+
|
96
|
+
interaktor2 = Class.new.include(Interaktor)
|
97
|
+
interaktor2.class_eval { required :bar }
|
98
|
+
|
99
|
+
allow(organizer).to receive(:organized).and_return([interaktor2])
|
100
|
+
|
101
|
+
expect(interaktor2).to receive(:call!).once.ordered.and_call_original
|
102
|
+
|
103
|
+
expect {
|
104
|
+
organizer.call(foo: "bar")
|
105
|
+
}.to raise_error(an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar]))
|
106
|
+
end
|
107
|
+
|
108
|
+
it "raises an exception if the organizer attributes do not satisfy a non-first interaktor" do
|
109
|
+
organizer.class_eval { required :foo }
|
110
|
+
|
111
|
+
interaktor2 = Class.new.include(Interaktor)
|
112
|
+
interaktor2.class_eval { required :foo }
|
113
|
+
|
114
|
+
interaktor3 = Class.new.include(Interaktor)
|
115
|
+
interaktor3.class_eval { required :bar }
|
116
|
+
|
117
|
+
allow(organizer).to receive(:organized).and_return([interaktor2, interaktor3])
|
118
|
+
|
119
|
+
expect(interaktor2).to receive(:call!).once.ordered.and_call_original
|
120
|
+
expect(interaktor3).to receive(:call!).once.ordered.and_call_original
|
121
|
+
|
122
|
+
expect {
|
123
|
+
organizer.call(foo: "bar")
|
124
|
+
}.to raise_error(an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar]))
|
57
125
|
end
|
58
126
|
end
|
59
127
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,8 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
require "simplecov"
|
2
|
+
SimpleCov.start do
|
3
|
+
enable_coverage :branch
|
4
|
+
|
5
|
+
add_filter "/spec/"
|
6
|
+
add_filter "/vendor/"
|
7
|
+
add_filter "/lib/interaktor/error"
|
4
8
|
end
|
5
9
|
|
10
|
+
Bundler.require(:default, :test)
|
6
11
|
require "interaktor"
|
7
12
|
|
8
13
|
Dir[File.expand_path("support/*.rb", __dir__)].sort.each { |f| require f }
|
data/spec/support/lint.rb
CHANGED
@@ -1,82 +1,51 @@
|
|
1
1
|
shared_examples "lint" do
|
2
|
-
let(:interaktor)
|
3
|
-
klass = Class.new.include(described_class)
|
4
|
-
klass.class_eval do
|
5
|
-
optional :foo
|
6
|
-
end
|
7
|
-
|
8
|
-
klass
|
9
|
-
end
|
2
|
+
let(:interaktor) { Class.new.include(described_class) }
|
10
3
|
|
11
4
|
describe ".call" do
|
12
|
-
let(:context) { instance_double(Interaktor::Context) }
|
13
5
|
let(:instance) { instance_double(interaktor) }
|
14
6
|
|
15
|
-
it "calls an instance
|
16
|
-
|
17
|
-
expect(interaktor).to receive(:new).once.with(foo: "bar").and_return(instance)
|
18
|
-
expect(instance).to receive(:run).once.with(no_args)
|
7
|
+
it "calls an instance" do
|
8
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
19
9
|
|
20
|
-
|
10
|
+
result = interaktor.call
|
21
11
|
|
22
|
-
expect(
|
12
|
+
expect(result.success?).to be true
|
23
13
|
end
|
24
14
|
|
25
|
-
it "
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
resulting_context = interaktor.call({})
|
15
|
+
it "fails when an unknown attribute is provided" do
|
16
|
+
expect {
|
17
|
+
interaktor.call(baz: "wadus")
|
18
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownAttributeError).and having_attributes(attributes: [:baz]))
|
19
|
+
end
|
31
20
|
|
32
|
-
|
21
|
+
it "fails when a non-hash or non-context argument is passed" do
|
22
|
+
expect {
|
23
|
+
interaktor.call("foo")
|
24
|
+
}.to raise_error(ArgumentError, /Expected a hash argument/)
|
33
25
|
end
|
34
26
|
end
|
35
27
|
|
36
28
|
describe ".call!" do
|
37
|
-
let(:context) { instance_double(Interaktor::Context) }
|
38
29
|
let(:instance) { instance_double(interaktor) }
|
39
30
|
|
40
|
-
it "calls an instance
|
41
|
-
|
42
|
-
expect(interaktor).to receive(:new).once.with(foo: "bar").and_return(instance)
|
43
|
-
expect(instance).to receive(:run!).once.with(no_args)
|
31
|
+
it "calls an instance" do
|
32
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
44
33
|
|
45
|
-
|
34
|
+
result = interaktor.call!
|
46
35
|
|
47
|
-
expect(
|
36
|
+
expect(result.success?).to be true
|
48
37
|
end
|
49
38
|
|
50
|
-
it "
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
resulting_context = interaktor.call!({})
|
56
|
-
|
57
|
-
expect(resulting_context).to eq(context)
|
58
|
-
end
|
59
|
-
end
|
60
|
-
|
61
|
-
describe ".new" do
|
62
|
-
let(:context) { instance_double(Interaktor::Context) }
|
63
|
-
|
64
|
-
it "initializes a context" do
|
65
|
-
expect(Interaktor::Context).to receive(:build).once.with(foo: "bar").and_return(context)
|
66
|
-
|
67
|
-
instance = interaktor.new(foo: "bar")
|
68
|
-
|
69
|
-
expect(instance).to be_an(interaktor)
|
70
|
-
expect(instance.instance_variable_get(:@context)).to eq(context)
|
39
|
+
it "fails when an unknown attribute is provided" do
|
40
|
+
expect {
|
41
|
+
interaktor.call!(baz: "wadus")
|
42
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownAttributeError).and having_attributes(attributes: [:baz]))
|
71
43
|
end
|
72
44
|
|
73
|
-
it "
|
74
|
-
expect
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
expect(instance).to be_a(interaktor)
|
79
|
-
expect(instance.instance_variable_get(:@context)).to eq(context)
|
45
|
+
it "fails when a non-hash or non-context argument is passed" do
|
46
|
+
expect {
|
47
|
+
interaktor.call!("foo")
|
48
|
+
}.to raise_error(ArgumentError, /Expected a hash argument/)
|
80
49
|
end
|
81
50
|
end
|
82
51
|
|
@@ -151,4 +120,267 @@ shared_examples "lint" do
|
|
151
120
|
expect { instance.method(:rollback) }.not_to raise_error
|
152
121
|
end
|
153
122
|
end
|
123
|
+
|
124
|
+
describe "required attributes" do
|
125
|
+
let(:instance) { instance_double(interaktor) }
|
126
|
+
|
127
|
+
it "initializes successfully when the attribute is provided" do
|
128
|
+
interaktor.class_eval { required :bar }
|
129
|
+
|
130
|
+
expect(interaktor).to receive(:new).once.with(bar: "baz").and_call_original
|
131
|
+
|
132
|
+
result = interaktor.call(bar: "baz")
|
133
|
+
|
134
|
+
expect(result.success?).to be true
|
135
|
+
expect(result.bar).to eq "baz"
|
136
|
+
end
|
137
|
+
|
138
|
+
it "creates a value setter" do
|
139
|
+
interaktor.class_eval { required :bar }
|
140
|
+
|
141
|
+
expect(interaktor).to receive(:new).once.with(bar: "baz").and_call_original
|
142
|
+
|
143
|
+
interaktor.define_method(:call) do
|
144
|
+
self.bar = "wadus"
|
145
|
+
end
|
146
|
+
|
147
|
+
result = interaktor.call(bar: "baz")
|
148
|
+
|
149
|
+
expect(result.success?).to be true
|
150
|
+
expect(result.bar).to eq "wadus"
|
151
|
+
end
|
152
|
+
|
153
|
+
it "raises an exception when the attribute is not provided" do
|
154
|
+
interaktor.class_eval { required :bar }
|
155
|
+
|
156
|
+
expect {
|
157
|
+
interaktor.call!
|
158
|
+
}.to raise_error(an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar]))
|
159
|
+
end
|
160
|
+
|
161
|
+
describe "options" do
|
162
|
+
it "raises an exception when an unknown option is provided" do
|
163
|
+
expect {
|
164
|
+
interaktor.class_eval { required :bar, unknown: true }
|
165
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownOptionError).and having_attributes(options: { unknown: true }))
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "optional attributes" do
|
171
|
+
let(:instance) { instance_double(interaktor) }
|
172
|
+
|
173
|
+
it "initializes successfully when the attribute is provided" do
|
174
|
+
interaktor.class_eval { optional :bar }
|
175
|
+
|
176
|
+
expect(interaktor).to receive(:new).once.with(bar: "baz").and_call_original
|
177
|
+
|
178
|
+
result = interaktor.call(bar: "baz")
|
179
|
+
|
180
|
+
expect(result.success?).to be true
|
181
|
+
expect(result.bar).to eq "baz"
|
182
|
+
end
|
183
|
+
|
184
|
+
it "initializes successfully when the attribute is not provided" do
|
185
|
+
interaktor.class_eval { optional :bar }
|
186
|
+
|
187
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
188
|
+
|
189
|
+
result = interaktor.call
|
190
|
+
|
191
|
+
expect(result.success?).to be true
|
192
|
+
expect(result.bar).to be_nil
|
193
|
+
end
|
194
|
+
|
195
|
+
it "creates a value setter" do
|
196
|
+
interaktor.class_eval { optional :bar }
|
197
|
+
|
198
|
+
expect(interaktor).to receive(:new).once.with(bar: "baz").and_call_original
|
199
|
+
|
200
|
+
interaktor.define_method(:call) do
|
201
|
+
self.bar = "wadus"
|
202
|
+
end
|
203
|
+
|
204
|
+
result = interaktor.call(bar: "baz")
|
205
|
+
|
206
|
+
expect(result.success?).to be true
|
207
|
+
expect(result.bar).to eq "wadus"
|
208
|
+
end
|
209
|
+
|
210
|
+
it "raises an exception when assigning a value to an optional parameter which was not originally provided" do
|
211
|
+
interaktor.class_eval { optional :bar }
|
212
|
+
|
213
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
214
|
+
|
215
|
+
interaktor.define_method(:call) do
|
216
|
+
self.bar = "baz"
|
217
|
+
end
|
218
|
+
|
219
|
+
expect { interaktor.call }.to(
|
220
|
+
raise_error(
|
221
|
+
an_instance_of(Interaktor::Error::DisallowedAttributeAssignmentError)
|
222
|
+
.and(having_attributes(attributes: [:bar]))
|
223
|
+
)
|
224
|
+
)
|
225
|
+
end
|
226
|
+
|
227
|
+
describe "options" do
|
228
|
+
it "accepts a default value for the attribute" do
|
229
|
+
interaktor.class_eval { optional :bar, default: "baz" }
|
230
|
+
|
231
|
+
expect(interaktor).to receive(:new).once.with(bar: "baz").and_call_original
|
232
|
+
|
233
|
+
result = interaktor.call
|
234
|
+
|
235
|
+
expect(result.success?).to be true
|
236
|
+
expect(result.bar).to eq "baz"
|
237
|
+
end
|
238
|
+
|
239
|
+
it "raises an exception when an unknown option is provided" do
|
240
|
+
expect {
|
241
|
+
interaktor.class_eval { optional :bar, unknown: true }
|
242
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownOptionError).and having_attributes(options: { unknown: true }))
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
describe "success attributes" do
|
248
|
+
it "succeeds when the correct attributes are provided" do
|
249
|
+
interaktor.class_eval { success :bar }
|
250
|
+
|
251
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
252
|
+
|
253
|
+
interaktor.define_method(:call) do
|
254
|
+
success!(bar: "baz")
|
255
|
+
end
|
256
|
+
|
257
|
+
result = interaktor.call
|
258
|
+
|
259
|
+
expect(result.success?).to be true
|
260
|
+
expect(result.bar).to eq "baz"
|
261
|
+
end
|
262
|
+
|
263
|
+
it "raises an exception when the correct attributes are not provided because #success! is not called" do
|
264
|
+
interaktor.class_eval { success :bar }
|
265
|
+
|
266
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
267
|
+
|
268
|
+
expect { interaktor.call }.to(
|
269
|
+
raise_error(
|
270
|
+
an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar])
|
271
|
+
)
|
272
|
+
)
|
273
|
+
end
|
274
|
+
|
275
|
+
it "raises an exception when the correct attributes are not provided in the call to #success!" do
|
276
|
+
interaktor.class_eval { success :bar }
|
277
|
+
|
278
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
279
|
+
|
280
|
+
interaktor.define_method(:call) do
|
281
|
+
success!({})
|
282
|
+
end
|
283
|
+
|
284
|
+
expect { interaktor.call }.to(
|
285
|
+
raise_error(
|
286
|
+
an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar])
|
287
|
+
)
|
288
|
+
)
|
289
|
+
end
|
290
|
+
|
291
|
+
it "raises an exception when unknown attributes are provided" do
|
292
|
+
interaktor.class_eval { success :bar }
|
293
|
+
|
294
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
295
|
+
|
296
|
+
interaktor.define_method(:call) do
|
297
|
+
success!(bar: "baz", baz: "wadus")
|
298
|
+
end
|
299
|
+
|
300
|
+
expect { interaktor.call }.to(
|
301
|
+
raise_error(
|
302
|
+
an_instance_of(Interaktor::Error::UnknownAttributeError).and having_attributes(attributes: [:baz])
|
303
|
+
)
|
304
|
+
)
|
305
|
+
end
|
306
|
+
|
307
|
+
describe "options" do
|
308
|
+
it "raises an exception when an unknown option is provided" do
|
309
|
+
expect {
|
310
|
+
interaktor.class_eval { success :bar, unknown: true }
|
311
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownOptionError).and having_attributes(options: { unknown: true }))
|
312
|
+
end
|
313
|
+
end
|
314
|
+
end
|
315
|
+
|
316
|
+
describe "failure attributes" do
|
317
|
+
it "fails when the correct attributes are provided" do
|
318
|
+
interaktor.class_eval { failure :bar }
|
319
|
+
|
320
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
321
|
+
|
322
|
+
interaktor.define_method(:call) do
|
323
|
+
fail!(bar: "baz")
|
324
|
+
end
|
325
|
+
|
326
|
+
result = interaktor.call
|
327
|
+
|
328
|
+
expect(result.success?).to be false
|
329
|
+
expect(result.bar).to eq "baz"
|
330
|
+
end
|
331
|
+
|
332
|
+
it "raises an exception when the correct attributes are not provided" do
|
333
|
+
interaktor.class_eval { failure :bar }
|
334
|
+
|
335
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
336
|
+
|
337
|
+
interaktor.define_method(:call) do
|
338
|
+
fail!({})
|
339
|
+
end
|
340
|
+
|
341
|
+
expect { interaktor.call }.to(
|
342
|
+
raise_error(
|
343
|
+
an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar])
|
344
|
+
)
|
345
|
+
)
|
346
|
+
end
|
347
|
+
|
348
|
+
context "when the interaktor is called with #call!" do
|
349
|
+
it "raises an exception when the correct attributes are provided" do
|
350
|
+
interaktor.class_eval { failure :bar }
|
351
|
+
|
352
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
353
|
+
|
354
|
+
interaktor.define_method(:call) do
|
355
|
+
fail!(bar: "baz")
|
356
|
+
end
|
357
|
+
|
358
|
+
expect { interaktor.call! }.to raise_error(Interaktor::Failure)
|
359
|
+
end
|
360
|
+
|
361
|
+
it "raises an exception when the correct attributes are not provided" do
|
362
|
+
interaktor.class_eval { failure :bar }
|
363
|
+
|
364
|
+
expect(interaktor).to receive(:new).once.with({}).and_call_original
|
365
|
+
|
366
|
+
interaktor.define_method(:call) do
|
367
|
+
fail!({})
|
368
|
+
end
|
369
|
+
|
370
|
+
expect { interaktor.call }.to(
|
371
|
+
raise_error(
|
372
|
+
an_instance_of(Interaktor::Error::MissingAttributeError).and having_attributes(attributes: [:bar])
|
373
|
+
)
|
374
|
+
)
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
describe "options" do
|
379
|
+
it "raises an exception when an unknown option is provided" do
|
380
|
+
expect {
|
381
|
+
interaktor.class_eval { failure :bar, unknown: true }
|
382
|
+
}.to raise_error(an_instance_of(Interaktor::Error::UnknownOptionError).and having_attributes(options: { unknown: true }))
|
383
|
+
end
|
384
|
+
end
|
385
|
+
end
|
154
386
|
end
|