use_cases 0.2.5
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 +7 -0
- data/.github/workflows/main.yml +23 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/.rubocop.yml +19 -0
- data/.rubocop_todo.yml +28 -0
- data/CHANGELOG.md +20 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +20 -0
- data/Gemfile.lock +129 -0
- data/LICENSE.txt +21 -0
- data/README.md +265 -0
- data/Rakefile +22 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/use_case.rb +57 -0
- data/lib/use_cases/authorize.rb +20 -0
- data/lib/use_cases/base.rb +8 -0
- data/lib/use_cases/dsl.rb +35 -0
- data/lib/use_cases/errors.rb +9 -0
- data/lib/use_cases/module_optins.rb +43 -0
- data/lib/use_cases/notifications.rb +51 -0
- data/lib/use_cases/params.rb +15 -0
- data/lib/use_cases/prepare.rb +19 -0
- data/lib/use_cases/rspec/matchers.rb +31 -0
- data/lib/use_cases/stack.rb +51 -0
- data/lib/use_cases/stack_runner.rb +60 -0
- data/lib/use_cases/step_active_job_adapter.rb +34 -0
- data/lib/use_cases/step_adapters/abstract.rb +99 -0
- data/lib/use_cases/step_adapters/authorize.rb +22 -0
- data/lib/use_cases/step_adapters/check.rb +22 -0
- data/lib/use_cases/step_adapters/enqueue.rb +18 -0
- data/lib/use_cases/step_adapters/map.rb +18 -0
- data/lib/use_cases/step_adapters/step.rb +18 -0
- data/lib/use_cases/step_adapters/tee.rb +20 -0
- data/lib/use_cases/step_adapters/try.rb +20 -0
- data/lib/use_cases/step_adapters.rb +25 -0
- data/lib/use_cases/step_result.rb +55 -0
- data/lib/use_cases/transaction.rb +25 -0
- data/lib/use_cases/validate.rb +104 -0
- data/lib/use_cases/version.rb +5 -0
- data/lib/use_cases.rb +7 -0
- data/use_cases.gemspec +42 -0
- metadata +200 -0
data/lib/use_case.rb
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/monads"
|
4
|
+
require "dry/events"
|
5
|
+
require "dry/monads/do"
|
6
|
+
require "dry/monads/do/all"
|
7
|
+
require "dry/matcher/result_matcher"
|
8
|
+
|
9
|
+
require "use_cases/authorize"
|
10
|
+
require "use_cases/dsl"
|
11
|
+
require "use_cases/errors"
|
12
|
+
require "use_cases/validate"
|
13
|
+
require "use_cases/stack"
|
14
|
+
require "use_cases/params"
|
15
|
+
require "use_cases/stack_runner"
|
16
|
+
require "use_cases/step_result"
|
17
|
+
require "use_cases/notifications"
|
18
|
+
require "use_cases/prepare"
|
19
|
+
require "use_cases/step_adapters"
|
20
|
+
require "use_cases/module_optins"
|
21
|
+
|
22
|
+
module UseCase
|
23
|
+
extend UseCases::ModuleOptins
|
24
|
+
|
25
|
+
def self.included(base)
|
26
|
+
super
|
27
|
+
base.class_eval do
|
28
|
+
include Dry::Monads[:result]
|
29
|
+
include Dry::Monads::Do.for(:call)
|
30
|
+
include Dry::Matcher.for(:call, with: Dry::Matcher::ResultMatcher)
|
31
|
+
|
32
|
+
extend UseCases::DSL
|
33
|
+
extend UseCases::ModuleOptins
|
34
|
+
|
35
|
+
include UseCases::StepAdapters
|
36
|
+
include UseCases::Notifications
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
attr_reader :stack
|
41
|
+
|
42
|
+
def initialize(*)
|
43
|
+
@stack = UseCases::Stack.new(self.class.__steps__).bind(self)
|
44
|
+
# self.class.bind_step_subscriptions
|
45
|
+
end
|
46
|
+
|
47
|
+
def call(params, current_user = nil)
|
48
|
+
params = UseCases::Params.new(params)
|
49
|
+
do_call(params, current_user)
|
50
|
+
end
|
51
|
+
|
52
|
+
private
|
53
|
+
|
54
|
+
def do_call(*args)
|
55
|
+
UseCases::StackRunner.new(stack).call(*args)
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
module Authorize
|
5
|
+
class NoAuthorizationError < StandardError; end
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
extend DSL
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module DSL
|
14
|
+
def authorize(step_name, options = {})
|
15
|
+
options[:failure] = :unauthorized
|
16
|
+
check step_name, **options
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/inflector/methods"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module DSL
|
7
|
+
include ActiveSupport::Inflector
|
8
|
+
|
9
|
+
def register_adapter(step_class)
|
10
|
+
step_name = underscore(demodulize(step_class.name))
|
11
|
+
|
12
|
+
define_singleton_method(step_name) do |name, options = {}|
|
13
|
+
__steps__ << step_class.new(name, nil, options)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def __steps__
|
18
|
+
@__steps__ ||= []
|
19
|
+
end
|
20
|
+
|
21
|
+
def subscribe(listeners)
|
22
|
+
@listeners = listeners
|
23
|
+
|
24
|
+
if listeners.is_a?(Hash)
|
25
|
+
listeners.each do |step_name, listener|
|
26
|
+
__steps__.detect { |step| step.name == step_name }.subscribe(listener)
|
27
|
+
end
|
28
|
+
else
|
29
|
+
__steps__.each do |step|
|
30
|
+
step.subscribe(listeners)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/authorize"
|
4
|
+
require "use_cases/prepare"
|
5
|
+
require "use_cases/transaction"
|
6
|
+
require "use_cases/validate"
|
7
|
+
|
8
|
+
module UseCases
|
9
|
+
module ModuleOptins
|
10
|
+
attr_accessor :options
|
11
|
+
|
12
|
+
def [](*options)
|
13
|
+
@modules = []
|
14
|
+
@modules << UseCases::Authorize if options.include?(:authorized)
|
15
|
+
@modules << UseCases::Transaction if options.include?(:transactional)
|
16
|
+
@modules << UseCases::Validate if options.include?(:validated)
|
17
|
+
@modules << UseCases::Prepare if options.include?(:prepared)
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def included(base)
|
22
|
+
super
|
23
|
+
@modules ||= []
|
24
|
+
return if @modules.empty?
|
25
|
+
|
26
|
+
base.include(*@modules)
|
27
|
+
@modules = nil
|
28
|
+
end
|
29
|
+
|
30
|
+
def inherited(base)
|
31
|
+
super
|
32
|
+
@modules ||= []
|
33
|
+
return if @modules.empty?
|
34
|
+
|
35
|
+
base.include(*@modules)
|
36
|
+
@modules = nil
|
37
|
+
end
|
38
|
+
|
39
|
+
def descendants
|
40
|
+
ObjectSpace.each_object(Class).select { |klass| klass < self }
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "byebug"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module Notifications
|
7
|
+
def self.included(base)
|
8
|
+
base.extend DSL
|
9
|
+
end
|
10
|
+
|
11
|
+
module DSL
|
12
|
+
def subscribe_to_step(event_id, listener)
|
13
|
+
step_subscriptions << StepSubscription.new(event_id, listener)
|
14
|
+
end
|
15
|
+
|
16
|
+
def bind_step_subscriptions
|
17
|
+
step_subscriptions.each { |subscription| subscription.bind(__steps__) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def step_subscriptions
|
21
|
+
@step_subscriptions ||= []
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
class StepSubscription
|
26
|
+
attr_reader :event_id, :listener, :steps
|
27
|
+
|
28
|
+
def initialize(event_id, listener)
|
29
|
+
@event_id = event_id
|
30
|
+
@listener = listener
|
31
|
+
end
|
32
|
+
|
33
|
+
def bind(steps)
|
34
|
+
@steps = steps
|
35
|
+
|
36
|
+
step = steps.find { |s| s.name == step_name }
|
37
|
+
step.subscribe(event_predicate, listener)
|
38
|
+
end
|
39
|
+
|
40
|
+
def event_predicate
|
41
|
+
predicate = event_id.to_s.gsub(step_name.to_s, "")
|
42
|
+
|
43
|
+
"step#{predicate}".to_sym
|
44
|
+
end
|
45
|
+
|
46
|
+
def step_name
|
47
|
+
steps.map(&:name).find { |step_name| step_name.start_with?(event_id.to_s) }
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/hash_with_indifferent_access"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
class Params < ActiveSupport::HashWithIndifferentAccess
|
7
|
+
def initialize(params)
|
8
|
+
if defined?(Rails) && params.is_a?(ActionController::Parameters)
|
9
|
+
super(params.permit!.to_h)
|
10
|
+
else
|
11
|
+
super(params)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/tee"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module Prepare
|
7
|
+
def self.included(base)
|
8
|
+
base.class_eval do
|
9
|
+
extend DSL
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module DSL
|
14
|
+
def prepare(name, options = {})
|
15
|
+
__steps__.unshift StepAdapters::Tee.new(name, nil, options)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "rspec"
|
4
|
+
|
5
|
+
RSpec::Matchers.define(:fail_with_code) do |expected_code|
|
6
|
+
match do |test_subject|
|
7
|
+
expect(test_subject.failure?).to be true
|
8
|
+
expect(test_subject.failure.first).to eq expected_code
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec::Matchers.define(:fail_with_payload) do |expected_result|
|
13
|
+
match do |test_subject|
|
14
|
+
expect(test_subject.failure?).to be true
|
15
|
+
expect(test_subject.failure.last).to eq expected_result
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
RSpec::Matchers.define(:fail_with) do |*expected_failure|
|
20
|
+
match do |test_subject|
|
21
|
+
expect(test_subject.failure?).to be true
|
22
|
+
expect(test_subject.failure).to eq expected_failure
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
RSpec::Matchers.define(:succeed_with) do |expected_result|
|
27
|
+
match do |test_subject|
|
28
|
+
expect(test_subject.success?).to be true
|
29
|
+
expect(test_subject.success).to eq expected_result
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
class Stack
|
5
|
+
attr_reader :steps
|
6
|
+
|
7
|
+
attr_accessor :prev_step_result, :current_step
|
8
|
+
|
9
|
+
def initialize(steps)
|
10
|
+
@steps = steps
|
11
|
+
end
|
12
|
+
|
13
|
+
def bind(object)
|
14
|
+
steps.map! { |step| step.bind(object) }
|
15
|
+
self
|
16
|
+
end
|
17
|
+
|
18
|
+
def call(initial_value = nil)
|
19
|
+
steps.reduce(initial_value) do |prev_result, current_step|
|
20
|
+
self.current_step = current_step
|
21
|
+
self.prev_step_result = prev_result
|
22
|
+
|
23
|
+
yield
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def in_first_step?
|
28
|
+
steps.find_index(current_step).zero?
|
29
|
+
end
|
30
|
+
|
31
|
+
def previous_result_empty?
|
32
|
+
prev_step_result.nil?
|
33
|
+
end
|
34
|
+
|
35
|
+
def previous_step_value
|
36
|
+
prev_step_result.value
|
37
|
+
end
|
38
|
+
|
39
|
+
def step_names
|
40
|
+
steps.map(&:name)
|
41
|
+
end
|
42
|
+
|
43
|
+
def include_step?(step_name)
|
44
|
+
step_names.include?(step_name)
|
45
|
+
end
|
46
|
+
|
47
|
+
def find_step(step_name)
|
48
|
+
steps.find { |step| step.name == step_name }
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
class StackRunner
|
5
|
+
attr_reader :stack
|
6
|
+
|
7
|
+
def initialize(stack)
|
8
|
+
@stack = stack
|
9
|
+
end
|
10
|
+
|
11
|
+
def call(*args, &around_block)
|
12
|
+
return around_block.call { do_call(*args) } if around_block
|
13
|
+
|
14
|
+
do_call(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def do_call(*args)
|
20
|
+
stack.call do
|
21
|
+
result = _run_step(stack, args)
|
22
|
+
|
23
|
+
return result if result.failure?
|
24
|
+
|
25
|
+
result
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def _run_step(stack, args)
|
30
|
+
step = stack.current_step
|
31
|
+
expected_args_count = step.args_count
|
32
|
+
step_args = _assert_step_arguments_with_count(stack, args)
|
33
|
+
|
34
|
+
raise MissingStepError, "Missing ##{step.name} implementation." if step.missing?
|
35
|
+
|
36
|
+
if expected_args_count != step_args.count
|
37
|
+
raise StepArgumentError,
|
38
|
+
"##{step.name} expects #{expected_args_count} arguments it only received #{step_args.count}, make sure your previous step Success() statement has a payload."
|
39
|
+
end
|
40
|
+
|
41
|
+
step.call(*step_args)
|
42
|
+
end
|
43
|
+
|
44
|
+
def _assert_step_arguments_with_count(stack, args)
|
45
|
+
step_args_count = stack.current_step.args_count
|
46
|
+
|
47
|
+
if _should_prepend_previous_step_result_to_args?(stack)
|
48
|
+
prev_step_result_value = stack.previous_step_value
|
49
|
+
|
50
|
+
args = [prev_step_result_value] + args
|
51
|
+
end
|
52
|
+
|
53
|
+
args.first(step_args_count)
|
54
|
+
end
|
55
|
+
|
56
|
+
def _should_prepend_previous_step_result_to_args?(stack)
|
57
|
+
!stack.previous_result_empty? && !stack.in_first_step?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "active_support/inflector"
|
4
|
+
|
5
|
+
return unless defined? ActiveJob
|
6
|
+
|
7
|
+
module UseCases
|
8
|
+
class StepActiveJobAdapter < ActiveJob::Base
|
9
|
+
def perform(use_case_name, step_name, *args)
|
10
|
+
args = deserialize_step_arguments(args)
|
11
|
+
|
12
|
+
use_case = ActiveSupport::Inflector.constantize(use_case_name)
|
13
|
+
use_case.new.send(step_name, *args)
|
14
|
+
end
|
15
|
+
|
16
|
+
def deserialize_step_arguments(args)
|
17
|
+
args.map { |arg| arg.is_a?(Hash) && arg.delete("_serialized_by_use_case") ? arg.deserialize : arg }
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.serialize_step_arguments(args)
|
21
|
+
args.select.with_index do |arg, index|
|
22
|
+
ActiveJob::Arguments.send(:serialize_argument, arg)
|
23
|
+
|
24
|
+
rescue ActiveJob::SerializationError => _e
|
25
|
+
arg.serialize.merge("_serialized_by_use_case" => true)
|
26
|
+
|
27
|
+
rescue NoMethodError => _e
|
28
|
+
puts "[WARNING] #{arg.class} (index = #{index})" \
|
29
|
+
"is not serializable and does not repond to #serialize and will be ignored."
|
30
|
+
false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,99 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "dry/monads/all"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Abstract
|
8
|
+
include Dry::Monads
|
9
|
+
|
10
|
+
# include Dry::Events::Publisher[name || object_id]
|
11
|
+
|
12
|
+
# def self.inherited(subclass)
|
13
|
+
# super
|
14
|
+
# subclass.register_event(:step)
|
15
|
+
# subclass.register_event(:step_succeeded)
|
16
|
+
# subclass.register_event(:step_failed)
|
17
|
+
# end
|
18
|
+
|
19
|
+
include Dry::Monads[:result]
|
20
|
+
|
21
|
+
attr_reader :name, :object, :failure, :options
|
22
|
+
|
23
|
+
def initialize(name, *args, **options)
|
24
|
+
@name = name
|
25
|
+
@object = args.first
|
26
|
+
@options = options
|
27
|
+
end
|
28
|
+
|
29
|
+
def previous_step_result
|
30
|
+
object.stack.prev_step_result
|
31
|
+
end
|
32
|
+
|
33
|
+
def call(*args)
|
34
|
+
around_call(name, args: args) do
|
35
|
+
before_call(name, args: args)
|
36
|
+
|
37
|
+
result = StepResult.new(self, do_call(*args))
|
38
|
+
|
39
|
+
if result.success?
|
40
|
+
after_call_success(name, args: args, value: result.value)
|
41
|
+
else
|
42
|
+
after_call_failure(name, args: args, value: result.value)
|
43
|
+
end
|
44
|
+
|
45
|
+
result
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def do_call(*args)
|
50
|
+
callable_proc.call(*args)
|
51
|
+
end
|
52
|
+
|
53
|
+
def bind(object)
|
54
|
+
self.class.new(name, object, options)
|
55
|
+
end
|
56
|
+
|
57
|
+
def callable_proc
|
58
|
+
callable_object.method(callable_method)
|
59
|
+
end
|
60
|
+
|
61
|
+
def callable_object
|
62
|
+
case options[:with]
|
63
|
+
when NilClass, FalseClass then object
|
64
|
+
when String then object.send(options[:with])
|
65
|
+
else options[:with]
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def callable_method
|
70
|
+
case options[:with]
|
71
|
+
when NilClass, FalseClass then name
|
72
|
+
else :call
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
def external?
|
77
|
+
options[:with].present?
|
78
|
+
end
|
79
|
+
|
80
|
+
def args_count
|
81
|
+
callable_proc.parameters.count
|
82
|
+
end
|
83
|
+
|
84
|
+
def missing?
|
85
|
+
!callable_object.respond_to?(callable_method, true)
|
86
|
+
end
|
87
|
+
|
88
|
+
def before_call(*args); end
|
89
|
+
|
90
|
+
def after_call_success(*args); end
|
91
|
+
|
92
|
+
def after_call_failure(*args); end
|
93
|
+
|
94
|
+
def around_call(*_args, &blk)
|
95
|
+
blk.call
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/check"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Authorize < UseCases::StepAdapters::Check
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
prev_result = previous_step_result.value
|
13
|
+
raise InvalidReturnValue, "The return value should not be a Monad." if result.is_a?(Dry::Monads::Result)
|
14
|
+
|
15
|
+
failure_code = options[:failure] || :check_failure
|
16
|
+
failure_message = options[:failure_message] || "Failed"
|
17
|
+
|
18
|
+
result ? Success(prev_result) : Failure([failure_code, failure_message])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/abstract"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Check < UseCases::StepAdapters::Abstract
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
prev_result = previous_step_result.value
|
13
|
+
raise InvalidReturnValue, "The return value should not be a Monad." if result.is_a?(Dry::Monads::Result)
|
14
|
+
|
15
|
+
failure_code = options[:failure] || :check_failure
|
16
|
+
failure_message = options[:failure_message] || "Failed"
|
17
|
+
|
18
|
+
result ? Success(prev_result) : Failure([failure_code, failure_message])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module UseCases
|
4
|
+
module StepAdapters
|
5
|
+
class Enqueue < UseCases::StepAdapters::Tee
|
6
|
+
def do_call(*base_args)
|
7
|
+
args = [object.class.name, name.to_s, *base_args]
|
8
|
+
args = ::UseCases::StepActiveJobAdapter.serialize_step_arguments(args)
|
9
|
+
|
10
|
+
job_options = options.slice(:queue, :wait, :wait_until, :priority)
|
11
|
+
|
12
|
+
::UseCases::StepActiveJobAdapter.set(job_options).perform_later(*args)
|
13
|
+
|
14
|
+
Success(previous_step_result.value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/abstract"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Map < UseCases::StepAdapters::Abstract
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
raise InvalidReturnValue, "The return value should not be a Monad." if result.is_a?(Dry::Monads::Result)
|
13
|
+
|
14
|
+
Success(result)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/abstract"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Step < UseCases::StepAdapters::Abstract
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
raise InvalidReturnValue, "Return value should be a Monad" unless result.is_a?(Dry::Monads::Result)
|
13
|
+
|
14
|
+
result
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/abstract"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Tee < UseCases::StepAdapters::Abstract
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
rescue StandardError => _e
|
13
|
+
raise InvalidReturnValue, "For a tee step, a Monad will have no effect." if result.is_a?(Dry::Monads::Result)
|
14
|
+
|
15
|
+
prev_result = previous_step_result.value
|
16
|
+
Success(prev_result)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "use_cases/step_adapters/abstract"
|
4
|
+
|
5
|
+
module UseCases
|
6
|
+
module StepAdapters
|
7
|
+
class Try < UseCases::StepAdapters::Abstract
|
8
|
+
class InvalidReturnValue < StandardError; end
|
9
|
+
|
10
|
+
def do_call(*args)
|
11
|
+
result = super(*args)
|
12
|
+
raise InvalidReturnValue, "The return value should not be a Monad." if result.is_a?(Dry::Monads::Result)
|
13
|
+
|
14
|
+
Success(result)
|
15
|
+
rescue options[:catch] || StandardError => e
|
16
|
+
Failure([options[:failure], e.message])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|