activeinteractor 0.1.7 → 1.0.0.beta.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 +4 -4
- data/CHANGELOG.md +36 -1
- data/README.md +397 -395
- data/lib/active_interactor.rb +12 -30
- data/lib/active_interactor/base.rb +18 -8
- data/lib/active_interactor/context.rb +4 -181
- data/lib/active_interactor/context/attributes.rb +37 -149
- data/lib/active_interactor/context/base.rb +141 -0
- data/lib/active_interactor/context/loader.rb +45 -0
- data/lib/active_interactor/error.rb +22 -15
- data/lib/active_interactor/interactor.rb +24 -57
- data/lib/active_interactor/interactor/callbacks.rb +64 -76
- data/lib/active_interactor/interactor/context.rb +97 -63
- data/lib/active_interactor/interactor/worker.rb +22 -65
- data/lib/active_interactor/organizer.rb +180 -164
- data/lib/active_interactor/version.rb +2 -3
- data/lib/rails/generators/active_interactor.rb +2 -37
- data/lib/rails/generators/active_interactor/application_interactor_generator.rb +23 -0
- data/lib/rails/generators/active_interactor/install_generator.rb +8 -12
- data/lib/rails/generators/active_interactor/templates/application_context.rb +4 -0
- data/lib/rails/generators/{templates/application_interactor.erb → active_interactor/templates/application_interactor.rb} +0 -0
- data/lib/rails/generators/active_interactor/templates/application_organizer.rb +4 -0
- data/lib/rails/generators/active_interactor/templates/initializer.erb +5 -0
- data/lib/rails/generators/interactor/context/rspec_generator.rb +19 -0
- data/lib/rails/generators/interactor/context/templates/rspec.erb +7 -0
- data/lib/rails/generators/interactor/context/templates/test_unit.erb +9 -0
- data/lib/rails/generators/interactor/context/test_unit_generator.rb +19 -0
- data/lib/rails/generators/interactor/context_generator.rb +19 -0
- data/lib/rails/generators/interactor/interactor_generator.rb +8 -3
- data/lib/rails/generators/interactor/organizer_generator.rb +8 -3
- data/lib/rails/generators/interactor/rspec_generator.rb +4 -3
- data/lib/rails/generators/interactor/templates/context.erb +4 -0
- data/lib/rails/generators/{templates → interactor/templates}/interactor.erb +0 -0
- data/lib/rails/generators/{templates → interactor/templates}/organizer.erb +1 -1
- data/lib/rails/generators/{templates → interactor/templates}/rspec.erb +0 -0
- data/lib/rails/generators/{templates → interactor/templates}/test_unit.erb +0 -0
- data/lib/rails/generators/interactor/test_unit_generator.rb +4 -3
- data/spec/active_interactor/base_spec.rb +51 -0
- data/spec/active_interactor/context/base_spec.rb +229 -0
- data/spec/active_interactor/error_spec.rb +43 -0
- data/spec/active_interactor/interactor/worker_spec.rb +89 -0
- data/spec/active_interactor/organizer_spec.rb +178 -0
- data/spec/active_interactor_spec.rb +26 -0
- data/spec/integration/basic_callback_integration_spec.rb +355 -0
- data/spec/integration/basic_context_integration_spec.rb +73 -0
- data/spec/integration/basic_integration_spec.rb +220 -0
- data/spec/integration/basic_validations_integration_spec.rb +204 -0
- data/spec/spec_helper.rb +44 -0
- data/spec/support/helpers/factories.rb +41 -0
- data/spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb +99 -0
- data/spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb +58 -0
- data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +21 -0
- data/spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb +39 -0
- data/spec/support/spec_helpers.rb +7 -0
- metadata +68 -138
- data/lib/active_interactor/configuration.rb +0 -38
- data/lib/active_interactor/interactor/execution.rb +0 -24
- data/lib/rails/generators/templates/initializer.erb +0 -15
@@ -0,0 +1,141 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_model'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require 'active_interactor/context/attributes'
|
7
|
+
|
8
|
+
module ActiveInteractor
|
9
|
+
module Context
|
10
|
+
# The base context class. All interactor contexts should inherit from
|
11
|
+
# {Context::Base}.
|
12
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
13
|
+
# @since 0.0.1
|
14
|
+
class Base < OpenStruct
|
15
|
+
include ActiveModel::Validations
|
16
|
+
include Attributes
|
17
|
+
|
18
|
+
# @!method valid?(context = nil)
|
19
|
+
# @see
|
20
|
+
# https://github.com/rails/rails/blob/master/activemodel/lib/active_model/validations.rb#L305
|
21
|
+
# ActiveModel::Validations#valid?
|
22
|
+
|
23
|
+
# @api private
|
24
|
+
# Track that an Interactor has been called. The {#called!} method
|
25
|
+
# is used by the interactor being invoked with this context. After an
|
26
|
+
# interactor is successfully called, the interactor instance is tracked in
|
27
|
+
# the context for the purpose of potential future rollback
|
28
|
+
# @param interactor [ActiveInteractor::Base] the called interactor
|
29
|
+
# @return [Array<ActiveInteractor::Base>] all called interactors
|
30
|
+
def called!(interactor)
|
31
|
+
_called << interactor
|
32
|
+
end
|
33
|
+
|
34
|
+
# Fail the context instance. Failing a context raises an error
|
35
|
+
# that may be rescued by the calling interactor. The context is also flagged
|
36
|
+
# as having failed
|
37
|
+
#
|
38
|
+
# @example Fail an interactor context
|
39
|
+
# class MyInteractor < ActiveInteractor::Base
|
40
|
+
# def perform
|
41
|
+
# context.fail!
|
42
|
+
# end
|
43
|
+
# end
|
44
|
+
#
|
45
|
+
# MyInteractor.perform!
|
46
|
+
# #=> ActiveInteractor::Error::ContextFailure: <#MyInteractor::Context>
|
47
|
+
# @param errors [ActiveModel::Errors|nil] errors to add to the context on failure
|
48
|
+
# @see https://api.rubyonrails.org/classes/ActiveModel/Errors.html ActiveModel::Errors
|
49
|
+
# @raise [Error::ContextFailure]
|
50
|
+
def fail!(errors = nil)
|
51
|
+
merge_errors!(errors) if errors
|
52
|
+
@_failed = true
|
53
|
+
raise Error::ContextFailure, self
|
54
|
+
end
|
55
|
+
|
56
|
+
# Whether the context instance has failed. By default, a new
|
57
|
+
# context is successful and only changes when explicitly failed
|
58
|
+
# @note The {#failure?} method is the inverse of the {#success?} method
|
59
|
+
# @example Check if a context has failed
|
60
|
+
# class MyInteractor < ActiveInteractor::Base
|
61
|
+
# def perform; end
|
62
|
+
# end
|
63
|
+
#
|
64
|
+
# result = MyInteractor.perform
|
65
|
+
# #=> <#MyInteractor::Context>
|
66
|
+
#
|
67
|
+
# result.failure?
|
68
|
+
# #=> false
|
69
|
+
# @return [Boolean] `false` by default or `true` if failed
|
70
|
+
def failure?
|
71
|
+
@_failed || false
|
72
|
+
end
|
73
|
+
alias fail? failure?
|
74
|
+
|
75
|
+
# Roll back an interactor context. Any interactors to which this
|
76
|
+
# context has been passed and which have been successfully called are asked
|
77
|
+
# to roll themselves back by invoking their
|
78
|
+
# {ActiveInteractor::Base#rollback} instance methods.
|
79
|
+
# @example Rollback an interactor's context
|
80
|
+
# class MyInteractor < ActiveInteractor::Base
|
81
|
+
# def perform
|
82
|
+
# context.fail!
|
83
|
+
# end
|
84
|
+
#
|
85
|
+
# def rollback
|
86
|
+
# context.user&.destroy
|
87
|
+
# end
|
88
|
+
# end
|
89
|
+
#
|
90
|
+
# user = User.create
|
91
|
+
# #=> <#User>
|
92
|
+
#
|
93
|
+
# result = MyInteractor.perform(user: user)
|
94
|
+
# #=> <#MyInteractor::Context user=<#User>>
|
95
|
+
#
|
96
|
+
# result.user.destroyed?
|
97
|
+
# #=> true
|
98
|
+
# @return [Boolean] `true` if rolled back successfully or `false` if already
|
99
|
+
# rolled back
|
100
|
+
def rollback!
|
101
|
+
return false if @_rolled_back
|
102
|
+
|
103
|
+
_called.reverse_each(&:rollback)
|
104
|
+
@_rolled_back = true
|
105
|
+
end
|
106
|
+
|
107
|
+
# Whether the context instance is successful. By default, a new
|
108
|
+
# context is successful and only changes when explicitly failed
|
109
|
+
# @note the {#success?} method is the inverse of the {#failure?} method
|
110
|
+
# @example Check if a context is successful
|
111
|
+
# class MyInteractor < ActiveInteractor::Base
|
112
|
+
# def perform; end
|
113
|
+
# end
|
114
|
+
#
|
115
|
+
# result = MyInteractor.perform
|
116
|
+
# #=> <#MyInteractor::Context>
|
117
|
+
#
|
118
|
+
# result.success?
|
119
|
+
# #=> true
|
120
|
+
# @return [Boolean] `true` by default or `false` if failed
|
121
|
+
def success?
|
122
|
+
!failure?
|
123
|
+
end
|
124
|
+
alias successful? success?
|
125
|
+
|
126
|
+
private
|
127
|
+
|
128
|
+
def _called
|
129
|
+
@_called ||= []
|
130
|
+
end
|
131
|
+
|
132
|
+
def merge_errors!(errors)
|
133
|
+
if errors.is_a? String
|
134
|
+
self.errors.add(:context, errors)
|
135
|
+
else
|
136
|
+
self.errors.merge!(errors)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/core_ext/string/inflections'
|
4
|
+
|
5
|
+
module ActiveInteractor
|
6
|
+
module Context
|
7
|
+
# @api private
|
8
|
+
# Load, find or create {Context::Base} classes for a given interactor.
|
9
|
+
# @author Aaron Allen <hello@aaronmallen.me>
|
10
|
+
# @since 1.0.0
|
11
|
+
module Loader
|
12
|
+
# @return [Array<Class>] ActiveInteractor base classes
|
13
|
+
BASE_CLASSES = [ActiveInteractor::Base, ActiveInteractor::Organizer].freeze
|
14
|
+
# @return [Class] the base context class
|
15
|
+
BASE_CONTEXT = ActiveInteractor::Context::Base
|
16
|
+
|
17
|
+
# Create a new context class on an interactor
|
18
|
+
# @param context_class_name [String] the name of the class to create
|
19
|
+
# @param interactor_class [Class] the interactor class to create the context for
|
20
|
+
# @return [Class] the created context class
|
21
|
+
def self.create(context_class_name, interactor_class)
|
22
|
+
interactor_class.const_set(context_class_name.to_s.classify, Class.new(BASE_CONTEXT))
|
23
|
+
end
|
24
|
+
|
25
|
+
# Find or create a new context class for an interactor
|
26
|
+
# @note the loader will attempt to find an existing context given the naming conventions:
|
27
|
+
# `MyInteractor::Context` or `MyInteractorContext`
|
28
|
+
# @param interactor_class [Class] the interactor class to find or create the context for
|
29
|
+
def self.find_or_create(interactor_class)
|
30
|
+
return BASE_CONTEXT if BASE_CLASSES.include?(interactor_class)
|
31
|
+
|
32
|
+
klass = possible_classes(interactor_class).first
|
33
|
+
klass || create('Context', interactor_class)
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.possible_classes(interactor_class)
|
37
|
+
["#{interactor_class.name}::Context", "#{interactor_class.name}Context"]
|
38
|
+
.map(&:safe_constantize)
|
39
|
+
.compact
|
40
|
+
.reject { |klass| klass&.name&.include?('ActiveInteractor') }
|
41
|
+
end
|
42
|
+
private_class_method :possible_classes
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -1,30 +1,37 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
|
-
# ActiveInteractor
|
5
|
-
#
|
4
|
+
# ActiveInteractor errors
|
6
5
|
# @author Aaron Allen <hello@aaronmallen.me>
|
7
6
|
# @since 0.1.5
|
8
|
-
# @version 0.1
|
9
7
|
module Error
|
10
|
-
# Raised when an interactor context fails
|
11
|
-
#
|
12
|
-
# @author Aaron Allen <hello@aaronmallen.me>
|
13
|
-
# @since 0.1.5
|
14
|
-
# @version 0.1
|
15
|
-
#
|
8
|
+
# Raised when an interactor context fails.
|
16
9
|
# @!attribute [r] context
|
17
|
-
# @return [Base] an instance of {Base}
|
10
|
+
# @return [Context::Base] an instance of {Context::Base}
|
18
11
|
class ContextFailure < StandardError
|
19
12
|
attr_reader :context
|
20
13
|
|
21
|
-
#
|
22
|
-
# @
|
23
|
-
# instance of {ActiveInteractor::Context::Base}
|
24
|
-
# @return [ContextFailure] a new instance of {ContextFailure}
|
14
|
+
# @param context [Context::Base] the failed context instance.
|
15
|
+
# @return [ContextFailure] a new instance of {ContextFailure}.
|
25
16
|
def initialize(context = nil)
|
26
17
|
@context = context
|
27
|
-
|
18
|
+
context_class_name = context&.class&.name || 'Context'
|
19
|
+
super("#{context_class_name} failed!")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
# Raised when an invalid context class is assigned to an interactor.
|
24
|
+
# @since 1.0.0
|
25
|
+
# @!attribute [r] class_name
|
26
|
+
# @return [String|nil] the class name of the context
|
27
|
+
class InvalidContextClass < StandardError
|
28
|
+
attr_reader :class_name
|
29
|
+
|
30
|
+
# @param class_name [String] the context class name
|
31
|
+
# @return [InvalidContextClass] a new instance of {InvalidContextClass}
|
32
|
+
def initialize(class_name = nil)
|
33
|
+
@class_name = class_name
|
34
|
+
super("invalid context class #{class_name}")
|
28
35
|
end
|
29
36
|
end
|
30
37
|
end
|
@@ -1,65 +1,48 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module ActiveInteractor
|
4
|
-
#
|
5
|
-
#
|
4
|
+
# Interactor methods. {Base} includes {Interactor} all interactors
|
5
|
+
# should inherit from {Base}.
|
6
6
|
# @author Aaron Allen <hello@aaronmallen.me>
|
7
7
|
# @since 0.0.1
|
8
|
-
# @version 0.1
|
9
8
|
module Interactor
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
attr_accessor :context
|
9
|
+
def self.included(base)
|
10
|
+
base.class_eval do
|
11
|
+
extend ClassMethods
|
12
|
+
include Callbacks
|
13
|
+
include Context
|
14
|
+
delegate :execute_perform, :execute_perform!, :execute_rollback, to: :worker
|
15
|
+
end
|
21
16
|
end
|
22
|
-
|
17
|
+
# Interactor class methods.
|
23
18
|
module ClassMethods
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
19
|
+
# Run an interactor context. This it the primary API method for
|
20
|
+
# interacting with interactors.
|
27
21
|
# @example Run an interactor
|
28
22
|
# MyInteractor.perform(name: 'Aaron')
|
29
23
|
# #=> <#MyInteractor::Context name='Aaron'>
|
30
|
-
#
|
31
|
-
#
|
32
|
-
# @return [
|
24
|
+
# @param context [Hash|Context::Base] properties to assign to
|
25
|
+
# an interactor's context.
|
26
|
+
# @return [Context::Base] an instance of context.
|
33
27
|
def perform(context = {})
|
34
28
|
new(context).execute_perform
|
35
29
|
end
|
36
30
|
|
37
|
-
#
|
31
|
+
# Run an interactor context. The {.perform!} method behaves identically to
|
38
32
|
# the {.perform} method with one notable exception. If the context is failed
|
39
|
-
# during invocation of the interactor, the {
|
33
|
+
# during invocation of the interactor, the {Error::ContextFailure}
|
40
34
|
# is raised.
|
41
|
-
#
|
42
35
|
# @example Run an interactor
|
43
36
|
# MyInteractor.perform!(name: 'Aaron')
|
44
37
|
# #=> <#MyInteractor::Context name='Aaron'>
|
45
|
-
#
|
46
|
-
# @
|
47
|
-
# @return [
|
38
|
+
# @param context [Hash|Context::Base] properties to assign to the interactor context.
|
39
|
+
# @raise [Error::ContextFailure] if the context fails.
|
40
|
+
# @return [Context::Base] an instance of context.
|
48
41
|
def perform!(context = {})
|
49
42
|
new(context).execute_perform!
|
50
43
|
end
|
51
44
|
end
|
52
45
|
|
53
|
-
# Whether or not the context should fail when invalid
|
54
|
-
# this will return false if
|
55
|
-
# {Interactor::Callbacks::ClassMethods#allow_context_to_be_invalid}
|
56
|
-
# has been invoked on the class.
|
57
|
-
# @return [Boolean] `true` if the context should fail
|
58
|
-
# `false` if it should not.
|
59
|
-
def fail_on_invalid_context?
|
60
|
-
self.class.__fail_on_invalid_context
|
61
|
-
end
|
62
|
-
|
63
46
|
# Invoke an Interactor instance without any hooks, tracking, or rollback
|
64
47
|
# @abstract It is expected that the {#perform} method is overwritten
|
65
48
|
# for each interactor class.
|
@@ -70,28 +53,12 @@ module ActiveInteractor
|
|
70
53
|
# failure is expected to overwrite the {#rollback} method.
|
71
54
|
def rollback; end
|
72
55
|
|
73
|
-
|
74
|
-
# if {#skip_clean_context!} has not been invoked on the instance
|
75
|
-
# and {Interactor::Callbacks::ClassMethods#clean_context_on_completion}
|
76
|
-
# is invoked on the class this will return `true`.
|
77
|
-
#
|
78
|
-
# @return [Boolean] `true` if the context should be cleaned
|
79
|
-
# `false` if it should not be cleaned.
|
80
|
-
def should_clean_context?
|
81
|
-
@should_clean_context.nil? && self.class.__clean_after_perform
|
82
|
-
end
|
56
|
+
private
|
83
57
|
|
84
|
-
|
85
|
-
|
86
|
-
# This method is meant to be invoked by organizer interactors
|
87
|
-
# to ensure contexts are approriately passed between interactors.
|
88
|
-
#
|
89
|
-
# @return [Boolean] `true` if the context should be cleaned
|
90
|
-
# `false` if it should not.
|
91
|
-
def skip_clean_context!
|
92
|
-
@should_clean_context = false
|
58
|
+
def worker
|
59
|
+
Worker.new(self)
|
93
60
|
end
|
94
61
|
end
|
95
62
|
end
|
96
63
|
|
97
|
-
Dir[File.expand_path('interactor/*.rb', __dir__)].each { |file| require file }
|
64
|
+
Dir[File.expand_path('interactor/*.rb', __dir__)].sort.each { |file| require file }
|
@@ -1,62 +1,56 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'active_support/callbacks'
|
3
4
|
require 'active_support/core_ext/array/extract_options'
|
4
5
|
require 'active_support/core_ext/class/attribute'
|
5
6
|
|
6
7
|
module ActiveInteractor
|
7
8
|
module Interactor
|
8
|
-
#
|
9
|
-
#
|
9
|
+
# Interactor callback methods included by all {Base}
|
10
10
|
# @author Aaron Allen <hello@aaronmallen.me>
|
11
11
|
# @since 0.0.1
|
12
|
-
# @version 0.1
|
13
12
|
module Callbacks
|
14
|
-
|
13
|
+
def self.included(base)
|
14
|
+
base.class_eval do
|
15
|
+
extend ClassMethods
|
16
|
+
include ActiveSupport::Callbacks
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
class_attribute :__fail_on_invalid_context, instance_writer: false, default: true
|
22
|
-
define_callbacks :validation,
|
23
|
-
skip_after_callbacks_if_terminated: true,
|
24
|
-
scope: %i[kind name]
|
25
|
-
define_callbacks :perform, :rollback
|
18
|
+
define_callbacks :validation,
|
19
|
+
skip_after_callbacks_if_terminated: true,
|
20
|
+
scope: %i[kind name]
|
21
|
+
define_callbacks :perform, :rollback
|
22
|
+
end
|
26
23
|
end
|
27
24
|
|
25
|
+
# Interactor callback class methods extended by all {Base}
|
28
26
|
module ClassMethods
|
29
|
-
# Define a callback to call after
|
27
|
+
# Define a callback to call after {ActiveInteractor::Context::Base#valid? #valid?} has been invoked on an
|
30
28
|
# interactor's context
|
31
|
-
#
|
32
29
|
# @example Implement an after_context_validation callback
|
33
30
|
# class MyInteractor < ActiveInteractor::Base
|
34
|
-
# after_context_validation :
|
35
|
-
#
|
31
|
+
# after_context_validation :downcase_name
|
32
|
+
#
|
33
|
+
# private
|
36
34
|
#
|
37
|
-
# def
|
38
|
-
# context.name
|
35
|
+
# def downcase_name
|
36
|
+
# context.name.downcase!
|
39
37
|
# end
|
40
38
|
# end
|
41
39
|
#
|
42
|
-
#
|
43
|
-
# #=> <MyInteractor::Context name='
|
40
|
+
# result = MyInteractor.perform(name: 'Aaron')
|
41
|
+
# #=> <MyInteractor::Context name='aaron'>
|
44
42
|
#
|
45
|
-
#
|
46
|
-
# #=> false
|
47
|
-
#
|
48
|
-
# context.name
|
49
|
-
# #=> 'Aaron'
|
50
|
-
#
|
51
|
-
# context.valid?
|
43
|
+
# result.valid?
|
52
44
|
# #=> true
|
45
|
+
#
|
46
|
+
# result.name
|
47
|
+
# #=> 'aaron'
|
53
48
|
def after_context_validation(*args, &block)
|
54
49
|
options = normalize_options(args.extract_options!.dup.merge(prepend: true))
|
55
50
|
set_callback(:validation, :after, *args, options, &block)
|
56
51
|
end
|
57
52
|
|
58
|
-
# Define a callback to call after {
|
59
|
-
#
|
53
|
+
# Define a callback to call after {Interactor#perform #perform} has been invoked
|
60
54
|
# @example
|
61
55
|
# class MyInteractor < ActiveInteractor::Base
|
62
56
|
# after_perform :print_done
|
@@ -65,6 +59,8 @@ module ActiveInteractor
|
|
65
59
|
# puts 'Performing'
|
66
60
|
# end
|
67
61
|
#
|
62
|
+
# private
|
63
|
+
#
|
68
64
|
# def print_done
|
69
65
|
# puts 'Done'
|
70
66
|
# end
|
@@ -78,16 +74,21 @@ module ActiveInteractor
|
|
78
74
|
set_callback(:perform, :after, *filters, &block)
|
79
75
|
end
|
80
76
|
|
81
|
-
# Define a callback to call after {
|
82
|
-
#
|
77
|
+
# Define a callback to call after {Interactor#rollback #rollback} has been invoked
|
83
78
|
# @example
|
84
79
|
# class MyInteractor < ActiveInteractor::Base
|
85
80
|
# after_rollback :print_done
|
86
81
|
#
|
82
|
+
# def perform
|
83
|
+
# context.fail!
|
84
|
+
# end
|
85
|
+
#
|
87
86
|
# def rollback
|
88
87
|
# puts 'Rolling back'
|
89
88
|
# end
|
90
89
|
#
|
90
|
+
# private
|
91
|
+
#
|
91
92
|
# def print_done
|
92
93
|
# puts 'Done'
|
93
94
|
# end
|
@@ -103,17 +104,7 @@ module ActiveInteractor
|
|
103
104
|
set_callback(:rollback, :after, *filters, &block)
|
104
105
|
end
|
105
106
|
|
106
|
-
#
|
107
|
-
# invalid before or after the {ActiveInteractor::Base.perform} method
|
108
|
-
# is invoked. Calling this method on an interactor class
|
109
|
-
# will not invoke {ActiveInteractor::Context::Base#fail!} if the
|
110
|
-
# context is invalid.
|
111
|
-
def allow_context_to_be_invalid
|
112
|
-
self.__fail_on_invalid_context = false
|
113
|
-
end
|
114
|
-
|
115
|
-
# Define a callback to call around {ActiveInteractor::Base.perform} invokation
|
116
|
-
#
|
107
|
+
# Define a callback to call around {Interactor#perform #perform} invokation
|
117
108
|
# @example
|
118
109
|
# class MyInteractor < ActiveInteractor::Base
|
119
110
|
# around_perform :track_time
|
@@ -122,6 +113,8 @@ module ActiveInteractor
|
|
122
113
|
# sleep(1)
|
123
114
|
# end
|
124
115
|
#
|
116
|
+
# private
|
117
|
+
#
|
125
118
|
# def track_time
|
126
119
|
# context.start_time = Time.now.utc
|
127
120
|
# yield
|
@@ -129,20 +122,19 @@ module ActiveInteractor
|
|
129
122
|
# end
|
130
123
|
# end
|
131
124
|
#
|
132
|
-
#
|
125
|
+
# result = MyInteractor.perform(name: 'Aaron')
|
133
126
|
# #=> <MyInteractor::Context name='Aaron'>
|
134
127
|
#
|
135
|
-
#
|
128
|
+
# result.start_time
|
136
129
|
# #=> 2019-01-01 00:00:00 UTC
|
137
130
|
#
|
138
|
-
#
|
131
|
+
# result.end_time
|
139
132
|
# #=> 2019-01-01 00:00:01 UTC
|
140
133
|
def around_perform(*filters, &block)
|
141
134
|
set_callback(:perform, :around, *filters, &block)
|
142
135
|
end
|
143
136
|
|
144
|
-
# Define a callback to call around {
|
145
|
-
#
|
137
|
+
# Define a callback to call around {Interactor#rollback #rollback} invokation
|
146
138
|
# @example
|
147
139
|
# class MyInteractor < ActiveInteractor::Base
|
148
140
|
# around_rollback :track_time
|
@@ -151,6 +143,8 @@ module ActiveInteractor
|
|
151
143
|
# sleep(1)
|
152
144
|
# end
|
153
145
|
#
|
146
|
+
# private
|
147
|
+
#
|
154
148
|
# def track_time
|
155
149
|
# context.start_time = Time.now.utc
|
156
150
|
# yield
|
@@ -158,49 +152,48 @@ module ActiveInteractor
|
|
158
152
|
# end
|
159
153
|
# end
|
160
154
|
#
|
161
|
-
#
|
155
|
+
# result = MyInteractor.perform(name: 'Aaron')
|
162
156
|
# #=> <MyInteractor::Context name='Aaron'>
|
163
157
|
#
|
164
|
-
#
|
158
|
+
# result.rollback!
|
165
159
|
# #=> true
|
166
160
|
#
|
167
|
-
#
|
161
|
+
# result.start_time
|
168
162
|
# #=> 2019-01-01 00:00:00 UTC
|
169
163
|
#
|
170
|
-
#
|
164
|
+
# result.end_time
|
171
165
|
# #=> 2019-01-01 00:00:01 UTC
|
172
166
|
def around_rollback(*filters, &block)
|
173
167
|
set_callback(:rollback, :around, *filters, &block)
|
174
168
|
end
|
175
169
|
|
176
|
-
# Define a callback to call before
|
170
|
+
# Define a callback to call before {ActiveInteractor::Context::Base#valid? #valid?} has been invoked on an
|
177
171
|
# interactor's context
|
178
|
-
#
|
179
172
|
# @example Implement an after_context_validation callback
|
180
173
|
# class MyInteractor < ActiveInteractor::Base
|
181
|
-
# before_context_validation :
|
182
|
-
# context_validates :name, inclusion: { in: %w[Aaron] }
|
174
|
+
# before_context_validation :downcase_name
|
183
175
|
#
|
184
|
-
#
|
185
|
-
#
|
176
|
+
# private
|
177
|
+
#
|
178
|
+
# def downcase_name
|
179
|
+
# context.name.downcase!
|
186
180
|
# end
|
187
181
|
# end
|
188
182
|
#
|
189
|
-
#
|
190
|
-
# #=> <MyInteractor::Context name='
|
183
|
+
# result = MyInteractor.perform(name: 'Aaron')
|
184
|
+
# #=> <MyInteractor::Context name='aaron'>
|
191
185
|
#
|
192
|
-
#
|
186
|
+
# result.valid?
|
193
187
|
# #=> true
|
194
188
|
#
|
195
|
-
#
|
196
|
-
# #=> '
|
189
|
+
# result.name
|
190
|
+
# #=> 'aaron'
|
197
191
|
def before_context_validation(*args, &block)
|
198
192
|
options = normalize_options(args.extract_options!.dup)
|
199
193
|
set_callback(:validation, :before, *args, options, &block)
|
200
194
|
end
|
201
195
|
|
202
|
-
# Define a callback to call before {
|
203
|
-
#
|
196
|
+
# Define a callback to call before {Interactor#perform #perform} has been invoked
|
204
197
|
# @example
|
205
198
|
# class MyInteractor < ActiveInteractor::Base
|
206
199
|
# before_perform :print_start
|
@@ -209,6 +202,8 @@ module ActiveInteractor
|
|
209
202
|
# puts 'Performing'
|
210
203
|
# end
|
211
204
|
#
|
205
|
+
# private
|
206
|
+
#
|
212
207
|
# def print_start
|
213
208
|
# puts 'Start'
|
214
209
|
# end
|
@@ -222,8 +217,7 @@ module ActiveInteractor
|
|
222
217
|
set_callback(:perform, :before, *filters, &block)
|
223
218
|
end
|
224
219
|
|
225
|
-
# Define a callback to call before {
|
226
|
-
#
|
220
|
+
# Define a callback to call before {Interactor#rollback #rollback} has been invoked
|
227
221
|
# @example
|
228
222
|
# class MyInteractor < ActiveInteractor::Base
|
229
223
|
# before_rollback :print_start
|
@@ -232,6 +226,8 @@ module ActiveInteractor
|
|
232
226
|
# puts 'Rolling Back'
|
233
227
|
# end
|
234
228
|
#
|
229
|
+
# private
|
230
|
+
#
|
235
231
|
# def print_start
|
236
232
|
# puts 'Start'
|
237
233
|
# end
|
@@ -248,14 +244,6 @@ module ActiveInteractor
|
|
248
244
|
set_callback(:rollback, :before, *filters, &block)
|
249
245
|
end
|
250
246
|
|
251
|
-
# Calling this method on an interactor class will invoke
|
252
|
-
# {ActiveInteractor::Context::Base#clean!} on the interactor's
|
253
|
-
# context instance after {ActiveInteractor::Base.perform}
|
254
|
-
# is invoked.
|
255
|
-
def clean_context_on_completion
|
256
|
-
self.__clean_after_perform = true
|
257
|
-
end
|
258
|
-
|
259
247
|
private
|
260
248
|
|
261
249
|
def normalize_options(options)
|