flow 0.9.3 → 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +177 -245
- data/lib/flow.rb +2 -0
- data/lib/flow/concerns/transaction_wrapper.rb +10 -17
- data/lib/flow/custom_matchers.rb +5 -3
- data/lib/flow/custom_matchers/define_failure.rb +21 -0
- data/lib/flow/custom_matchers/define_output.rb +34 -0
- data/lib/flow/custom_matchers/handle_error.rb +32 -0
- data/lib/flow/custom_matchers/have_on_state.rb +54 -0
- data/lib/flow/custom_matchers/use_operations.rb +13 -11
- data/lib/flow/custom_matchers/wrap_in_transaction.rb +60 -0
- data/lib/flow/flow/callbacks.rb +1 -1
- data/lib/flow/flow/core.rb +1 -0
- data/lib/flow/flow/flux.rb +0 -2
- data/lib/flow/flow/status.rb +0 -4
- data/lib/flow/flow/transactions.rb +2 -2
- data/lib/flow/flow/trigger.rb +1 -1
- data/lib/flow/flow_base.rb +13 -15
- data/lib/flow/operation/accessors.rb +66 -0
- data/lib/flow/operation/callbacks.rb +12 -10
- data/lib/flow/operation/core.rb +10 -8
- data/lib/flow/operation/error_handler.rb +18 -12
- data/lib/flow/operation/errors/already_executed.rb +5 -3
- data/lib/flow/operation/errors/already_rewound.rb +5 -3
- data/lib/flow/operation/execute.rb +28 -26
- data/lib/flow/operation/failures.rb +48 -42
- data/lib/flow/operation/status.rb +18 -21
- data/lib/flow/operation/transactions.rb +8 -6
- data/lib/flow/operation_base.rb +15 -13
- data/lib/flow/rspec_configuration.rb +5 -0
- data/lib/flow/spec_helper.rb +3 -0
- data/lib/flow/state/errors/not_validated.rb +9 -0
- data/lib/flow/state/output.rb +59 -0
- data/lib/flow/state/status.rb +22 -0
- data/lib/flow/state_base.rb +9 -16
- data/lib/flow/version.rb +1 -1
- data/lib/generators/flow/application_flow/templates/application_flow.rb +1 -1
- data/lib/generators/flow/application_operation/templates/application_operation.rb +1 -1
- data/lib/generators/flow/application_state/templates/application_state.rb +1 -1
- data/lib/generators/flow/operation/USAGE +1 -1
- data/lib/generators/flow/operation/templates/operation.rb.erb +0 -5
- data/lib/generators/flow/state/USAGE +1 -1
- data/lib/generators/flow/state/templates/state.rb.erb +2 -1
- data/lib/generators/rspec/application_flow/templates/application_flow_spec.rb +1 -1
- data/lib/generators/rspec/application_operation/templates/application_operation_spec.rb +1 -9
- data/lib/generators/rspec/application_state/templates/application_state_spec.rb +1 -1
- data/lib/generators/rspec/flow/templates/flow_spec.rb.erb +0 -8
- data/lib/generators/rspec/operation/templates/operation_spec.rb.erb +5 -11
- data/lib/generators/rspec/state/templates/state_spec.rb.erb +8 -10
- metadata +39 -52
- data/lib/flow/custom_matchers/define_argument.rb +0 -19
- data/lib/flow/custom_matchers/define_attribute.rb +0 -19
- data/lib/flow/custom_matchers/define_option.rb +0 -26
- data/lib/flow/flow/ebb.rb +0 -28
- data/lib/flow/flow/revert.rb +0 -18
- data/lib/flow/operation/rewind.rb +0 -25
- data/lib/flow/state/arguments.rb +0 -30
- data/lib/flow/state/attributes.rb +0 -31
- data/lib/flow/state/callbacks.rb +0 -13
- data/lib/flow/state/core.rb +0 -14
- data/lib/flow/state/options.rb +0 -45
- data/lib/flow/state/string.rb +0 -34
@@ -1,18 +1,20 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Callbacks provide an extensible mechanism for hooking into a Operation.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Callbacks
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
included do
|
10
|
+
include ActiveSupport::Callbacks
|
11
|
+
define_callbacks :failure, :execute, :behavior
|
12
|
+
end
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
class_methods do
|
15
|
+
def on_failure(*filters, &block)
|
16
|
+
set_callback(:failure, :before, *filters, &block)
|
17
|
+
end
|
16
18
|
end
|
17
19
|
end
|
18
20
|
end
|
data/lib/flow/operation/core.rb
CHANGED
@@ -1,16 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Operations take a state as input.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Core
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
included do
|
10
|
+
attr_reader :state
|
11
|
+
end
|
11
12
|
|
12
|
-
|
13
|
-
|
13
|
+
def initialize(state)
|
14
|
+
@state = state
|
15
|
+
end
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -1,22 +1,28 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# When an exception is raised during during execution, but a handler can rescue, it causes a failure instead.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module ErrorHandler
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
class_methods do
|
10
|
+
private
|
10
11
|
|
11
|
-
|
12
|
-
|
12
|
+
def handle_error(error_class, problem: error_class.name.demodulize.underscore, with: nil, &block)
|
13
|
+
failure problem
|
13
14
|
|
14
|
-
|
15
|
+
rescue_from(error_class) { |exception| fail!(problem.to_sym, exception: exception) }
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
if with.present?
|
18
|
+
rescue_from(error_class, with: with)
|
19
|
+
elsif block_given?
|
20
|
+
rescue_from(error_class, &block)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def handle_errors(*errors)
|
25
|
+
errors.flatten.each(&method(:handle_error))
|
20
26
|
end
|
21
27
|
end
|
22
28
|
end
|
@@ -1,41 +1,43 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Operations define a `#behavior` that occurs when `#execute` is called.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Execute
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
included do
|
10
|
+
include ActiveSupport::Rescuable
|
10
11
|
|
11
|
-
|
12
|
+
attr_reader :operation_failure
|
12
13
|
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
def execute!
|
18
|
-
run_callbacks(:execute) do
|
19
|
-
run_callbacks(:behavior) { behavior }
|
14
|
+
set_callback :execute, :around, ->(_, block) { surveil(:execute) { block.call } }
|
15
|
+
set_callback :execute, :before, -> { raise Operation::Errors::AlreadyExecuted }, if: :executed?
|
20
16
|
end
|
21
17
|
|
22
|
-
|
23
|
-
|
24
|
-
|
18
|
+
def execute!
|
19
|
+
run_callbacks(:execute) do
|
20
|
+
run_callbacks(:behavior) { behavior }
|
21
|
+
end
|
25
22
|
|
26
|
-
|
27
|
-
|
23
|
+
self
|
24
|
+
rescue StandardError => exception
|
25
|
+
rescue_with_handler(exception) || raise
|
26
|
+
|
27
|
+
self
|
28
|
+
end
|
28
29
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
30
|
+
def execute
|
31
|
+
execute!
|
32
|
+
rescue Operation::Failures::OperationFailure => exception
|
33
|
+
@operation_failure = exception
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
self
|
36
|
+
end
|
36
37
|
|
37
|
-
|
38
|
-
|
38
|
+
def behavior
|
39
|
+
# abstract method which should be defined by descendants with the functionality of the given operation
|
40
|
+
end
|
39
41
|
end
|
40
42
|
end
|
41
43
|
end
|
@@ -1,64 +1,70 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# When `#execute` is unsuccessful, expected problems are **failures** and unexpected problems are **Exceptions**.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Failures
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
9
|
+
included do
|
10
|
+
class_attribute :_failures, instance_writer: false, default: []
|
10
11
|
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
class_methods do
|
15
|
-
def inherited(base)
|
16
|
-
base._failures = _failures.dup
|
17
|
-
super
|
12
|
+
delegate :_failures, to: :class
|
18
13
|
end
|
19
14
|
|
20
|
-
|
15
|
+
class_methods do
|
16
|
+
def inherited(base)
|
17
|
+
base._failures = _failures.dup
|
18
|
+
super
|
19
|
+
end
|
21
20
|
|
22
|
-
|
23
|
-
problem = problem.to_s.to_sym
|
24
|
-
warn(:problem_already_defined) if _failures.include? problem
|
21
|
+
private
|
25
22
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
23
|
+
def failure(problem, **options)
|
24
|
+
problem = problem.to_s.to_sym
|
25
|
+
_failures << problem
|
26
|
+
define_callbacks problem
|
27
|
+
define_on_failure_for_problem(problem)
|
28
|
+
define_fail_method_for_problem(problem)
|
29
|
+
define_proactive_failure_for_problem(problem, **options)
|
30
|
+
end
|
31
31
|
|
32
|
-
|
33
|
-
|
34
|
-
|
32
|
+
def define_on_failure_for_problem(problem)
|
33
|
+
on_failure_name = "on_#{problem}_failure".to_sym
|
34
|
+
return if respond_to?(on_failure_name)
|
35
35
|
|
36
|
-
|
37
|
-
|
36
|
+
define_singleton_method(on_failure_name) { |*filters, &block| set_callback(problem, :before, *filters, &block) }
|
37
|
+
end
|
38
38
|
|
39
|
-
|
40
|
-
|
41
|
-
|
39
|
+
def define_fail_method_for_problem(problem)
|
40
|
+
problem_failure_name = "#{problem}_failure!".to_sym
|
41
|
+
return if method_defined?(problem_failure_name)
|
42
42
|
|
43
|
-
|
43
|
+
define_method(problem_failure_name) { |**details| fail!(problem, **details) }
|
44
|
+
end
|
45
|
+
|
46
|
+
def define_proactive_failure_for_problem(problem, **options)
|
47
|
+
conditional_options = options.slice(:if, :unless)
|
48
|
+
set_callback(:execute, :before, -> { fail!(problem) }, **conditional_options) if conditional_options.present?
|
49
|
+
end
|
44
50
|
end
|
45
|
-
end
|
46
51
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
52
|
+
def fail!(problem, **details)
|
53
|
+
run_callbacks(problem) do
|
54
|
+
run_callbacks(:failure) do
|
55
|
+
error! OperationFailure.new(problem, **details), **details
|
56
|
+
end
|
51
57
|
end
|
52
58
|
end
|
53
|
-
end
|
54
59
|
|
55
|
-
|
56
|
-
|
60
|
+
class OperationFailure < StandardError
|
61
|
+
attr_reader :problem, :details
|
57
62
|
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
63
|
+
def initialize(problem = nil, **details)
|
64
|
+
super(problem)
|
65
|
+
@problem = problem
|
66
|
+
@details = OpenStruct.new(details)
|
67
|
+
end
|
62
68
|
end
|
63
69
|
end
|
64
70
|
end
|
@@ -1,33 +1,30 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# The Operation status is used by the Flow calling it to determine what to do next; continue on or stop and rollback.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Status
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
set_callback(:rewind, :before) { self.was_rewound = true }
|
9
|
+
included do
|
10
|
+
set_callback(:execute, :before) { self.was_executed = true }
|
11
11
|
|
12
|
-
|
12
|
+
private
|
13
13
|
|
14
|
-
|
15
|
-
|
14
|
+
attr_accessor :was_executed
|
15
|
+
end
|
16
16
|
|
17
|
-
|
18
|
-
|
19
|
-
|
17
|
+
def executed?
|
18
|
+
was_executed.present?
|
19
|
+
end
|
20
20
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
def failed?
|
26
|
-
operation_failure.present?
|
27
|
-
end
|
21
|
+
def failed?
|
22
|
+
operation_failure.present?
|
23
|
+
end
|
28
24
|
|
29
|
-
|
30
|
-
|
25
|
+
def success?
|
26
|
+
executed? && !failed?
|
27
|
+
end
|
31
28
|
end
|
32
29
|
end
|
33
30
|
end
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Operations which modify several persisted objects together should use a transaction.
|
4
|
-
module
|
5
|
-
module
|
6
|
-
|
4
|
+
module Flow
|
5
|
+
module Operation
|
6
|
+
module Transactions
|
7
|
+
extend ActiveSupport::Concern
|
7
8
|
|
8
|
-
|
9
|
-
|
10
|
-
|
9
|
+
class_methods do
|
10
|
+
def callback_name
|
11
|
+
:behavior
|
12
|
+
end
|
11
13
|
end
|
12
14
|
end
|
13
15
|
end
|
data/lib/flow/operation_base.rb
CHANGED
@@ -3,26 +3,28 @@
|
|
3
3
|
require_relative "operation/errors/already_executed"
|
4
4
|
require_relative "operation/errors/already_rewound"
|
5
5
|
|
6
|
+
require_relative "operation/accessors"
|
6
7
|
require_relative "operation/callbacks"
|
7
8
|
require_relative "operation/core"
|
8
9
|
require_relative "operation/error_handler"
|
9
10
|
require_relative "operation/execute"
|
10
11
|
require_relative "operation/failures"
|
11
|
-
require_relative "operation/rewind"
|
12
12
|
require_relative "operation/status"
|
13
13
|
require_relative "operation/transactions"
|
14
14
|
|
15
15
|
# An **Operation** is a service object which is executed with a **State**.
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
16
|
+
module Flow
|
17
|
+
class OperationBase
|
18
|
+
include ShortCircuIt
|
19
|
+
include Technologic
|
20
|
+
include Flow::TransactionWrapper
|
21
|
+
include Flow::Operation::Accessors
|
22
|
+
include Flow::Operation::Callbacks
|
23
|
+
include Flow::Operation::Core
|
24
|
+
include Flow::Operation::ErrorHandler
|
25
|
+
include Flow::Operation::Execute
|
26
|
+
include Flow::Operation::Failures
|
27
|
+
include Flow::Operation::Status
|
28
|
+
include Flow::Operation::Transactions
|
29
|
+
end
|
28
30
|
end
|
data/lib/flow/spec_helper.rb
CHANGED