Class: ActiveInteractor::Organizer::InteractorInterface Private

Inherits:
Object
  • Object
show all
Defined in:
lib/active_interactor/organizer/interactor_interface.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

An interface object to facilitate conditionally calling .perform on an interactor

Author:

Since:

  • 1.0.0

Constant Summary collapse

CONDITIONAL_FILTERS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Keywords for conditional filters

Returns:

  • (Array<Symbol>)

Since:

  • 1.0.0

%i[if unless].freeze
CALLBACKS =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 1.0.0

%i[before after].freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(interactor_class, options = {}) ⇒ InteractorInterface

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Initialize a new instance of ActiveInteractor::Organizer::InteractorInterface

Parameters:

Since:

  • 1.0.0



56
57
58
59
60
61
62
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 56

def initialize(interactor_class, options = {})
  @interactor_class = interactor_class.to_s.camelize.safe_constantize
  @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
  @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
  @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
  init_deferred_after_perform_callbacks
end

Instance Attribute Details

#callbacksHash{Symbol=>*} (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Callbacks for the interactor_class

Returns:

  • (Hash{Symbol=>*})

    the interactor callbacks

Since:

  • 1.1.0



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 42

class InteractorInterface
  attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks

  # Keywords for conditional filters
  # @return [Array<Symbol>]
  CONDITIONAL_FILTERS = %i[if unless].freeze
  CALLBACKS = %i[before after].freeze

  # Initialize a new instance of {InteractorInterface}
  #
  # @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
  # @param options [Hash] options to use for the {ActiveInteractor::Base interactor's}
  #  {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
  # @return [InteractorInterface] a new instance of {InteractorInterface}
  def initialize(interactor_class, options = {})
    @interactor_class = interactor_class.to_s.camelize.safe_constantize
    @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
    @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
    @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
    init_deferred_after_perform_callbacks
  end

  # Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
  # {Interactor::Perform::ClassMethods#perform! .perform!} method if all conditions in {#filters} are properly met.
  #
  # @param target [Class] the calling {Base organizer} instance
  # @param context [Class] an instance of {Context::Base context}
  # @param fail_on_error [Boolean] if `true` {Interactor::Perform::ClassMethods#perform! .perform!} will be called
  #  on the {#interactor_class} other wise {Interactor::Perform::ClassMethods#perform .perform} will be called.
  # @param perform_options [Hash] additional {Interactor::Perform::Options} to merge with {#perform_options}
  # @raise [Error::ContextFailure] if `fail_on_error` is `true` and the {#interactor_class}
  #  {Context::Status#fail! fails} its {Context::Base context}.
  # @return [Class] an instance of {Context::Base context}
  def perform(target, context, fail_on_error = false, perform_options = {})
    return if check_conditionals(target, :if) == false
    return if check_conditionals(target, :unless) == true

    skip_deferred_after_perform_callbacks

    method = fail_on_error ? :perform! : :perform
    options = self.perform_options.merge(perform_options)
    interactor_class.send(method, context, options)
  end

  def execute_inplace_callback(target, callback)
    resolve_option(target, callbacks[callback])
  end

  def execute_deferred_after_perform_callbacks(context)
    return unless deferred_after_perform_callbacks.present?

    interactor = interactor_class.new(context)
    env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
    deferred_after_perform_callbacks.compile.invoke_after(env)
    interactor.send(:context)
  end

  private

  def init_deferred_after_perform_callbacks
    after_callbacks_deferred = interactor_class.present? &&
                               interactor_class.after_callbacks_deferred_when_organized
    @deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
  end

  def skip_deferred_after_perform_callbacks
    return unless deferred_after_perform_callbacks.present?

    deferred_after_perform_callbacks.each do |callback|
      interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
    end
  end

  def check_conditionals(target, filter)
    resolve_option(target, filters[filter])
  end

  def resolve_option(target, opt)
    return unless opt

    return target.send(opt) if opt.is_a?(Symbol)
    return target.instance_exec(&opt) if opt.is_a?(Proc)
  end
end

#deferred_after_perform_callbacksHash{Symbol=>*} (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Deffered callbacks for the interactor_class

Returns:

  • (Hash{Symbol=>*})

    the interactor callbacks

Since:

  • 1.2.0



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 42

class InteractorInterface
  attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks

  # Keywords for conditional filters
  # @return [Array<Symbol>]
  CONDITIONAL_FILTERS = %i[if unless].freeze
  CALLBACKS = %i[before after].freeze

  # Initialize a new instance of {InteractorInterface}
  #
  # @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
  # @param options [Hash] options to use for the {ActiveInteractor::Base interactor's}
  #  {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
  # @return [InteractorInterface] a new instance of {InteractorInterface}
  def initialize(interactor_class, options = {})
    @interactor_class = interactor_class.to_s.camelize.safe_constantize
    @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
    @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
    @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
    init_deferred_after_perform_callbacks
  end

  # Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
  # {Interactor::Perform::ClassMethods#perform! .perform!} method if all conditions in {#filters} are properly met.
  #
  # @param target [Class] the calling {Base organizer} instance
  # @param context [Class] an instance of {Context::Base context}
  # @param fail_on_error [Boolean] if `true` {Interactor::Perform::ClassMethods#perform! .perform!} will be called
  #  on the {#interactor_class} other wise {Interactor::Perform::ClassMethods#perform .perform} will be called.
  # @param perform_options [Hash] additional {Interactor::Perform::Options} to merge with {#perform_options}
  # @raise [Error::ContextFailure] if `fail_on_error` is `true` and the {#interactor_class}
  #  {Context::Status#fail! fails} its {Context::Base context}.
  # @return [Class] an instance of {Context::Base context}
  def perform(target, context, fail_on_error = false, perform_options = {})
    return if check_conditionals(target, :if) == false
    return if check_conditionals(target, :unless) == true

    skip_deferred_after_perform_callbacks

    method = fail_on_error ? :perform! : :perform
    options = self.perform_options.merge(perform_options)
    interactor_class.send(method, context, options)
  end

  def execute_inplace_callback(target, callback)
    resolve_option(target, callbacks[callback])
  end

  def execute_deferred_after_perform_callbacks(context)
    return unless deferred_after_perform_callbacks.present?

    interactor = interactor_class.new(context)
    env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
    deferred_after_perform_callbacks.compile.invoke_after(env)
    interactor.send(:context)
  end

  private

  def init_deferred_after_perform_callbacks
    after_callbacks_deferred = interactor_class.present? &&
                               interactor_class.after_callbacks_deferred_when_organized
    @deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
  end

  def skip_deferred_after_perform_callbacks
    return unless deferred_after_perform_callbacks.present?

    deferred_after_perform_callbacks.each do |callback|
      interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
    end
  end

  def check_conditionals(target, filter)
    resolve_option(target, filters[filter])
  end

  def resolve_option(target, opt)
    return unless opt

    return target.send(opt) if opt.is_a?(Symbol)
    return target.instance_exec(&opt) if opt.is_a?(Proc)
  end
end

#filtersHash{Symbol=>Proc, Symbol} (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Conditional options for the interactor class

Returns:

  • (Hash{Symbol=>Proc, Symbol})

    conditional options for the interactor class

Since:

  • 1.0.0



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 42

class InteractorInterface
  attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks

  # Keywords for conditional filters
  # @return [Array<Symbol>]
  CONDITIONAL_FILTERS = %i[if unless].freeze
  CALLBACKS = %i[before after].freeze

  # Initialize a new instance of {InteractorInterface}
  #
  # @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
  # @param options [Hash] options to use for the {ActiveInteractor::Base interactor's}
  #  {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
  # @return [InteractorInterface] a new instance of {InteractorInterface}
  def initialize(interactor_class, options = {})
    @interactor_class = interactor_class.to_s.camelize.safe_constantize
    @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
    @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
    @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
    init_deferred_after_perform_callbacks
  end

  # Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
  # {Interactor::Perform::ClassMethods#perform! .perform!} method if all conditions in {#filters} are properly met.
  #
  # @param target [Class] the calling {Base organizer} instance
  # @param context [Class] an instance of {Context::Base context}
  # @param fail_on_error [Boolean] if `true` {Interactor::Perform::ClassMethods#perform! .perform!} will be called
  #  on the {#interactor_class} other wise {Interactor::Perform::ClassMethods#perform .perform} will be called.
  # @param perform_options [Hash] additional {Interactor::Perform::Options} to merge with {#perform_options}
  # @raise [Error::ContextFailure] if `fail_on_error` is `true` and the {#interactor_class}
  #  {Context::Status#fail! fails} its {Context::Base context}.
  # @return [Class] an instance of {Context::Base context}
  def perform(target, context, fail_on_error = false, perform_options = {})
    return if check_conditionals(target, :if) == false
    return if check_conditionals(target, :unless) == true

    skip_deferred_after_perform_callbacks

    method = fail_on_error ? :perform! : :perform
    options = self.perform_options.merge(perform_options)
    interactor_class.send(method, context, options)
  end

  def execute_inplace_callback(target, callback)
    resolve_option(target, callbacks[callback])
  end

  def execute_deferred_after_perform_callbacks(context)
    return unless deferred_after_perform_callbacks.present?

    interactor = interactor_class.new(context)
    env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
    deferred_after_perform_callbacks.compile.invoke_after(env)
    interactor.send(:context)
  end

  private

  def init_deferred_after_perform_callbacks
    after_callbacks_deferred = interactor_class.present? &&
                               interactor_class.after_callbacks_deferred_when_organized
    @deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
  end

  def skip_deferred_after_perform_callbacks
    return unless deferred_after_perform_callbacks.present?

    deferred_after_perform_callbacks.each do |callback|
      interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
    end
  end

  def check_conditionals(target, filter)
    resolve_option(target, filters[filter])
  end

  def resolve_option(target, opt)
    return unless opt

    return target.send(opt) if opt.is_a?(Symbol)
    return target.instance_exec(&opt) if opt.is_a?(Proc)
  end
end

#interactor_classConst (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

An interactor class

Returns:

Since:

  • 1.0.0



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 42

class InteractorInterface
  attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks

  # Keywords for conditional filters
  # @return [Array<Symbol>]
  CONDITIONAL_FILTERS = %i[if unless].freeze
  CALLBACKS = %i[before after].freeze

  # Initialize a new instance of {InteractorInterface}
  #
  # @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
  # @param options [Hash] options to use for the {ActiveInteractor::Base interactor's}
  #  {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
  # @return [InteractorInterface] a new instance of {InteractorInterface}
  def initialize(interactor_class, options = {})
    @interactor_class = interactor_class.to_s.camelize.safe_constantize
    @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
    @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
    @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
    init_deferred_after_perform_callbacks
  end

  # Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
  # {Interactor::Perform::ClassMethods#perform! .perform!} method if all conditions in {#filters} are properly met.
  #
  # @param target [Class] the calling {Base organizer} instance
  # @param context [Class] an instance of {Context::Base context}
  # @param fail_on_error [Boolean] if `true` {Interactor::Perform::ClassMethods#perform! .perform!} will be called
  #  on the {#interactor_class} other wise {Interactor::Perform::ClassMethods#perform .perform} will be called.
  # @param perform_options [Hash] additional {Interactor::Perform::Options} to merge with {#perform_options}
  # @raise [Error::ContextFailure] if `fail_on_error` is `true` and the {#interactor_class}
  #  {Context::Status#fail! fails} its {Context::Base context}.
  # @return [Class] an instance of {Context::Base context}
  def perform(target, context, fail_on_error = false, perform_options = {})
    return if check_conditionals(target, :if) == false
    return if check_conditionals(target, :unless) == true

    skip_deferred_after_perform_callbacks

    method = fail_on_error ? :perform! : :perform
    options = self.perform_options.merge(perform_options)
    interactor_class.send(method, context, options)
  end

  def execute_inplace_callback(target, callback)
    resolve_option(target, callbacks[callback])
  end

  def execute_deferred_after_perform_callbacks(context)
    return unless deferred_after_perform_callbacks.present?

    interactor = interactor_class.new(context)
    env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
    deferred_after_perform_callbacks.compile.invoke_after(env)
    interactor.send(:context)
  end

  private

  def init_deferred_after_perform_callbacks
    after_callbacks_deferred = interactor_class.present? &&
                               interactor_class.after_callbacks_deferred_when_organized
    @deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
  end

  def skip_deferred_after_perform_callbacks
    return unless deferred_after_perform_callbacks.present?

    deferred_after_perform_callbacks.each do |callback|
      interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
    end
  end

  def check_conditionals(target, filter)
    resolve_option(target, filters[filter])
  end

  def resolve_option(target, opt)
    return unless opt

    return target.send(opt) if opt.is_a?(Symbol)
    return target.instance_exec(&opt) if opt.is_a?(Proc)
  end
end

#perform_optionsHash{Symbol=>*} (readonly)

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Interactor::Perform::Options for the interactor #perform

Returns:

See Also:

Since:

  • 1.0.0



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 42

class InteractorInterface
  attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks

  # Keywords for conditional filters
  # @return [Array<Symbol>]
  CONDITIONAL_FILTERS = %i[if unless].freeze
  CALLBACKS = %i[before after].freeze

  # Initialize a new instance of {InteractorInterface}
  #
  # @param interactor_class [Const] an {ActiveInteractor::Base interactor} class
  # @param options [Hash] options to use for the {ActiveInteractor::Base interactor's}
  #  {Interactor::Perform::ClassMethods#perform .perform}. See {Interactor::Perform::Options}.
  # @return [InteractorInterface] a new instance of {InteractorInterface}
  def initialize(interactor_class, options = {})
    @interactor_class = interactor_class.to_s.camelize.safe_constantize
    @filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
    @callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
    @perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
    init_deferred_after_perform_callbacks
  end

  # Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
  # {Interactor::Perform::ClassMethods#perform! .perform!} method if all conditions in {#filters} are properly met.
  #
  # @param target [Class] the calling {Base organizer} instance
  # @param context [Class] an instance of {Context::Base context}
  # @param fail_on_error [Boolean] if `true` {Interactor::Perform::ClassMethods#perform! .perform!} will be called
  #  on the {#interactor_class} other wise {Interactor::Perform::ClassMethods#perform .perform} will be called.
  # @param perform_options [Hash] additional {Interactor::Perform::Options} to merge with {#perform_options}
  # @raise [Error::ContextFailure] if `fail_on_error` is `true` and the {#interactor_class}
  #  {Context::Status#fail! fails} its {Context::Base context}.
  # @return [Class] an instance of {Context::Base context}
  def perform(target, context, fail_on_error = false, perform_options = {})
    return if check_conditionals(target, :if) == false
    return if check_conditionals(target, :unless) == true

    skip_deferred_after_perform_callbacks

    method = fail_on_error ? :perform! : :perform
    options = self.perform_options.merge(perform_options)
    interactor_class.send(method, context, options)
  end

  def execute_inplace_callback(target, callback)
    resolve_option(target, callbacks[callback])
  end

  def execute_deferred_after_perform_callbacks(context)
    return unless deferred_after_perform_callbacks.present?

    interactor = interactor_class.new(context)
    env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
    deferred_after_perform_callbacks.compile.invoke_after(env)
    interactor.send(:context)
  end

  private

  def init_deferred_after_perform_callbacks
    after_callbacks_deferred = interactor_class.present? &&
                               interactor_class.after_callbacks_deferred_when_organized
    @deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
  end

  def skip_deferred_after_perform_callbacks
    return unless deferred_after_perform_callbacks.present?

    deferred_after_perform_callbacks.each do |callback|
      interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
    end
  end

  def check_conditionals(target, filter)
    resolve_option(target, filters[filter])
  end

  def resolve_option(target, opt)
    return unless opt

    return target.send(opt) if opt.is_a?(Symbol)
    return target.instance_exec(&opt) if opt.is_a?(Proc)
  end
end

Instance Method Details

#execute_deferred_after_perform_callbacks(context) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 1.0.0



90
91
92
93
94
95
96
97
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 90

def execute_deferred_after_perform_callbacks(context)
  return unless deferred_after_perform_callbacks.present?

  interactor = interactor_class.new(context)
  env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
  deferred_after_perform_callbacks.compile.invoke_after(env)
  interactor.send(:context)
end

#execute_inplace_callback(target, callback) ⇒ Object

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Since:

  • 1.0.0



86
87
88
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 86

def execute_inplace_callback(target, callback)
  resolve_option(target, callbacks[callback])
end

#perform(target, context, fail_on_error = false, perform_options = {}) ⇒ Class

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

Call the #interactor_class .perform or .perform! method if all conditions in #filters are properly met.

Parameters:

Returns:

  • (Class)

    an instance of context

Raises:

Since:

  • 1.0.0



75
76
77
78
79
80
81
82
83
84
# File 'lib/active_interactor/organizer/interactor_interface.rb', line 75

def perform(target, context, fail_on_error = false, perform_options = {})
  return if check_conditionals(target, :if) == false
  return if check_conditionals(target, :unless) == true

  skip_deferred_after_perform_callbacks

  method = fail_on_error ? :perform! : :perform
  options = self.perform_options.merge(perform_options)
  interactor_class.send(method, context, options)
end