call_sheet 0.3.2 → 0.4.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: 22cdd99caebdca48c7f1af8c352946c346de879a
4
- data.tar.gz: 9330dd2494ced730459a53e810ac1076dd66f162
3
+ metadata.gz: 04addbea6823e48be8a177f6ed780599763e6e60
4
+ data.tar.gz: 0b8fc7f7227ee2b2deb80d5c480738d9a6c2968f
5
5
  SHA512:
6
- metadata.gz: 44a856b644c6e36dc2cf8a29e724f1d1c03a9263eb43b8be7f9fc042429e7b58d57d865d87a45e61ec4a587515f93c76719bf0997a7f6148fdb3c40aaa5a631e
7
- data.tar.gz: bfc12f1e07ea2783c8a4fe52e364593148de4f56c21f695582c7dfef14d6ef525b9270099231fccddb55610b35c3ae8ea0f570c50fb65839505104d9ce67dd8a
6
+ metadata.gz: ff2fae39de04d6840acfba7b5f802b0b018eb108e4e2eee2de3c536b53adad1220d382091cfc9059f1b08d1b1e1bd459f7b6cb971e6f56f0b817cf49c23a899f
7
+ data.tar.gz: e5b423a612353fcdc38ffe7b0a7904a2848da73ab78e9242092e124cc8841622d9408aa98d910f535509185cc464248d679510cd15671d5313cdf2498c2e39a5
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- call_sheet (0.3.1)
4
+ call_sheet (0.4.0)
5
5
  kleisli
6
6
  wisper (>= 1.6.0)
7
7
 
data/README.md CHANGED
@@ -1,8 +1,9 @@
1
+ [gitter]: https://gitter.im/icelab/call_sheet?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge
1
2
  [gem]: https://rubygems.org/gems/call_sheet
2
3
  [code_climate]: https://codeclimate.com/github/icelab/call_sheet
3
4
  [inch]: http://inch-ci.org/github/icelab/call_sheet
4
5
 
5
- # Call Sheet
6
+ # Call Sheet [![Join the chat at https://gitter.im/icelab/call_sheet](https://badges.gitter.im/Join%20Chat.svg)](gitter)
6
7
 
7
8
  [![Gem Version](https://img.shields.io/gem/v/call_sheet.svg)][gem]
8
9
  [![Code Climate](https://img.shields.io/codeclimate/github/icelab/call_sheet.svg)][code_climate]
@@ -23,35 +24,53 @@ Call Sheet is based on the following ideas, drawn mostly from [Transflow](http:/
23
24
 
24
25
  ## Why?
25
26
 
26
- Requiring a business transaction's steps to exist as independent operations directly addressable voa a container means that they can be tested in isolation and easily reused throughout your application. Following from this, keeping the business transaction to a series of high-level, declarative steps ensures that it's easy to understand at a glance.
27
+ Requiring a business transactions steps to exist as independent operations directly addressable via a container means that they can be tested in isolation and easily reused throughout your application. Following from this, keeping the business transaction to a series of high-level, declarative steps ensures that its easy to understand at a glance.
27
28
 
28
29
  The output of each step is wrapped in a [Kleisli](https://github.com/txus/kleisli) `Either` object (`Right` for success or `Left` for failure). This allows the steps to be chained together and ensures that processing stops in the case of a failure. Returning an `Either` from the overall transaction also allows for error handling to remain a primary concern without it getting in the way of tidy, straightforward operation logic. Wrapping the step output also means that you can work with a wide variety of operations within your application – they don’t need to return an `Either` already.
29
30
 
30
31
  ## Usage
31
32
 
32
- All you need to use Call Sheet is a container of operations that respond to `#call(input)`. The operations will be resolved from the container via `#[]`. The examples below use a plain Hash for simplicity, but for a larger app you may like to consider something like [dry-container](https://github.com/dryrb/dry-container).
33
+ ### Container
33
34
 
34
- Each operation is integrated into your business transaction through one of the following step adapters:
35
+ All you need to use Call Sheet is a container to hold your application’s operations. Each operation must respond to `#call(input)`.
35
36
 
36
- * `map` any output is considered successful and returned as `Right(output)`
37
- * `try` – the operation may raise an exception in an error case. This is caught and returned as `Left(exception)`. The output is otherwise returned as `Right(output)`.
38
- * `tee` – the operation interacts with some external system and has no meaningful output. The original input is passed through and returned as `Right(input)`.
39
- * `raw` or `step` – the operation already returns its own `Either` object, and needs no special handling.
37
+ The operations will be resolved from the container via `#[]`. For our examples, we’ll use a plain hash:
40
38
 
41
39
  ```ruby
42
- DB = []
43
-
44
40
  container = {
45
41
  process: -> input { {name: input["name"], email: input["email"]} },
46
42
  validate: -> input { input[:email].nil? ? raise(ValidationFailure, "not valid") : input },
47
43
  persist: -> input { DB << input and true }
48
44
  }
45
+ ```
46
+
47
+ For larger apps, you may like to consider something like [dry-container](https://github.com/dryrb/dry-container).
49
48
 
49
+ ### Defining a transaction
50
+
51
+ Define a transaction to bring your opererations together:
52
+
53
+ ```ruby
50
54
  save_user = CallSheet(container: container) do
51
55
  map :process
52
56
  try :validate, catch: ValidationFailure
53
57
  tee :persist
54
58
  end
59
+ ```
60
+
61
+ Operations are formed into steps using _step adapters._ Step adapters wrap the output of your operations to make them easy to integrate into a transaction. The following adapters are available:
62
+
63
+ * `step` – the operation already returns an `Either` object (`Right(output)` for success and `Left(output)` for failure), and needs no special handling.
64
+ * `map` – any output is considered successful and returned as `Right(output)`
65
+ * `try` – the operation may raise an exception in an error case. This is caught and returned as `Left(exception)`. The output is otherwise returned as `Right(output)`.
66
+ * `tee` – the operation interacts with some external system and has no meaningful output. The original input is passed through and returned as `Right(input)`.
67
+
68
+ ### Calling a transaction
69
+
70
+ Calling a transaction will run its operations in their specified order, with the output of each operation becoming the input for the next.
71
+
72
+ ```ruby
73
+ DB = []
55
74
 
56
75
  save_user.call("name" => "Jane", "email" => "jane@doe.com")
57
76
  # => Right({:name=>"Jane", :email=>"jane@doe.com"})
@@ -60,7 +79,7 @@ DB
60
79
  # => [{:name=>"Jane", :email=>"jane@doe.com"}]
61
80
  ```
62
81
 
63
- Each transaction returns a result value wrapped in a `Left` or `Right` object. You can handle these different results (including errors arising from particular steps) with a match block:
82
+ Each transaction returns a result value wrapped in a `Left` or `Right` object (based on the output of its final step). You can handle these results (including errors arising from particular steps) with a match block:
64
83
 
65
84
  ```ruby
66
85
  save_user.call(name: "Jane", email: "jane@doe.com") do |m|
@@ -139,6 +158,10 @@ NOTIFICATIONS
139
158
 
140
159
  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)`.
141
160
 
161
+ ### Extending transactions
162
+
163
+ You can extend existing transactions by inserting or removing steps. See the [API docs](http://www.rubydoc.info/github/icelab/call_sheet/CallSheet/Transaction) for more information.
164
+
142
165
  ### Working with a larger container
143
166
 
144
167
  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:
@@ -151,8 +174,6 @@ save_user = CallSheet(container: large_whole_app_container) do
151
174
  end
152
175
  ```
153
176
 
154
- A `raw` step (also aliased as `step`) can be used if the operation in your container already returns an `Either` and therefore doesn’t need any special handling.
155
-
156
177
  ## Installation
157
178
 
158
179
  Add this line to your application’s `Gemfile`:
@@ -163,6 +184,10 @@ gem "call_sheet"
163
184
 
164
185
  Run `bundle` to install the gem.
165
186
 
187
+ ## Documentation
188
+
189
+ View the [full API documentation](http://www.rubydoc.info/github/icelab/call_sheet) on RubyDoc.info.
190
+
166
191
  ## Contributing
167
192
 
168
193
  Bug reports and pull requests are welcome on [GitHub](http://github.com/icelab/call_sheet).
data/lib/call_sheet.rb CHANGED
@@ -12,25 +12,24 @@ require "call_sheet/dsl"
12
12
  # `#call(*args, input)`.
13
13
  #
14
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.
15
+ # transaction, with its output is passed as the input to the next operation.
16
16
  # Operations will only be called if the previous step was a success.
17
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.
18
+ # A step is successful when it returns a [Kleisli](kleisli) `Right` object
19
+ # wrapping its output value. A step is a failure when it returns a `Left`
20
+ # object. If your operations already return a `Right` or `Left`, they can be
21
+ # added to your operation as plain `step` steps.
23
22
  #
24
- # If your operations don't already return `Success` or `Failure`, then they
25
- # can be added to the transaction with the following steps:
23
+ # If your operations don't already return `Right` or `Left`, then they can be
24
+ # added to the transaction with the following steps:
26
25
  #
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`.
26
+ # * `map` --- wrap the output of the operation in a `Right`
27
+ # * `try` --- wrap the output of the operation in a `Right`, unless a certain
28
+ # exception is raised, which will be caught and returned as a `Left`.
30
29
  # * `tee` --- ignore the output of the operation and pass through its original
31
- # input as a `Sucess`.
30
+ # input as a `Right`.
32
31
  #
33
- # [deterministic]: https://github.com/pzol/deterministic
32
+ # [kleisli]: https://rubygems.org/gems/kleisli
34
33
  #
35
34
  # @example
36
35
  # container = {do_first: some_obj, do_second: some_obj}
@@ -42,7 +41,7 @@ require "call_sheet/dsl"
42
41
  #
43
42
  # my_transaction.call(some_input)
44
43
  #
45
- # @param [Hash] options the options hash
44
+ # @param options [Hash] the options hash
46
45
  # @option options [#[]] :container the operations container
47
46
  #
48
47
  # @return [CallSheet::Transaction] the transaction object
@@ -1,39 +1,23 @@
1
1
  module CallSheet
2
2
  class ResultMatcher
3
3
  attr_reader :result
4
- attr_reader :value
4
+ attr_reader :output
5
5
 
6
6
  def initialize(result)
7
7
  @result = result
8
- @value = result.value
9
8
  end
10
9
 
11
10
  def success(&block)
12
- block.call value if result.is_a?(Kleisli::Either::Right)
13
- end
11
+ return output unless result.is_a?(Kleisli::Either::Right)
14
12
 
15
- def failure(&block)
16
- block.call FailureMatcher.new(result) if result.is_a?(Kleisli::Either::Left)
13
+ @output = block.call(result.value)
17
14
  end
18
15
 
19
- class FailureMatcher
20
- attr_reader :result
21
- attr_reader :value
22
-
23
- def initialize(result)
24
- @result = result
25
- @value = result.value
26
- end
27
-
28
- def on(step_name, &block)
29
- if value.__step_name == step_name
30
- @matched = true
31
- block.call value
32
- end
33
- end
16
+ def failure(step_name = nil, &block)
17
+ return output unless result.is_a?(Kleisli::Either::Left)
34
18
 
35
- def otherwise(&block)
36
- block.call value unless @matched
19
+ if step_name.nil? || step_name == result.value.__step_name
20
+ @output = block.call(result.value)
37
21
  end
38
22
  end
39
23
  end
@@ -8,6 +8,5 @@ module CallSheet
8
8
  end
9
9
 
10
10
  register :step, Raw
11
- register :raw, Raw
12
11
  end
13
12
  end
@@ -4,13 +4,39 @@ module CallSheet
4
4
  class Transaction
5
5
  # @api private
6
6
  attr_reader :steps
7
- private :steps
8
7
 
9
8
  # @api private
10
9
  def initialize(steps)
11
10
  @steps = steps
12
11
  end
13
12
 
13
+ # Run the transaction.
14
+ #
15
+ # Each operation will be called in the order it was specified, with its
16
+ # output passed as input to the next operation. Operations will only be
17
+ # called if the previous step was a success.
18
+ #
19
+ # If any of the operations require extra arguments beyond the main input
20
+ # e.g. with a signature like `#call(something_else, input)`, then you must
21
+ # pass the extra arguments as arrays for each step in the options hash.
22
+ #
23
+ # @example Running a transaction
24
+ # my_transaction.call(some_input)
25
+ #
26
+ # @example Running a transaction with extra step arguments
27
+ # my_transaction.call(some_input, step_name: [extra_argument])
28
+ #
29
+ # The return value will be the output from the last operation, wrapped in
30
+ # a [Kleisli](kleisli) `Either` object, a `Right` for a successful
31
+ # transaction or a `Left` for a failed transaction.
32
+ #
33
+ # [kleisli]: https://rubygems.org/gems/kleisli
34
+ #
35
+ # @param input
36
+ # @param options [Hash] extra step arguments
37
+ #
38
+ # @return [Right, Left] output from the final step
39
+ #
14
40
  # @api public
15
41
  def call(input, options = {}, &block)
16
42
  assert_valid_options(options)
@@ -19,11 +45,40 @@ module CallSheet
19
45
  steps = steps_with_options_applied(options)
20
46
  result = steps.inject(Right(input), :>>)
21
47
 
22
- block.call ResultMatcher.new(result) if block
23
- result
48
+ if block
49
+ block.call(ResultMatcher.new(result))
50
+ else
51
+ result
52
+ end
24
53
  end
25
54
  alias_method :[], :call
26
55
 
56
+ # Subscribe to notifications from steps.
57
+ #
58
+ # When each step completes, it will send a `[step_name]_success` or
59
+ # `[step_name]_failure` message to any subscribers.
60
+ #
61
+ # For example, if you had a step called `persist`, then it would send
62
+ # either `persist_success` or `persist_failure` messages to subscribers
63
+ # after the operation completes.
64
+ #
65
+ # Pass a single object to subscribe to notifications from all steps, or
66
+ # pass a hash with step names as keys to subscribe to notifications from
67
+ # specific steps.
68
+ #
69
+ # @example Subscribing to notifications from all steps
70
+ # my_transaction.subscribe(my_listener)
71
+ #
72
+ # @example Subscribing to notifications from specific steps
73
+ # my_transaction.subscirbe(some_step: my_listener, another_step: another_listener)
74
+ #
75
+ # Notifications are implemented using the [Wisper](wisper) gem.
76
+ #
77
+ # [wisper]: https://rubygems.org/gems/wisper
78
+ #
79
+ # @param listeners [Object, Hash{Symbol => Object}] the listener object or
80
+ # hash of steps and listeners
81
+ #
27
82
  # @api public
28
83
  def subscribe(listeners)
29
84
  if listeners.is_a?(Hash)
@@ -39,6 +94,163 @@ module CallSheet
39
94
  self
40
95
  end
41
96
 
97
+ # Return a transaction with the steps from the provided transaction
98
+ # prepended onto the beginning of the steps in `self`.
99
+ #
100
+ # @example Prepend an existing transaction
101
+ # my_transaction = CallSheet(container: container) do
102
+ # step :first
103
+ # step :second
104
+ # end
105
+ #
106
+ # other_transaction = CallSheet(container: container) do
107
+ # step :another
108
+ # end
109
+ #
110
+ # my_transaction.prepend(other_transaction)
111
+ #
112
+ # @example Prepend a transaction defined inline
113
+ # my_transaction = CallSheet(container: container) do
114
+ # step :first
115
+ # step :second
116
+ # end
117
+ #
118
+ # my_transaction.prepend(container: container) do
119
+ # step :another
120
+ # end
121
+ #
122
+ # @param other [CallSheet::Transaction] the transaction to prepend.
123
+ # Optional if you will define a transaction inline via a block.
124
+ # @param options [Hash] the options hash for defining a transaction inline
125
+ # via a block. Optional if the transaction is passed directly as
126
+ # `other`.
127
+ # @option options [#[]] :container the operations container
128
+ #
129
+ # @return [CallSheet::Transaction] the modified transaction object
130
+ #
131
+ # @api public
132
+ def prepend(other = nil, **options, &block)
133
+ other = accept_or_build_transaction(other, **options, &block)
134
+
135
+ self.class.new(other.steps + steps)
136
+ end
137
+
138
+ # Return a transaction with the steps from the provided transaction
139
+ # appended onto the end of the steps in `self`.
140
+ #
141
+ # @example Append an existing transaction
142
+ # my_transaction = CallSheet(container: container) do
143
+ # step :first
144
+ # step :second
145
+ # end
146
+ #
147
+ # other_transaction = CallSheet(container: container) do
148
+ # step :another
149
+ # end
150
+ #
151
+ # my_transaction.append(other_transaction)
152
+ #
153
+ # @example Append a transaction defined inline
154
+ # my_transaction = CallSheet(container: container) do
155
+ # step :first
156
+ # step :second
157
+ # end
158
+ #
159
+ # my_transaction.append(container: container) do
160
+ # step :another
161
+ # end
162
+ #
163
+ # @param other [CallSheet::Transaction] the transaction to append.
164
+ # Optional if you will define a transaction inline via a block.
165
+ # @param options [Hash] the options hash for defining a transaction inline
166
+ # via a block. Optional if the transaction is passed directly as
167
+ # `other`.
168
+ # @option options [#[]] :container the operations container
169
+ #
170
+ # @return [CallSheet::Transaction] the modified transaction object
171
+ #
172
+ # @api public
173
+ def append(other = nil, **options, &block)
174
+ other = accept_or_build_transaction(other, **options, &block)
175
+
176
+ self.class.new(steps + other.steps)
177
+ end
178
+
179
+ # Return a transaction with the steps from the provided transaction
180
+ # inserted into a specific place among the steps in `self`.
181
+ #
182
+ # Transactions can be inserted either before or after a named step.
183
+ #
184
+ # @example Insert an existing transaction (before a step)
185
+ # my_transaction = CallSheet(container: container) do
186
+ # step :first
187
+ # step :second
188
+ # end
189
+ #
190
+ # other_transaction = CallSheet(container: container) do
191
+ # step :another
192
+ # end
193
+ #
194
+ # my_transaction.insert(other_transaction, before: :second)
195
+ #
196
+ # @example Append a transaction defined inline (after a step)
197
+ # my_transaction = CallSheet(container: container) do
198
+ # step :first
199
+ # step :second
200
+ # end
201
+ #
202
+ # my_transaction.insert(after: :first, container: container) do
203
+ # step :another
204
+ # end
205
+ #
206
+ # @param other [CallSheet::Transaction] the transaction to append.
207
+ # Optional if you will define a transaction inline via a block.
208
+ # @param before [Symbol] the name of the step before which the transaction
209
+ # should be inserted (provide either this or `after`)
210
+ # @param after [Symbol] the name of the step after which the transaction
211
+ # should be inserted (provide either this or `before`)
212
+ # @param options [Hash] the options hash for defining a transaction inline
213
+ # via a block. Optional if the transaction is passed directly as
214
+ # `other`.
215
+ # @option options [#[]] :container the operations container
216
+ #
217
+ # @return [CallSheet::Transaction] the modified transaction object
218
+ #
219
+ # @api public
220
+ def insert(other = nil, before: nil, after: nil, **options, &block)
221
+ insertion_step = before || after
222
+ unless steps.map(&:step_name).include?(insertion_step)
223
+ raise ArgumentError, "+#{insertion_step}+ is not a valid step name"
224
+ end
225
+
226
+ other = accept_or_build_transaction(other, **options, &block)
227
+ index = steps.index { |step| step.step_name == insertion_step } + (!!after ? 1 : 0)
228
+
229
+ self.class.new(steps.dup.insert(index, *other.steps))
230
+ end
231
+
232
+ # @overload remove(step, ...)
233
+ # Return a transaction with steps removed.
234
+ #
235
+ # @example
236
+ # my_transaction = CallSheet(container: container) do
237
+ # step :first
238
+ # step :second
239
+ # step :third
240
+ # end
241
+ #
242
+ # my_transaction.remove(:first, :third)
243
+ #
244
+ # @param step [Symbol] the names of a step to remove
245
+ # @param ... [Symbol] more names of steps to remove
246
+ #
247
+ # @return [CallSheet::Transaction] the modified transaction object
248
+ #
249
+ # @api public
250
+ def remove(*steps_to_remove)
251
+ self.class.new(steps.reject { |step| steps_to_remove.include?(step.step_name) })
252
+ end
253
+
42
254
  private
43
255
 
44
256
  def assert_valid_options(options)
@@ -69,5 +281,13 @@ module CallSheet
69
281
  end
70
282
  }
71
283
  end
284
+
285
+ def accept_or_build_transaction(other_transaction = nil, **options, &block)
286
+ unless other_transaction || block
287
+ raise ArgumentError, "a transaction must be provided or defined in a block"
288
+ end
289
+
290
+ other_transaction || DSL.new(**options, &block).call
291
+ end
72
292
  end
73
293
  end
@@ -1,4 +1,4 @@
1
1
  # Business transaction DSL.
2
2
  module CallSheet
3
- VERSION = "0.3.2".freeze
3
+ VERSION = "0.4.0".freeze
4
4
  end
data/spec/examples.txt CHANGED
@@ -1,23 +1,41 @@
1
1
  example_id | status | run_time |
2
2
  -------------------------------------------------------- | ------ | --------------- |
3
- ./spec/integration/call_sheet_spec.rb[1:1:1] | passed | 0.00146 seconds |
4
- ./spec/integration/call_sheet_spec.rb[1:1:2] | passed | 0.00022 seconds |
3
+ ./spec/integration/call_sheet_spec.rb[1:1:1] | passed | 0.00106 seconds |
4
+ ./spec/integration/call_sheet_spec.rb[1:1:2] | passed | 0.00021 seconds |
5
5
  ./spec/integration/call_sheet_spec.rb[1:1:3] | passed | 0.00019 seconds |
6
- ./spec/integration/call_sheet_spec.rb[1:1:4] | passed | 0.00028 seconds |
7
- ./spec/integration/call_sheet_spec.rb[1:1:5] | passed | 0.00104 seconds |
8
- ./spec/integration/call_sheet_spec.rb[1:2:1] | passed | 0.00206 seconds |
9
- ./spec/integration/call_sheet_spec.rb[1:2:2] | passed | 0.00023 seconds |
10
- ./spec/integration/call_sheet_spec.rb[1:2:3] | passed | 0.00022 seconds |
11
- ./spec/integration/call_sheet_spec.rb[1:2:4] | passed | 0.00022 seconds |
12
- ./spec/integration/call_sheet_spec.rb[1:2:5] | passed | 0.00022 seconds |
13
- ./spec/integration/call_sheet_spec.rb[1:2:6] | passed | 0.00032 seconds |
14
- ./spec/integration/call_sheet_spec.rb[1:3:1] | passed | 0.00019 seconds |
15
- ./spec/integration/call_sheet_spec.rb[1:3:2] | passed | 0.00016 seconds |
16
- ./spec/integration/call_sheet_spec.rb[1:3:3] | passed | 0.00017 seconds |
17
- ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00113 seconds |
18
- ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.0002 seconds |
19
- ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00221 seconds |
20
- ./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00194 seconds |
21
- ./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00042 seconds |
22
- ./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.00032 seconds |
23
- ./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00027 seconds |
6
+ ./spec/integration/call_sheet_spec.rb[1:1:4] | passed | 0.00033 seconds |
7
+ ./spec/integration/call_sheet_spec.rb[1:1:5] | passed | 0.00021 seconds |
8
+ ./spec/integration/call_sheet_spec.rb[1:2:1] | passed | 0.00153 seconds |
9
+ ./spec/integration/call_sheet_spec.rb[1:2:2] | passed | 0.00052 seconds |
10
+ ./spec/integration/call_sheet_spec.rb[1:2:3] | passed | 0.00021 seconds |
11
+ ./spec/integration/call_sheet_spec.rb[1:2:4] | passed | 0.00024 seconds |
12
+ ./spec/integration/call_sheet_spec.rb[1:2:5] | passed | 0.00023 seconds |
13
+ ./spec/integration/call_sheet_spec.rb[1:2:6] | passed | 0.00023 seconds |
14
+ ./spec/integration/call_sheet_spec.rb[1:3:1] | passed | 0.00022 seconds |
15
+ ./spec/integration/call_sheet_spec.rb[1:3:2] | passed | 0.00017 seconds |
16
+ ./spec/integration/call_sheet_spec.rb[1:3:3] | passed | 0.00018 seconds |
17
+ ./spec/integration/passing_step_arguments_spec.rb[1:1:1] | passed | 0.00037 seconds |
18
+ ./spec/integration/passing_step_arguments_spec.rb[1:2:1] | passed | 0.00026 seconds |
19
+ ./spec/integration/passing_step_arguments_spec.rb[1:3:1] | passed | 0.00026 seconds |
20
+ ./spec/integration/publishing_step_events_spec.rb[1:1:1] | passed | 0.00134 seconds |
21
+ ./spec/integration/publishing_step_events_spec.rb[1:1:2] | passed | 0.00051 seconds |
22
+ ./spec/integration/publishing_step_events_spec.rb[1:2:1] | passed | 0.00039 seconds |
23
+ ./spec/integration/publishing_step_events_spec.rb[1:2:2] | passed | 0.00035 seconds |
24
+ ./spec/unit/transaction_spec.rb[1:1:1] | passed | 0.00014 seconds |
25
+ ./spec/unit/transaction_spec.rb[1:1:2] | passed | 0.00028 seconds |
26
+ ./spec/unit/transaction_spec.rb[1:1:3] | passed | 0.00013 seconds |
27
+ ./spec/unit/transaction_spec.rb[1:1:4] | passed | 0.00013 seconds |
28
+ ./spec/unit/transaction_spec.rb[1:2:1] | passed | 0.00018 seconds |
29
+ ./spec/unit/transaction_spec.rb[1:2:2] | passed | 0.00079 seconds |
30
+ ./spec/unit/transaction_spec.rb[1:2:3] | passed | 0.00145 seconds |
31
+ ./spec/unit/transaction_spec.rb[1:2:4] | passed | 0.00014 seconds |
32
+ ./spec/unit/transaction_spec.rb[1:3:1] | passed | 0.00022 seconds |
33
+ ./spec/unit/transaction_spec.rb[1:3:2] | passed | 0.00016 seconds |
34
+ ./spec/unit/transaction_spec.rb[1:4:1] | passed | 0.00036 seconds |
35
+ ./spec/unit/transaction_spec.rb[1:4:2] | passed | 0.00017 seconds |
36
+ ./spec/unit/transaction_spec.rb[1:4:3] | passed | 0.00013 seconds |
37
+ ./spec/unit/transaction_spec.rb[1:4:4] | passed | 0.00012 seconds |
38
+ ./spec/unit/transaction_spec.rb[1:4:5:1] | passed | 0.00018 seconds |
39
+ ./spec/unit/transaction_spec.rb[1:4:5:2] | passed | 0.00031 seconds |
40
+ ./spec/unit/transaction_spec.rb[1:4:6:1] | passed | 0.00021 seconds |
41
+ ./spec/unit/transaction_spec.rb[1:4:6:2] | passed | 0.00021 seconds |
@@ -2,7 +2,7 @@ RSpec.describe CallSheet do
2
2
  let(:call_sheet) {
3
3
  CallSheet(container: container) do
4
4
  map :process
5
- raw :verify
5
+ step :verify
6
6
  try :validate, catch: Test::NotValidError
7
7
  tee :persist
8
8
  end
@@ -79,8 +79,8 @@ RSpec.describe CallSheet do
79
79
  results = []
80
80
 
81
81
  call_sheet.call(input) do |m|
82
- m.failure do |f|
83
- results << "Failed: #{f.value}"
82
+ m.failure do |value|
83
+ results << "Failed: #{value}"
84
84
  end
85
85
  end
86
86
 
@@ -91,10 +91,8 @@ RSpec.describe CallSheet do
91
91
  results = []
92
92
 
93
93
  call_sheet.call(input) do |m|
94
- m.failure do |f|
95
- f.on :validate do |v|
96
- results << "Validation failure: #{v}"
97
- end
94
+ m.failure :validate do |value|
95
+ results << "Validation failure: #{value}"
98
96
  end
99
97
  end
100
98
 
@@ -105,14 +103,12 @@ RSpec.describe CallSheet do
105
103
  results = []
106
104
 
107
105
  call_sheet.call(input) do |m|
108
- m.failure do |f|
109
- f.on :some_other_step do |v|
110
- results << "Some other step failure"
111
- end
112
-
113
- f.otherwise do |v|
114
- results << "Catch-all failure: #{v}"
115
- end
106
+ m.failure :some_other_step do |value|
107
+ results << "Some other step failure"
108
+ end
109
+
110
+ m.failure do |value|
111
+ results << "Catch-all failure: #{value}"
116
112
  end
117
113
  end
118
114
 
@@ -2,7 +2,7 @@ RSpec.describe "publishing step events" do
2
2
  let(:call_sheet) {
3
3
  CallSheet(container: container) do
4
4
  map :process
5
- raw :verify
5
+ step :verify
6
6
  tee :persist
7
7
  end
8
8
  }
@@ -0,0 +1,173 @@
1
+ RSpec.describe CallSheet::Transaction do
2
+ subject(:container) {
3
+ {
4
+ upcase: -> input { input.upcase },
5
+ reverse: -> input { input.reverse },
6
+ exclaim_all: -> input { input.split(" ").map { |str| str + "!" }.join(" ") },
7
+ }
8
+ }
9
+
10
+ describe "#prepend" do
11
+ let(:initial_transaction) {
12
+ CallSheet(container: container) do
13
+ map :exclaim_all
14
+ end
15
+ }
16
+
17
+ it "prepends the transaction" do
18
+ other_transaction = CallSheet(container: container) do
19
+ map :reverse
20
+ end
21
+ new_transaction = initial_transaction.prepend(other_transaction)
22
+
23
+ expect(new_transaction.call("hello world").right).to eq "dlrow! olleh!"
24
+ end
25
+
26
+ it "accepts a transaction defined in a block" do
27
+ new_transaction = initial_transaction.prepend(container: container) do
28
+ map :reverse
29
+ end
30
+
31
+ expect(new_transaction.call("hello world").right).to eq "dlrow! olleh!"
32
+ end
33
+
34
+ it "raises an argument error if a transaction is neither passed nor defined" do
35
+ expect { initial_transaction.prepend }.to raise_error(ArgumentError)
36
+ end
37
+
38
+ it "leaves the original transaction unmodified" do
39
+ new_transaction = initial_transaction.prepend(container: container) do
40
+ map :reverse
41
+ end
42
+
43
+ expect(initial_transaction.call("the quick brown fox").right).to eq "the! quick! brown! fox!"
44
+ end
45
+ end
46
+
47
+ describe "#append" do
48
+ let(:initial_transaction) {
49
+ CallSheet(container: container) do
50
+ map :exclaim_all
51
+ end
52
+ }
53
+
54
+ it "appends the transaction" do
55
+ other_transaction = CallSheet(container: container) do
56
+ map :reverse
57
+ end
58
+ new_transaction = initial_transaction.append(other_transaction)
59
+
60
+ expect(new_transaction.call("hello world").right).to eq "!dlrow !olleh"
61
+ end
62
+
63
+ it "accepts a transaction defined in a block" do
64
+ new_transaction = initial_transaction.append(container: container) do
65
+ map :reverse
66
+ end
67
+
68
+ expect(new_transaction.call("hello world").right).to eq "!dlrow !olleh"
69
+ end
70
+
71
+ it "raises an argument error if a transaction is neither passed nor defined" do
72
+ expect { initial_transaction.insert(before: :reverse) }.to raise_error(ArgumentError)
73
+ end
74
+
75
+ it "leaves the original transaction unmodified" do
76
+ new_transaction = initial_transaction.append(container: container) do
77
+ map :reverse
78
+ end
79
+
80
+ expect(initial_transaction.call("hello world").right).to eq "hello! world!"
81
+ end
82
+ end
83
+
84
+ describe "#remove" do
85
+ let(:initial_transaction) {
86
+ CallSheet(container: container) do
87
+ map :upcase
88
+ map :exclaim_all
89
+ map :reverse
90
+ end
91
+ }
92
+
93
+ it "removes the specified steps" do
94
+ new_transaction = initial_transaction.remove(:exclaim_all, :reverse)
95
+ expect(new_transaction.call("hello world").right).to eq "HELLO WORLD"
96
+ end
97
+
98
+ it "leaves the original transaction unmodified" do
99
+ new_transaction = initial_transaction.remove(:exclaim_all, :reverse)
100
+ expect(initial_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
101
+ end
102
+ end
103
+
104
+ describe "#insert" do
105
+ let(:initial_transaction) {
106
+ CallSheet(container: container) do
107
+ map :upcase
108
+ map :reverse
109
+ end
110
+ }
111
+
112
+ it "accepts a transaction passed as an argument" do
113
+ other_transaction = CallSheet(container: container) do
114
+ map :exclaim_all
115
+ end
116
+ new_transaction = initial_transaction.insert(other_transaction, before: :reverse)
117
+
118
+ expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
119
+ end
120
+
121
+ it "accepts a transaction defined in a block" do
122
+ new_transaction = initial_transaction.insert(before: :reverse, container: container) do
123
+ map :exclaim_all
124
+ end
125
+
126
+ expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
127
+ end
128
+
129
+ it "raises an argument error if a transaction is neither passed nor defined" do
130
+ expect { initial_transaction.insert(before: :reverse) }.to raise_error(ArgumentError)
131
+ end
132
+
133
+ it "raises an argument error if an invalid step name is provided" do
134
+ expect {
135
+ initial_transaction.insert(before: :non_existent, container: container) do
136
+ map :exclaim_all
137
+ end
138
+ }.to raise_error(ArgumentError)
139
+ end
140
+
141
+ context "before" do
142
+ let!(:new_transaction) {
143
+ initial_transaction.insert(before: :reverse, container: container) do
144
+ map :exclaim_all
145
+ end
146
+ }
147
+
148
+ it "inserts the new steps before the specified one" do
149
+ expect(new_transaction.call("hello world").right).to eq "!DLROW !OLLEH"
150
+ end
151
+
152
+ it "leaves the original transaction unmodified" do
153
+ expect(initial_transaction.call("hello world").right).to eq "DLROW OLLEH"
154
+ end
155
+ end
156
+
157
+ context "after" do
158
+ let!(:new_transaction) {
159
+ initial_transaction.insert(after: :reverse, container: container) do
160
+ map :exclaim_all
161
+ end
162
+ }
163
+
164
+ it "inserts the new steps after the specified one" do
165
+ expect(new_transaction.call("hello world").right).to eq "DLROW! OLLEH!"
166
+ end
167
+
168
+ it "leaves the original transaction unmodified" do
169
+ expect(initial_transaction.call("hello world").right).to eq "DLROW OLLEH"
170
+ end
171
+ end
172
+ end
173
+ 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.3.2
4
+ version: 0.4.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-11-13 00:00:00.000000000 Z
11
+ date: 2015-12-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kleisli
@@ -153,6 +153,7 @@ files:
153
153
  - spec/integration/publishing_step_events_spec.rb
154
154
  - spec/spec_helper.rb
155
155
  - spec/support/test_module_constants.rb
156
+ - spec/unit/transaction_spec.rb
156
157
  homepage: https://github.com/icelab/call_sheet
157
158
  licenses:
158
159
  - MIT
@@ -165,7 +166,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
165
166
  requirements:
166
167
  - - ">="
167
168
  - !ruby/object:Gem::Version
168
- version: '0'
169
+ version: 2.0.0
169
170
  required_rubygems_version: !ruby/object:Gem::Requirement
170
171
  requirements:
171
172
  - - ">="