call_sheet 0.1.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b3c20bf00a8dd774a7a7a9110001576dfae39667
4
- data.tar.gz: acca5a6e3f2575b54b13c7d3744f466e471ff753
3
+ metadata.gz: 96d48219b6b93de88c46f9bdd0e146a1d7874fc7
4
+ data.tar.gz: d8f8982248cab8b53578356484b0a933aaab5a92
5
5
  SHA512:
6
- metadata.gz: 5442457894d06089e52de190a7ccd62b504e71d7cd66ba4764ee01134c48c2e5cc923b534fbc3caff3d41f3f2368d5a89af373e44393a2f933a6504392ae271b
7
- data.tar.gz: 05acf6f917f9fbc1102c12bfb54e1a60aa0089d8e810a2a70ddec22d44f31c43b7d4368997fb3180a47fa7312013395606191642ae06888fda808bbde3955583
6
+ metadata.gz: 460c3efef5e4b95ab44bb4a6b105c022e60fd57b0830f8c6ecbbdbaca20b29698a51e2389104823381785dba3893af85f57f29b0621d622690cab0d3d694ca93
7
+ data.tar.gz: ab53c4c441ab6c0b58baaff91b8a8ba188bf190d5b12355922f51719d86ec9c565660df927f5b34f2011da3972dfd4c12a1bcb37ed43ee193e8d965415fdba52
data/Gemfile.lock CHANGED
@@ -3,6 +3,7 @@ PATH
3
3
  specs:
4
4
  call_sheet (0.1.0)
5
5
  deterministic (>= 0.15.3)
6
+ wisper (>= 1.6.0)
6
7
 
7
8
  GEM
8
9
  remote: https://rubygems.org/
@@ -44,6 +45,8 @@ GEM
44
45
  json (~> 1.8)
45
46
  simplecov-html (~> 0.10.0)
46
47
  simplecov-html (0.10.0)
48
+ wisper (1.6.1)
49
+ yard (0.8.7.6)
47
50
 
48
51
  PLATFORMS
49
52
  ruby
@@ -55,6 +58,7 @@ DEPENDENCIES
55
58
  rspec (~> 3.3.0)
56
59
  rubocop (~> 0.34.2)
57
60
  simplecov (~> 0.10.0)
61
+ yard
58
62
 
59
63
  BUNDLED WITH
60
64
  1.10.6
data/README.md CHANGED
@@ -1,5 +1,13 @@
1
+ [gem]: https://rubygems.org/gems/call_sheet
2
+ [code_climate]: https://codeclimate.com/github/icelab/call_sheet
3
+ [inch]: http://inch-ci.org/github/icelab/call_sheet
4
+
1
5
  # Call Sheet
2
6
 
7
+ [![Gem Version](https://img.shields.io/gem/v/call_sheet.svg)][gem]
8
+ [![Code Climate](https://img.shields.io/codeclimate/github/icelab/call_sheet.svg)][code_climate]
9
+ [![API Documentation Coverage](http://inch-ci.org/github/icelab/call_sheet.svg)][inch]
10
+
3
11
  Call Sheet is a business transaction DSL. It provides a simple way to define a complex business transaction that includes processing by many different objects. It makes error handling a primary concern by using a “[Railway Oriented Programming](http://fsharpforfunandprofit.com/rop/)” approach for capturing and returning errors from any step in the transaction.
4
12
 
5
13
  Call Sheet is based on the following ideas, drawn mostly from [Transflow](http://github.com/solnic/transflow):
@@ -28,20 +36,20 @@ Each operation is integrated into your business transaction through one of the f
28
36
  * `map` – any output is considered successful and returned as `Success(output)`
29
37
  * `try` – the operation may raise an exception in an error case. This is caught and returned as `Failure(exception)`. The output is otherwise returned as `Success(output)`.
30
38
  * `tee` – the operation interacts with some external system and has no meaningful output. The original input is passed through and returned as `Success(input)`.
31
- * `raw` – the operation already returns its own `Result` object, and needs no special handling.
39
+ * `raw` or `step` – the operation already returns its own `Result` object, and needs no special handling.
32
40
 
33
41
  ```ruby
34
42
  DB = []
35
43
 
36
44
  container = {
37
45
  process: -> input { {name: input["name"], email: input["email"]} },
38
- validate: -> input { input[:email].nil? ? raise("not valid") : input },
46
+ validate: -> input { input[:email].nil? ? raise(ValidationFailure, "not valid") : input },
39
47
  persist: -> input { DB << input and true }
40
48
  }
41
49
 
42
50
  save_user = CallSheet(container: container) do
43
51
  map :process
44
- try :validate
52
+ try :validate, catch: ValidationFailure
45
53
  tee :persist
46
54
  end
47
55
 
@@ -73,24 +81,24 @@ You can use guard expressions like `where { f == :step_name }` in the failure ma
73
81
 
74
82
  ### Passing additional step arguments
75
83
 
76
- Additional arguments for step operations can be passed at the time of calling your transaction. Provide these arguments as an array, and they’ll be [splatted](https://endofline.wordpress.com/2011/01/21/the-strange-ruby-splat/) into the front of the operation’s arguments. This effectively means that transactions can support operations with any sort of `#call(*args, input)` interface.
84
+ Additional arguments for step operations can be passed at the time of calling your transaction. Provide these arguments as an array, and they’ll be [splatted](https://endofline.wordpress.com/2011/01/21/the-strange-ruby-splat/) into the front of the operation’s arguments. This means that transactions can effectively support operations with any sort of `#call(*args, input)` interface.
77
85
 
78
86
  ```ruby
79
87
  DB = []
80
88
 
81
89
  container = {
82
90
  process: -> input { {name: input["name"], email: input["email"]} },
83
- validate: -> allowed, input { input[:email].include?(allowed) ? raise("not allowed") : input },
91
+ validate: -> allowed, input { input[:email].include?(allowed) ? raise(ValidationFailure, "not allowed") : input },
84
92
  persist: -> input { DB << input and true }
85
93
  }
86
94
 
87
95
  save_user = CallSheet(container: container) do
88
96
  map :process
89
- try :validate
97
+ try :validate, catch: ValidationFailure
90
98
  tee :persist
91
99
  end
92
100
 
93
- input = {name: "Jane", email: "jane@doe.com"}
101
+ input = {"name" => "Jane", "email" => "jane@doe.com"}
94
102
  save_user.call(input, validate: ["doe.com"])
95
103
  # => Success({:name=>"Jane", :email=>"jane@doe.com"})
96
104
 
@@ -98,28 +106,46 @@ save_user.call(input, validate: ["smith.com"])
98
106
  # => Failure("not allowed")
99
107
  ```
100
108
 
101
- ### Working with a larger container
109
+ ### Subscribing to step notifications
102
110
 
103
- In practice, your container won’t be a trivial collection of generically named operations. You can keep your transaction step names simple by using the `with:` option to provide the identifiers for the operations within your container:
111
+ As well as pattern matching on the final transaction result, you can subscribe to individual steps and trigger specific behaviour based on their success or failure:
104
112
 
105
113
  ```ruby
106
- save_user = CallSheet(container: large_whole_app_container) do
107
- map :process, with: "attributes.user"
108
- try :validate, with: "validations.user"
109
- tee :persist, with: "persistance.commands.update_user"
114
+ NOTIFICATIONS = []
115
+
116
+ module UserPersistListener
117
+ extend self
118
+
119
+ def persist_success(user)
120
+ NOTIFICATIONS << "#{user[:email]} persisted"
121
+ end
122
+
123
+ def persist_failure(user)
124
+ NOTIFICATIONS << "#{user[:email]} failed to persist"
125
+ end
110
126
  end
127
+
128
+
129
+ input = {"name" => "Jane", "email" => "jane@doe.com"}
130
+
131
+ save_user.subscribe(persist: UserPersistListener)
132
+ save_user.call(input, validate: ["doe.com"])
133
+
134
+ NOTIFICATIONS
135
+ # => ["jane@doe.com persisted"]
111
136
  ```
112
137
 
113
- ### Using inline procs
138
+ This pub/sub mechanism is provided by the [Wisper](https://github.com/krisleech/wisper) gem. You can subscribe to specific steps using the `#subscribe(step_name: listener)` API, or subscribe to all steps via `#subscribe(listener)`.
139
+
140
+ ### Working with a larger container
114
141
 
115
- You can inject small pieces of custom behavior into your transaction using inline procs and a `raw` step. This can be helpful if you want to provide a special failure case based on the output of a previous step.
142
+ In practice, your container won’t be a trivial collection of generically named operations. You can keep your transaction step names simple by using the `with:` option to provide the identifiers for the operations within your container:
116
143
 
117
144
  ```ruby
118
- update_user = CallSheet(container: container) do
119
- map :find_user
120
- raw :check_locked, with: -> input { input.locked? ? Failure("Cannot update locked user") : Success(input) }
121
- try :validate
122
- tee :persist
145
+ save_user = CallSheet(container: large_whole_app_container) do
146
+ map :process, with: "attributes.user"
147
+ try :validate, with: "validations.user", catch: ValidationFailure
148
+ tee :persist, with: "persistance.commands.update_user"
123
149
  end
124
150
  ```
125
151
 
data/lib/call_sheet.rb CHANGED
@@ -2,7 +2,52 @@ require "deterministic"
2
2
  require "call_sheet/version"
3
3
  require "call_sheet/dsl"
4
4
 
5
- # rubocop:disable Style/MethodName
5
+ # Define a business transaction.
6
+ #
7
+ # A business transaction is a series of callable operation objects that
8
+ # receive input and produce an output.
9
+ #
10
+ # The operations should be addressable via `#[]` in a container object that
11
+ # you pass when creating the transaction. The operations must respond to
12
+ # `#call(*args, input)`.
13
+ #
14
+ # Each operation will be called in the order it was specified in your
15
+ # transaction, with its output is passed as the intput to the next operation.
16
+ # Operations will only be called if the previous step was a success.
17
+ #
18
+ # A step is successful when it returns a `Success` object (from the
19
+ # [Deterministic](deterministic) gem) wrapping its output value. A step is a
20
+ # failure when it returns a `Failure` object. If your operations already
21
+ # return a `Success` or `Failure`, they can be added to your operation as
22
+ # plain `step` or `raw` steps.
23
+ #
24
+ # If your operations don't already return `Success` or `Failure`, then they
25
+ # can be added to the transaction with the following steps:
26
+ #
27
+ # * `map` --- wrap the output of the operation in a `Success`
28
+ # * `try` --- wrap the output of the operation in a `Success`, unless a certain
29
+ # exception is raised, which will be caught and returned as a `Failure`.
30
+ # * `tee` --- ignore the output of the operation and pass through its original
31
+ # input as a `Sucess`.
32
+ #
33
+ # [deterministic]: https://github.com/pzol/deterministic
34
+ #
35
+ # @example
36
+ # container = {do_first: some_obj, do_second: some_obj}
37
+ #
38
+ # my_transaction = CallSheet(container: container) do
39
+ # step :do_first
40
+ # step :do_second
41
+ # end
42
+ #
43
+ # my_transaction.call(some_input)
44
+ #
45
+ # @param [Hash] options the options hash
46
+ # @option options [#[]] :container the operations container
47
+ #
48
+ # @return [CallSheet::Transaction] the transaction object
49
+ #
50
+ # @api public
6
51
  def CallSheet(options = {}, &block)
7
52
  CallSheet::DSL.new(options, &block).call
8
53
  end
@@ -1,8 +1,8 @@
1
1
  require "call_sheet/step"
2
2
  require "call_sheet/step_adapters"
3
3
  require "call_sheet/step_adapters/base"
4
- require "call_sheet/step_adapters/raw"
5
4
  require "call_sheet/step_adapters/map"
5
+ require "call_sheet/step_adapters/raw"
6
6
  require "call_sheet/step_adapters/tee"
7
7
  require "call_sheet/step_adapters/try"
8
8
  require "call_sheet/transaction"
@@ -11,10 +11,16 @@ module CallSheet
11
11
  class DSL
12
12
  include Deterministic::Prelude::Result
13
13
 
14
- attr_reader :options # are we actually doing anything with this besides passing the container?
14
+ # @api private
15
+ attr_reader :options
16
+
17
+ # @api private
15
18
  attr_reader :container
19
+
20
+ # @api private
16
21
  attr_reader :steps
17
22
 
23
+ # @api private
18
24
  def initialize(options, &block)
19
25
  @options = options
20
26
  @container = options.fetch(:container)
@@ -25,11 +31,12 @@ module CallSheet
25
31
 
26
32
  StepAdapters.each do |adapter_name, adapter_class|
27
33
  define_method adapter_name do |step_name, options = {}|
28
- operation = options[:with].is_a?(Proc) ? options[:with] : container[options.fetch(:with, step_name)]
34
+ operation = container[options.fetch(:with, step_name)]
29
35
  steps << Step.new(step_name, adapter_class.new(operation, options))
30
36
  end
31
37
  end
32
38
 
39
+ # @api private
33
40
  def call
34
41
  Transaction.new(steps)
35
42
  end
@@ -1,8 +1,11 @@
1
+ require "wisper"
1
2
  require "call_sheet/step_failure"
2
3
 
3
4
  module CallSheet
5
+ # @api private
4
6
  class Step
5
7
  include Deterministic::Prelude::Result
8
+ include Wisper::Publisher
6
9
 
7
10
  attr_reader :step_name
8
11
  attr_reader :operation
@@ -19,8 +22,16 @@ module CallSheet
19
22
  end
20
23
 
21
24
  def call(input)
22
- result = operation.call(*(call_args << input))
23
- result.map_err { |v| Failure(StepFailure.new(step_name, v)) }
25
+ args = (call_args << input)
26
+ result = operation.call(*args)
27
+
28
+ result.map { |value|
29
+ broadcast :"#{step_name}_success", value
30
+ Success(value)
31
+ }.map_err { |value|
32
+ broadcast :"#{step_name}_failure", *args, value
33
+ Failure(StepFailure.new(step_name, value))
34
+ }
24
35
  end
25
36
 
26
37
  def arity
@@ -11,6 +11,12 @@ module CallSheet
11
11
  extend Forwardable
12
12
  def_delegators :registry, :[], :each
13
13
 
14
+ # Register a step adapter.
15
+ #
16
+ # @param [Symbol] name the name to expose for adding steps to a transaction
17
+ # @param klass the step adapter class
18
+ #
19
+ # @api public
14
20
  def register(name, klass)
15
21
  registry[name.to_sym] = klass
16
22
  end
@@ -1,5 +1,6 @@
1
1
  module CallSheet
2
2
  module StepAdapters
3
+ # @api private
3
4
  class Base
4
5
  include Deterministic::Prelude::Result
5
6
 
@@ -1,5 +1,6 @@
1
1
  module CallSheet
2
2
  module StepAdapters
3
+ # @api private
3
4
  class Map < Base
4
5
  def call(*args, input)
5
6
  Success(operation.call(input, *args))
@@ -1,11 +1,13 @@
1
1
  module CallSheet
2
2
  module StepAdapters
3
+ # @api private
3
4
  class Raw < Base
4
5
  def call(*args, input)
5
6
  operation.call(input, *args)
6
7
  end
7
8
  end
8
9
 
10
+ register :step, Raw
9
11
  register :raw, Raw
10
12
  end
11
13
  end
@@ -1,5 +1,6 @@
1
1
  module CallSheet
2
2
  module StepAdapters
3
+ # @api private
3
4
  class Tee < Base
4
5
  def call(*args, input)
5
6
  operation.call(*args, input)
@@ -1,8 +1,16 @@
1
1
  module CallSheet
2
2
  module StepAdapters
3
+ # @api private
3
4
  class Try < Base
5
+ def initialize(*)
6
+ super
7
+ raise ArgumentError, "+try+ steps require one or more exception classes provided via +catch:+" unless options[:catch]
8
+ end
9
+
4
10
  def call(*args, input)
5
- try! { operation.call(*args, input) }
11
+ Success(operation.call(*args, input))
12
+ rescue *Array(options[:catch]) => e
13
+ Failure(e)
6
14
  end
7
15
  end
8
16
 
@@ -2,13 +2,16 @@ module CallSheet
2
2
  class Transaction
3
3
  include Deterministic::Prelude::Result
4
4
 
5
+ # @api private
5
6
  attr_reader :steps
6
7
  private :steps
7
8
 
9
+ # @api private
8
10
  def initialize(steps)
9
11
  @steps = steps
10
12
  end
11
13
 
14
+ # @api public
12
15
  def call(input, options = {})
13
16
  assert_valid_options(options)
14
17
  assert_options_satisfy_step_arity(options)
@@ -18,6 +21,21 @@ module CallSheet
18
21
  end
19
22
  alias_method :[], :call
20
23
 
24
+ # @api public
25
+ def subscribe(listeners)
26
+ if listeners.is_a?(Hash)
27
+ listeners.each do |step_name, listener|
28
+ steps.detect { |step| step.step_name == step_name }.subscribe(listener)
29
+ end
30
+ else
31
+ steps.each do |step|
32
+ step.subscribe(listeners)
33
+ end
34
+ end
35
+
36
+ self
37
+ end
38
+
21
39
  private
22
40
 
23
41
  def assert_valid_options(options)
@@ -1,3 +1,4 @@
1
+ # Business transaction DSL.
1
2
  module CallSheet
2
- VERSION = "0.1.0".freeze
3
+ VERSION = "0.2.0".freeze
3
4
  end
data/spec/examples.txt CHANGED
@@ -1,17 +1,21 @@
1
1
  example_id | status | run_time |
2
2
  -------------------------------------------------------- | ------ | --------------- |
3
- ./spec/integration/call_sheet_spec.rb[1:1:1] | passed | 0.00285 seconds |
4
- ./spec/integration/call_sheet_spec.rb[1:1:2] | passed | 0.0025 seconds |
5
- ./spec/integration/call_sheet_spec.rb[1:1:3] | passed | 0.00373 seconds |
6
- ./spec/integration/call_sheet_spec.rb[1:1:4] | passed | 0.00084 seconds |
7
- ./spec/integration/call_sheet_spec.rb[1:2:1] | passed | 0.00061 seconds |
8
- ./spec/integration/call_sheet_spec.rb[1:2:2] | passed | 0.00084 seconds |
9
- ./spec/integration/call_sheet_spec.rb[1:2:3] | passed | 0.00176 seconds |
10
- ./spec/integration/call_sheet_spec.rb[1:2:4] | passed | 0.00068 seconds |
11
- ./spec/integration/call_sheet_spec.rb[1:2:5] | passed | 0.00063 seconds |
12
- ./spec/integration/inline_procs_spec.rb[1:1:1] | passed | 0.0004 seconds |
13
- ./spec/integration/inline_procs_spec.rb[1:2:1] | passed | 0.00042 seconds |
14
- ./spec/integration/inline_procs_spec.rb[1:2:2] | passed | 0.00045 seconds |
15
- ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00065 seconds |
16
- ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00216 seconds |
17
- ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00023 seconds |
3
+ ./spec/integration/call_sheet_spec.rb[1:1:1] | passed | 0.00244 seconds |
4
+ ./spec/integration/call_sheet_spec.rb[1:1:2] | passed | 0.00114 seconds |
5
+ ./spec/integration/call_sheet_spec.rb[1:1:3] | passed | 0.00101 seconds |
6
+ ./spec/integration/call_sheet_spec.rb[1:1:4] | passed | 0.00237 seconds |
7
+ ./spec/integration/call_sheet_spec.rb[1:2:1] | passed | 0.0008 seconds |
8
+ ./spec/integration/call_sheet_spec.rb[1:2:2] | passed | 0.00086 seconds |
9
+ ./spec/integration/call_sheet_spec.rb[1:2:3] | passed | 0.00154 seconds |
10
+ ./spec/integration/call_sheet_spec.rb[1:2:4] | passed | 0.00087 seconds |
11
+ ./spec/integration/call_sheet_spec.rb[1:2:5] | passed | 0.00085 seconds |
12
+ ./spec/integration/call_sheet_spec.rb[1:3:1] | passed | 0.00068 seconds |
13
+ ./spec/integration/call_sheet_spec.rb[1:3:2] | passed | 0.00072 seconds |
14
+ ./spec/integration/call_sheet_spec.rb[1:3:3] | passed | 0.00065 seconds |
15
+ ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00312 seconds |
16
+ ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00023 seconds |
17
+ ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00202 seconds |
18
+ ./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00096 seconds |
19
+ ./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00077 seconds |
20
+ ./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.00254 seconds |
21
+ ./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00083 seconds |
@@ -1,8 +1,11 @@
1
1
  RSpec.describe CallSheet do
2
+ include Deterministic::Prelude::Result
3
+
2
4
  let(:call_sheet) {
3
5
  CallSheet(container: container) do
4
6
  map :process
5
- try :validate
7
+ raw :verify
8
+ try :validate, catch: Test::NotValidError
6
9
  tee :persist
7
10
  end
8
11
  }
@@ -10,6 +13,7 @@ RSpec.describe CallSheet do
10
13
  let(:container) {
11
14
  {
12
15
  process: -> input { {name: input["name"], email: input["email"]} },
16
+ verify: -> input { Success(input) },
13
17
  validate: -> input { input[:email].nil? ? raise(Test::NotValidError, "email required") : input },
14
18
  persist: -> input { Test::DB << input and true }
15
19
  }
@@ -83,4 +87,26 @@ RSpec.describe CallSheet do
83
87
  expect(match).to eq "Matched validate failure"
84
88
  end
85
89
  end
90
+
91
+ context "failed in a raw step" do
92
+ let(:input) { {"name" => "Jane", "email" => "jane@doe.com"} }
93
+ let(:run_call_sheet) { call_sheet.call(input) }
94
+
95
+ before do
96
+ container[:verify] = -> input { Failure("raw failure") }
97
+ end
98
+
99
+ it "does not run subsequent operations" do
100
+ run_call_sheet
101
+ expect(Test::DB).to be_empty
102
+ end
103
+
104
+ it "returns a failure" do
105
+ expect(run_call_sheet).to be_failure
106
+ end
107
+
108
+ it "returns the failing value from the operation" do
109
+ expect(run_call_sheet.value).to eq "raw failure"
110
+ end
111
+ end
86
112
  end
@@ -4,7 +4,7 @@ RSpec.describe "Passing additional arguments to step operations" do
4
4
  let(:call_sheet) {
5
5
  CallSheet(container: container) do
6
6
  map :process
7
- try :validate
7
+ try :validate, catch: Test::NotValidError
8
8
  tee :persist
9
9
  end
10
10
  }
@@ -0,0 +1,67 @@
1
+ RSpec.describe "publishing step events" do
2
+ include Deterministic::Prelude::Result
3
+
4
+ let(:call_sheet) {
5
+ CallSheet(container: container) do
6
+ map :process
7
+ raw :verify
8
+ tee :persist
9
+ end
10
+ }
11
+
12
+ let(:container) {
13
+ {
14
+ process: -> input { {name: input["name"]} },
15
+ verify: -> input { input[:name].to_s != "" ? Success(input) : Failure("no name") },
16
+ persist: -> input { Test::DB << input and true }
17
+ }
18
+ }
19
+
20
+ let(:subscriber) { spy(:subscriber) }
21
+
22
+ before do
23
+ Test::DB = []
24
+ end
25
+
26
+ context "subscribing to all step events" do
27
+ before do
28
+ call_sheet.subscribe(subscriber)
29
+ end
30
+
31
+ specify "subscriber receives success events" do
32
+ call_sheet.call("name" => "Jane")
33
+
34
+ expect(subscriber).to have_received(:process_success).with(name: "Jane")
35
+ expect(subscriber).to have_received(:verify_success).with(name: "Jane")
36
+ expect(subscriber).to have_received(:persist_success).with(name: "Jane")
37
+ end
38
+
39
+ specify "subsriber receives success events for passing steps, a failure event for the failing step, and no subsequent events" do
40
+ call_sheet.call("name" => "")
41
+
42
+ expect(subscriber).to have_received(:process_success).with(name: "")
43
+ expect(subscriber).to have_received(:verify_failure).with({name: ""}, "no name")
44
+ expect(subscriber).not_to have_received(:persist_success)
45
+ end
46
+ end
47
+
48
+ context "subscribing to particular step events" do
49
+ before do
50
+ call_sheet.subscribe(verify: subscriber)
51
+ end
52
+
53
+ specify "subscriber receives success event for the specified step" do
54
+ call_sheet.call("name" => "Jane")
55
+
56
+ expect(subscriber).to have_received(:verify_success).with(name: "Jane")
57
+ expect(subscriber).not_to have_received(:process_success)
58
+ expect(subscriber).not_to have_received(:persist_success)
59
+ end
60
+
61
+ specify "subscriber receives failure event for the specified step" do
62
+ call_sheet.call("name" => "")
63
+
64
+ expect(subscriber).to have_received(:verify_failure).with({name: ""}, "no name")
65
+ end
66
+ end
67
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: call_sheet
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tim Riley
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-10-28 00:00:00.000000000 Z
11
+ date: 2015-11-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: deterministic
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.15.3
27
+ - !ruby/object:Gem::Dependency
28
+ name: wisper
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: 1.6.0
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: 1.6.0
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -94,6 +108,20 @@ dependencies:
94
108
  - - "~>"
95
109
  - !ruby/object:Gem::Version
96
110
  version: 0.10.0
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - ">="
116
+ - !ruby/object:Gem::Version
117
+ version: '0'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - ">="
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
97
125
  description:
98
126
  email:
99
127
  - tim@icelab.com.au
@@ -120,8 +148,8 @@ files:
120
148
  - lib/call_sheet/version.rb
121
149
  - spec/examples.txt
122
150
  - spec/integration/call_sheet_spec.rb
123
- - spec/integration/inline_procs_spec.rb
124
151
  - spec/integration/passing_step_arguments_spec.rb
152
+ - spec/integration/publishing_step_events_spec.rb
125
153
  - spec/spec_helper.rb
126
154
  - spec/support/test_module_constants.rb
127
155
  homepage: https://github.com/icelab/call_sheet
@@ -149,3 +177,4 @@ signing_key:
149
177
  specification_version: 4
150
178
  summary: Business Transaction Flow DSL
151
179
  test_files: []
180
+ has_rdoc:
@@ -1,40 +0,0 @@
1
- RSpec.describe "using inline procs with raw steps" do
2
- let(:call_sheet) {
3
- CallSheet(container: container) do
4
- map :process
5
- raw :validate, with: -> input { input[:email].nil? ? Failure("email required") : Success(input) }
6
- end
7
- }
8
-
9
- let(:container) { {process: -> input { {name: input["name"], email: input["email"]} }} }
10
-
11
- before do
12
- Test::NotValidError = Class.new(StandardError)
13
- Test::DB = []
14
- end
15
-
16
- context "inline step returns Success" do
17
- it "calls all the operations" do
18
- input = {"name" => "Jane", "email" => "jane@doe.com"}
19
- expect(call_sheet.call(input)).to be_success
20
- end
21
- end
22
-
23
- context "inline step returns Failure" do
24
- let(:input) { {"name" => "Jane"} }
25
-
26
- it "stops running the step operations and returns the failure" do
27
- expect(call_sheet.call(input)).to be_failure
28
- end
29
-
30
- it "supports pattern matching on the failed step name" do
31
- match = call_sheet.call(input).match do
32
- Success(_) {}
33
- Failure(f, where { f == :validate }) { "Matched validate failure" }
34
- Failure(_) {}
35
- end
36
-
37
- expect(match).to eq "Matched validate failure"
38
- end
39
- end
40
- end