interactor_with_steroids 0.0.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.
@@ -0,0 +1,358 @@
1
+ module Interactor
2
+ describe Hooks do
3
+ describe "#with_hooks" do
4
+ def build_hooked(&block)
5
+ hooked = Class.new.send(:include, Interactor::Hooks)
6
+
7
+ hooked.class_eval do
8
+ attr_reader :steps
9
+
10
+ def self.process
11
+ new.tap(&:process).steps
12
+ end
13
+
14
+ def initialize
15
+ @steps = []
16
+ end
17
+
18
+ def process
19
+ with_hooks { steps << :process }
20
+ end
21
+ end
22
+
23
+ hooked.class_eval(&block) if block
24
+ hooked
25
+ end
26
+
27
+ context "with an around hook method" do
28
+ let(:hooked) {
29
+ build_hooked do
30
+ around :add_around_before_and_around_after
31
+
32
+ private
33
+
34
+ def add_around_before_and_around_after(hooked)
35
+ steps << :around_before
36
+ hooked.call
37
+ steps << :around_after
38
+ end
39
+ end
40
+ }
41
+
42
+ it "runs the around hook method" do
43
+ expect(hooked.process).to eq([
44
+ :around_before,
45
+ :process,
46
+ :around_after,
47
+ ])
48
+ end
49
+ end
50
+
51
+ context "with an around hook block" do
52
+ let(:hooked) {
53
+ build_hooked do
54
+ around do |hooked|
55
+ steps << :around_before
56
+ hooked.call
57
+ steps << :around_after
58
+ end
59
+ end
60
+ }
61
+
62
+ it "runs the around hook block" do
63
+ expect(hooked.process).to eq([
64
+ :around_before,
65
+ :process,
66
+ :around_after,
67
+ ])
68
+ end
69
+ end
70
+
71
+ context "with an around hook method and block in one call" do
72
+ let(:hooked) {
73
+ build_hooked do
74
+ around :add_around_before1_and_around_after1 do |hooked|
75
+ steps << :around_before2
76
+ hooked.call
77
+ steps << :around_after2
78
+ end
79
+
80
+ private
81
+
82
+ def add_around_before1_and_around_after1(hooked)
83
+ steps << :around_before1
84
+ hooked.call
85
+ steps << :around_after1
86
+ end
87
+ end
88
+ }
89
+
90
+ it "runs the around hook method and block in order" do
91
+ expect(hooked.process).to eq([
92
+ :around_before1,
93
+ :around_before2,
94
+ :process,
95
+ :around_after2,
96
+ :around_after1,
97
+ ])
98
+ end
99
+ end
100
+
101
+ context "with an around hook method and block in multiple calls" do
102
+ let(:hooked) {
103
+ build_hooked do
104
+ around do |hooked|
105
+ steps << :around_before1
106
+ hooked.call
107
+ steps << :around_after1
108
+ end
109
+
110
+ around :add_around_before2_and_around_after2
111
+
112
+ private
113
+
114
+ def add_around_before2_and_around_after2(hooked)
115
+ steps << :around_before2
116
+ hooked.call
117
+ steps << :around_after2
118
+ end
119
+ end
120
+ }
121
+
122
+ it "runs the around hook block and method in order" do
123
+ expect(hooked.process).to eq([
124
+ :around_before1,
125
+ :around_before2,
126
+ :process,
127
+ :around_after2,
128
+ :around_after1,
129
+ ])
130
+ end
131
+ end
132
+
133
+ context "with a before hook method" do
134
+ let(:hooked) {
135
+ build_hooked do
136
+ before :add_before
137
+
138
+ private
139
+
140
+ def add_before
141
+ steps << :before
142
+ end
143
+ end
144
+ }
145
+
146
+ it "runs the before hook method" do
147
+ expect(hooked.process).to eq([
148
+ :before,
149
+ :process,
150
+ ])
151
+ end
152
+ end
153
+
154
+ context "with a before hook block" do
155
+ let(:hooked) {
156
+ build_hooked do
157
+ before do
158
+ steps << :before
159
+ end
160
+ end
161
+ }
162
+
163
+ it "runs the before hook block" do
164
+ expect(hooked.process).to eq([
165
+ :before,
166
+ :process,
167
+ ])
168
+ end
169
+ end
170
+
171
+ context "with a before hook method and block in one call" do
172
+ let(:hooked) {
173
+ build_hooked do
174
+ before :add_before1 do
175
+ steps << :before2
176
+ end
177
+
178
+ private
179
+
180
+ def add_before1
181
+ steps << :before1
182
+ end
183
+ end
184
+ }
185
+
186
+ it "runs the before hook method and block in order" do
187
+ expect(hooked.process).to eq([
188
+ :before1,
189
+ :before2,
190
+ :process,
191
+ ])
192
+ end
193
+ end
194
+
195
+ context "with a before hook method and block in multiple calls" do
196
+ let(:hooked) {
197
+ build_hooked do
198
+ before do
199
+ steps << :before1
200
+ end
201
+
202
+ before :add_before2
203
+
204
+ private
205
+
206
+ def add_before2
207
+ steps << :before2
208
+ end
209
+ end
210
+ }
211
+
212
+ it "runs the before hook block and method in order" do
213
+ expect(hooked.process).to eq([
214
+ :before1,
215
+ :before2,
216
+ :process,
217
+ ])
218
+ end
219
+ end
220
+
221
+ context "with an after hook method" do
222
+ let(:hooked) {
223
+ build_hooked do
224
+ after :add_after
225
+
226
+ private
227
+
228
+ def add_after
229
+ steps << :after
230
+ end
231
+ end
232
+ }
233
+
234
+ it "runs the after hook method" do
235
+ expect(hooked.process).to eq([
236
+ :process,
237
+ :after,
238
+ ])
239
+ end
240
+ end
241
+
242
+ context "with an after hook block" do
243
+ let(:hooked) {
244
+ build_hooked do
245
+ after do
246
+ steps << :after
247
+ end
248
+ end
249
+ }
250
+
251
+ it "runs the after hook block" do
252
+ expect(hooked.process).to eq([
253
+ :process,
254
+ :after,
255
+ ])
256
+ end
257
+ end
258
+
259
+ context "with an after hook method and block in one call" do
260
+ let(:hooked) {
261
+ build_hooked do
262
+ after :add_after1 do
263
+ steps << :after2
264
+ end
265
+
266
+ private
267
+
268
+ def add_after1
269
+ steps << :after1
270
+ end
271
+ end
272
+ }
273
+
274
+ it "runs the after hook method and block in order" do
275
+ expect(hooked.process).to eq([
276
+ :process,
277
+ :after2,
278
+ :after1,
279
+ ])
280
+ end
281
+ end
282
+
283
+ context "with an after hook method and block in multiple calls" do
284
+ let(:hooked) {
285
+ build_hooked do
286
+ after do
287
+ steps << :after1
288
+ end
289
+
290
+ after :add_after2
291
+
292
+ private
293
+
294
+ def add_after2
295
+ steps << :after2
296
+ end
297
+ end
298
+ }
299
+
300
+ it "runs the after hook block and method in order" do
301
+ expect(hooked.process).to eq([
302
+ :process,
303
+ :after2,
304
+ :after1,
305
+ ])
306
+ end
307
+ end
308
+
309
+ context "with around, before and after hooks" do
310
+ let(:hooked) {
311
+ build_hooked do
312
+ around do |hooked|
313
+ steps << :around_before1
314
+ hooked.call
315
+ steps << :around_after1
316
+ end
317
+
318
+ around do |hooked|
319
+ steps << :around_before2
320
+ hooked.call
321
+ steps << :around_after2
322
+ end
323
+
324
+ before do
325
+ steps << :before1
326
+ end
327
+
328
+ before do
329
+ steps << :before2
330
+ end
331
+
332
+ after do
333
+ steps << :after1
334
+ end
335
+
336
+ after do
337
+ steps << :after2
338
+ end
339
+ end
340
+ }
341
+
342
+ it "runs hooks in the proper order" do
343
+ expect(hooked.process).to eq([
344
+ :around_before1,
345
+ :around_before2,
346
+ :before1,
347
+ :before2,
348
+ :process,
349
+ :after2,
350
+ :after1,
351
+ :around_after2,
352
+ :around_after1,
353
+ ])
354
+ end
355
+ end
356
+ end
357
+ end
358
+ end
@@ -0,0 +1,60 @@
1
+ module Interactor
2
+ describe Organizer do
3
+ let(:organizer) {
4
+ Class.new do
5
+ include Organizer
6
+ include Declaration
7
+ end
8
+ }
9
+
10
+ describe ".organize" do
11
+ let(:interactor2) { double(:interactor2) }
12
+ let(:interactor3) { double(:interactor3) }
13
+
14
+ it "sets interactors given class arguments" do
15
+ expect {
16
+ organizer.organize(interactor2, interactor3)
17
+ }.to change {
18
+ organizer.organized
19
+ }.from([]).to([interactor2, interactor3])
20
+ end
21
+
22
+ it "sets interactors given an array of classes" do
23
+ expect {
24
+ organizer.organize([interactor2, interactor3])
25
+ }.to change {
26
+ organizer.organized
27
+ }.from([]).to([interactor2, interactor3])
28
+ end
29
+ end
30
+
31
+ describe ".organized" do
32
+ it "is empty by default" do
33
+ expect(organizer.organized).to eq([])
34
+ end
35
+ end
36
+
37
+ describe "#call" do
38
+ let(:instance) { organizer.new }
39
+ let(:context) { double(:context) }
40
+ let(:interactor2) { Class.new.send(:include, Interactor) }
41
+ let(:interactor3) { Class.new.send(:include, Interactor) }
42
+ let(:interactor4) { Class.new.send(:include, Interactor) }
43
+
44
+ before do
45
+ allow(instance).to receive(:context) { context }
46
+ allow(organizer).to receive(:organized) {
47
+ [interactor2, interactor3, interactor4]
48
+ }
49
+ end
50
+
51
+ it "calls each interactor in order with the context" do
52
+ expect(interactor2).to receive(:call!).once.ordered
53
+ expect(interactor3).to receive(:call!).once.ordered
54
+ expect(interactor4).to receive(:call!).once.ordered
55
+
56
+ instance.call
57
+ end
58
+ end
59
+ end
60
+ end
@@ -0,0 +1,127 @@
1
+ describe Interactor do
2
+ let(:interactor) { Class.new.send(:include, described_class) }
3
+
4
+ describe ".call" do
5
+ let(:context) { double(:context) }
6
+ let(:instance) { double(:instance, context: context) }
7
+
8
+ it "calls an instance with the given context" do
9
+ expect(interactor).to receive(:new).once.with(foo: "bar") { instance }
10
+ expect(instance).to receive(:run).once.with(no_args)
11
+
12
+ expect(interactor.call(foo: "bar")).to eq(context)
13
+ end
14
+
15
+ it "provides a blank context if none is given" do
16
+ expect(interactor).to receive(:new).once.with({}) { instance }
17
+ expect(instance).to receive(:run).once.with(no_args)
18
+
19
+ expect(interactor.call).to eq(context)
20
+ end
21
+ end
22
+
23
+ describe ".call!" do
24
+ let(:context) { double(:context) }
25
+ let(:instance) { double(:instance, context: context) }
26
+
27
+ it "calls an instance with the given context" do
28
+ expect(interactor).to receive(:new).once.with(foo: "bar") { instance }
29
+ expect(instance).to receive(:run!).once.with(no_args)
30
+
31
+ expect(interactor.call!(foo: "bar")).to eq(context)
32
+ end
33
+
34
+ it "provides a blank context if none is given" do
35
+ expect(interactor).to receive(:new).once.with({}) { instance }
36
+ expect(instance).to receive(:run!).once.with(no_args)
37
+
38
+ expect(interactor.call!).to eq(context)
39
+ end
40
+ end
41
+
42
+ describe ".new" do
43
+ let(:context) { double(:context) }
44
+
45
+ it "initializes a context" do
46
+ expect(Interactor::Context).to receive(:build).once.with(foo: "bar") { context }
47
+
48
+ instance = interactor.new(foo: "bar")
49
+
50
+ expect(instance).to be_a(interactor)
51
+ expect(instance.context).to eq(context)
52
+ end
53
+
54
+ it "initializes a blank context if none is given" do
55
+ expect(Interactor::Context).to receive(:build).once.with({}) { context }
56
+
57
+ instance = interactor.new
58
+
59
+ expect(instance).to be_a(interactor)
60
+ expect(instance.context).to eq(context)
61
+ end
62
+ end
63
+
64
+ describe "#run" do
65
+ let(:instance) { interactor.new }
66
+
67
+ it "runs the interactor" do
68
+ expect(instance).to receive(:run!).once.with(no_args)
69
+
70
+ instance.run
71
+ end
72
+
73
+ it "rescues failure" do
74
+ expect(instance).to receive(:run!).and_raise(Interactor::Failure)
75
+
76
+ expect {
77
+ instance.run
78
+ }.not_to raise_error
79
+ end
80
+
81
+ it "raises other errors" do
82
+ expect(instance).to receive(:run!).and_raise("foo")
83
+
84
+ expect {
85
+ instance.run
86
+ }.to raise_error("foo")
87
+ end
88
+ end
89
+
90
+ describe "#run!" do
91
+ let(:instance) { interactor.new(context) }
92
+ let(:context) { double(:context, to_h: {}) }
93
+
94
+ it "calls the interactor" do
95
+ expect(instance).to receive(:call).once.with(no_args)
96
+
97
+ instance.run!
98
+ end
99
+
100
+ it "raises failure" do
101
+ expect(instance).to receive(:call).and_raise(Interactor::Failure)
102
+ expect(instance.context).to receive(:fail!).and_raise(Interactor::Failure)
103
+
104
+ expect {
105
+ instance.run!
106
+ }.to raise_error(Interactor::Failure)
107
+ end
108
+
109
+ it "raises other errors" do
110
+ expect(instance).to receive(:run!).and_raise("foo")
111
+
112
+ expect {
113
+ instance.run
114
+ }.to raise_error("foo")
115
+ end
116
+ end
117
+
118
+ describe "#call" do
119
+ let(:instance) { interactor.new }
120
+
121
+ it "exists" do
122
+ expect(instance).to respond_to(:call)
123
+ expect { instance.call }.not_to raise_error
124
+ expect { instance.method(:call) }.not_to raise_error
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,6 @@
1
+ if ENV["CODECLIMATE_REPO_TOKEN"]
2
+ require "simplecov"
3
+ SimpleCov.start
4
+ end
5
+
6
+ require "interactor"
metadata ADDED
@@ -0,0 +1,113 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: interactor_with_steroids
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Collective Idea/Sorare Team
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-01-09 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: activesupport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Interactor provides a common interface for performing complex user interactions.
56
+ email: hello@sorare.com
57
+ executables: []
58
+ extensions: []
59
+ extra_rdoc_files: []
60
+ files:
61
+ - ".gitignore"
62
+ - ".rspec"
63
+ - ".standard.yml"
64
+ - ".travis.yml"
65
+ - CHANGELOG.md
66
+ - CONTRIBUTING.md
67
+ - Gemfile
68
+ - LICENSE.txt
69
+ - README.md
70
+ - Rakefile
71
+ - interactor.gemspec
72
+ - lib/interactor.rb
73
+ - lib/interactor/context.rb
74
+ - lib/interactor/declaration.rb
75
+ - lib/interactor/error.rb
76
+ - lib/interactor/hooks.rb
77
+ - lib/interactor/organizer.rb
78
+ - spec/interactor/context_spec.rb
79
+ - spec/interactor/declaration_spec.rb
80
+ - spec/interactor/hooks_spec.rb
81
+ - spec/interactor/organizer_spec.rb
82
+ - spec/interactor_spec.rb
83
+ - spec/spec_helper.rb
84
+ homepage: https://github.com/sorare/interactor
85
+ licenses:
86
+ - MIT
87
+ metadata: {}
88
+ post_install_message:
89
+ rdoc_options: []
90
+ require_paths:
91
+ - lib
92
+ required_ruby_version: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ required_rubygems_version: !ruby/object:Gem::Requirement
98
+ requirements:
99
+ - - ">="
100
+ - !ruby/object:Gem::Version
101
+ version: '0'
102
+ requirements: []
103
+ rubygems_version: 3.1.6
104
+ signing_key:
105
+ specification_version: 4
106
+ summary: Simple interactor implementation
107
+ test_files:
108
+ - spec/interactor/context_spec.rb
109
+ - spec/interactor/declaration_spec.rb
110
+ - spec/interactor/hooks_spec.rb
111
+ - spec/interactor/organizer_spec.rb
112
+ - spec/interactor_spec.rb
113
+ - spec/spec_helper.rb