call_sheet 0.3.2 → 0.4.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: 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
  - - ">="