verbalize 1.4.1 → 2.0.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 +39 -57
- data/lib/verbalize/action.rb +12 -26
- data/lib/verbalize/build_dangerous_action_method.rb +2 -6
- data/lib/verbalize/build_initialize_method.rb +1 -1
- data/lib/verbalize/build_method_base.rb +54 -42
- data/lib/verbalize/build_safe_action_method.rb +2 -6
- data/lib/verbalize/error.rb +1 -1
- data/lib/verbalize/failure.rb +4 -4
- data/lib/verbalize/result.rb +1 -3
- data/lib/verbalize/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ca403601a9b7decbc85e77a20103926c8d92765a
|
4
|
+
data.tar.gz: ad015b2d9a8bfa2afa3e9524be0bc8dcfe4260d8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10d7fcf1fda2c00aa8b12d571858595222bc329d8714234ffc4d52a247e31c66fa183e5c0da9d52475a88ca76de7c407a9d6ced73c30aa9dbe2ba88b8a103d38
|
7
|
+
data.tar.gz: c0699fbe4b2c5da4e8f40f143058c552e90c2ffb421ebbc42946d138269c6b7f16d5167cb783885239e76d8ac4e2ba86fa22a2cad2ff01657690b9c4afb06ac2
|
data/README.md
CHANGED
@@ -179,8 +179,10 @@ end
|
|
179
179
|
### Sad Path
|
180
180
|
|
181
181
|
When testing negative cases of a `Verbalize::Action`, it is recommended to test using the `call` non-bang
|
182
|
-
class method
|
183
|
-
|
182
|
+
class method which will return a `Verbalize::Failure` on failure.
|
183
|
+
|
184
|
+
Use of `call!` here is not advised as it will result in an exception being thrown. Set assertions on both
|
185
|
+
the failure outcome and value:
|
184
186
|
|
185
187
|
```ruby
|
186
188
|
class MyAction
|
@@ -199,95 +201,75 @@ it 'fails when the input is out of bounds' do
|
|
199
201
|
result = MyAction.call(a: 1000)
|
200
202
|
|
201
203
|
expect(result).to be_failed
|
202
|
-
expect(result.
|
204
|
+
expect(result.failure).to eq '1000 is greater than 100!'
|
203
205
|
end
|
204
206
|
```
|
205
207
|
|
206
208
|
### Stubbing Responses
|
207
209
|
|
208
|
-
When unit testing, it may be necessary to stub responses of
|
209
|
-
|
210
|
+
When unit testing, it may be necessary to stub the responses of Verbalize actions. To correctly stub responses,
|
211
|
+
you should __always__ stub the `MyAction.perform` class method on the action class being stubbed per the
|
212
|
+
instructions below. __Never__ stub the `call` or `call!` methods directly.
|
213
|
+
|
214
|
+
Stubbing `.perform` will enable `Verbalize` to wrap results correctly for references to either `call` or `call!`.
|
210
215
|
|
211
|
-
#### Stubbing
|
216
|
+
#### Stubbing Successful Responses
|
212
217
|
|
213
|
-
|
214
|
-
`
|
218
|
+
To simulate a successful response of the `Verbalize::Action` being stubbed, you should stub the `MyAction.perform`
|
219
|
+
class method to return the __value__ you expect the `MyAction#call` instance method to return.
|
215
220
|
|
216
|
-
|
221
|
+
For example, if you expect the action to return the value `123` on success:
|
217
222
|
|
218
223
|
```ruby
|
219
224
|
class Foo
|
220
|
-
def
|
225
|
+
def self.multiply_by(multiple)
|
221
226
|
result = MyAction.call(a: 1)
|
222
|
-
raise
|
227
|
+
raise "I couldn't do the thing!" if result.failure?
|
223
228
|
|
224
|
-
|
229
|
+
result.value * multiple
|
225
230
|
end
|
226
231
|
end
|
227
232
|
|
228
233
|
# rspec:
|
229
234
|
describe Foo do
|
230
235
|
describe '#something' do
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
.with(a: 1)
|
237
|
-
.and_return(successful_result)
|
238
|
-
|
239
|
-
result = described_class.do_something
|
236
|
+
it 'does the thing when MyAction succeeds' do
|
237
|
+
# Simulate the successful result
|
238
|
+
allow(MyAction).to receive(:perform)
|
239
|
+
.with(a: 1)
|
240
|
+
.and_return(123)
|
240
241
|
|
241
|
-
|
242
|
-
end
|
243
|
-
|
244
|
-
it 'raises an error when MyAction fails' do
|
245
|
-
failed_result = Verbalize::Failure.new('Y U NO!')
|
246
|
-
allow(MyAction).to receive(:call)
|
247
|
-
.with(a: 3)
|
248
|
-
.and_return(failed_result)
|
242
|
+
result = described_class.multiply_by(100)
|
249
243
|
|
250
|
-
expect
|
251
|
-
described_class.do_something
|
252
|
-
}.to raise_error(StandardError, 'I couldnt do the thing!')
|
244
|
+
expect(result).to eq 12300
|
253
245
|
end
|
254
246
|
end
|
255
247
|
end
|
256
248
|
```
|
257
249
|
|
258
|
-
#### Stubbing
|
250
|
+
#### Stubbing Failure Responses
|
259
251
|
|
260
|
-
|
261
|
-
|
262
|
-
|
252
|
+
To simulate a __failure__ response of the `Verbalize::Action` being stubbed, you should stub the `MyAction.perform`
|
253
|
+
class method to __throw__ `::Verbalize::THROWN_SYMBOL` with the __message__ you expect `MyAction#call` to throw
|
254
|
+
when the simulated failure occurs.
|
263
255
|
|
264
|
-
|
256
|
+
For example, when you expect the outer class to raise an exception when MyAction fails:
|
265
257
|
|
266
258
|
```ruby
|
259
|
+
# See also: Foo class definition in Stubbing Successful Responses above
|
260
|
+
|
267
261
|
# rspec:
|
268
262
|
describe Foo do
|
269
|
-
describe '#
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
.and_return(123)
|
276
|
-
|
277
|
-
result = described_class.something
|
278
|
-
|
279
|
-
expect(result).to eq 'baz'
|
280
|
-
end
|
281
|
-
|
282
|
-
it 'returns an error when MyAction fails' do
|
283
|
-
failed_result = Verbalize::Failure.new('Y U NO!')
|
284
|
-
allow(MyAction).to receive(:call)
|
285
|
-
.with(a: 3)
|
286
|
-
.and_throw(::Verbalize::THROWN_SYMBOL, 'the failure message, if any')
|
263
|
+
describe '#multiply_by' do
|
264
|
+
it 'raises an error when MyAction fails' do
|
265
|
+
# Simulate the failure
|
266
|
+
allow(MyAction).to receive(:perform)
|
267
|
+
.with(a: 1)
|
268
|
+
.and_throw(::Verbalize::THROWN_SYMBOL, 'Y U NO!')
|
287
269
|
|
288
270
|
expect {
|
289
|
-
described_class.
|
290
|
-
}.to raise_error
|
271
|
+
described_class.multiply_by(100)
|
272
|
+
}.to raise_error "I couldn't do the thing!"
|
291
273
|
end
|
292
274
|
end
|
293
275
|
end
|
data/lib/verbalize/action.rb
CHANGED
@@ -19,20 +19,11 @@ module Verbalize
|
|
19
19
|
end
|
20
20
|
|
21
21
|
module ClassMethods
|
22
|
-
def verbalize(*arguments, **keyword_arguments)
|
23
|
-
method_name, *arguments = arguments
|
24
|
-
input(*arguments, method_name: method_name, **keyword_arguments)
|
25
|
-
end
|
26
|
-
|
27
22
|
def input( # rubocop:disable Metrics/MethodLength
|
28
23
|
*required_keywords,
|
29
|
-
optional:
|
30
|
-
method_name: :call,
|
24
|
+
optional: [],
|
31
25
|
**other_keyword_arguments
|
32
26
|
)
|
33
|
-
|
34
|
-
deprecate_custom_methods(method_name)
|
35
|
-
|
36
27
|
unless other_keyword_arguments.empty?
|
37
28
|
raise(
|
38
29
|
ArgumentError,
|
@@ -44,14 +35,12 @@ module Verbalize
|
|
44
35
|
|
45
36
|
class_eval BuildSafeActionMethod.call(
|
46
37
|
required_keywords: required_keywords,
|
47
|
-
optional_keywords: optional_keywords
|
48
|
-
method_name: method_name
|
38
|
+
optional_keywords: optional_keywords
|
49
39
|
)
|
50
40
|
|
51
41
|
class_eval BuildDangerousActionMethod.call(
|
52
42
|
required_keywords: required_keywords,
|
53
|
-
optional_keywords: optional_keywords
|
54
|
-
method_name: method_name
|
43
|
+
optional_keywords: optional_keywords
|
55
44
|
)
|
56
45
|
|
57
46
|
class_eval BuildInitializeMethod.call(
|
@@ -65,36 +54,33 @@ module Verbalize
|
|
65
54
|
end
|
66
55
|
|
67
56
|
def call
|
68
|
-
__verbalized_send
|
57
|
+
__verbalized_send
|
69
58
|
end
|
70
59
|
|
71
60
|
def call!
|
72
|
-
__verbalized_send!
|
61
|
+
__verbalized_send!
|
73
62
|
end
|
74
63
|
|
75
64
|
private
|
76
65
|
|
77
|
-
def
|
78
|
-
|
79
|
-
warn Kernel.caller[2] + ': use of custom method names for Actions is deprecated and support ' \
|
80
|
-
'for it will be dropped in Verbalize v2.0. The `verbalize` method will also be removed.' \
|
81
|
-
'Use `input` and define `#call` on your Action class instead.'
|
66
|
+
def perform(*args)
|
67
|
+
new(*args).send(:call)
|
82
68
|
end
|
83
69
|
|
84
|
-
def __verbalized_send(
|
70
|
+
def __verbalized_send(*args)
|
85
71
|
error = catch(:verbalize_error) do
|
86
|
-
value =
|
72
|
+
value = perform(*args)
|
87
73
|
return Success.new(value)
|
88
74
|
end
|
89
75
|
|
90
76
|
Failure.new(error)
|
91
77
|
end
|
92
78
|
|
93
|
-
def __verbalized_send!(
|
94
|
-
|
79
|
+
def __verbalized_send!(*args)
|
80
|
+
perform(*args)
|
95
81
|
rescue UncaughtThrowError => uncaught_throw_error
|
96
82
|
fail_value = uncaught_throw_error.value
|
97
|
-
error =
|
83
|
+
error = Verbalize::Error.new("Unhandled fail! called with: #{fail_value.inspect}.")
|
98
84
|
error.set_backtrace(uncaught_throw_error.backtrace[2..-1])
|
99
85
|
raise error
|
100
86
|
end
|
@@ -5,15 +5,11 @@ module Verbalize
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def declaration
|
8
|
-
|
8
|
+
declare('self.call!')
|
9
9
|
end
|
10
10
|
|
11
11
|
def body
|
12
|
-
|
13
|
-
" __verbalized_send!(:#{method_name})"
|
14
|
-
else
|
15
|
-
" __verbalized_send!(:#{method_name}, #{initialize_keywords_and_values})"
|
16
|
-
end
|
12
|
+
verbalized_send_string(bang: true)
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
@@ -1,56 +1,68 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
1
|
+
module Verbalize
|
2
|
+
class BuildMethodBase
|
3
|
+
def self.call(required_keywords: [], optional_keywords: [])
|
4
|
+
new(
|
5
|
+
required_keywords: required_keywords,
|
6
|
+
optional_keywords: optional_keywords
|
7
|
+
).call
|
8
|
+
end
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
10
|
+
def initialize(required_keywords: [], optional_keywords: [])
|
11
|
+
@required_keywords = required_keywords
|
12
|
+
@optional_keywords = optional_keywords
|
13
|
+
end
|
15
14
|
|
16
|
-
|
17
|
-
|
18
|
-
|
15
|
+
def call
|
16
|
+
parts.compact.join "\n"
|
17
|
+
end
|
19
18
|
|
20
|
-
|
19
|
+
private
|
21
20
|
|
22
|
-
|
21
|
+
attr_reader :required_keywords, :optional_keywords
|
23
22
|
|
24
|
-
|
25
|
-
|
26
|
-
|
23
|
+
def parts
|
24
|
+
[declaration, body, "end\n"]
|
25
|
+
end
|
27
26
|
|
28
|
-
|
29
|
-
|
30
|
-
|
27
|
+
def declaration
|
28
|
+
raise NotImplementedError
|
29
|
+
end
|
31
30
|
|
32
|
-
|
33
|
-
|
34
|
-
|
31
|
+
def body
|
32
|
+
raise NotImplementedError
|
33
|
+
end
|
35
34
|
|
36
|
-
|
37
|
-
|
38
|
-
|
35
|
+
def declare(method_name)
|
36
|
+
"def #{method_name}(#{declaration_keyword_arguments})"
|
37
|
+
end
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
39
|
+
def all_keywords
|
40
|
+
required_keywords + optional_keywords
|
41
|
+
end
|
43
42
|
|
44
|
-
|
45
|
-
|
46
|
-
|
43
|
+
def required_keyword_segments
|
44
|
+
required_keywords.map { |keyword| "#{keyword}:" }
|
45
|
+
end
|
47
46
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
47
|
+
def optional_keyword_segments
|
48
|
+
optional_keywords.map { |keyword| "#{keyword}: nil" }
|
49
|
+
end
|
50
|
+
|
51
|
+
def declaration_keyword_arguments
|
52
|
+
return if all_keywords.empty?
|
53
|
+
(required_keyword_segments + optional_keyword_segments).join(', ')
|
54
|
+
end
|
55
|
+
|
56
|
+
def initialize_keywords_and_values
|
57
|
+
all_keywords.map { |variable| "#{variable}: #{variable}" }.join(', ')
|
58
|
+
end
|
59
|
+
|
60
|
+
def verbalized_send_string(bang: false)
|
61
|
+
send_string = ' __verbalized_send'
|
62
|
+
send_string += '!' if bang
|
52
63
|
|
53
|
-
|
54
|
-
|
64
|
+
return send_string if all_keywords.empty?
|
65
|
+
send_string + "(#{initialize_keywords_and_values})"
|
66
|
+
end
|
55
67
|
end
|
56
68
|
end
|
@@ -5,15 +5,11 @@ module Verbalize
|
|
5
5
|
private
|
6
6
|
|
7
7
|
def declaration
|
8
|
-
|
8
|
+
declare('self.call')
|
9
9
|
end
|
10
10
|
|
11
11
|
def body
|
12
|
-
|
13
|
-
" __verbalized_send(:#{method_name})"
|
14
|
-
else
|
15
|
-
" __verbalized_send(:#{method_name}, #{initialize_keywords_and_values})"
|
16
|
-
end
|
12
|
+
verbalized_send_string(bang: false)
|
17
13
|
end
|
18
14
|
end
|
19
15
|
end
|
data/lib/verbalize/error.rb
CHANGED
data/lib/verbalize/failure.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'result'
|
2
|
+
require_relative 'error'
|
2
3
|
|
3
4
|
module Verbalize
|
4
5
|
class Failure < Result
|
@@ -13,10 +14,9 @@ module Verbalize
|
|
13
14
|
end
|
14
15
|
|
15
16
|
def value
|
16
|
-
|
17
|
-
'
|
18
|
-
'
|
19
|
-
@value
|
17
|
+
raise Verbalize::Error, 'You called #value on a Failure result. You should never use `Verbalize::Action#call` ' \
|
18
|
+
'without also explicitly handling potential errors. Please use `Verbalize::Action#call!` to return a value ' \
|
19
|
+
'directly on successful execution of an action, or handle the error case explicitly if using `#call`.'
|
20
20
|
end
|
21
21
|
end
|
22
22
|
end
|
data/lib/verbalize/result.rb
CHANGED
@@ -22,9 +22,7 @@ module Verbalize
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def value
|
25
|
-
|
26
|
-
'Use `Verbalize::Failure#error` or `Verbalize::Success#value` instead.'
|
27
|
-
@value
|
25
|
+
raise NotImplementedError, 'Subclasses must override Verbalize::Result#value'
|
28
26
|
end
|
29
27
|
end
|
30
28
|
end
|
data/lib/verbalize/version.rb
CHANGED