verbalize 1.4.1 → 2.0.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 +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