interactor_with_steroids 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|