tzu 0.1.0.0 → 0.1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +144 -10
- data/lib/tzu/errors.rb +4 -0
- data/lib/tzu/hooks.rb +4 -4
- data/lib/tzu/run_methods.rb +2 -2
- data/lib/tzu/sequence.rb +19 -13
- data/lib/tzu/step.rb +38 -8
- data/lib/tzu.rb +1 -0
- data/spec/sequence_spec.rb +45 -19
- data/spec/step_spec.rb +32 -0
- metadata +5 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b65373fa789405d5d165a29c71bd15b3a227450b
|
4
|
+
data.tar.gz: e7a9845bc66eba286135a9e7cbb64b9c197fa409
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a9a239244309bd5eae81848753bbdcdad5b22aac74b070ff73cb4ea843be47c1715a19758e06bcf6ed0025066423c2f6cace651b1f84f4f8b02888e767a09044
|
7
|
+
data.tar.gz: 14b6723526bfa3dbe24a36d5dc65caa122cbc5f2e12eb2c7891aacedb6d89542736809ecca93044da744e2296e8ff190995695b05a49d042e15e4f883756815d
|
data/README.md
CHANGED
@@ -1,5 +1,36 @@
|
|
1
1
|
# Tzu
|
2
2
|
|
3
|
+
Tzu provides a simple interface for writing classes that encapsulate a single command.
|
4
|
+
|
5
|
+
**Commands should:**
|
6
|
+
|
7
|
+
- Do exactly one thing (Single Responsibility Priciple)
|
8
|
+
- Be self-documenting
|
9
|
+
- Be testable
|
10
|
+
- Be easy to mock and stub
|
11
|
+
|
12
|
+
**Benefits**
|
13
|
+
|
14
|
+
- File and class names say what your code *actually does*, making onboarding and debugging a much simpler process.
|
15
|
+
- Minimize the instances of persistence logic throughout the application
|
16
|
+
- The Rails 'where do I put...?' question is solved. Models, Controllers, Workers and even Rake Tasks become slim.
|
17
|
+
- Maintain all of the benefits of Object Oriented programming while executing a procedural action, or Sequence of procedural actions.
|
18
|
+
|
19
|
+
**Documentation**
|
20
|
+
|
21
|
+
- [Usage](#usage)
|
22
|
+
- [Validation](#validation)
|
23
|
+
- [Passing Blocks](#passing-blocks)
|
24
|
+
- [Hooks](#hooks)
|
25
|
+
- [Request Objects](#request-objects)
|
26
|
+
|
27
|
+
**Sequences**
|
28
|
+
- [Configure](#configure)
|
29
|
+
- [Execute](#execute)
|
30
|
+
- [Integrating Non Tzu Classes](#integrating-non-tzu-classes)
|
31
|
+
- [Hooks for Sequences](#hooks-for-sequences)
|
32
|
+
- [Mocking and Stubbing](#mocking-and-stubbing)
|
33
|
+
|
3
34
|
## Usage
|
4
35
|
|
5
36
|
Tzu commands must include Tzu and implement a `#call` method.
|
@@ -79,7 +110,11 @@ outcome = MyRescueCommand.run!(params_that_cause_error)
|
|
79
110
|
|
80
111
|
Note that if you pass a string to `invalid!`, it will coerce the result into a hash of the form:
|
81
112
|
|
82
|
-
```
|
113
|
+
```ruby
|
114
|
+
# Invoking:
|
115
|
+
invalid!('Error String')
|
116
|
+
|
117
|
+
# Translates to:
|
83
118
|
{ errors: 'Error String' }
|
84
119
|
```
|
85
120
|
|
@@ -149,9 +184,7 @@ MyCommand.run(message: 'Hello!')
|
|
149
184
|
#=> End Around 1
|
150
185
|
```
|
151
186
|
|
152
|
-
|
153
|
-
|
154
|
-
## Request objects
|
187
|
+
## Request Objects
|
155
188
|
|
156
189
|
You can define a request object for your command using the `#request_object` method.
|
157
190
|
|
@@ -196,6 +229,7 @@ Virtus.model validates the types of your inputs, and also makes them available v
|
|
196
229
|
class MyRequestObject
|
197
230
|
include Virtus.model
|
198
231
|
include ActiveModel::Validations
|
232
|
+
|
199
233
|
validates :name, :age, presence: :true
|
200
234
|
|
201
235
|
attribute :name, String
|
@@ -225,7 +259,9 @@ outcome.type? #=> :validation
|
|
225
259
|
outcome.result #=> {:age=>["can't be blank"]}
|
226
260
|
```
|
227
261
|
|
228
|
-
#
|
262
|
+
# Execute Commands in Sequence
|
263
|
+
|
264
|
+
## Configure
|
229
265
|
|
230
266
|
Tzu provides a declarative way of encapsulating sequential command execution.
|
231
267
|
|
@@ -249,7 +285,7 @@ class MakeMeSoundImportant
|
|
249
285
|
end
|
250
286
|
```
|
251
287
|
|
252
|
-
|
288
|
+
Tzu::Sequence provides a DSL for executing them in sequence:
|
253
289
|
|
254
290
|
```ruby
|
255
291
|
class ProclaimMyImportance
|
@@ -276,7 +312,7 @@ Each command to be executed is defined as the first argument of `step`.
|
|
276
312
|
The `receives` method inside the `step` block allows you to mutate the parameters being passed into the command.
|
277
313
|
It is passed both the original parameters and a hash containing the results of prior commands.
|
278
314
|
|
279
|
-
By default, the keys of the `prior_results` hash are underscored/symbolized command names.
|
315
|
+
By default, the keys of the `prior_results` hash are demodulized/underscored/symbolized command names.
|
280
316
|
You can define your own keys using the `as` method.
|
281
317
|
|
282
318
|
```ruby
|
@@ -288,9 +324,15 @@ step SayMyName do
|
|
288
324
|
end
|
289
325
|
```
|
290
326
|
|
291
|
-
|
327
|
+
If you don't need to mutate the parameters for the command, simply omit `receives`.
|
328
|
+
|
329
|
+
```ruby
|
330
|
+
step SayMyName
|
331
|
+
```
|
292
332
|
|
293
|
-
|
333
|
+
## Execute
|
334
|
+
|
335
|
+
By default, Sequences return the result of the final command.
|
294
336
|
|
295
337
|
```ruby
|
296
338
|
outcome = ProclaimMyImportance.run(name: 'Jessica', country: 'Azerbaijan')
|
@@ -363,7 +405,95 @@ outcome.result
|
|
363
405
|
#=> { name: 'Jessica', original_message: 'Hello, Jessica', message: 'BULLETIN: Hello, Jessica! You are the most important citizen of Azerbaijan!' }
|
364
406
|
```
|
365
407
|
|
366
|
-
|
408
|
+
## Integrating Non Tzu Classes
|
409
|
+
|
410
|
+
Sometimes there is a need to combine non-Tzu classes with Tzu classes in a sequence.
|
411
|
+
|
412
|
+
As an example, let's say I wanted to query a record, update it, and pass the updated record to a Tzu command.
|
413
|
+
To do this, I'll use the [Get](https://github.com/onfido/get) and [Tradesman](https://github.com/onfido/tradesman/) libraries.
|
414
|
+
|
415
|
+
When invoked on its own, Get looks like this:
|
416
|
+
```ruby
|
417
|
+
Get::UserByName.run(name)
|
418
|
+
```
|
419
|
+
|
420
|
+
Tradesman Update looks like this:
|
421
|
+
```ruby
|
422
|
+
Tradesman::UpdateUser.go(user_id, update_params)
|
423
|
+
```
|
424
|
+
|
425
|
+
The integration of Get into `Tzu::Sequence` is easy, as it only expects one parameter, and it's invoked with `#run`.
|
426
|
+
Tradesman is more complicated; it expects two parameters - a User ID and a hash to update that record with - and it's invoked with `#go`.
|
427
|
+
|
428
|
+
Tradesman offers the `invoke_with` and `receives_many` arguments to deal with these differences.
|
429
|
+
|
430
|
+
`invoke_with` is self-explanatory, and defaults to `#run`.
|
431
|
+
|
432
|
+
The `receives_many` block must return an array, which will be passed as a splat to the `invoke_with` method.
|
433
|
+
```ruby
|
434
|
+
class NonTzuSequence
|
435
|
+
include Tzu::Sequence
|
436
|
+
|
437
|
+
step Get::UserByName do
|
438
|
+
receives do |params|
|
439
|
+
params[:name]
|
440
|
+
end
|
441
|
+
end
|
442
|
+
|
443
|
+
step Tradesman::UpdateUser do
|
444
|
+
invoke_with :go
|
445
|
+
|
446
|
+
receives_many do |params, prior_results|
|
447
|
+
[
|
448
|
+
prior_results[:user_by_name].id,
|
449
|
+
params[:update_params]
|
450
|
+
]
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
step SayMyName do
|
455
|
+
receives do |params, prior_results|
|
456
|
+
prior_results[:update_user].name
|
457
|
+
end
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
outcome = NonTzuSequence.run(name: 'Blake', update_params: { name: 'Morgan' })
|
462
|
+
outcome.result #=> 'Hello, Morgan'
|
463
|
+
```
|
464
|
+
|
465
|
+
You can pass multiple parameters to `Tzu::Sequence` instead of a parameters hash, just make sure you add the correct amount of arguments to your `receives` and `receives_many` blocks.
|
466
|
+
|
467
|
+
```ruby
|
468
|
+
class NonTzuSequence
|
469
|
+
include Tzu::Sequence
|
470
|
+
|
471
|
+
step Get::UserByName do
|
472
|
+
receives do |name, update_params|
|
473
|
+
name
|
474
|
+
end
|
475
|
+
end
|
476
|
+
|
477
|
+
step Tradesman::UpdateUser do
|
478
|
+
invoke_with :go
|
479
|
+
|
480
|
+
receives_many do |name, update_params, prior_results|
|
481
|
+
[prior_results[:user_by_name].id, update_params]
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
step SayMyName do
|
486
|
+
receives do |name, update_params, prior_results|
|
487
|
+
prior_results[:update_user].name
|
488
|
+
end
|
489
|
+
end
|
490
|
+
end
|
491
|
+
|
492
|
+
outcome = NonTzuSequence.run('Blake', { name: 'Morgan' })
|
493
|
+
outcome.result #=> 'Hello, Morgan'
|
494
|
+
```
|
495
|
+
|
496
|
+
## Hooks for Sequences
|
367
497
|
|
368
498
|
Tzu sequences have the same `before`, `after`, and `around` hooks available in Tzu commands.
|
369
499
|
This is particularly useful for wrapping multiple commands in a transaction.
|
@@ -394,3 +524,7 @@ class ProclaimMyImportance
|
|
394
524
|
end
|
395
525
|
end
|
396
526
|
```
|
527
|
+
|
528
|
+
## Mocking and Stubbing
|
529
|
+
|
530
|
+
Tzu has a specialized (and well-documented) gem for mocking/stubbing, [TzuMock](https://github.com/onfido/tzu_mock).
|
data/lib/tzu/errors.rb
ADDED
data/lib/tzu/hooks.rb
CHANGED
@@ -37,12 +37,12 @@ module Tzu
|
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
40
|
-
def with_hooks(params, &block)
|
40
|
+
def with_hooks(*params, &block)
|
41
41
|
result = nil
|
42
42
|
run_around_hooks do
|
43
|
-
run_before_hooks(params)
|
44
|
-
result = yield(params)
|
45
|
-
run_after_hooks(params)
|
43
|
+
run_before_hooks(*params)
|
44
|
+
result = yield(*params)
|
45
|
+
run_after_hooks(*params)
|
46
46
|
end
|
47
47
|
result
|
48
48
|
end
|
data/lib/tzu/run_methods.rb
CHANGED
data/lib/tzu/sequence.rb
CHANGED
@@ -7,13 +7,8 @@ module Tzu
|
|
7
7
|
class << self
|
8
8
|
attr_reader :steps, :result_block
|
9
9
|
|
10
|
-
def run(params)
|
11
|
-
new(params).run
|
12
|
-
end
|
13
|
-
|
14
|
-
def method_missing(method, *args, &block)
|
15
|
-
return add_step(args.first, &block) if method == :step
|
16
|
-
super
|
10
|
+
def run(*params)
|
11
|
+
new(*params).run
|
17
12
|
end
|
18
13
|
|
19
14
|
def type
|
@@ -25,19 +20,20 @@ module Tzu
|
|
25
20
|
@type = type
|
26
21
|
end
|
27
22
|
|
28
|
-
def
|
23
|
+
def step(klass, &block)
|
29
24
|
@steps = [] unless @steps
|
30
25
|
|
31
26
|
step = Step.new(klass)
|
32
|
-
step.instance_eval(&block)
|
27
|
+
step.instance_eval(&block) if block
|
33
28
|
|
34
29
|
@steps << step
|
35
30
|
end
|
36
31
|
end
|
37
32
|
|
38
|
-
def initialize(params)
|
33
|
+
def initialize(*params)
|
39
34
|
@params = params
|
40
35
|
@last_outcome = nil
|
36
|
+
@prior_results = {}
|
41
37
|
end
|
42
38
|
|
43
39
|
def run
|
@@ -50,15 +46,25 @@ module Tzu
|
|
50
46
|
def sequence_results
|
51
47
|
with_hooks(@params) do |params|
|
52
48
|
self.class.steps.reduce({}) do |prior_results, step|
|
53
|
-
@last_outcome = step.run(params, prior_results)
|
54
|
-
break if
|
55
|
-
|
49
|
+
@last_outcome = step.run(*params, prior_results)
|
50
|
+
break if last_outcome_is_failure?
|
51
|
+
merge_last_outcome_into_prior_results(step, prior_results)
|
56
52
|
end
|
57
53
|
end
|
58
54
|
end
|
59
55
|
|
60
56
|
private
|
61
57
|
|
58
|
+
def last_outcome_is_failure?
|
59
|
+
return true if (@last_outcome.respond_to?(:failure?) && @last_outcome.failure?)
|
60
|
+
false
|
61
|
+
end
|
62
|
+
|
63
|
+
def merge_last_outcome_into_prior_results(step, prior_results)
|
64
|
+
result = @last_outcome.respond_to?(:result) ? @last_outcome.result : @last_outcome
|
65
|
+
prior_results.merge(step.name => result)
|
66
|
+
end
|
67
|
+
|
62
68
|
def mutated_result(results)
|
63
69
|
Outcome.new(true, instance_exec(@params, results, &self.class.result_block))
|
64
70
|
end
|
data/lib/tzu/step.rb
CHANGED
@@ -1,34 +1,64 @@
|
|
1
1
|
module Tzu
|
2
2
|
class Step
|
3
|
+
DOUBLE_MUTATOR = 'You cannot define both receives and receives_many'
|
4
|
+
|
3
5
|
String.send(:include, ::Tzu::CoreExtensions::String)
|
4
|
-
attr_reader :klass, :
|
6
|
+
attr_reader :klass, :single_mutator, :splat_mutator
|
5
7
|
|
6
8
|
def initialize(klass)
|
7
9
|
@klass = klass
|
10
|
+
@invoke_method = :run
|
8
11
|
end
|
9
12
|
|
10
|
-
def run(params, prior_results)
|
11
|
-
|
12
|
-
@klass.
|
13
|
+
def run(*params, prior_results)
|
14
|
+
# Forward parameters as splat if no mutators are defined
|
15
|
+
return @klass.send(@invoke_method, *params) if mutator.nil?
|
16
|
+
|
17
|
+
command_params = process(*params, prior_results)
|
18
|
+
|
19
|
+
return @klass.send(@invoke_method, command_params) unless splat?
|
20
|
+
@klass.send(@invoke_method, *command_params)
|
13
21
|
end
|
14
22
|
|
15
23
|
def name
|
16
24
|
return @name if @name && @name.is_a?(Symbol)
|
17
|
-
@klass.to_s.symbolize
|
25
|
+
@klass.to_s.split('::').last.symbolize
|
18
26
|
end
|
19
27
|
|
20
28
|
def receives(&block)
|
21
|
-
|
29
|
+
double_mutator_error if splat?
|
30
|
+
@single_mutator = block
|
31
|
+
end
|
32
|
+
|
33
|
+
def receives_many(&block)
|
34
|
+
double_mutator_error if @single_mutator.present?
|
35
|
+
@splat_mutator = block
|
22
36
|
end
|
23
37
|
|
24
38
|
def as(name)
|
25
39
|
@name = name
|
26
40
|
end
|
27
41
|
|
42
|
+
def invoke_with(method)
|
43
|
+
@invoke_method = method
|
44
|
+
end
|
45
|
+
|
28
46
|
private
|
29
47
|
|
30
|
-
def
|
31
|
-
|
48
|
+
def double_mutator_error
|
49
|
+
raise Tzu::InvalidSequence.new(DOUBLE_MUTATOR)
|
50
|
+
end
|
51
|
+
|
52
|
+
def mutator
|
53
|
+
@single_mutator || @splat_mutator
|
54
|
+
end
|
55
|
+
|
56
|
+
def splat?
|
57
|
+
@splat_mutator.present?
|
58
|
+
end
|
59
|
+
|
60
|
+
def process(*params, prior_results)
|
61
|
+
instance_exec(*params, prior_results, &mutator)
|
32
62
|
end
|
33
63
|
end
|
34
64
|
end
|
data/lib/tzu.rb
CHANGED
data/spec/sequence_spec.rb
CHANGED
@@ -16,7 +16,7 @@ class MakeMeSoundImportant
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
class
|
19
|
+
class ThrowInvalidError
|
20
20
|
include Tzu
|
21
21
|
|
22
22
|
def call(params)
|
@@ -24,6 +24,14 @@ class InvalidCommand
|
|
24
24
|
end
|
25
25
|
end
|
26
26
|
|
27
|
+
class ConstructGreeting
|
28
|
+
class << self
|
29
|
+
def go(greeting, name)
|
30
|
+
"#{greeting}, #{name}"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
27
35
|
class MultiStepSimple
|
28
36
|
include Tzu::Sequence
|
29
37
|
|
@@ -43,14 +51,33 @@ class MultiStepSimple
|
|
43
51
|
end
|
44
52
|
end
|
45
53
|
|
54
|
+
class MultiStepNonTzu
|
55
|
+
include Tzu::Sequence
|
56
|
+
|
57
|
+
step ConstructGreeting do
|
58
|
+
as :say_my_name
|
59
|
+
invoke_with :go
|
60
|
+
|
61
|
+
receives_many do |greeting, name, country|
|
62
|
+
[greeting, name]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
step MakeMeSoundImportant do
|
67
|
+
receives do |greeting, name, country, prior_results|
|
68
|
+
{
|
69
|
+
boring_message: prior_results[:say_my_name],
|
70
|
+
country: country
|
71
|
+
}
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
46
76
|
class MultiStepComplex
|
47
77
|
include Tzu::Sequence
|
48
78
|
|
49
79
|
step SayMyName do
|
50
80
|
as :first_command
|
51
|
-
receives do |params|
|
52
|
-
{ name: params[:name] }
|
53
|
-
end
|
54
81
|
end
|
55
82
|
|
56
83
|
step MakeMeSoundImportant do
|
@@ -71,9 +98,6 @@ class MultiStepProcessResults
|
|
71
98
|
|
72
99
|
step SayMyName do
|
73
100
|
as :first_command
|
74
|
-
receives do |params|
|
75
|
-
{ name: params[:name] }
|
76
|
-
end
|
77
101
|
end
|
78
102
|
|
79
103
|
step MakeMeSoundImportant do
|
@@ -97,13 +121,9 @@ end
|
|
97
121
|
class MultiStepInvalid
|
98
122
|
include Tzu::Sequence
|
99
123
|
|
100
|
-
step SayMyName
|
101
|
-
receives do |params|
|
102
|
-
{ name: params[:name] }
|
103
|
-
end
|
104
|
-
end
|
124
|
+
step SayMyName
|
105
125
|
|
106
|
-
step
|
126
|
+
step ThrowInvalidError do
|
107
127
|
receives do |params, prior_results|
|
108
128
|
{ answer: "#{params[:name]}!!! #{prior_results[:say_my_name]}" }
|
109
129
|
end
|
@@ -128,16 +148,16 @@ describe Tzu::Sequence do
|
|
128
148
|
steps.each { |step| expect(step.is_a? Tzu::Step).to be true }
|
129
149
|
end
|
130
150
|
|
131
|
-
it 'passes the appropriate klass, name, and
|
151
|
+
it 'passes the appropriate klass, name, and param_mutators to each step' do
|
132
152
|
say_my_name = steps.first
|
133
153
|
expect(say_my_name.klass).to eq SayMyName
|
134
154
|
expect(say_my_name.name).to eq :say_my_name
|
135
|
-
expect(say_my_name.
|
155
|
+
expect(say_my_name.single_mutator.is_a? Proc).to be true
|
136
156
|
|
137
157
|
make_me_sound_important = steps.last
|
138
158
|
expect(make_me_sound_important.klass).to eq MakeMeSoundImportant
|
139
159
|
expect(make_me_sound_important.name).to eq :make_me_sound_important
|
140
|
-
expect(make_me_sound_important.
|
160
|
+
expect(make_me_sound_important.single_mutator.is_a? Proc).to be true
|
141
161
|
end
|
142
162
|
end
|
143
163
|
|
@@ -148,16 +168,15 @@ describe Tzu::Sequence do
|
|
148
168
|
steps.each { |step| expect(step.is_a? Tzu::Step).to be true }
|
149
169
|
end
|
150
170
|
|
151
|
-
it 'passes the appropriate klass, name, and
|
171
|
+
it 'passes the appropriate klass, name, and param_mutators to each step' do
|
152
172
|
say_my_name = steps.first
|
153
173
|
expect(say_my_name.klass).to eq SayMyName
|
154
174
|
expect(say_my_name.name).to eq :first_command
|
155
|
-
expect(say_my_name.param_mutator.is_a? Proc).to be true
|
156
175
|
|
157
176
|
make_me_sound_important = steps.last
|
158
177
|
expect(make_me_sound_important.klass).to eq MakeMeSoundImportant
|
159
178
|
expect(make_me_sound_important.name).to eq :final_command
|
160
|
-
expect(make_me_sound_important.
|
179
|
+
expect(make_me_sound_important.single_mutator.is_a? Proc).to be true
|
161
180
|
end
|
162
181
|
end
|
163
182
|
end
|
@@ -177,6 +196,13 @@ describe Tzu::Sequence do
|
|
177
196
|
end
|
178
197
|
end
|
179
198
|
|
199
|
+
context MultiStepNonTzu do
|
200
|
+
it 'returns the outcome of the last command' do
|
201
|
+
outcome = MultiStepNonTzu.run('Greetings', 'Christopher', 'Canada')
|
202
|
+
expect(outcome.result).to eq 'Greetings, Christopher! You are the most important citizen of Canada!'
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
180
206
|
context MultiStepComplex do
|
181
207
|
it 'returns the outcome of the last command' do
|
182
208
|
outcome = MultiStepComplex.run(params)
|
data/spec/step_spec.rb
CHANGED
@@ -21,4 +21,36 @@ describe Tzu::Step do
|
|
21
21
|
end
|
22
22
|
end
|
23
23
|
end
|
24
|
+
|
25
|
+
context '#receives' do
|
26
|
+
context 'when splat_mutator is already defined' do
|
27
|
+
let(:step) { Tzu::Step.new(:step_name) }
|
28
|
+
|
29
|
+
before do
|
30
|
+
step.receives_many do |variable|
|
31
|
+
[1, 2, 3]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'throws error' do
|
36
|
+
expect { step.receives { |var| 'foo'} } .to raise_error(Tzu::InvalidSequence)
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
context '#receives_many' do
|
42
|
+
context 'when single_mutator is already defined' do
|
43
|
+
let(:step) { Tzu::Step.new(:step_name) }
|
44
|
+
|
45
|
+
before do
|
46
|
+
step.receives do |var|
|
47
|
+
'hello'
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'throws error' do
|
52
|
+
expect { step.receives_many { |var| [1, 2, 3] } } .to raise_error(Tzu::InvalidSequence)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
24
56
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tzu
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Morgan Bruce
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2015-07-
|
12
|
+
date: 2015-07-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -109,7 +109,7 @@ dependencies:
|
|
109
109
|
- - ">="
|
110
110
|
- !ruby/object:Gem::Version
|
111
111
|
version: '0'
|
112
|
-
description:
|
112
|
+
description: Tzu is a library for issuing commands in Ruby
|
113
113
|
email: morgan@onfido.com
|
114
114
|
executables: []
|
115
115
|
extensions: []
|
@@ -119,6 +119,7 @@ files:
|
|
119
119
|
- README.md
|
120
120
|
- lib/tzu.rb
|
121
121
|
- lib/tzu/core_extensions/string.rb
|
122
|
+
- lib/tzu/errors.rb
|
122
123
|
- lib/tzu/failure.rb
|
123
124
|
- lib/tzu/hooks.rb
|
124
125
|
- lib/tzu/invalid.rb
|
@@ -159,8 +160,7 @@ rubyforge_project:
|
|
159
160
|
rubygems_version: 2.2.2
|
160
161
|
signing_key:
|
161
162
|
specification_version: 4
|
162
|
-
summary:
|
163
|
-
query pollution in the view layer.
|
163
|
+
summary: Standardise and encapsulate your application's actions
|
164
164
|
test_files:
|
165
165
|
- spec/hooks_spec.rb
|
166
166
|
- spec/outcome_spec.rb
|