interactify 0.1.0.pre.alpha.1 → 0.3.0.pre.alpha.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/.rubocop.yml +23 -0
- data/CHANGELOG.md +9 -1
- data/README.md +174 -105
- data/lib/interactify/async_job_klass.rb +61 -0
- data/lib/interactify/call_wrapper.rb +2 -0
- data/lib/interactify/contract_failure.rb +6 -0
- data/lib/interactify/contract_helpers.rb +10 -10
- data/lib/interactify/dsl.rb +6 -2
- data/lib/interactify/each_chain.rb +12 -4
- data/lib/interactify/if_interactor.rb +10 -4
- data/lib/interactify/interactor_wiring/callable_representation.rb +79 -0
- data/lib/interactify/interactor_wiring/constants.rb +125 -0
- data/lib/interactify/interactor_wiring/error_context.rb +41 -0
- data/lib/interactify/interactor_wiring/files.rb +51 -0
- data/lib/interactify/interactor_wiring.rb +57 -272
- data/lib/interactify/interactor_wrapper.rb +72 -0
- data/lib/interactify/job_maker.rb +20 -69
- data/lib/interactify/jobable.rb +9 -7
- data/lib/interactify/mismatching_promise_error.rb +17 -0
- data/lib/interactify/organizer.rb +30 -0
- data/lib/interactify/promising.rb +34 -0
- data/lib/interactify/rspec/matchers.rb +9 -11
- data/lib/interactify/unique_klass_name.rb +21 -0
- data/lib/interactify/version.rb +1 -1
- data/lib/interactify.rb +39 -9
- metadata +14 -3
- data/lib/interactify/organizer_call_monkey_patch.rb +0 -40
@@ -0,0 +1,72 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/unique_klass_name"
|
4
|
+
|
5
|
+
module Interactify
|
6
|
+
class InteractorWrapper
|
7
|
+
attr_reader :organizer, :interactor
|
8
|
+
|
9
|
+
def self.wrap_many(organizer, interactors)
|
10
|
+
Array(interactors).map do |interactor|
|
11
|
+
wrap(organizer, interactor)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def self.wrap(organizer, interactor)
|
16
|
+
new(organizer, interactor).wrap
|
17
|
+
end
|
18
|
+
|
19
|
+
def initialize(organizer, interactor)
|
20
|
+
@organizer = organizer
|
21
|
+
@interactor = interactor
|
22
|
+
end
|
23
|
+
|
24
|
+
def wrap
|
25
|
+
case interactor
|
26
|
+
when Hash
|
27
|
+
wrap_conditional
|
28
|
+
when Array
|
29
|
+
wrap_chain
|
30
|
+
when Proc
|
31
|
+
wrap_proc
|
32
|
+
else
|
33
|
+
interactor
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def wrap_chain
|
38
|
+
return self.class.wrap(organizer, interactor.first) if interactor.length == 1
|
39
|
+
|
40
|
+
klass_name = UniqueKlassName.for(organizer, "Chained")
|
41
|
+
organizer.chain(klass_name, *interactor.map { self.class.wrap(organizer, _1) })
|
42
|
+
end
|
43
|
+
|
44
|
+
def wrap_conditional
|
45
|
+
raise ArgumentError, "Hash must have at least :if, and :then key" unless condition && then_do
|
46
|
+
|
47
|
+
return organizer.if(condition, then_do, else_do) if else_do
|
48
|
+
|
49
|
+
organizer.if(condition, then_do)
|
50
|
+
end
|
51
|
+
|
52
|
+
def condition = interactor[:if]
|
53
|
+
def then_do = interactor[:then]
|
54
|
+
def else_do = interactor[:else]
|
55
|
+
|
56
|
+
def wrap_proc
|
57
|
+
this = self
|
58
|
+
|
59
|
+
Class.new do
|
60
|
+
include Interactify
|
61
|
+
|
62
|
+
define_singleton_method :wrapped do
|
63
|
+
this.interactor
|
64
|
+
end
|
65
|
+
|
66
|
+
define_method(:call) do
|
67
|
+
this.interactor.call(context)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -1,5 +1,9 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "sidekiq"
|
4
|
+
require "sidekiq/job"
|
5
|
+
|
6
|
+
require "interactify/async_job_klass"
|
3
7
|
|
4
8
|
module Interactify
|
5
9
|
class JobMaker
|
@@ -13,93 +17,40 @@ module Interactify
|
|
13
17
|
end
|
14
18
|
|
15
19
|
concerning :JobClass do
|
16
|
-
def
|
17
|
-
@
|
20
|
+
def job_klass
|
21
|
+
@job_klass ||= define_job_klass
|
18
22
|
end
|
19
23
|
|
20
24
|
private
|
21
25
|
|
22
|
-
def
|
26
|
+
def define_job_klass
|
23
27
|
this = self
|
24
28
|
|
25
29
|
invalid_keys = this.opts.symbolize_keys.keys - %i[queue retry dead backtrace pool tags]
|
26
30
|
|
27
31
|
raise ArgumentError, "Invalid keys: #{invalid_keys}" if invalid_keys.any?
|
28
32
|
|
29
|
-
|
33
|
+
build_job_klass(opts).tap do |klass|
|
34
|
+
klass.const_set(:JOBABLE_OPTS, opts)
|
35
|
+
klass.const_set(:JOBABLE_METHOD_NAME, method_name)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_job_klass(opts)
|
40
|
+
Class.new do
|
30
41
|
include Sidekiq::Job
|
31
42
|
|
32
|
-
sidekiq_options(
|
43
|
+
sidekiq_options(opts)
|
33
44
|
|
34
45
|
def perform(...)
|
35
46
|
self.class.module_parent.send(self.class::JOBABLE_METHOD_NAME, ...)
|
36
47
|
end
|
37
48
|
end
|
38
|
-
|
39
|
-
job_class.const_set(:JOBABLE_OPTS, opts)
|
40
|
-
job_class.const_set(:JOBABLE_METHOD_NAME, method_name)
|
41
|
-
job_class
|
42
49
|
end
|
43
50
|
end
|
44
51
|
|
45
|
-
|
46
|
-
|
47
|
-
klass = Class.new do
|
48
|
-
include Interactor
|
49
|
-
include Interactor::Contracts
|
50
|
-
end
|
51
|
-
|
52
|
-
attach_call(klass)
|
53
|
-
attach_call!(klass)
|
54
|
-
|
55
|
-
klass
|
56
|
-
end
|
57
|
-
|
58
|
-
def args(context)
|
59
|
-
args = context.to_h.stringify_keys
|
60
|
-
|
61
|
-
return args unless container_klass.respond_to?(:contract)
|
62
|
-
|
63
|
-
restrict_to_optional_or_keys_from_contract(args)
|
64
|
-
end
|
65
|
-
|
66
|
-
private
|
67
|
-
|
68
|
-
def attach_call(async_job_class)
|
69
|
-
# e.g. SomeInteractor::AsyncWithSuffix.call(foo: 'bar')
|
70
|
-
async_job_class.send(:define_singleton_method, :call) do |context|
|
71
|
-
call!(context)
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
def attach_call!(async_job_class)
|
76
|
-
this = self
|
77
|
-
|
78
|
-
# e.g. SomeInteractor::AsyncWithSuffix.call!(foo: 'bar')
|
79
|
-
async_job_class.send(:define_singleton_method, :call!) do |context|
|
80
|
-
# e.g. SomeInteractor::JobWithSuffix
|
81
|
-
job_klass = this.container_klass.const_get("Job#{this.klass_suffix}")
|
82
|
-
|
83
|
-
# e.g. SomeInteractor::JobWithSuffix.perform_async({foo: 'bar'})
|
84
|
-
job_klass.perform_async(this.args(context))
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
def restrict_to_optional_or_keys_from_contract(args)
|
89
|
-
keys = container_klass
|
90
|
-
.contract
|
91
|
-
.expectations
|
92
|
-
.instance_eval { @terms }
|
93
|
-
.schema
|
94
|
-
.key_map
|
95
|
-
.to_dot_notation
|
96
|
-
.map(&:to_s)
|
97
|
-
|
98
|
-
optional = Array(container_klass.optional_attrs).map(&:to_s)
|
99
|
-
keys += optional
|
100
|
-
|
101
|
-
args.slice(*keys)
|
102
|
-
end
|
52
|
+
def async_job_klass
|
53
|
+
AsyncJobKlass.new(container_klass:, klass_suffix:).async_job_klass
|
103
54
|
end
|
104
55
|
end
|
105
56
|
end
|
data/lib/interactify/jobable.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/job_maker"
|
2
4
|
|
3
5
|
module Interactify
|
4
6
|
module Jobable
|
@@ -18,7 +20,7 @@ module Interactify
|
|
18
20
|
|
19
21
|
to_call = defined?(super_klass::Async) ? :interactor_job : :job_calling
|
20
22
|
|
21
|
-
klass.send(to_call, opts
|
23
|
+
klass.send(to_call, opts:, method_name: jobable_method_name)
|
22
24
|
super(klass)
|
23
25
|
end
|
24
26
|
end
|
@@ -51,18 +53,18 @@ module Interactify
|
|
51
53
|
# obviously you will need to be aware that later interactors
|
52
54
|
# in an interactor chain cannot depend on the result of the async
|
53
55
|
# interactor
|
54
|
-
def interactor_job(method_name: :call!, opts: {}, klass_suffix:
|
56
|
+
def interactor_job(method_name: :call!, opts: {}, klass_suffix: "")
|
55
57
|
job_maker = JobMaker.new(container_klass: self, opts:, method_name:, klass_suffix:)
|
56
58
|
# with WhateverInteractor::Job you can perform the interactor as a job
|
57
59
|
# from sidekiq
|
58
60
|
# e.g. WhateverInteractor::Job.perform_async(...)
|
59
|
-
const_set("Job#{klass_suffix}", job_maker.
|
61
|
+
const_set("Job#{klass_suffix}", job_maker.job_klass)
|
60
62
|
|
61
63
|
# with WhateverInteractor::Async you can call WhateverInteractor::Job
|
62
64
|
# in an organizer oro on its oen using normal interactor call call! semantics
|
63
65
|
# e.g. WhateverInteractor::Async.call(...)
|
64
66
|
# WhateverInteractor::Async.call!(...)
|
65
|
-
const_set("Async#{klass_suffix}", job_maker.
|
67
|
+
const_set("Async#{klass_suffix}", job_maker.async_job_klass)
|
66
68
|
end
|
67
69
|
|
68
70
|
# if this was defined in ExampleClass this creates the following class
|
@@ -80,10 +82,10 @@ module Interactify
|
|
80
82
|
# # the following class is created that you can use to enqueue a job
|
81
83
|
# in the sidekiq yaml file
|
82
84
|
# ExampleClass::Job.some_method
|
83
|
-
def job_calling(method_name:, opts: {}, klass_suffix:
|
85
|
+
def job_calling(method_name:, opts: {}, klass_suffix: "")
|
84
86
|
job_maker = JobMaker.new(container_klass: self, opts:, method_name:, klass_suffix:)
|
85
87
|
|
86
|
-
const_set("Job#{klass_suffix}", job_maker.
|
88
|
+
const_set("Job#{klass_suffix}", job_maker.job_klass)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/contract_failure"
|
4
|
+
|
5
|
+
module Interactify
|
6
|
+
class MismatchingPromiseError < ContractFailure
|
7
|
+
def initialize(interactor, promising, promised_keys)
|
8
|
+
super <<~MESSAGE.chomp
|
9
|
+
#{interactor} does not promise:
|
10
|
+
#{promising.inspect}
|
11
|
+
|
12
|
+
Actual promises are:
|
13
|
+
#{promised_keys.inspect}
|
14
|
+
MESSAGE
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/interactor_wrapper"
|
4
|
+
|
5
|
+
module Interactify
|
6
|
+
module Organizer
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def organize(*interactors)
|
11
|
+
wrapped = InteractorWrapper.wrap_many(self, interactors)
|
12
|
+
|
13
|
+
super(*wrapped)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def call
|
18
|
+
self.class.organized.each do |interactor|
|
19
|
+
instance = interactor.new(context)
|
20
|
+
|
21
|
+
instance.instance_variable_set(
|
22
|
+
:@_interactor_called_by_non_bang_method,
|
23
|
+
@_interactor_called_by_non_bang_method
|
24
|
+
)
|
25
|
+
|
26
|
+
instance.tap(&:run!)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/mismatching_promise_error"
|
4
|
+
|
5
|
+
module Interactify
|
6
|
+
class Promising
|
7
|
+
attr_reader :interactor, :promising
|
8
|
+
|
9
|
+
def self.validate(interactor, *promising)
|
10
|
+
new(interactor, *promising).validate
|
11
|
+
|
12
|
+
interactor
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize(interactor, *promising)
|
16
|
+
@interactor = interactor
|
17
|
+
@promising = format_keys promising
|
18
|
+
end
|
19
|
+
|
20
|
+
def validate
|
21
|
+
return if promising == promised_keys
|
22
|
+
|
23
|
+
raise MismatchingPromiseError.new(interactor, promising, promised_keys)
|
24
|
+
end
|
25
|
+
|
26
|
+
def promised_keys
|
27
|
+
format_keys interactor.promised_keys
|
28
|
+
end
|
29
|
+
|
30
|
+
def format_keys(keys)
|
31
|
+
Array(keys).compact.map(&:to_sym).sort
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "interactify/interactor_wiring"
|
2
4
|
|
3
5
|
# Custom matcher that implements expect_inputs
|
4
6
|
# e.g.
|
@@ -6,7 +8,9 @@ require 'interactify/interactor_wiring'
|
|
6
8
|
|
7
9
|
RSpec::Matchers.define :expect_inputs do |*expected_inputs|
|
8
10
|
match do |actual|
|
9
|
-
|
11
|
+
next false unless actual.respond_to?(:expected_keys)
|
12
|
+
|
13
|
+
actual_inputs = Array(actual.expected_keys)
|
10
14
|
@missing_inputs = expected_inputs - actual_inputs
|
11
15
|
@extra_inputs = actual_inputs - expected_inputs
|
12
16
|
|
@@ -19,17 +23,15 @@ RSpec::Matchers.define :expect_inputs do |*expected_inputs|
|
|
19
23
|
message += "\n\textra inputs: #{@extra_inputs}" if @extra_inputs
|
20
24
|
message
|
21
25
|
end
|
22
|
-
|
23
|
-
def expected_keys(klass)
|
24
|
-
Array(klass.contract.expectations.instance_eval { @terms }.json&.rules&.keys)
|
25
|
-
end
|
26
26
|
end
|
27
27
|
|
28
28
|
# Custom matcher that implements promise_outputs
|
29
29
|
# e.g. expect(described_class).to promise_outputs(:request_logger)
|
30
30
|
RSpec::Matchers.define :promise_outputs do |*expected_outputs|
|
31
31
|
match do |actual|
|
32
|
-
|
32
|
+
next false unless actual.respond_to?(:promised_keys)
|
33
|
+
|
34
|
+
actual_outputs = Array(actual.promised_keys)
|
33
35
|
@missing_outputs = expected_outputs - actual_outputs
|
34
36
|
@extra_outputs = actual_outputs - expected_outputs
|
35
37
|
|
@@ -42,10 +44,6 @@ RSpec::Matchers.define :promise_outputs do |*expected_outputs|
|
|
42
44
|
message += "\n\textra outputs: #{@extra_outputs}" if @extra_outputs
|
43
45
|
message
|
44
46
|
end
|
45
|
-
|
46
|
-
def promised_keys(klass)
|
47
|
-
Array(klass.contract.promises.instance_eval { @terms }.json&.rules&.keys)
|
48
|
-
end
|
49
47
|
end
|
50
48
|
|
51
49
|
# Custom matcher that implements organize_interactors
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Interactify
|
4
|
+
module UniqueKlassName
|
5
|
+
def self.for(namespace, prefix)
|
6
|
+
id = generate_unique_id
|
7
|
+
klass_name = :"#{prefix}#{id}"
|
8
|
+
|
9
|
+
while namespace.const_defined?(klass_name)
|
10
|
+
id = generate_unique_id
|
11
|
+
klass_name = :"#{prefix}#{id}"
|
12
|
+
end
|
13
|
+
|
14
|
+
klass_name.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.generate_unique_id
|
18
|
+
rand(10_000)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/interactify/version.rb
CHANGED
data/lib/interactify.rb
CHANGED
@@ -1,14 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
3
|
+
require "interactor"
|
4
|
+
require "interactor-contracts"
|
5
|
+
require "rails"
|
6
|
+
require "active_support/all"
|
7
7
|
|
8
|
-
require
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
8
|
+
require "interactify/version"
|
9
|
+
require "interactify/contract_helpers"
|
10
|
+
require "interactify/dsl"
|
11
|
+
require "interactify/interactor_wiring"
|
12
|
+
require "interactify/promising"
|
12
13
|
|
13
14
|
module Interactify
|
14
15
|
extend ActiveSupport::Concern
|
@@ -18,6 +19,12 @@ module Interactify
|
|
18
19
|
Interactify::InteractorWiring.new(root: Interactify.configuration.root, ignore:).validate_app
|
19
20
|
end
|
20
21
|
|
22
|
+
def reset
|
23
|
+
@on_contract_breach = nil
|
24
|
+
@before_raise_hook = nil
|
25
|
+
@configuration = nil
|
26
|
+
end
|
27
|
+
|
21
28
|
def trigger_contract_breach_hook(...)
|
22
29
|
@on_contract_breach&.call(...)
|
23
30
|
end
|
@@ -75,11 +82,34 @@ module Interactify
|
|
75
82
|
interactor_job
|
76
83
|
end
|
77
84
|
|
85
|
+
class_methods do
|
86
|
+
def promising(*args)
|
87
|
+
Promising.validate(self, *args)
|
88
|
+
end
|
89
|
+
|
90
|
+
def promised_keys
|
91
|
+
_interactify_extract_keys(contract.promises)
|
92
|
+
end
|
93
|
+
|
94
|
+
def expected_keys
|
95
|
+
_interactify_extract_keys(contract.expectations)
|
96
|
+
end
|
97
|
+
|
98
|
+
private
|
99
|
+
|
100
|
+
# this is the most brittle part of the code, relying on
|
101
|
+
# interactor-contracts internals
|
102
|
+
# so extracted it to here so change is isolated
|
103
|
+
def _interactify_extract_keys(clauses)
|
104
|
+
clauses.instance_eval { @terms }.json&.rules&.keys
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
78
108
|
class Configuration
|
79
109
|
attr_writer :root
|
80
110
|
|
81
111
|
def root
|
82
|
-
@root ||= Rails.root /
|
112
|
+
@root ||= Rails.root / "app"
|
83
113
|
end
|
84
114
|
end
|
85
115
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interactify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0.pre.alpha.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Burns
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-12-
|
11
|
+
date: 2023-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: interactor
|
@@ -109,21 +109,32 @@ extensions: []
|
|
109
109
|
extra_rdoc_files: []
|
110
110
|
files:
|
111
111
|
- ".rspec"
|
112
|
+
- ".rubocop.yml"
|
112
113
|
- CHANGELOG.md
|
113
114
|
- LICENSE.txt
|
114
115
|
- README.md
|
115
116
|
- Rakefile
|
116
117
|
- lib/interactify.rb
|
118
|
+
- lib/interactify/async_job_klass.rb
|
117
119
|
- lib/interactify/call_wrapper.rb
|
120
|
+
- lib/interactify/contract_failure.rb
|
118
121
|
- lib/interactify/contract_helpers.rb
|
119
122
|
- lib/interactify/dsl.rb
|
120
123
|
- lib/interactify/each_chain.rb
|
121
124
|
- lib/interactify/if_interactor.rb
|
122
125
|
- lib/interactify/interactor_wiring.rb
|
126
|
+
- lib/interactify/interactor_wiring/callable_representation.rb
|
127
|
+
- lib/interactify/interactor_wiring/constants.rb
|
128
|
+
- lib/interactify/interactor_wiring/error_context.rb
|
129
|
+
- lib/interactify/interactor_wiring/files.rb
|
130
|
+
- lib/interactify/interactor_wrapper.rb
|
123
131
|
- lib/interactify/job_maker.rb
|
124
132
|
- lib/interactify/jobable.rb
|
125
|
-
- lib/interactify/
|
133
|
+
- lib/interactify/mismatching_promise_error.rb
|
134
|
+
- lib/interactify/organizer.rb
|
135
|
+
- lib/interactify/promising.rb
|
126
136
|
- lib/interactify/rspec/matchers.rb
|
137
|
+
- lib/interactify/unique_klass_name.rb
|
127
138
|
- lib/interactify/version.rb
|
128
139
|
- sig/interactify.rbs
|
129
140
|
homepage: https://github.com/markburns/interactify
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Interactify
|
2
|
-
module OrganizerCallMonkeyPatch
|
3
|
-
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
class_methods do
|
6
|
-
def organize(*interactors)
|
7
|
-
wrapped = wrap_lambdas_in_interactors(interactors)
|
8
|
-
|
9
|
-
super(*wrapped)
|
10
|
-
end
|
11
|
-
|
12
|
-
def wrap_lambdas_in_interactors(interactors)
|
13
|
-
Array(interactors).map do |interactor|
|
14
|
-
case interactor
|
15
|
-
when Proc
|
16
|
-
Class.new do
|
17
|
-
include Interactify
|
18
|
-
|
19
|
-
define_method(:call) do
|
20
|
-
interactor.call(context)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
else
|
24
|
-
interactor
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def call
|
31
|
-
self.class.organized.each do |interactor|
|
32
|
-
instance = interactor.new(context)
|
33
|
-
instance.instance_variable_set(:@_interactor_called_by_non_bang_method,
|
34
|
-
@_interactor_called_by_non_bang_method)
|
35
|
-
|
36
|
-
instance.tap(&:run!)
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|