activeinteractor 2.0.0.alpha.3.0.1 → 2.0.0.alpha.4.0.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/README.md +1 -0
- data/lib/active_interactor/context/attribute.rb +2 -1
- data/lib/active_interactor/context/attribute_validation.rb +22 -0
- data/lib/active_interactor/context/base.rb +64 -10
- data/lib/active_interactor/context/input.rb +11 -0
- data/lib/active_interactor/context/output.rb +5 -1
- data/lib/active_interactor/context/result.rb +4 -2
- data/lib/active_interactor/context/runtime.rb +1 -0
- data/lib/active_interactor/context.rb +0 -2
- data/lib/active_interactor/errors.rb +2 -11
- data/lib/active_interactor/interactor/base.rb +271 -13
- data/lib/active_interactor/interactor/options.rb +23 -0
- data/lib/active_interactor/interactor.rb +1 -2
- data/lib/active_interactor/result.rb +110 -88
- data/lib/active_interactor/type/decleration_methods.rb +0 -4
- data/lib/active_interactor/type.rb +1 -1
- data/lib/active_interactor.rb +2 -1
- metadata +8 -11
- data/lib/active_interactor/active_model_error_methods.rb +0 -30
- data/lib/active_interactor/context/attribute_assignment.rb +0 -64
- data/lib/active_interactor/context/attribute_registration.rb +0 -27
- data/lib/active_interactor/interactor/context_methods.rb +0 -83
- data/lib/active_interactor/interactor/interaction_methods.rb +0 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ec1233daeb01ec3145d13cef57caf6c7f69a8128c311e5a0414c594c9b36f5b
|
4
|
+
data.tar.gz: e76d9a078f540d5e8eaa953cb1f88726bde6f507222f5f6f8c807a4f771dd6e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 79f453fbfafecdf6cc59c1eebcb26229132818c18c5109977cf70efd40e94dbfb8ce7094b3e24cb9c39238a787bcf92b12f1c39716992402e7627e6c454defe1
|
7
|
+
data.tar.gz: a58f48730d1494e0a52608a8b76f07a11c53158d1f67966a4f5538965fc1e0495abd847613660f1be72cfbd9b21e720d4631a8d562c37bdd28567f1acc3e73fa
|
data/README.md
CHANGED
@@ -2,6 +2,7 @@
|
|
2
2
|
|
3
3
|
[](https://rubygems.org/gems/activeinteractor)
|
4
4
|
[](https://github.com/activeinteractor/activeinteractor/actions/workflows/build.yml)
|
5
|
+
[](https://codeclimate.com/github/activeinteractor/activeinteractor/test_coverage)
|
5
6
|
[](https://activeinteractor.org/)
|
6
7
|
[](https://github.com/activeinteractor/activeinteractor/blob/main/LICENSE)
|
7
8
|
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Context
|
5
|
+
module AttributeValidation
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
validate :validate_attributes!
|
10
|
+
end
|
11
|
+
|
12
|
+
protected
|
13
|
+
|
14
|
+
def validate_attributes!
|
15
|
+
attribute_set.attributes.each do |attribute|
|
16
|
+
attribute.validate!
|
17
|
+
attribute.error_messages.each { |message| errors.add(attribute.name, message) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -2,27 +2,81 @@
|
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Context
|
5
|
+
# The base class for all context objects
|
5
6
|
class Base
|
7
|
+
extend Type::DeclerationMethods::ClassMethods
|
6
8
|
include ActiveModel::Validations
|
7
|
-
include ActiveModelErrorMethods
|
8
|
-
include AttributeRegistration
|
9
|
-
include AttributeAssignment
|
10
9
|
include Type::DeclerationMethods
|
11
10
|
|
12
|
-
|
11
|
+
class << self
|
12
|
+
def method_defined?(method_name)
|
13
|
+
attribute_set.attribute_names.include?(method_name.to_s.delete('=').to_sym) || super
|
14
|
+
end
|
15
|
+
|
16
|
+
protected
|
17
|
+
|
18
|
+
def attribute_set
|
19
|
+
@attribute_set ||= AttributeSet.new(self)
|
20
|
+
end
|
21
|
+
end
|
13
22
|
|
14
23
|
def initialize(attributes = {})
|
15
|
-
|
16
|
-
|
24
|
+
attribute_set.attributes.each do |attribute|
|
25
|
+
next unless attributes.with_indifferent_access.key?(attribute.name)
|
26
|
+
|
27
|
+
assign_attribute_value(attribute.name, attributes.with_indifferent_access[attribute.name])
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def [](attribute_name)
|
32
|
+
read_attribute_value(attribute_name)
|
33
|
+
end
|
34
|
+
|
35
|
+
def []=(attribute_name, value)
|
36
|
+
assign_attribute_value(attribute_name, value)
|
17
37
|
end
|
18
38
|
|
19
39
|
protected
|
20
40
|
|
21
|
-
def
|
22
|
-
attribute_set.
|
23
|
-
|
24
|
-
|
41
|
+
def assign_attribute_value(attribute_name, value)
|
42
|
+
attribute = attribute_set.find(attribute_name)
|
43
|
+
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
44
|
+
|
45
|
+
attribute.assign_value(value)
|
46
|
+
end
|
47
|
+
|
48
|
+
def assignment_method_missing(method_name, *arguments)
|
49
|
+
if arguments.length != 1
|
50
|
+
raise ArgumentError,
|
51
|
+
"wrong number of arguments (given #{arguments.length}, expected 1)"
|
25
52
|
end
|
53
|
+
|
54
|
+
assign_attribute_value(method_name.to_s.delete('=').to_sym, arguments.first)
|
55
|
+
end
|
56
|
+
|
57
|
+
def attribute_set
|
58
|
+
@attribute_set ||= AttributeSet.new(self, *self.class.send(:attribute_set).attributes.map(&:dup))
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(method_name, *arguments)
|
62
|
+
return super unless respond_to_missing?(method_name)
|
63
|
+
return assignment_method_missing(method_name, *arguments) if method_name.to_s.end_with?('=')
|
64
|
+
|
65
|
+
read_attribute_value(method_name)
|
66
|
+
end
|
67
|
+
|
68
|
+
def read_attribute_value(attribute_name)
|
69
|
+
attribute = attribute_set.find(attribute_name)
|
70
|
+
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
71
|
+
|
72
|
+
attribute.value
|
73
|
+
end
|
74
|
+
|
75
|
+
def respond_to_missing?(method_name, _include_private = false)
|
76
|
+
return true if attribute_set.attribute_names.include?(method_name.to_sym)
|
77
|
+
return true if attribute_set.attribute_names.include?(method_name.to_s.delete('=').to_sym)
|
78
|
+
|
79
|
+
super
|
26
80
|
end
|
27
81
|
end
|
28
82
|
end
|
@@ -3,6 +3,11 @@
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Context
|
5
5
|
class Input < Base
|
6
|
+
delegate :as_json, to: :arguments
|
7
|
+
delegate :to_h, to: :arguments
|
8
|
+
delegate :to_hash, to: :arguments
|
9
|
+
delegate :to_json, to: :arguments
|
10
|
+
|
6
11
|
def self.argument(*attribute_args)
|
7
12
|
attribute_set.add(*attribute_args)
|
8
13
|
end
|
@@ -14,6 +19,12 @@ module ActiveInteractor
|
|
14
19
|
def self.arguments
|
15
20
|
attribute_set.attributes
|
16
21
|
end
|
22
|
+
|
23
|
+
def arguments
|
24
|
+
attribute_set.attributes.each_with_object({}) do |attribute, result|
|
25
|
+
result[attribute.name] = attribute.value
|
26
|
+
end
|
27
|
+
end
|
17
28
|
end
|
18
29
|
end
|
19
30
|
end
|
@@ -2,8 +2,12 @@
|
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Context
|
5
|
+
# The base class for all output context objects
|
5
6
|
class Output < Base
|
6
|
-
delegate :
|
7
|
+
delegate :as_json, to: :fields
|
8
|
+
delegate :to_h, to: :fields
|
9
|
+
delegate :to_hash, to: :fields
|
10
|
+
delegate :to_json, to: :fields
|
7
11
|
|
8
12
|
def self.returns(*attribute_args)
|
9
13
|
attribute_set.add(*attribute_args)
|
@@ -3,7 +3,9 @@
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Context
|
5
5
|
class Result
|
6
|
-
delegate :[],
|
6
|
+
delegate :[], to: :to_hash
|
7
|
+
delegate :as_json, to: :to_hash
|
8
|
+
delegate :to_json, to: :to_hash
|
7
9
|
|
8
10
|
def self.register_owner(owner)
|
9
11
|
owner.const_set(:ResultContext, Class.new(self))
|
@@ -11,7 +13,7 @@ module ActiveInteractor
|
|
11
13
|
|
12
14
|
def self.for_output_context(owner, context)
|
13
15
|
context.fields.each_key { |field| owner::ResultContext.send(:attr_reader, field) }
|
14
|
-
owner::ResultContext.new(context.fields)
|
16
|
+
owner::ResultContext.new(context.fields.deep_dup)
|
15
17
|
end
|
16
18
|
|
17
19
|
def initialize(attributes = {})
|
@@ -1,22 +1,13 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
|
-
# Raised
|
4
|
+
# Raised on interactor failure
|
5
5
|
#
|
6
6
|
# @!attribute [r] result
|
7
|
-
# @return [ActiveInteractor::Result]
|
8
|
-
# {ActiveInteractor::Interactor::Base interactor} that failed
|
7
|
+
# @return [ActiveInteractor::Result] the result of the interactor that failed
|
9
8
|
class Error < StandardError
|
10
9
|
attr_reader :result
|
11
10
|
|
12
|
-
# Create a new instance of {ActiveInteractor::Error}
|
13
|
-
#
|
14
|
-
# @param result [ActiveInteractor::Result] An instance of {ActiveInteractor::Result} for the
|
15
|
-
# {ActiveInteractor::Interactor::Base interactor} that failed
|
16
|
-
# @param message [String] The error message
|
17
|
-
#
|
18
|
-
# @private
|
19
|
-
# @return [ActiveInteractor::Error]
|
20
11
|
def initialize(result, message = nil)
|
21
12
|
@result = result
|
22
13
|
super(message)
|
@@ -2,37 +2,295 @@
|
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
4
|
module Interactor
|
5
|
+
# The Base Class inherited by all Interactors
|
5
6
|
class Base
|
6
|
-
include
|
7
|
-
|
7
|
+
include ActiveSupport::Callbacks
|
8
|
+
extend Type::DeclerationMethods::ClassMethods
|
8
9
|
include Type::DeclerationMethods
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
define_callbacks :fail, :input_context_create, :input_context_validation, :output_context_create,
|
12
|
+
:output_context_validation, :perform, :rollback, :runtime_context_create
|
13
|
+
|
14
|
+
class << self
|
15
|
+
delegate :argument, :argument_names, :arguments, to: :input_context_class
|
16
|
+
delegate :returns, :field_names, :fields, to: :output_context_class
|
17
|
+
delegate(*ActiveModel::Validations::ClassMethods.instance_methods, to: :input_context_class, prefix: :input)
|
18
|
+
delegate(*ActiveModel::Validations::HelperMethods.instance_methods, to: :input_context_class, prefix: :input)
|
19
|
+
delegate(*ActiveModel::Validations::ClassMethods.instance_methods, to: :output_context_class, prefix: :output)
|
20
|
+
delegate(*ActiveModel::Validations::HelperMethods.instance_methods, to: :output_context_class, prefix: :output)
|
21
|
+
|
22
|
+
def accepts_arguments_matching(set_input_context_class)
|
23
|
+
@input_context_class = set_input_context_class
|
24
|
+
end
|
25
|
+
alias input_context accepts_arguments_matching
|
26
|
+
alias input_type accepts_arguments_matching
|
27
|
+
|
28
|
+
def after_fail(...)
|
29
|
+
set_callback(:fail, :after, ...)
|
30
|
+
end
|
31
|
+
|
32
|
+
def after_input_context_create(...)
|
33
|
+
set_callback(:input_context_create, :after, ...)
|
34
|
+
end
|
35
|
+
|
36
|
+
def after_input_context_validation(...)
|
37
|
+
set_callback(:input_context_validation, :after, ...)
|
38
|
+
end
|
39
|
+
|
40
|
+
def after_output_context_create(...)
|
41
|
+
set_callback(:output_context_create, :after, ...)
|
42
|
+
end
|
43
|
+
|
44
|
+
def after_output_context_validation(...)
|
45
|
+
set_callback(:output_context_validation, :after, ...)
|
46
|
+
end
|
47
|
+
|
48
|
+
def after_perform(...)
|
49
|
+
set_callback(:perform, :after, ...)
|
50
|
+
end
|
51
|
+
|
52
|
+
def after_rollback(...)
|
53
|
+
set_callback(:rollback, :after, ...)
|
54
|
+
end
|
55
|
+
|
56
|
+
def after_runtime_context_create(...)
|
57
|
+
set_callback(:runtime_context_create, :after, ...)
|
58
|
+
end
|
59
|
+
|
60
|
+
def around_fail(...)
|
61
|
+
set_callback(:fail, :around, ...)
|
62
|
+
end
|
63
|
+
|
64
|
+
def around_input_context_create(...)
|
65
|
+
set_callback(:input_context_create, :around, ...)
|
66
|
+
end
|
67
|
+
|
68
|
+
def around_input_context_validation(...)
|
69
|
+
set_callback(:input_context_validation, :around, ...)
|
70
|
+
end
|
71
|
+
|
72
|
+
def around_output_context_create(...)
|
73
|
+
set_callback(:output_context_create, :around, ...)
|
74
|
+
end
|
75
|
+
|
76
|
+
def around_output_context_validation(...)
|
77
|
+
set_callback(:output_context_validation, :around, ...)
|
78
|
+
end
|
79
|
+
|
80
|
+
def around_perform(...)
|
81
|
+
set_callback(:perform, :around, ...)
|
82
|
+
end
|
83
|
+
|
84
|
+
def around_rollback(...)
|
85
|
+
set_callback(:rollback, :around, ...)
|
86
|
+
end
|
87
|
+
|
88
|
+
def around_runtime_context_create(...)
|
89
|
+
set_callback(:runtime_context_create, :around, ...)
|
90
|
+
end
|
91
|
+
|
92
|
+
def before_fail(...)
|
93
|
+
set_callback(:fail, :before, ...)
|
94
|
+
end
|
95
|
+
|
96
|
+
def before_input_context_create(...)
|
97
|
+
set_callback(:input_context_create, :before, ...)
|
98
|
+
end
|
99
|
+
|
100
|
+
def before_input_context_validation(...)
|
101
|
+
set_callback(:input_context_validation, :before, ...)
|
102
|
+
end
|
103
|
+
|
104
|
+
def before_output_context_create(...)
|
105
|
+
set_callback(:output_context_create, :before, ...)
|
106
|
+
end
|
107
|
+
|
108
|
+
def before_output_context_validation(...)
|
109
|
+
set_callback(:output_context_validation, :before, ...)
|
110
|
+
end
|
111
|
+
|
112
|
+
def before_perform(...)
|
113
|
+
set_callback(:perform, :before, ...)
|
114
|
+
end
|
115
|
+
|
116
|
+
def before_rollback(...)
|
117
|
+
set_callback(:rollback, :before, ...)
|
118
|
+
end
|
119
|
+
|
120
|
+
def before_runtime_context_create(...)
|
121
|
+
set_callback(:runtime_context_create, :before, ...)
|
122
|
+
end
|
123
|
+
|
124
|
+
def input_context_class
|
125
|
+
@input_context_class ||= const_set(:InputContext, Class.new(Context::Input))
|
126
|
+
end
|
127
|
+
|
128
|
+
def output_context_class
|
129
|
+
@output_context_class ||= const_set(:OutputContext, Class.new(Context::Output))
|
130
|
+
end
|
131
|
+
|
132
|
+
def perform!(input_context = {}, options = {})
|
133
|
+
new(options).perform!(input_context)
|
134
|
+
end
|
135
|
+
|
136
|
+
def perform(input_context = {}, options = {})
|
137
|
+
perform!(input_context, options)
|
138
|
+
rescue Error => e
|
139
|
+
e.result
|
140
|
+
rescue StandardError => e
|
141
|
+
Result.failure(errors: e.message)
|
142
|
+
end
|
143
|
+
|
144
|
+
def returns_data_matching(set_output_context_class)
|
145
|
+
@output_context_class = set_output_context_class
|
146
|
+
end
|
147
|
+
alias output_context returns_data_matching
|
148
|
+
alias output_type returns_data_matching
|
149
|
+
|
150
|
+
def runtime_context_class
|
151
|
+
@runtime_context_class ||= begin
|
152
|
+
context_class = const_set(:RuntimeContext, Class.new(Context::Runtime))
|
153
|
+
context_class.send(:attribute_set).merge(input_context_class.send(:attribute_set).attributes)
|
154
|
+
context_class.send(:attribute_set).merge(output_context_class.send(:attribute_set).attributes)
|
155
|
+
context_class
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
def with_options(options)
|
160
|
+
new(options)
|
161
|
+
end
|
162
|
+
|
163
|
+
protected
|
164
|
+
|
165
|
+
def result_context
|
166
|
+
@result_context ||= Context::Result.register_owner(self)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def initialize(options = {})
|
171
|
+
@options = Options.new(options.deep_dup)
|
13
172
|
end
|
14
173
|
|
15
|
-
def
|
174
|
+
def interact; end
|
175
|
+
|
176
|
+
def perform!(input_context = {})
|
177
|
+
@raw_input = input_context.deep_dup
|
178
|
+
create_input_context
|
179
|
+
validate_input_context!
|
180
|
+
create_runtime_context
|
181
|
+
return execute_perform_with_callbacks unless @options.skip_perform_callbacks
|
182
|
+
|
183
|
+
execute_perform
|
184
|
+
end
|
185
|
+
|
186
|
+
def perform(input_context = {})
|
187
|
+
perform!(input_context)
|
188
|
+
rescue Error => e
|
189
|
+
e.result
|
190
|
+
rescue StandardError => e
|
191
|
+
Result.failure(errors: e.message)
|
192
|
+
end
|
193
|
+
|
194
|
+
def rollback; end
|
195
|
+
|
196
|
+
def with_options(options)
|
197
|
+
@options = Options.new(options.deep_dup)
|
198
|
+
self
|
199
|
+
end
|
200
|
+
|
201
|
+
protected
|
202
|
+
|
203
|
+
attr_reader :context
|
204
|
+
|
205
|
+
def create_input_context
|
206
|
+
run_callbacks :input_context_create do
|
207
|
+
@input_context = self.class.input_context_class.new(@raw_input.deep_dup)
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
def create_output_context
|
212
|
+
run_callbacks :output_context_create do
|
213
|
+
@output_context = self.class.output_context_class.new(@context.attributes.deep_dup)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def create_runtime_context
|
218
|
+
run_callbacks :runtime_context_create do
|
219
|
+
@context = self.class.runtime_context_class.new(@input_context.to_h.deep_dup)
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def execute_perform
|
16
224
|
with_notification(:perform) do |payload|
|
17
225
|
interact
|
18
|
-
|
226
|
+
create_output_context
|
227
|
+
validate_output_context!
|
19
228
|
payload[:result] = Result.success(data: output_to_result_context!)
|
20
229
|
end
|
21
230
|
end
|
22
231
|
|
23
|
-
|
232
|
+
def execute_perform_with_callbacks
|
233
|
+
run_callbacks :perform do
|
234
|
+
execute_perform
|
235
|
+
end
|
236
|
+
end
|
24
237
|
|
25
|
-
def
|
26
|
-
|
27
|
-
with_notification(:rollback) do |payload|
|
238
|
+
def execute_rollback_with_callbacks
|
239
|
+
run_callbacks :rollback do
|
28
240
|
rollback
|
29
|
-
|
30
|
-
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
def fail!(errors = {})
|
245
|
+
run_callbacks :fail do
|
246
|
+
result = nil
|
247
|
+
with_notification(:rollback) do |payload|
|
248
|
+
perform_rollback unless @options.skip_rollback
|
249
|
+
result = Result.failure(data: @output, errors: errors)
|
250
|
+
payload[:result] = result
|
251
|
+
end
|
31
252
|
end
|
32
253
|
|
33
254
|
raise Error, result
|
34
255
|
end
|
35
256
|
|
257
|
+
def output_to_result_context!
|
258
|
+
self.class.send(:result_context).for_output_context(self.class, @output_context)
|
259
|
+
end
|
260
|
+
|
261
|
+
def perform_rollback
|
262
|
+
return execute_rollback_with_callbacks unless @options.skip_rollback_callbacks
|
263
|
+
|
264
|
+
rollback
|
265
|
+
end
|
266
|
+
|
267
|
+
def validate_input_context!
|
268
|
+
return unless @options.validate && @options.validate_input_context
|
269
|
+
|
270
|
+
run_callbacks :input_context_validation do
|
271
|
+
@input_context.valid?
|
272
|
+
end
|
273
|
+
return if @input_context.errors.empty?
|
274
|
+
|
275
|
+
raise Error,
|
276
|
+
Result.failure(errors: @input_context.errors,
|
277
|
+
status: Result::STATUS[:failed_at_input])
|
278
|
+
end
|
279
|
+
|
280
|
+
def validate_output_context!
|
281
|
+
return unless @options.validate && @options.validate_output_context
|
282
|
+
|
283
|
+
run_callbacks :output_context_validation do
|
284
|
+
@output_context.valid?
|
285
|
+
end
|
286
|
+
|
287
|
+
return if @output_context.errors.empty?
|
288
|
+
|
289
|
+
raise Error,
|
290
|
+
Result.failure(errors: @output_context.errors,
|
291
|
+
status: Result::STATUS[:failed_at_output])
|
292
|
+
end
|
293
|
+
|
36
294
|
def with_notification(action)
|
37
295
|
ActiveSupport::Notifications.instrument("#{self.class.name}::#{action.to_s.classify}") do |payload|
|
38
296
|
yield payload if block_given?
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module ActiveInteractor
|
4
|
+
module Interactor
|
5
|
+
class Options
|
6
|
+
DEFAULTS = {
|
7
|
+
skip_perform_callbacks: false,
|
8
|
+
skip_rollback: false,
|
9
|
+
skip_rollback_callbacks: false,
|
10
|
+
validate: true,
|
11
|
+
validate_input_context: true,
|
12
|
+
validate_output_context: true
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader(*DEFAULTS.keys)
|
16
|
+
|
17
|
+
def initialize(options = {})
|
18
|
+
prepared_options = DEFAULTS.merge(options.deep_dup)
|
19
|
+
prepared_options.each_pair { |key, value| instance_variable_set(:"@#{key}", value) }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,64 +1,38 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
|
-
#
|
4
|
+
# An interactor result
|
5
5
|
#
|
6
6
|
# @!attribute [r] data
|
7
|
+
# @return [ActiveInteractor::Context::Result, Object, nil] the data returned by the interactor
|
7
8
|
#
|
8
|
-
# @example
|
9
|
-
#
|
10
|
-
# argument :login, String, 'The login for the User', required: true
|
11
|
-
# argument :password, String, 'The password for the User', required: true
|
12
|
-
# argument :password_confirmation, String, 'The password confirmation for the user', required: true
|
13
|
-
#
|
14
|
-
# returns :user, User, 'The created User', required: true
|
15
|
-
#
|
16
|
-
# def interact
|
17
|
-
# context.user = User.new(context)
|
18
|
-
# fail!(context.user.errors) unless context.user.save
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# result = CreateUser.perform(login: 'johndoe', password: 'password', password_confirmation: 'password')
|
9
|
+
# @example
|
10
|
+
# result = CreateUser.perform(email: 'hello@aaronmallen.me', password: 'password')
|
23
11
|
# result.data.user
|
24
|
-
#
|
25
|
-
# #=> <# User @login='johndoe'>
|
26
|
-
#
|
27
|
-
# @return [ActiveInteractor::Context::Result] the data returned by the
|
28
|
-
# {ActiveInteractor::Interactor::Base interactor}
|
12
|
+
# #=> <#User @email="hello@aaronmallen.me">
|
29
13
|
#
|
30
14
|
# @!attribute [r] errors
|
31
|
-
# @return [ActiveModel::Errors] the errors
|
32
|
-
#
|
33
|
-
# @
|
15
|
+
# @return [ActiveModel::Errors] the errors from the interactor
|
16
|
+
#
|
17
|
+
# @example
|
18
|
+
# result = CreateUser.perform(
|
19
|
+
# email: 'hello@aaronmallen',
|
20
|
+
# password: 'password',
|
21
|
+
# password_confirmation: 'not password'
|
22
|
+
# )
|
23
|
+
# result.errors.full_messages
|
24
|
+
# #=> ["Password confirmation doesn't match Password"]
|
34
25
|
class Result
|
35
|
-
|
26
|
+
extend ActiveModel::Naming
|
36
27
|
|
37
|
-
|
38
|
-
|
39
|
-
#
|
40
|
-
# @example When an {ActiveInteractor::Interactor::Base interactor} succeeds
|
41
|
-
# result = CreateUser.perform(login: 'johndoe', password: 'password', password_confirmation: 'password')
|
42
|
-
# result.to_hash
|
43
|
-
#
|
44
|
-
# #=> { :success => true, :errors => {}, :data => { :login => 'johndoe' } }
|
45
|
-
#
|
46
|
-
# @example When an {ActiveInteractor::Interactor::Base interactor} fails
|
47
|
-
# result = CreateUser.perform(login: 'johndoe', password: 'password', password_confirmation: 'notpassword')
|
48
|
-
# result.to_hash
|
49
|
-
#
|
50
|
-
# #=> {
|
51
|
-
# #=> :success => false,
|
52
|
-
# #=> :errors => { :password_confirmation => ["doesn't match Password"] },
|
53
|
-
# #=> :data => { :login => 'johndoe' }
|
54
|
-
# #=> }
|
55
|
-
#
|
56
|
-
# @deprecated will be removed in version 2.0.0-alpha.3.0.0
|
57
|
-
# use {#to_hash} instead
|
58
|
-
# @return [Hash {Symbol => Boolean, Hash}]
|
28
|
+
attr_reader :data, :errors
|
29
|
+
|
30
|
+
# Return a result as a JSON string
|
59
31
|
delegate :to_json, to: :to_hash
|
60
32
|
|
61
|
-
#
|
33
|
+
# Status codes for interactor results
|
34
|
+
#
|
35
|
+
# @visibility private
|
62
36
|
STATUS = {
|
63
37
|
success: 0,
|
64
38
|
failed_at_input: 1,
|
@@ -66,15 +40,16 @@ module ActiveInteractor
|
|
66
40
|
failed_at_output: 3
|
67
41
|
}.freeze
|
68
42
|
|
69
|
-
attr_reader :data
|
70
|
-
|
71
43
|
class << self
|
72
|
-
#
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
# @
|
44
|
+
# Return a failed result
|
45
|
+
#
|
46
|
+
# @visibility private
|
47
|
+
#
|
48
|
+
# @param data [ActiveInteractor::Context::Result, Object, nil] the data returned by the interactor
|
49
|
+
# @param errors [ActiveModel::Errors, Hash, String] the errors from the interactor
|
50
|
+
# @param status [Integer] the status code for the result
|
51
|
+
#
|
52
|
+
# @return [ActiveInteractor::Result] the failed result
|
78
53
|
def failure(data: {}, errors: {}, status: STATUS[:failed_at_runtime])
|
79
54
|
result = new(status: status, data: data)
|
80
55
|
parse_errors(errors).each_pair do |attribute, messages|
|
@@ -83,6 +58,31 @@ module ActiveInteractor
|
|
83
58
|
result
|
84
59
|
end
|
85
60
|
|
61
|
+
# Needed for ActiveModel::Errors
|
62
|
+
#
|
63
|
+
# @visibility private
|
64
|
+
def human_attribute_name(attribute, _options = {})
|
65
|
+
attribute.respond_to?(:to_s) ? attribute.to_s.humanize : attribute
|
66
|
+
end
|
67
|
+
|
68
|
+
# Needed for ActiveModel::Errors
|
69
|
+
#
|
70
|
+
# @visibility private
|
71
|
+
def lookup_ancestors
|
72
|
+
[self]
|
73
|
+
end
|
74
|
+
|
75
|
+
# Return a successful result
|
76
|
+
#
|
77
|
+
# @visibility private
|
78
|
+
#
|
79
|
+
# @param data [ActiveInteractor::Context::Result, Object, nil] the data returned by the interactor
|
80
|
+
#
|
81
|
+
# @return [ActiveInteractor::Result] the successful result
|
82
|
+
def success(data: {})
|
83
|
+
new(status: STATUS[:success], data: data)
|
84
|
+
end
|
85
|
+
|
86
86
|
private
|
87
87
|
|
88
88
|
def parse_errors(errors)
|
@@ -98,68 +98,90 @@ module ActiveInteractor
|
|
98
98
|
end
|
99
99
|
|
100
100
|
private_class_method :new
|
101
|
-
|
101
|
+
|
102
|
+
# Create a new instance of {ActiveInteractor::Result}
|
103
|
+
#
|
104
|
+
# @visibility private
|
105
|
+
#
|
106
|
+
# @param status [Integer] the status code for the result
|
107
|
+
# @param data [ActiveInteractor::Context::Result, Object, nil] the data returned by the interactor
|
108
|
+
#
|
109
|
+
# @return [ActiveInteractor::Result] the result
|
102
110
|
def initialize(status:, data: {})
|
103
111
|
@status = status
|
104
112
|
@data = data
|
105
113
|
@errors = ActiveModel::Errors.new(self)
|
106
114
|
end
|
107
115
|
|
108
|
-
# Whether or not the
|
109
|
-
#
|
110
|
-
# @example When
|
111
|
-
# result = CreateUser.perform(
|
116
|
+
# Whether or not the result is a failure
|
117
|
+
#
|
118
|
+
# @example When the result is a success
|
119
|
+
# result = CreateUser.perform(
|
120
|
+
# email: 'hello@aaronmallen',
|
121
|
+
# password: 'password',
|
122
|
+
# password_confirmation: 'password'
|
123
|
+
# )
|
112
124
|
# result.failure?
|
125
|
+
# #=> false
|
113
126
|
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
# @
|
117
|
-
#
|
127
|
+
# @example When the result is a failure
|
128
|
+
# result = CreateUser.perform(
|
129
|
+
# email: 'hello@aaronmallen',
|
130
|
+
# password: 'password',
|
131
|
+
# password_confirmation: 'not password'
|
132
|
+
# )
|
118
133
|
# result.failure?
|
134
|
+
# #=> true
|
119
135
|
#
|
120
|
-
#
|
121
|
-
#
|
122
|
-
# @return [Boolean]
|
136
|
+
# @return [Boolean] whether or not the result is a failure
|
123
137
|
def failure?
|
124
138
|
!success?
|
125
139
|
end
|
126
140
|
alias failed? failure?
|
127
141
|
|
128
|
-
#
|
142
|
+
# Needed for ActiveModel::Errors
|
143
|
+
#
|
144
|
+
# @visibility private
|
129
145
|
def read_attribute_for_validation(attribute_name)
|
130
146
|
data&.send(attribute_name.to_sym)
|
131
147
|
end
|
132
148
|
|
133
|
-
# Whether or not the
|
149
|
+
# Whether or not the result is a success
|
150
|
+
#
|
151
|
+
# @example When the result is a success
|
152
|
+
# result = CreateUser.perform(
|
153
|
+
# email: 'hello@aaronmallen',
|
154
|
+
# password: 'password',
|
155
|
+
# password_confirmation: 'password'
|
156
|
+
# )
|
157
|
+
# result.success?
|
158
|
+
# #=> true
|
159
|
+
#
|
160
|
+
# @example When the result is a failure
|
161
|
+
# result = CreateUser.perform(
|
162
|
+
# email: 'hello@aaronmallen',
|
163
|
+
# password: 'password',
|
164
|
+
# password_confirmation: 'not password'
|
165
|
+
# )
|
166
|
+
# result.success?
|
167
|
+
# #=> false
|
134
168
|
#
|
135
|
-
# @return [Boolean]
|
169
|
+
# @return [Boolean] whether or not the result is a failure
|
136
170
|
def success?
|
137
171
|
@status == STATUS[:success]
|
138
172
|
end
|
139
173
|
alias successful? success?
|
140
174
|
|
141
|
-
#
|
142
|
-
#
|
143
|
-
# @example When an {ActiveInteractor::Interactor::Base interactor} succeeds
|
144
|
-
# result = CreateUser.perform(login: 'johndoe', password: 'password', password_confirmation: 'password')
|
145
|
-
# result.to_hash
|
175
|
+
# Return the result as a hash
|
146
176
|
#
|
147
|
-
#
|
148
|
-
#
|
149
|
-
# @example When an {ActiveInteractor::Interactor::Base interactor} fails
|
150
|
-
# result = CreateUser.perform(login: 'johndoe', password: 'password', password_confirmation: 'notpassword')
|
177
|
+
# @example
|
178
|
+
# result = CreateUser.perform(email: 'hello@aaronmallen', password: 'password')
|
151
179
|
# result.to_hash
|
152
|
-
#
|
153
|
-
# #=> {
|
154
|
-
# #=> :success => false,
|
155
|
-
# #=> :errors => { :password_confirmation => ["doesn't match Password"] },
|
156
|
-
# #=> :data => { :login => 'johndoe' }
|
157
|
-
# #=> }
|
158
|
-
#
|
159
|
-
# @return [Hash {Symbol => Boolean, Hash}]
|
180
|
+
# #=> { success: true, status: 0, errors: {}, data: { user: <#User> } }
|
160
181
|
def to_hash
|
161
182
|
{
|
162
183
|
success: success?,
|
184
|
+
status: @status,
|
163
185
|
errors: errors.to_hash,
|
164
186
|
data: data.to_json
|
165
187
|
}
|
data/lib/active_interactor.rb
CHANGED
@@ -33,6 +33,8 @@ require_relative 'active_interactor/errors'
|
|
33
33
|
# It has features like rich support for attributes, callbacks, and validations, and
|
34
34
|
# thread safe performance methods.
|
35
35
|
#
|
36
|
+
# {https://activeinteractor.org/docs/getting-started Getting Started}
|
37
|
+
#
|
36
38
|
# {file:CHANGELOG.md Changelog}
|
37
39
|
#
|
38
40
|
# {file:HUMANS.md Acknowledgements}
|
@@ -44,7 +46,6 @@ require_relative 'active_interactor/errors'
|
|
44
46
|
module ActiveInteractor
|
45
47
|
extend ActiveSupport::Autoload
|
46
48
|
|
47
|
-
autoload :ActiveModelErrorMethods
|
48
49
|
autoload :Context
|
49
50
|
autoload :Interactor
|
50
51
|
autoload :Result
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeinteractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.0.0.alpha.
|
4
|
+
version: 2.0.0.alpha.4.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -63,12 +63,10 @@ files:
|
|
63
63
|
- LICENSE
|
64
64
|
- README.md
|
65
65
|
- lib/active_interactor.rb
|
66
|
-
- lib/active_interactor/active_model_error_methods.rb
|
67
66
|
- lib/active_interactor/context.rb
|
68
67
|
- lib/active_interactor/context/attribute.rb
|
69
|
-
- lib/active_interactor/context/attribute_assignment.rb
|
70
|
-
- lib/active_interactor/context/attribute_registration.rb
|
71
68
|
- lib/active_interactor/context/attribute_set.rb
|
69
|
+
- lib/active_interactor/context/attribute_validation.rb
|
72
70
|
- lib/active_interactor/context/base.rb
|
73
71
|
- lib/active_interactor/context/input.rb
|
74
72
|
- lib/active_interactor/context/output.rb
|
@@ -77,8 +75,7 @@ files:
|
|
77
75
|
- lib/active_interactor/errors.rb
|
78
76
|
- lib/active_interactor/interactor.rb
|
79
77
|
- lib/active_interactor/interactor/base.rb
|
80
|
-
- lib/active_interactor/interactor/
|
81
|
-
- lib/active_interactor/interactor/interaction_methods.rb
|
78
|
+
- lib/active_interactor/interactor/options.rb
|
82
79
|
- lib/active_interactor/result.rb
|
83
80
|
- lib/active_interactor/type.rb
|
84
81
|
- lib/active_interactor/type/base.rb
|
@@ -92,10 +89,10 @@ licenses:
|
|
92
89
|
- MIT
|
93
90
|
metadata:
|
94
91
|
bug_tracker_uri: https://github.com/activeinteractor/activeinteractor/issues
|
95
|
-
changelog_uri: https://github.com/activeinteractor/activeinteractor/blob/v2.0.0-alpha.
|
92
|
+
changelog_uri: https://github.com/activeinteractor/activeinteractor/blob/v2.0.0-alpha.4.0.0/CHANGELOG.md
|
96
93
|
homepage_uri: https://activeinteractor.org
|
97
|
-
source_code_uri: https://github.com/activeinteractor/activeinteractor/tree/v2.0.0-alpha.
|
98
|
-
documentation_uri: https://activeinteractor.org/api/activeinteractor/v2.0.0-alpha.
|
94
|
+
source_code_uri: https://github.com/activeinteractor/activeinteractor/tree/v2.0.0-alpha.4.0.0
|
95
|
+
documentation_uri: https://activeinteractor.org/api/activeinteractor/v2.0.0-alpha.4.0.0
|
99
96
|
wiki_uri: https://github.com/activeinteractor/activeinteractor/wiki
|
100
97
|
rubygems_mfa_required: 'true'
|
101
98
|
post_install_message:
|
@@ -113,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
113
110
|
- !ruby/object:Gem::Version
|
114
111
|
version: 1.3.1
|
115
112
|
requirements: []
|
116
|
-
rubygems_version: 3.4.
|
113
|
+
rubygems_version: 3.4.22
|
117
114
|
signing_key:
|
118
115
|
specification_version: 4
|
119
116
|
summary: Ruby interactors with ActiveModel::Validations
|
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveInteractor
|
4
|
-
# @private
|
5
|
-
module ActiveModelErrorMethods
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
attr_reader :errors
|
9
|
-
|
10
|
-
# @private
|
11
|
-
module ClassMethods
|
12
|
-
def human_attribute_name(attribute, _options = {})
|
13
|
-
attribute.respond_to?(:to_s) ? attribute.to_s.humanize : attribute
|
14
|
-
end
|
15
|
-
|
16
|
-
def lookup_ancestors
|
17
|
-
[self]
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
included do
|
22
|
-
extend ActiveModel::Naming
|
23
|
-
extend ClassMethods
|
24
|
-
end
|
25
|
-
|
26
|
-
def read_attribute_for_validation(attribute_name)
|
27
|
-
send(attribute_name.to_sym)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,64 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveInteractor
|
4
|
-
module Context
|
5
|
-
module AttributeAssignment
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
def initialize(attributes = {})
|
9
|
-
attribute_set.attributes.each do |attribute|
|
10
|
-
next unless attributes.with_indifferent_access.key?(attribute.name)
|
11
|
-
|
12
|
-
assign_attribute_value(attribute.name, attributes.with_indifferent_access[attribute.name])
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
def [](attribute_name)
|
17
|
-
read_attribute_value(attribute_name)
|
18
|
-
end
|
19
|
-
|
20
|
-
def []=(attribute_name, value)
|
21
|
-
assign_attribute_value(attribute_name, value)
|
22
|
-
end
|
23
|
-
|
24
|
-
protected
|
25
|
-
|
26
|
-
def assign_attribute_value(attribute_name, value)
|
27
|
-
attribute = attribute_set.find(attribute_name)
|
28
|
-
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
29
|
-
|
30
|
-
attribute.assign_value(value)
|
31
|
-
end
|
32
|
-
|
33
|
-
def assignment_method_missing(method_name, *arguments)
|
34
|
-
if arguments.length != 1
|
35
|
-
raise ArgumentError,
|
36
|
-
"wrong number of arguments (given #{arguments.length}, expected 1)"
|
37
|
-
end
|
38
|
-
|
39
|
-
assign_attribute_value(method_name.to_s.delete('=').to_sym, arguments.first)
|
40
|
-
end
|
41
|
-
|
42
|
-
def method_missing(method_name, *arguments)
|
43
|
-
return super unless respond_to_missing?(method_name)
|
44
|
-
return assignment_method_missing(method_name, *arguments) if method_name.to_s.end_with?('=')
|
45
|
-
|
46
|
-
read_attribute_value(method_name)
|
47
|
-
end
|
48
|
-
|
49
|
-
def read_attribute_value(attribute_name)
|
50
|
-
attribute = attribute_set.find(attribute_name)
|
51
|
-
raise NoMethodError, "unknown attribute '#{attribute_name}' for #{self.class.name}" unless attribute
|
52
|
-
|
53
|
-
attribute.value
|
54
|
-
end
|
55
|
-
|
56
|
-
def respond_to_missing?(method_name, _include_private = false)
|
57
|
-
return true if attribute_set.attribute_names.include?(method_name.to_sym)
|
58
|
-
return true if attribute_set.attribute_names.include?(method_name.to_s.delete('=').to_sym)
|
59
|
-
|
60
|
-
super
|
61
|
-
end
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveInteractor
|
4
|
-
module Context
|
5
|
-
module AttributeRegistration
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
protected
|
10
|
-
|
11
|
-
def attribute_set
|
12
|
-
@attribute_set ||= AttributeSet.new(self)
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
included do
|
17
|
-
extend ClassMethods
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
def attribute_set
|
23
|
-
@attribute_set ||= AttributeSet.new(self, *self.class.send(:attribute_set).attributes.map(&:dup))
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,83 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveInteractor
|
4
|
-
module Interactor
|
5
|
-
module ContextMethods
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
delegate :argument, :argument_names, :arguments, to: :input_context_class
|
10
|
-
delegate :returns, :field_names, :fields, to: :output_context_class
|
11
|
-
delegate(*ActiveModel::Validations::ClassMethods.instance_methods, to: :input_context_class, prefix: :input)
|
12
|
-
delegate(*ActiveModel::Validations::HelperMethods.instance_methods, to: :input_context_class, prefix: :input)
|
13
|
-
delegate(*ActiveModel::Validations::ClassMethods.instance_methods, to: :output_context_class, prefix: :output)
|
14
|
-
delegate(*ActiveModel::Validations::HelperMethods.instance_methods, to: :output_context_class, prefix: :output)
|
15
|
-
|
16
|
-
def input_context_class
|
17
|
-
@input_context_class ||= const_set(:InputContext, Class.new(Context::Input))
|
18
|
-
end
|
19
|
-
|
20
|
-
def accepts_arguments_matching(set_input_context_class)
|
21
|
-
@input_context_class = set_input_context_class
|
22
|
-
end
|
23
|
-
alias input_context accepts_arguments_matching
|
24
|
-
alias input_type accepts_arguments_matching
|
25
|
-
|
26
|
-
def output_context_class
|
27
|
-
@output_context_class ||= const_set(:OutputContext, Class.new(Context::Output))
|
28
|
-
end
|
29
|
-
|
30
|
-
def returns_data_matching(set_output_context_class)
|
31
|
-
@output_context_class = set_output_context_class
|
32
|
-
end
|
33
|
-
alias output_context returns_data_matching
|
34
|
-
alias output_type returns_data_matching
|
35
|
-
|
36
|
-
def runtime_context_class
|
37
|
-
@runtime_context_class ||= begin
|
38
|
-
context_class = const_set(:RuntimeContext, Class.new(Context::Runtime))
|
39
|
-
context_class.send(:attribute_set).merge(input_context_class.send(:attribute_set).attributes)
|
40
|
-
context_class.send(:attribute_set).merge(output_context_class.send(:attribute_set).attributes)
|
41
|
-
context_class
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
protected
|
46
|
-
|
47
|
-
def result_context
|
48
|
-
@result_context ||= Context::Result.register_owner(self)
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
included do
|
53
|
-
extend ClassMethods
|
54
|
-
|
55
|
-
protected
|
56
|
-
|
57
|
-
attr_reader :context
|
58
|
-
end
|
59
|
-
|
60
|
-
protected # rubocop:disable Lint/UselessAccessModifier
|
61
|
-
|
62
|
-
def generate_and_validate_output_context!
|
63
|
-
@output = self.class.output_context_class.new(context.attributes)
|
64
|
-
@output.valid?
|
65
|
-
return if @output.errors.empty?
|
66
|
-
|
67
|
-
raise Error, Result.failure(errors: @output.errors, status: Result::STATUS[:failed_at_output])
|
68
|
-
end
|
69
|
-
|
70
|
-
def output_to_result_context!
|
71
|
-
self.class.send(:result_context).for_output_context(self.class, @output)
|
72
|
-
end
|
73
|
-
|
74
|
-
def validate_input_and_generate_runtime_context!
|
75
|
-
@input = self.class.input_context_class.new(@raw_input)
|
76
|
-
@input.valid?
|
77
|
-
return (@context = self.class.runtime_context_class.new(@raw_input)) if @input.errors.empty?
|
78
|
-
|
79
|
-
raise Error, Result.failure(errors: @input.errors, status: Result::STATUS[:failed_at_input])
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
@@ -1,38 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module ActiveInteractor
|
4
|
-
module Interactor
|
5
|
-
module InteractionMethods
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
module ClassMethods
|
9
|
-
def perform!(input_context = {})
|
10
|
-
new(input_context).perform!
|
11
|
-
end
|
12
|
-
|
13
|
-
def perform(input_context = {})
|
14
|
-
perform!(input_context)
|
15
|
-
rescue Error => e
|
16
|
-
e.result
|
17
|
-
rescue StandardError => e
|
18
|
-
Result.failure(errors: e.message)
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
included do
|
23
|
-
extend ClassMethods
|
24
|
-
end
|
25
|
-
|
26
|
-
def perform
|
27
|
-
perform!
|
28
|
-
rescue Error => e
|
29
|
-
e.result
|
30
|
-
rescue StandardError => e
|
31
|
-
Result.failure(errors: e.message)
|
32
|
-
end
|
33
|
-
|
34
|
-
def interact; end
|
35
|
-
def rollback; end
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|