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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.rspec +3 -0
- data/.standard.yml +4 -0
- data/.travis.yml +37 -0
- data/CHANGELOG.md +50 -0
- data/CONTRIBUTING.md +49 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +602 -0
- data/Rakefile +7 -0
- data/interactor.gemspec +20 -0
- data/lib/interactor/context.rb +139 -0
- data/lib/interactor/declaration.rb +85 -0
- data/lib/interactor/error.rb +31 -0
- data/lib/interactor/hooks.rb +263 -0
- data/lib/interactor/organizer.rb +69 -0
- data/lib/interactor.rb +158 -0
- data/spec/interactor/context_spec.rb +141 -0
- data/spec/interactor/declaration_spec.rb +116 -0
- data/spec/interactor/hooks_spec.rb +358 -0
- data/spec/interactor/organizer_spec.rb +60 -0
- data/spec/interactor_spec.rb +127 -0
- data/spec/spec_helper.rb +6 -0
- metadata +113 -0
@@ -0,0 +1,139 @@
|
|
1
|
+
require "active_support/core_ext/module/delegation"
|
2
|
+
|
3
|
+
module Interactor
|
4
|
+
# Public: The object for tracking state of an Interactor's invocation. The
|
5
|
+
# context is used to initialize the interactor with the information required
|
6
|
+
# for invocation. The interactor manipulates the context to produce the result
|
7
|
+
# of invocation.
|
8
|
+
#
|
9
|
+
# The context is the mechanism by which success and failure are determined and
|
10
|
+
# the context is responsible for tracking individual interactor invocations
|
11
|
+
# for the purpose of rollback.
|
12
|
+
#
|
13
|
+
# The context may be manipulated using arbitrary getter and setter methods.
|
14
|
+
#
|
15
|
+
# Examples
|
16
|
+
#
|
17
|
+
# context = Interactor::Context.new
|
18
|
+
# # => #<Interactor::Context>
|
19
|
+
# context.foo = "bar"
|
20
|
+
# # => "bar"
|
21
|
+
# context
|
22
|
+
# # => #<Interactor::Context foo="bar">
|
23
|
+
# context.hello = "world"
|
24
|
+
# # => "world"
|
25
|
+
# context
|
26
|
+
# # => #<Interactor::Context foo="bar" hello="world">
|
27
|
+
# context.foo = "baz"
|
28
|
+
# # => "baz"
|
29
|
+
# context
|
30
|
+
# # => #<Interactor::Context foo="baz" hello="world">
|
31
|
+
class Context
|
32
|
+
# Internal: Initialize an Interactor::Context or preserve an existing one.
|
33
|
+
# If the argument given is an Interactor::Context, the argument is returned.
|
34
|
+
# Otherwise, a new Interactor::Context is initialized from the provided
|
35
|
+
# hash.
|
36
|
+
#
|
37
|
+
# The "build" method is used during interactor initialization.
|
38
|
+
#
|
39
|
+
# context - A Hash whose key/value pairs are used in initializing a new
|
40
|
+
# Interactor::Context object. If an existing Interactor::Context
|
41
|
+
# is given, it is simply returned. (default: {})
|
42
|
+
#
|
43
|
+
# Examples
|
44
|
+
#
|
45
|
+
# context = Interactor::Context.build(foo: "bar")
|
46
|
+
# # => #<Interactor::Context foo="bar">
|
47
|
+
# context.object_id
|
48
|
+
# # => 2170969340
|
49
|
+
# context = Interactor::Context.build(context)
|
50
|
+
# # => #<Interactor::Context foo="bar">
|
51
|
+
# context.object_id
|
52
|
+
# # => 2170969340
|
53
|
+
#
|
54
|
+
# Returns the Interactor::Context.
|
55
|
+
def self.build(context = {})
|
56
|
+
new(**context.to_h)
|
57
|
+
end
|
58
|
+
|
59
|
+
attr_accessor :error
|
60
|
+
delegate :to_s, to: :to_h
|
61
|
+
|
62
|
+
def initialize(*)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Public: Whether the Interactor::Context is successful. By default, a new
|
66
|
+
# context is successful and only changes when explicitly failed.
|
67
|
+
#
|
68
|
+
# The "success?" method is the inverse of the "failure?" method.
|
69
|
+
#
|
70
|
+
# Examples
|
71
|
+
#
|
72
|
+
# context = Interactor::Context.new
|
73
|
+
# # => #<Interactor::Context>
|
74
|
+
# context.success?
|
75
|
+
# # => true
|
76
|
+
# context.fail!
|
77
|
+
# # => Interactor::Failure: #<Interactor::Context>
|
78
|
+
# context.success?
|
79
|
+
# # => false
|
80
|
+
#
|
81
|
+
# Returns true by default or false if failed.
|
82
|
+
def success?
|
83
|
+
!failure?
|
84
|
+
end
|
85
|
+
|
86
|
+
# Public: Whether the Interactor::Context has failed. By default, a new
|
87
|
+
# context is successful and only changes when explicitly failed.
|
88
|
+
#
|
89
|
+
# The "failure?" method is the inverse of the "success?" method.
|
90
|
+
#
|
91
|
+
# Examples
|
92
|
+
#
|
93
|
+
# context = Interactor::Context.new
|
94
|
+
# # => #<Interactor::Context>
|
95
|
+
# context.failure?
|
96
|
+
# # => false
|
97
|
+
# context.fail!
|
98
|
+
# # => Interactor::Failure: #<Interactor::Context>
|
99
|
+
# context.failure?
|
100
|
+
# # => true
|
101
|
+
#
|
102
|
+
# Returns false by default or true if failed.
|
103
|
+
def failure?
|
104
|
+
@failure || false
|
105
|
+
end
|
106
|
+
|
107
|
+
# Public: Fail the Interactor::Context. Failing a context raises an error
|
108
|
+
# that may be rescued by the calling interactor. The context is also flagged
|
109
|
+
# as having failed.
|
110
|
+
#
|
111
|
+
# Optionally the caller may provide a hash of key/value pairs to be merged
|
112
|
+
# into the context before failure.
|
113
|
+
#
|
114
|
+
# context - A Hash whose key/value pairs are merged into the existing
|
115
|
+
# Interactor::Context instance. (default: {})
|
116
|
+
#
|
117
|
+
# Examples
|
118
|
+
#
|
119
|
+
# context = Interactor::Context.new
|
120
|
+
# # => #<Interactor::Context>
|
121
|
+
# context.fail!
|
122
|
+
# # => Interactor::Failure: #<Interactor::Context>
|
123
|
+
# context.fail! rescue false
|
124
|
+
# # => false
|
125
|
+
# context.fail!(foo: "baz")
|
126
|
+
# # => Interactor::Failure: #<Interactor::Context foo="baz">
|
127
|
+
#
|
128
|
+
# Raises Interactor::Failure initialized with the Interactor::Context.
|
129
|
+
def fail!(error: nil)
|
130
|
+
self.error = error
|
131
|
+
@failure = true
|
132
|
+
raise Failure, self
|
133
|
+
end
|
134
|
+
|
135
|
+
def to_h
|
136
|
+
{ error: error }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
|
2
|
+
require "active_support/core_ext/module/delegation"
|
3
|
+
require "active_support/core_ext/class/attribute"
|
4
|
+
require "active_support/concern"
|
5
|
+
|
6
|
+
module Interactor
|
7
|
+
# Internal: Methods relating to declaring what we receive and what will be stored in the context.
|
8
|
+
module Declaration
|
9
|
+
extend ActiveSupport::Concern
|
10
|
+
|
11
|
+
included do
|
12
|
+
class_attribute :context_class, instance_writer: false, default: Context
|
13
|
+
end
|
14
|
+
|
15
|
+
class_methods do
|
16
|
+
def receive(*required_arguments, **optional_arguments)
|
17
|
+
@required_arguments ||= []
|
18
|
+
new_required_arguments = required_arguments - @required_arguments
|
19
|
+
@required_arguments += new_required_arguments
|
20
|
+
|
21
|
+
delegate(*new_required_arguments, to: :context) unless new_required_arguments.empty?
|
22
|
+
delegate(*optional_arguments.keys, to: :context) unless optional_arguments.empty?
|
23
|
+
|
24
|
+
attributes = [*new_required_arguments, *optional_arguments.keys]
|
25
|
+
|
26
|
+
self.context_class = Class.new(context_class) do
|
27
|
+
attr_accessor *new_required_arguments
|
28
|
+
attr_writer *optional_arguments.keys
|
29
|
+
|
30
|
+
optional_arguments.each do |k, v|
|
31
|
+
define_method(k) do
|
32
|
+
ivar = "@#{k}"
|
33
|
+
return instance_variable_get(ivar) if instance_variable_defined?(ivar)
|
34
|
+
|
35
|
+
instance_variable_set(ivar, v.is_a?(Proc) ? instance_eval(&v) : v)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
class_eval %Q<
|
40
|
+
def initialize(
|
41
|
+
#{new_required_arguments.map { |a| "#{a}:" }.join(', ')}#{new_required_arguments.empty? ? '' : ', '}
|
42
|
+
**rest
|
43
|
+
)
|
44
|
+
super(**rest)
|
45
|
+
|
46
|
+
#{new_required_arguments.map { |a| "self.#{a} = #{a}" }.join(';')}
|
47
|
+
|
48
|
+
#{
|
49
|
+
optional_arguments.keys.map do |k|
|
50
|
+
"instance_variable_set('@#{k}', rest[:#{k}]) if rest.key?(:#{k})"
|
51
|
+
end.join("\n")
|
52
|
+
}
|
53
|
+
end
|
54
|
+
>
|
55
|
+
|
56
|
+
class_eval %Q<
|
57
|
+
def to_h
|
58
|
+
super.merge(
|
59
|
+
#{attributes.map { |a| "#{a}: self.#{a}"}.join(', ')}
|
60
|
+
)
|
61
|
+
end
|
62
|
+
>
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def hold(*held_fields)
|
67
|
+
@held_fields ||= []
|
68
|
+
@held_fields += held_fields
|
69
|
+
|
70
|
+
delegate(*@held_fields, to: :context)
|
71
|
+
|
72
|
+
self.context_class = Class.new(context_class) do
|
73
|
+
attr_accessor *held_fields
|
74
|
+
|
75
|
+
class_eval %Q<
|
76
|
+
def to_h
|
77
|
+
super.merge(#{held_fields.map { |f| "#{f}: self.#{f}"}.join(', ')})
|
78
|
+
end
|
79
|
+
>
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module Interactor
|
2
|
+
# Internal: Error raised during Interactor::Context failure. The error stores
|
3
|
+
# a copy of the failed context for debugging purposes.
|
4
|
+
class Failure < StandardError
|
5
|
+
# Internal: Gets the Interactor::Context of the Interactor::Failure
|
6
|
+
# instance.
|
7
|
+
attr_reader :context
|
8
|
+
|
9
|
+
# Internal: Initialize an Interactor::Failure.
|
10
|
+
#
|
11
|
+
# context - An Interactor::Context to be stored within the
|
12
|
+
# Interactor::Failure instance. (default: nil)
|
13
|
+
#
|
14
|
+
# Examples
|
15
|
+
#
|
16
|
+
# Interactor::Failure.new
|
17
|
+
# # => #<Interactor::Failure: Interactor::Failure>
|
18
|
+
#
|
19
|
+
# context = Interactor::Context.new(foo: "bar")
|
20
|
+
# # => #<Interactor::Context foo="bar">
|
21
|
+
# Interactor::Failure.new(context)
|
22
|
+
# # => #<Interactor::Failure: #<Interactor::Context foo="bar">>
|
23
|
+
#
|
24
|
+
# raise Interactor::Failure, context
|
25
|
+
# # => Interactor::Failure: #<Interactor::Context foo="bar">
|
26
|
+
def initialize(context = nil)
|
27
|
+
@context = context
|
28
|
+
super
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,263 @@
|
|
1
|
+
require "active_support/concern"
|
2
|
+
|
3
|
+
module Interactor
|
4
|
+
# Internal: Methods relating to supporting hooks around Interactor invocation.
|
5
|
+
module Hooks
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
# Internal: Interactor::Hooks class methods.
|
9
|
+
class_methods do
|
10
|
+
# Public: Declare hooks to run around Interactor invocation. The around
|
11
|
+
# method may be called multiple times; subsequent calls append declared
|
12
|
+
# hooks to existing around hooks.
|
13
|
+
#
|
14
|
+
# hooks - Zero or more Symbol method names representing instance methods
|
15
|
+
# to be called around interactor invocation. Each instance method
|
16
|
+
# invocation receives an argument representing the next link in
|
17
|
+
# the around hook chain.
|
18
|
+
# block - An optional block to be executed as a hook. If given, the block
|
19
|
+
# is executed after methods corresponding to any given Symbols.
|
20
|
+
#
|
21
|
+
# Examples
|
22
|
+
#
|
23
|
+
# class MyInteractor
|
24
|
+
# include Interactor
|
25
|
+
#
|
26
|
+
# around :time_execution
|
27
|
+
#
|
28
|
+
# around do |interactor|
|
29
|
+
# puts "started"
|
30
|
+
# interactor.call
|
31
|
+
# puts "finished"
|
32
|
+
# end
|
33
|
+
#
|
34
|
+
# def call
|
35
|
+
# puts "called"
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# private
|
39
|
+
#
|
40
|
+
# def time_execution(interactor)
|
41
|
+
# context.start_time = Time.now
|
42
|
+
# interactor.call
|
43
|
+
# context.finish_time = Time.now
|
44
|
+
# end
|
45
|
+
# end
|
46
|
+
#
|
47
|
+
# Returns nothing.
|
48
|
+
def around(*hooks, &block)
|
49
|
+
hooks << block if block
|
50
|
+
hooks.each { |hook| around_hooks.push(hook) }
|
51
|
+
end
|
52
|
+
|
53
|
+
# Public: Declare hooks to run before Interactor invocation. The before
|
54
|
+
# method may be called multiple times; subsequent calls append declared
|
55
|
+
# hooks to existing before hooks.
|
56
|
+
#
|
57
|
+
# hooks - Zero or more Symbol method names representing instance methods
|
58
|
+
# to be called before interactor invocation.
|
59
|
+
# block - An optional block to be executed as a hook. If given, the block
|
60
|
+
# is executed after methods corresponding to any given Symbols.
|
61
|
+
#
|
62
|
+
# Examples
|
63
|
+
#
|
64
|
+
# class MyInteractor
|
65
|
+
# include Interactor
|
66
|
+
#
|
67
|
+
# before :set_start_time
|
68
|
+
#
|
69
|
+
# before do
|
70
|
+
# puts "started"
|
71
|
+
# end
|
72
|
+
#
|
73
|
+
# def call
|
74
|
+
# puts "called"
|
75
|
+
# end
|
76
|
+
#
|
77
|
+
# private
|
78
|
+
#
|
79
|
+
# def set_start_time
|
80
|
+
# context.start_time = Time.now
|
81
|
+
# end
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
# Returns nothing.
|
85
|
+
def before(*hooks, &block)
|
86
|
+
hooks << block if block
|
87
|
+
hooks.each { |hook| before_hooks.push(hook) }
|
88
|
+
end
|
89
|
+
|
90
|
+
# Public: Declare hooks to run after Interactor invocation. The after
|
91
|
+
# method may be called multiple times; subsequent calls prepend declared
|
92
|
+
# hooks to existing after hooks.
|
93
|
+
#
|
94
|
+
# hooks - Zero or more Symbol method names representing instance methods
|
95
|
+
# to be called after interactor invocation.
|
96
|
+
# block - An optional block to be executed as a hook. If given, the block
|
97
|
+
# is executed before methods corresponding to any given Symbols.
|
98
|
+
#
|
99
|
+
# Examples
|
100
|
+
#
|
101
|
+
# class MyInteractor
|
102
|
+
# include Interactor
|
103
|
+
#
|
104
|
+
# after :set_finish_time
|
105
|
+
#
|
106
|
+
# after do
|
107
|
+
# puts "finished"
|
108
|
+
# end
|
109
|
+
#
|
110
|
+
# def call
|
111
|
+
# puts "called"
|
112
|
+
# end
|
113
|
+
#
|
114
|
+
# private
|
115
|
+
#
|
116
|
+
# def set_finish_time
|
117
|
+
# context.finish_time = Time.now
|
118
|
+
# end
|
119
|
+
# end
|
120
|
+
#
|
121
|
+
# Returns nothing.
|
122
|
+
def after(*hooks, &block)
|
123
|
+
hooks << block if block
|
124
|
+
hooks.each { |hook| after_hooks.unshift(hook) }
|
125
|
+
end
|
126
|
+
|
127
|
+
# Internal: An Array of declared hooks to run around Interactor
|
128
|
+
# invocation. The hooks appear in the order in which they will be run.
|
129
|
+
#
|
130
|
+
# Examples
|
131
|
+
#
|
132
|
+
# class MyInteractor
|
133
|
+
# include Interactor
|
134
|
+
#
|
135
|
+
# around :time_execution, :use_transaction
|
136
|
+
# end
|
137
|
+
#
|
138
|
+
# MyInteractor.around_hooks
|
139
|
+
# # => [:time_execution, :use_transaction]
|
140
|
+
#
|
141
|
+
# Returns an Array of Symbols and Procs.
|
142
|
+
def around_hooks
|
143
|
+
@around_hooks ||= []
|
144
|
+
end
|
145
|
+
|
146
|
+
# Internal: An Array of declared hooks to run before Interactor
|
147
|
+
# invocation. The hooks appear in the order in which they will be run.
|
148
|
+
#
|
149
|
+
# Examples
|
150
|
+
#
|
151
|
+
# class MyInteractor
|
152
|
+
# include Interactor
|
153
|
+
#
|
154
|
+
# before :set_start_time, :say_hello
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# MyInteractor.before_hooks
|
158
|
+
# # => [:set_start_time, :say_hello]
|
159
|
+
#
|
160
|
+
# Returns an Array of Symbols and Procs.
|
161
|
+
def before_hooks
|
162
|
+
@before_hooks ||= []
|
163
|
+
end
|
164
|
+
|
165
|
+
# Internal: An Array of declared hooks to run before Interactor
|
166
|
+
# invocation. The hooks appear in the order in which they will be run.
|
167
|
+
#
|
168
|
+
# Examples
|
169
|
+
#
|
170
|
+
# class MyInteractor
|
171
|
+
# include Interactor
|
172
|
+
#
|
173
|
+
# after :set_finish_time, :say_goodbye
|
174
|
+
# end
|
175
|
+
#
|
176
|
+
# MyInteractor.after_hooks
|
177
|
+
# # => [:say_goodbye, :set_finish_time]
|
178
|
+
#
|
179
|
+
# Returns an Array of Symbols and Procs.
|
180
|
+
def after_hooks
|
181
|
+
@after_hooks ||= []
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
private
|
186
|
+
|
187
|
+
# Internal: Run around, before and after hooks around yielded execution. The
|
188
|
+
# required block is surrounded with hooks and executed.
|
189
|
+
#
|
190
|
+
# Examples
|
191
|
+
#
|
192
|
+
# class MyProcessor
|
193
|
+
# include Interactor::Hooks
|
194
|
+
#
|
195
|
+
# def process_with_hooks
|
196
|
+
# with_hooks do
|
197
|
+
# process
|
198
|
+
# end
|
199
|
+
# end
|
200
|
+
#
|
201
|
+
# def process
|
202
|
+
# puts "processed!"
|
203
|
+
# end
|
204
|
+
# end
|
205
|
+
#
|
206
|
+
# Returns nothing.
|
207
|
+
def with_hooks
|
208
|
+
run_around_hooks do
|
209
|
+
run_before_hooks
|
210
|
+
yield
|
211
|
+
run_after_hooks
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# Internal: Run around hooks.
|
216
|
+
#
|
217
|
+
# Returns nothing.
|
218
|
+
def run_around_hooks(&block)
|
219
|
+
self.class.around_hooks.reverse.inject(block) { |chain, hook|
|
220
|
+
proc { run_hook(hook, chain) }
|
221
|
+
}.call
|
222
|
+
end
|
223
|
+
|
224
|
+
# Internal: Run before hooks.
|
225
|
+
#
|
226
|
+
# Returns nothing.
|
227
|
+
def run_before_hooks
|
228
|
+
run_hooks(self.class.before_hooks)
|
229
|
+
end
|
230
|
+
|
231
|
+
# Internal: Run after hooks.
|
232
|
+
#
|
233
|
+
# Returns nothing.
|
234
|
+
def run_after_hooks
|
235
|
+
run_hooks(self.class.after_hooks)
|
236
|
+
end
|
237
|
+
|
238
|
+
# Internal: Run a colection of hooks. The "run_hooks" method is the common
|
239
|
+
# interface by which collections of either before or after hooks are run.
|
240
|
+
#
|
241
|
+
# hooks - An Array of Symbol and Proc hooks.
|
242
|
+
#
|
243
|
+
# Returns nothing.
|
244
|
+
def run_hooks(hooks)
|
245
|
+
hooks.each { |hook| run_hook(hook) }
|
246
|
+
end
|
247
|
+
|
248
|
+
# Internal: Run an individual hook. The "run_hook" method is the common
|
249
|
+
# interface by which an individual hook is run. If the given hook is a
|
250
|
+
# symbol, the method is invoked whether public or private. If the hook is a
|
251
|
+
# proc, the proc is evaluated in the context of the current instance.
|
252
|
+
#
|
253
|
+
# hook - A Symbol or Proc hook.
|
254
|
+
# args - Zero or more arguments to be passed as block arguments into the
|
255
|
+
# given block or as arguments into the method described by the given
|
256
|
+
# Symbol method name.
|
257
|
+
#
|
258
|
+
# Returns nothing.
|
259
|
+
def run_hook(hook, *args)
|
260
|
+
hook.is_a?(Symbol) ? send(hook, *args) : instance_exec(*args, &hook)
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
module Interactor
|
2
|
+
# Public: Interactor::Organizer methods. Because Interactor::Organizer is a
|
3
|
+
# module, custom Interactor::Organizer classes should include
|
4
|
+
# Interactor::Organizer rather than inherit from it.
|
5
|
+
#
|
6
|
+
# Examples
|
7
|
+
#
|
8
|
+
# class MyOrganizer
|
9
|
+
# include Interactor::Organizer
|
10
|
+
#
|
11
|
+
# organizer InteractorOne, InteractorTwo
|
12
|
+
# end
|
13
|
+
module Organizer
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
include Interactor
|
16
|
+
|
17
|
+
# Internal: Interactor::Organizer class methods.
|
18
|
+
class_methods do
|
19
|
+
# Public: Declare Interactors to be invoked as part of the
|
20
|
+
# Interactor::Organizer's invocation. These interactors are invoked in
|
21
|
+
# the order in which they are declared.
|
22
|
+
#
|
23
|
+
# interactors - Zero or more (or an Array of) Interactor classes.
|
24
|
+
#
|
25
|
+
# Examples
|
26
|
+
#
|
27
|
+
# class MyFirstOrganizer
|
28
|
+
# include Interactor::Organizer
|
29
|
+
#
|
30
|
+
# organize InteractorOne, InteractorTwo
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# class MySecondOrganizer
|
34
|
+
# include Interactor::Organizer
|
35
|
+
#
|
36
|
+
# organize [InteractorThree, InteractorFour]
|
37
|
+
# end
|
38
|
+
#
|
39
|
+
# Returns nothing.
|
40
|
+
def organize(*interactors)
|
41
|
+
@organized = interactors.flatten
|
42
|
+
end
|
43
|
+
|
44
|
+
# Internal: An Array of declared Interactors to be invoked.
|
45
|
+
#
|
46
|
+
# Examples
|
47
|
+
#
|
48
|
+
# class MyOrganizer
|
49
|
+
# include Interactor::Organizer
|
50
|
+
#
|
51
|
+
# organize InteractorOne, InteractorTwo
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# MyOrganizer.organized
|
55
|
+
# # => [InteractorOne, InteractorTwo]
|
56
|
+
#
|
57
|
+
# Returns an Array of Interactor classes or an empty Array.
|
58
|
+
def organized
|
59
|
+
@organized ||= []
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def call
|
64
|
+
self.class.organized.inject(context) do |ctx, interactor|
|
65
|
+
interactor.call!(ctx)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|