use_cases 0.2.5
Sign up to get free protection for your applications and to get access to all the features.
- 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
|