flow 0.9.2 → 0.9.3

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.
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # A callback driven approach to wrap some business logic within a transaction.
3
+ # A callback driven approach to wrap business logic within database transaction.
4
4
  module TransactionWrapper
5
5
  extend ActiveSupport::Concern
6
6
 
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require_relative "custom_matchers/define_argument"
4
+ require_relative "custom_matchers/define_attribute"
4
5
  require_relative "custom_matchers/define_option"
5
6
  require_relative "custom_matchers/use_operations"
@@ -0,0 +1,19 @@
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,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Operations are an ordered list of the behaviors which should are executed with and possibly change the Flow's state.
3
+ # Operations are an ordered list of the behaviors which are executed with (and possibly change) the Flow's state.
4
4
  module Flow
5
5
  module Operations
6
6
  extend ActiveSupport::Concern
@@ -10,7 +10,7 @@ module Flow
10
10
  end
11
11
 
12
12
  def triggered?
13
- executed_operations.any?
13
+ executed_operations.any? || failed_operation?
14
14
  end
15
15
 
16
16
  def success?
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # It's best practice to have Flows in which nothing should be done unless everything is successful to use a transaction.
3
+ # Flows where no operation should be persisted unless all are successful should use a transaction.
4
4
  module Flow
5
5
  module Transactions
6
6
  extend ActiveSupport::Concern
@@ -12,7 +12,7 @@ require_relative "flow/status"
12
12
  require_relative "flow/transactions"
13
13
  require_relative "flow/trigger"
14
14
 
15
- # A flow is a collection of procedurally executed operations sharing a common state.
15
+ # A **Flow** is a collection of procedurally executed **Operations** sharing a common **State**.
16
16
  class FlowBase
17
17
  include ShortCircuIt
18
18
  include Technologic
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Accepts input representing the state.
3
+ # Operations take a state as input.
4
4
  module Operation
5
5
  module Core
6
6
  extend ActiveSupport::Concern
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # An unhandled error during execution is exceptional, and handlers unable to rescue an error cause a failure instead.
3
+ # When an exception is raised during during execution, but a handler can rescue, it causes a failure instead.
4
4
  module Operation
5
5
  module ErrorHandler
6
6
  extend ActiveSupport::Concern
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Operation
4
+ module Errors
5
+ class AlreadyExecuted < StandardError; end
6
+ end
7
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Operation
4
+ module Errors
5
+ class AlreadyRewound < StandardError; end
6
+ end
7
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Operations *must* define the `#behavior` that occurs when `#execute` is called.
3
+ # Operations define a `#behavior` that occurs when `#execute` is called.
4
4
  module Operation
5
5
  module Execute
6
6
  extend ActiveSupport::Concern
@@ -11,6 +11,7 @@ module Operation
11
11
  attr_reader :operation_failure
12
12
 
13
13
  set_callback :execute, :around, ->(_, block) { surveil(:execute) { block.call } }
14
+ set_callback :execute, :before, -> { raise Operation::Errors::AlreadyExecuted }, if: :executed?
14
15
  end
15
16
 
16
17
  def execute!
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # When `#execute` is unsuccessful, expected problems are *failures* and unexpected problems are *Exceptions*.
3
+ # When `#execute` is unsuccessful, expected problems are **failures** and unexpected problems are **Exceptions**.
4
4
  module Operation
5
5
  module Failures
6
6
  extend ActiveSupport::Concern
@@ -7,6 +7,7 @@ module Operation
7
7
 
8
8
  included do
9
9
  set_callback :rewind, :around, ->(_, block) { surveil(:rewind) { block.call } }
10
+ set_callback :rewind, :before, -> { raise Operation::Errors::AlreadyRewound }, if: :rewound?
10
11
  end
11
12
 
12
13
  def rewind
@@ -7,16 +7,21 @@ module Operation
7
7
 
8
8
  included do
9
9
  set_callback(:execute, :before) { self.was_executed = true }
10
+ set_callback(:rewind, :before) { self.was_rewound = true }
10
11
 
11
12
  private
12
13
 
13
- attr_accessor :was_executed
14
+ attr_accessor :was_executed, :was_rewound
14
15
  end
15
16
 
16
17
  def executed?
17
18
  was_executed.present?
18
19
  end
19
20
 
21
+ def rewound?
22
+ was_rewound.present?
23
+ end
24
+
20
25
  def failed?
21
26
  operation_failure.present?
22
27
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # It's best practice to have Operations which modify several persisted objects to use a transaction.
3
+ # Operations which modify several persisted objects together should use a transaction.
4
4
  module Operation
5
5
  module Transactions
6
6
  extend ActiveSupport::Concern
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative "flow/errors/state_invalid"
3
+ require_relative "operation/errors/already_executed"
4
+ require_relative "operation/errors/already_rewound"
4
5
 
5
6
  require_relative "operation/callbacks"
6
7
  require_relative "operation/core"
@@ -11,7 +12,7 @@ require_relative "operation/rewind"
11
12
  require_relative "operation/status"
12
13
  require_relative "operation/transactions"
13
14
 
14
- # Operations are service objects which are executed with a state.
15
+ # An **Operation** is a service object which is executed with a **State**.
15
16
  class OperationBase
16
17
  include ShortCircuIt
17
18
  include Technologic
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Defines the immutable structure by defining attribute accessors for the state data.
3
+ # A state's attributes provide accessors to the input data it was initialized with.
4
4
  module State
5
5
  module Attributes
6
6
  extend ActiveSupport::Concern
@@ -25,6 +25,7 @@ module State
25
25
  attr_accessor attribute
26
26
  define_attribute_methods attribute
27
27
  end
28
+ alias_method :attribute, :define_attribute
28
29
  end
29
30
  end
30
31
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Accepts input representing the arguments and options which define the initial state.
3
+ # A state accepts input represented by arguments and options which initialize it.
4
4
  module State
5
5
  module Core
6
6
  extend ActiveSupport::Concern
@@ -7,7 +7,7 @@ require_relative "state/options"
7
7
  require_relative "state/core"
8
8
  require_relative "state/string"
9
9
 
10
- # A flow state is the immutable structure of relevant data.
10
+ # A **State** is an aggregation of input and derived data.
11
11
  class StateBase
12
12
  include ShortCircuIt
13
13
  include Technologic
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Flow
4
- VERSION = "0.9.2"
4
+ VERSION = "0.9.3"
5
5
  end
@@ -5,4 +5,5 @@ class <%= class_name %>State < ApplicationState
5
5
  # option :optional_input
6
6
  # option :option_with_default, default: :default_static_value
7
7
  # option(:option_with_default_from_block) { required_input.default_dynamic_value }
8
+ # attribute :some_runtime_value
8
9
  end
@@ -11,4 +11,18 @@ RSpec.describe <%= class_name %>Flow, type: :flow do
11
11
 
12
12
  it { is_expected.to inherit_from ApplicationFlow }
13
13
  # it { is_expected.to use_operations ExampleOperation }
14
+
15
+ describe "#trigger" do
16
+ subject(:trigger) { flow.trigger! }
17
+
18
+ pending "describe the effects of a successful `Flow#flux` (or delete) #{__FILE__}"
19
+ end
20
+
21
+ describe "#revert" do
22
+ before { flow.trigger! }
23
+
24
+ subject(:revert) { flow.revert }
25
+
26
+ pending "describe the effects of a successful `Flow#ebb` (or delete) #{__FILE__}"
27
+ end
14
28
  end
@@ -18,7 +18,17 @@ RSpec.describe <%= class_name %>, type: :operation do
18
18
 
19
19
  it { is_expected.to inherit_from ApplicationOperation }
20
20
 
21
- describe "#execute" do
22
- pending "add some examples to (or delete) #{__FILE__}"
21
+ describe "#execute!" do
22
+ subject(:execute!) { operation.execute! }
23
+
24
+ pending "describe `Operation#behavior` (or delete) #{__FILE__}"
25
+ end
26
+
27
+ describe "#rewind" do
28
+ before { operation.execute! }
29
+
30
+ subject(:execute!) { operation.rewind }
31
+
32
+ pending "describe `Operation#undo` (or delete) #{__FILE__}"
23
33
  end
24
34
  end
@@ -15,4 +15,5 @@ RSpec.describe <%= class_name %>State, type: :state do
15
15
  # it { is_expected.to define_option(:foo).with_default_value(:bar) }
16
16
  # it { is_expected.to define_option(:foo).with_default_value_block }
17
17
  # it { is_expected.to validate_presence_of ... }
18
+ # it { is_expected.to define_attribute :foo }
18
19
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flow
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
4
+ version: 0.9.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Eric Garside
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-04-03 00:00:00.000000000 Z
11
+ date: 2019-04-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activemodel
@@ -234,6 +234,7 @@ files:
234
234
  - lib/flow/concerns/transaction_wrapper.rb
235
235
  - lib/flow/custom_matchers.rb
236
236
  - lib/flow/custom_matchers/define_argument.rb
237
+ - lib/flow/custom_matchers/define_attribute.rb
237
238
  - lib/flow/custom_matchers/define_option.rb
238
239
  - lib/flow/custom_matchers/use_operations.rb
239
240
  - lib/flow/flow/callbacks.rb
@@ -250,6 +251,8 @@ files:
250
251
  - lib/flow/operation/callbacks.rb
251
252
  - lib/flow/operation/core.rb
252
253
  - lib/flow/operation/error_handler.rb
254
+ - lib/flow/operation/errors/already_executed.rb
255
+ - lib/flow/operation/errors/already_rewound.rb
253
256
  - lib/flow/operation/execute.rb
254
257
  - lib/flow/operation/failures.rb
255
258
  - lib/flow/operation/rewind.rb