interaktor 0.2.0 → 0.4.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.
@@ -0,0 +1,249 @@
1
+ RSpec.describe Interaktor::Organizer do
2
+ it_behaves_like "lint", described_class
3
+
4
+ describe ".organize" do
5
+ let(:interaktor2) { instance_double(Interaktor) }
6
+ let(:interaktor3) { instance_double(Interaktor) }
7
+
8
+ it "sets interaktors given class arguments" do
9
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
10
+
11
+ expect {
12
+ organizer.organize(interaktor2, interaktor3)
13
+ }.to change(organizer, :organized)
14
+ .from([])
15
+ .to([interaktor2, interaktor3])
16
+ end
17
+
18
+ it "sets interaktors given an array of classes" do
19
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
20
+
21
+ expect {
22
+ organizer.organize([interaktor2, interaktor3])
23
+ }.to change(organizer, :organized)
24
+ .from([])
25
+ .to([interaktor2, interaktor3])
26
+ end
27
+
28
+ it "allows multiple organize calls" do
29
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
30
+ interaktor4 = instance_double(Interaktor)
31
+
32
+ expect {
33
+ organizer.organize(interaktor2, interaktor3)
34
+ organizer.organize(interaktor4)
35
+ }.to change(organizer, :organized)
36
+ .from([])
37
+ .to([interaktor2, interaktor3, interaktor4])
38
+ end
39
+ end
40
+
41
+ describe ".organized" do
42
+ it "is empty by default" do
43
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
44
+
45
+ expect(organizer.organized).to eq([])
46
+ end
47
+ end
48
+
49
+ describe "#call" do
50
+ it "calls each interaktor in order" do
51
+ organizer = FakeInteraktor.build_interaktor(type: described_class) do
52
+ input { required(:foo) }
53
+ success { required(:foo) }
54
+ end
55
+
56
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1") do
57
+ input { required(:foo) }
58
+ success { required(:foo) }
59
+
60
+ def call
61
+ success!(foo: "bar")
62
+ end
63
+ end
64
+
65
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor2") do
66
+ input { required(:foo) }
67
+ success { required(:foo) }
68
+
69
+ def call
70
+ success!(foo: "baz")
71
+ end
72
+ end
73
+
74
+ interaktor3 = FakeInteraktor.build_interaktor("Interaktor3") do
75
+ input { required(:foo) }
76
+ success { required(:foo) }
77
+
78
+ def call
79
+ success!(foo: "wadus")
80
+ end
81
+ end
82
+
83
+ allow(organizer).to receive(:organized) {
84
+ [interaktor1, interaktor2, interaktor3]
85
+ }
86
+
87
+ expect(interaktor1).to receive(:call!).once.ordered.and_call_original
88
+ expect(interaktor2).to receive(:call!).once.ordered.and_call_original
89
+ expect(interaktor3).to receive(:call!).once.ordered.and_call_original
90
+
91
+ result = organizer.call(foo: "asdf")
92
+
93
+ expect(result.foo).to eq "wadus"
94
+ end
95
+
96
+ it "calls each interaktor in order and passes success attributes" do
97
+ organizer = FakeInteraktor.build_interaktor(type: described_class) { input { required(:foo) } }
98
+
99
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1") do
100
+ input { required(:foo) }
101
+ success { required(:bar) }
102
+
103
+ def call
104
+ success!(bar: "baz")
105
+ end
106
+ end
107
+
108
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor1") do
109
+ input { required(:bar) }
110
+
111
+ def call
112
+ self.bar = "wadus"
113
+ end
114
+ end
115
+
116
+ allow(organizer).to receive(:organized) {
117
+ [interaktor1, interaktor2]
118
+ }
119
+
120
+ expect(interaktor1).to receive(:call!).once.ordered.and_call_original
121
+ expect(interaktor2).to receive(:call!).once.ordered.and_call_original
122
+
123
+ result = organizer.call(foo: "asdf")
124
+
125
+ expect(result.bar).to eq "wadus"
126
+ end
127
+
128
+ it "allows an interaktor to accept required attributes from previous success attributes" do
129
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
130
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1") do
131
+ success { required(:foo) }
132
+
133
+ def call
134
+ success!(foo: "whatever")
135
+ end
136
+ end
137
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor2") do
138
+ success { required(:bar) }
139
+
140
+ def call
141
+ success!(bar: "whatever")
142
+ end
143
+ end
144
+ interaktor3 = FakeInteraktor.build_interaktor("Interaktor3") do
145
+ input do
146
+ required(:foo)
147
+ required(:bar)
148
+ end
149
+ end
150
+
151
+ allow(organizer).to receive(:organized).and_return([interaktor1, interaktor2, interaktor3])
152
+
153
+ expect(interaktor1).to receive(:call!).once.ordered.and_call_original
154
+ expect(interaktor2).to receive(:call!).once.ordered.and_call_original
155
+ expect(interaktor3).to receive(:call!).once.ordered.and_call_original
156
+
157
+ organizer.call
158
+ end
159
+
160
+ it "allows an interaktor to accept required attributes from the original organizer" do
161
+ organizer = FakeInteraktor.build_interaktor(type: described_class) do
162
+ input do
163
+ required(:foo)
164
+ required(:bar)
165
+ end
166
+ end
167
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1")
168
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor2") { input { required(:foo) } }
169
+ interaktor3 = FakeInteraktor.build_interaktor("Interaktor3") { input { required(:bar) } }
170
+
171
+ allow(organizer).to receive(:organized).and_return([interaktor1, interaktor2, interaktor3])
172
+
173
+ expect(interaktor1).to receive(:call!).once.ordered.and_call_original
174
+ expect(interaktor2).to receive(:call!).once.ordered.and_call_original
175
+ expect(interaktor3).to receive(:call!).once.ordered.and_call_original
176
+
177
+ organizer.call(foo: "whatever", bar: "baz")
178
+ end
179
+
180
+ it "allows an interaktor to accept required attributes from the original organizer AND previous success attributes" do
181
+ organizer = FakeInteraktor.build_interaktor(type: described_class) { input { required(:foo) } }
182
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1") do
183
+ success { required(:bar) }
184
+
185
+ def call
186
+ success!(bar: "whatever")
187
+ end
188
+ end
189
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor2") do
190
+ success { required(:baz) }
191
+
192
+ def call
193
+ success!(baz: "whatever")
194
+ end
195
+ end
196
+ interaktor3 = FakeInteraktor.build_interaktor("Interaktor3") do
197
+ input do
198
+ required(:foo)
199
+ required(:bar)
200
+ required(:baz)
201
+ end
202
+ end
203
+
204
+ allow(organizer).to receive(:organized).and_return([interaktor1, interaktor2, interaktor3])
205
+
206
+ expect(interaktor1).to receive(:call!).once.ordered.and_call_original
207
+ expect(interaktor2).to receive(:call!).once.ordered.and_call_original
208
+ expect(interaktor3).to receive(:call!).once.ordered.and_call_original
209
+
210
+ organizer.call(foo: "whatever")
211
+ end
212
+
213
+ it "raises an exception if an interaktor requires an input attribute not provided by any previous interaktor" do
214
+ organizer = FakeInteraktor.build_interaktor(type: described_class)
215
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1")
216
+ interaktor2 = FakeInteraktor.build_interaktor("Interaktor2") { input { required(:foo) } }
217
+
218
+ allow(organizer).to receive(:organized).and_return([interaktor1, interaktor2])
219
+
220
+ expect(interaktor1).not_to receive(:call!)
221
+
222
+ expect {
223
+ organizer.call
224
+ }.to raise_error(
225
+ an_instance_of(Interaktor::Error::OrganizerMissingPassedAttributeError)
226
+ .and(having_attributes(
227
+ attribute: :foo,
228
+ interaktor: interaktor2,
229
+ ))
230
+ )
231
+ end
232
+
233
+ it "raises an exception if the organizer's last interaktor does not include the organizer's success attributes" do
234
+ organizer = FakeInteraktor.build_interaktor(type: described_class) { success { required(:final) } }
235
+ interaktor1 = FakeInteraktor.build_interaktor("Interaktor1")
236
+
237
+ allow(organizer).to receive(:organized).and_return([interaktor1])
238
+
239
+ expect(interaktor1).not_to receive(:call!)
240
+
241
+ expect {
242
+ organizer.call
243
+ }.to raise_error(
244
+ an_instance_of(Interaktor::Error::OrganizerSuccessAttributeMissingError)
245
+ .and(having_attributes(attribute: :final, interaktor: interaktor1))
246
+ )
247
+ end
248
+ end
249
+ end
@@ -1,3 +1,3 @@
1
- describe Interaktor do
2
- include_examples "lint"
1
+ RSpec.describe Interaktor do
2
+ it_behaves_like "lint", described_class
3
3
  end
data/spec/spec_helper.rb CHANGED
@@ -1,3 +1,23 @@
1
+ RSpec.configure do |config|
2
+ config.expect_with :rspec do |expectations|
3
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
4
+ end
5
+
6
+ config.mock_with :rspec do |mocks|
7
+ mocks.verify_partial_doubles = true
8
+ end
9
+
10
+ config.shared_context_metadata_behavior = :apply_to_host_groups
11
+ config.filter_run_when_matching :focus
12
+ config.example_status_persistence_file_path = "spec/examples.txt"
13
+ config.disable_monkey_patching!
14
+ config.order = :random
15
+
16
+ config.default_formatter = "doc" if config.files_to_run.one?
17
+
18
+ Kernel.srand config.seed
19
+ end
20
+
1
21
  require "simplecov"
2
22
  SimpleCov.start do
3
23
  enable_coverage :branch
@@ -0,0 +1,14 @@
1
+ class FakeInteraktor
2
+ # @param name [String]
3
+ def self.build_interaktor(name = nil, type: Interaktor, &block)
4
+ name ||= "MyTest#{type}"
5
+
6
+ result = Class.new.include(type)
7
+
8
+ result.class_eval(&block) if block
9
+ result.define_singleton_method(:inspect) { name.to_s }
10
+ result.define_singleton_method(:to_s) { inspect }
11
+
12
+ result
13
+ end
14
+ end