call_sheet 0.1.0 → 0.2.0

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