flow 0.9.3 → 0.10.0
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/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,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# RSpec matcher for flow state arguments.
|
4
|
-
#
|
5
|
-
# Usage:
|
6
|
-
#
|
7
|
-
# RSpec.describe ExampleState, type: :state do
|
8
|
-
# subject { described_class.new(**input) }
|
9
|
-
#
|
10
|
-
# let(:input) { {} }
|
11
|
-
#
|
12
|
-
# it { is_expected.to define_argument :foo }
|
13
|
-
# end
|
14
|
-
|
15
|
-
RSpec::Matchers.define :define_argument do |argument|
|
16
|
-
match { |state| expect(state._arguments).to include argument }
|
17
|
-
description { "has argument #{argument}" }
|
18
|
-
failure_message { |state| "expected #{state.class.name}# to have argument #{argument}" }
|
19
|
-
end
|
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# RSpec matcher for flow state attributes.
|
4
|
-
#
|
5
|
-
# Usage:
|
6
|
-
#
|
7
|
-
# RSpec.describe ExampleState, type: :state do
|
8
|
-
# subject { described_class.new(**input) }
|
9
|
-
#
|
10
|
-
# let(:input) { {} }
|
11
|
-
#
|
12
|
-
# it { is_expected.to define_attribute :foo }
|
13
|
-
# end
|
14
|
-
|
15
|
-
RSpec::Matchers.define :define_attribute do |attribute|
|
16
|
-
match { |state| expect(state.class._attributes).to include attribute }
|
17
|
-
description { "has attribute #{attribute}" }
|
18
|
-
failure_message { |state| "expected #{state.class.name}# to have attribute #{attribute}" }
|
19
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# RSpec matcher for flow state options.
|
4
|
-
#
|
5
|
-
# Usage:
|
6
|
-
#
|
7
|
-
# RSpec.describe ExampleState, type: :state do
|
8
|
-
# subject { described_class.new(**input) }
|
9
|
-
#
|
10
|
-
# let(:input) { {} }
|
11
|
-
#
|
12
|
-
# it { is_expected.to define_option :foo }
|
13
|
-
# it { is_expected.to define_option :foo, default_value }
|
14
|
-
# end
|
15
|
-
|
16
|
-
RSpec::Matchers.define :define_option do |option, default_value = nil|
|
17
|
-
match { |state| expect(state._options[option].default_value).to eq default_value }
|
18
|
-
description { "has option #{option}" }
|
19
|
-
failure_message { |state| "expected #{state.class.name}# to have option #{option}, #{for_default(default_value)}" }
|
20
|
-
|
21
|
-
def for_default(default_value)
|
22
|
-
return "without a default value" if default_value.nil?
|
23
|
-
|
24
|
-
"with default value #{default_value}"
|
25
|
-
end
|
26
|
-
end
|
data/lib/flow/flow/ebb.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# When a `#revert` is called on a Flow, `#rewind` is called on Operations in reverse of the order they were executed.
|
4
|
-
module Flow
|
5
|
-
module Ebb
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
set_callback(:initialize, :after) { @rewound_operations = [] }
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
attr_reader :rewound_operations
|
14
|
-
|
15
|
-
def _ebb
|
16
|
-
rewindable_operations.reverse_each { |executed_operation| rewound_operations << executed_operation.rewind }
|
17
|
-
end
|
18
|
-
|
19
|
-
def rewindable_operations
|
20
|
-
executed_operations - rewound_operations
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def ebb
|
25
|
-
run_callbacks(:ebb) { _ebb }
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/lib/flow/flow/revert.rb
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Reverting a Flow rewinds all its executed operations in reverse order (see `Flow::Ebb`).
|
4
|
-
module Flow
|
5
|
-
module Revert
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
set_callback :revert, :around, ->(_, block) { surveil(:revert) { block.call } }
|
10
|
-
end
|
11
|
-
|
12
|
-
def revert
|
13
|
-
run_callbacks(:revert) { ebb }
|
14
|
-
|
15
|
-
state
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# When something goes wrong in Flow, `#rewind` is called on all executed Operations to `#undo` their behavior.
|
4
|
-
module Operation
|
5
|
-
module Rewind
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
set_callback :rewind, :around, ->(_, block) { surveil(:rewind) { block.call } }
|
10
|
-
set_callback :rewind, :before, -> { raise Operation::Errors::AlreadyRewound }, if: :rewound?
|
11
|
-
end
|
12
|
-
|
13
|
-
def rewind
|
14
|
-
run_callbacks(:rewind) do
|
15
|
-
run_callbacks(:undo) { undo }
|
16
|
-
end
|
17
|
-
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
def undo
|
22
|
-
# abstract method which should be defined by descendants to undo the functionality of the `#behavior` method
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
data/lib/flow/state/arguments.rb
DELETED
@@ -1,30 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Arguments describe input required to define the initial state.
|
4
|
-
module State
|
5
|
-
module Arguments
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
class_attribute :_arguments, instance_writer: false, default: []
|
10
|
-
set_callback :initialize, :after do
|
11
|
-
missing = _arguments.select { |argument| public_send(argument).nil? }
|
12
|
-
raise ArgumentError, "Missing #{"argument".pluralize(missing.length)}: #{missing.join(", ")}" if missing.any?
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
class_methods do
|
17
|
-
def inherited(base)
|
18
|
-
base._arguments = _arguments.dup
|
19
|
-
super
|
20
|
-
end
|
21
|
-
|
22
|
-
private
|
23
|
-
|
24
|
-
def argument(argument)
|
25
|
-
_arguments << argument
|
26
|
-
define_attribute argument
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
@@ -1,31 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# A state's attributes provide accessors to the input data it was initialized with.
|
4
|
-
module State
|
5
|
-
module Attributes
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
include ActiveModel::AttributeMethods
|
10
|
-
|
11
|
-
class_attribute :_attributes, instance_writer: false, default: []
|
12
|
-
end
|
13
|
-
|
14
|
-
class_methods do
|
15
|
-
def inherited(base)
|
16
|
-
base._attributes = _attributes.dup
|
17
|
-
super
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def define_attribute(attribute)
|
23
|
-
_attributes << attribute
|
24
|
-
|
25
|
-
attr_accessor attribute
|
26
|
-
define_attribute_methods attribute
|
27
|
-
end
|
28
|
-
alias_method :attribute, :define_attribute
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
data/lib/flow/state/callbacks.rb
DELETED
@@ -1,13 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Callbacks provide an extensible mechanism for hooking into a State.
|
4
|
-
module State
|
5
|
-
module Callbacks
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
include ActiveSupport::Callbacks
|
10
|
-
define_callbacks :initialize
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
data/lib/flow/state/core.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# A state accepts input represented by arguments and options which initialize it.
|
4
|
-
module State
|
5
|
-
module Core
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
def initialize(**input)
|
9
|
-
run_callbacks(:initialize) do
|
10
|
-
input.each { |key, value| __send__("#{key}=".to_sym, value) }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
data/lib/flow/state/options.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Options describe input which may be provided to define or override the initial state.
|
4
|
-
module State
|
5
|
-
module Options
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
included do
|
9
|
-
class_attribute :_options, instance_writer: false, default: {}
|
10
|
-
|
11
|
-
set_callback :initialize, :after do
|
12
|
-
_options.each do |option, info|
|
13
|
-
__send__("#{option}=".to_sym, info.default_value.dup) if public_send(option).nil?
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
class_methods do
|
19
|
-
def inherited(base)
|
20
|
-
dup = _options.dup
|
21
|
-
base._options = dup.each { |k, v| dup[k] = v.dup }
|
22
|
-
super
|
23
|
-
end
|
24
|
-
|
25
|
-
private
|
26
|
-
|
27
|
-
def option(option, default: nil, &block)
|
28
|
-
_options[option] = Option.new(default: default, &block)
|
29
|
-
define_attribute option
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
class Option
|
34
|
-
def initialize(default:, &block)
|
35
|
-
@default_value = (default.nil? && block_given?) ? block : default
|
36
|
-
end
|
37
|
-
|
38
|
-
def default_value
|
39
|
-
return instance_eval(&@default_value) if @default_value.respond_to?(:call)
|
40
|
-
|
41
|
-
@default_value
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
data/lib/flow/state/string.rb
DELETED
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
# Formats the state as a string.
|
4
|
-
module State
|
5
|
-
module String
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
def to_s
|
9
|
-
string_for(__method__)
|
10
|
-
end
|
11
|
-
|
12
|
-
def inspect
|
13
|
-
string_for(__method__)
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def stringable_attributes
|
19
|
-
self.class._attributes
|
20
|
-
end
|
21
|
-
|
22
|
-
def string_for(method)
|
23
|
-
"#<#{self.class.name} #{attribute_string(method)}>"
|
24
|
-
end
|
25
|
-
|
26
|
-
def attribute_string(method)
|
27
|
-
stringable_attribute_values.map { |attribute, value| "#{attribute}=#{value.public_send(method)}" }.join(" ")
|
28
|
-
end
|
29
|
-
|
30
|
-
def stringable_attribute_values
|
31
|
-
stringable_attributes.each_with_object({}) { |attribute, result| result[attribute] = public_send(attribute) }
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|