verbalize 2.0.1 → 2.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/dependabot.yml +8 -0
- data/.github/workflows/tests.yml +25 -0
- data/CHANGELOG.md +91 -0
- data/Dockerfile +45 -0
- data/README.md +109 -28
- data/bin/console +2 -6
- data/docker-compose.yml +12 -0
- data/lib/verbalize/action.rb +120 -23
- data/lib/verbalize/build.rb +23 -14
- data/lib/verbalize/version.rb +1 -1
- data/verbalize.gemspec +2 -2
- metadata +20 -18
- data/.travis.yml +0 -4
- data/circle.yml +0 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: b4ab48694dce4b9810ed7289498ee4ff0533919ed08041d5abfa4dda1a3800a7
|
4
|
+
data.tar.gz: e2a160824182fef4e702a65b27116505f492cf5f02022bfe928198bb822b2aae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a533db1a4cc25d45a4c5474a96671d3f172f1e84e7c6bf574f2d281caebbce7967d61f96106a9582cdb3915d4d24c6d4ae33b39577734723b65e0ea4ffcab8d0
|
7
|
+
data.tar.gz: 9068fc27d208da171b89f173eec3af2d78b3a3d90bdc589ec737cf97a978c9044b22a7cc4a8b57237149562169859f819bfce672a65a94978ecaa227a216d907
|
@@ -0,0 +1,25 @@
|
|
1
|
+
name: Tests
|
2
|
+
|
3
|
+
on:
|
4
|
+
push:
|
5
|
+
branches: [ master ]
|
6
|
+
pull_request:
|
7
|
+
branches: [ master ]
|
8
|
+
|
9
|
+
jobs:
|
10
|
+
test:
|
11
|
+
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
strategy:
|
14
|
+
matrix:
|
15
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
16
|
+
|
17
|
+
steps:
|
18
|
+
- uses: actions/checkout@v2
|
19
|
+
- name: Set up Ruby
|
20
|
+
uses: ruby/setup-ruby@v1
|
21
|
+
with:
|
22
|
+
ruby-version: ${{ matrix.ruby-version }}
|
23
|
+
bundler-cache: true
|
24
|
+
- name: Run tests
|
25
|
+
run: bundle exec rspec
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](http://keepachangelog.com/)
|
5
|
+
and this project adheres to [Semantic Versioning](http://semver.org/).
|
6
|
+
|
7
|
+
## 2.3.1 - 2021-06-02
|
8
|
+
### Added
|
9
|
+
- release documentation
|
10
|
+
- ruby 2.7 compatibility to remove deprecation warnings
|
11
|
+
|
12
|
+
## 2.3.0 - 2019-09-23
|
13
|
+
### Added
|
14
|
+
- you can now specify `validates :key { |value| ... }` on actions to run validation on the input
|
15
|
+
*before* running the `call` block.
|
16
|
+
|
17
|
+
## 2.2.0 - 2017-08-19
|
18
|
+
### Added
|
19
|
+
- changelog started
|
20
|
+
- You can now specify default values for optional inputs in the `input` call.
|
21
|
+
Use a regular value to load it once, at load-time, and a lambda to lazily load
|
22
|
+
the value each time the action is called.
|
23
|
+
### Changed
|
24
|
+
- privatize Action.input. Now that we have Action.inputs, we want to avoid calling Action.input (no s) outside of the action itself
|
25
|
+
|
26
|
+
## 2.1.1 - 2017-02-21
|
27
|
+
### Fixed
|
28
|
+
- ensure Verbalize::Action.optional_input always returns an array
|
29
|
+
|
30
|
+
## 2.1.0 - 2017-02-21
|
31
|
+
### Added
|
32
|
+
- introspect Action input using Action.inputs, Action.required_inputs, and Action.optional_inputs
|
33
|
+
|
34
|
+
## 2.0.2 - 2017-2-21 [YANKED]
|
35
|
+
- new functionality was added, so minor version should have been increased instead of patch
|
36
|
+
|
37
|
+
## 2.0.1 - 2016-12-16
|
38
|
+
### Changed
|
39
|
+
- internal refactoring
|
40
|
+
|
41
|
+
## 2.0.0 - 2016-02-14
|
42
|
+
### Added
|
43
|
+
- execution of action routed through Action#perform to better support stubbing
|
44
|
+
- 100% test coverage!!!
|
45
|
+
### Changed
|
46
|
+
- calling Failure#value now raises an error, use Failure#failure instead? Did this happen in 1.3?
|
47
|
+
### Removed
|
48
|
+
- removes action implementation methods other than #call/#call!
|
49
|
+
|
50
|
+
## 1.4.1 - 2016-12-14
|
51
|
+
### Added
|
52
|
+
- Failure#failure added to replace Failure#value
|
53
|
+
### Changed
|
54
|
+
- Result split into Success/Failure
|
55
|
+
### Deprecated
|
56
|
+
- stop including Verbalize itself, use Verbalize::Action instead
|
57
|
+
- stop using action implementation methods other than #call/#call!
|
58
|
+
- stop using Failure#value, used Failure#failure instead
|
59
|
+
|
60
|
+
## 1.4.0 [YANKED] - 2016-12-14
|
61
|
+
### Fixed
|
62
|
+
- error while uploading to ruby gems, yanked and released v1.4.1
|
63
|
+
|
64
|
+
## 1.3.0 - 2016-11-09
|
65
|
+
### Changed
|
66
|
+
- better failure handling
|
67
|
+
|
68
|
+
## 1.2.0 - 2016-11-07
|
69
|
+
### Added
|
70
|
+
- alias Result.success? to Result.succeeded?
|
71
|
+
- alias Result.failure? to Result.failed?
|
72
|
+
### Changed
|
73
|
+
- Action now implements #to_ary instead of subclassing Array
|
74
|
+
|
75
|
+
## 1.1.2 - 2016-11-07 [YANKED]
|
76
|
+
- new functionality was added, so minor version should have been increased instead of patch
|
77
|
+
|
78
|
+
## 1.1.1 - 2016-08-25
|
79
|
+
### Changed
|
80
|
+
- internal refactoring
|
81
|
+
|
82
|
+
## 1.0.1 - 2016-08-10
|
83
|
+
### Fixed
|
84
|
+
- Use send to call Action#call so that Action#call can be privatized
|
85
|
+
|
86
|
+
## 1.0.0 - 2016-08-09
|
87
|
+
### Added
|
88
|
+
- optional input
|
89
|
+
|
90
|
+
## 0.1.0 - 2016-08-07
|
91
|
+
- initial release
|
data/Dockerfile
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
ARG BUNDLER_VERSION=2.0.2
|
2
|
+
ARG RUBY_VERSION=2.7.1
|
3
|
+
ARG APP_ROOT=/gem
|
4
|
+
|
5
|
+
#######################################
|
6
|
+
### Builder
|
7
|
+
FROM ruby:${RUBY_VERSION}-alpine AS build-env
|
8
|
+
|
9
|
+
ARG APP_ROOT
|
10
|
+
|
11
|
+
ENV BUNDLE_APP_CONFIG="$APP_ROOT/.bundle"
|
12
|
+
ARG PACKAGES="curl tzdata less git"
|
13
|
+
RUN mkdir $APP_ROOT
|
14
|
+
WORKDIR $APP_ROOT
|
15
|
+
|
16
|
+
RUN apk update \
|
17
|
+
&& apk upgrade \
|
18
|
+
&& apk add --update --no-cache $PACKAGES
|
19
|
+
|
20
|
+
#######################################
|
21
|
+
### Development
|
22
|
+
FROM build-env AS development
|
23
|
+
|
24
|
+
ARG BUNDLER_VERSION
|
25
|
+
ARG APP_ROOT
|
26
|
+
ENV BUNDLE_APP_CONFIG="$APP_ROOT/.bundle"
|
27
|
+
|
28
|
+
WORKDIR $APP_ROOT
|
29
|
+
|
30
|
+
RUN apk add --update --no-cache \
|
31
|
+
build-base \
|
32
|
+
git \
|
33
|
+
tzdata \
|
34
|
+
less
|
35
|
+
|
36
|
+
RUN gem install bundler:$BUNDLER_VERSION
|
37
|
+
|
38
|
+
COPY . $APP_ROOT
|
39
|
+
|
40
|
+
RUN bundle install -j4 --retry 3 \
|
41
|
+
&& rm -rf /usr/local/bundle/cache/*.gem \
|
42
|
+
&& find /usr/local/bundle/gems/ -name "*.c" -delete \
|
43
|
+
&& find /usr/local/bundle/gems/ -name "*.o" -delete
|
44
|
+
|
45
|
+
|
data/README.md
CHANGED
@@ -53,6 +53,35 @@ Add.call # => [:ok, 42]
|
|
53
53
|
Add.call(a: 660, b: 6) # => [:ok, 666]
|
54
54
|
```
|
55
55
|
|
56
|
+
## Default Values
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
# You can define defaults via key/value pairs, as so:
|
60
|
+
class Add
|
61
|
+
include Verbalize::Action
|
62
|
+
# note that these values are evaluated at load-time as they are not wrapped
|
63
|
+
# in lambdas.
|
64
|
+
input optional: [a: 35, b: 7]
|
65
|
+
def call; a + b; end
|
66
|
+
end
|
67
|
+
|
68
|
+
# default values can be lazily loaded by passing in a lambda, e.g.:
|
69
|
+
|
70
|
+
class Tomorrow
|
71
|
+
include Verbalize::Action
|
72
|
+
input optional: [as_of: -> { Time.now }]
|
73
|
+
def call
|
74
|
+
as_of + 1
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
start_time = Tomorrow.call!
|
79
|
+
sleep(1)
|
80
|
+
end_time = Tomorrow.call!
|
81
|
+
end_time - start_time # ~1s; the default is executed each call.
|
82
|
+
```
|
83
|
+
|
84
|
+
|
56
85
|
```ruby
|
57
86
|
class Divide
|
58
87
|
include Verbalize::Action
|
@@ -69,6 +98,52 @@ result = Divide.call(a: 1, b: 0) # => [:error, 'You can’t divide by 0']
|
|
69
98
|
result.failed? # => true
|
70
99
|
```
|
71
100
|
|
101
|
+
### Reflection
|
102
|
+
```ruby
|
103
|
+
class Add
|
104
|
+
include Verbalize::Action
|
105
|
+
|
106
|
+
input :a, :b, optional: [:c, :d]
|
107
|
+
|
108
|
+
def call
|
109
|
+
a + b + c + d
|
110
|
+
end
|
111
|
+
|
112
|
+
private
|
113
|
+
|
114
|
+
def c
|
115
|
+
@c ||= 0
|
116
|
+
end
|
117
|
+
|
118
|
+
def d
|
119
|
+
@d ||= 0
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
Add.required_inputs # [:a, :b]
|
124
|
+
Add.optional_inputs # [:c, :d]
|
125
|
+
Add.inputs # [:a, :b, :c, :d]
|
126
|
+
```
|
127
|
+
|
128
|
+
## Validation
|
129
|
+
```ruby
|
130
|
+
class FloatAdd
|
131
|
+
include Verbalize::Action
|
132
|
+
|
133
|
+
input :a, :b
|
134
|
+
validate(:a) { |a| a.is_a?(Float) }
|
135
|
+
validate(:b) { |b| b.is_a?(Float) && b > 10.0 }
|
136
|
+
|
137
|
+
def call
|
138
|
+
a + b
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
FloatAdd.call!(a: 1, b: 1) # fails with Input "a" failed validation!
|
143
|
+
FloatAdd.call!(a: 1.0, b: 1.0) # fails with Input "b" failed validation!
|
144
|
+
FloatAdd.call!(a: 1.0, b: 12.0) # 13.0
|
145
|
+
```
|
146
|
+
|
72
147
|
## Comparison/Benchmark
|
73
148
|
```ruby
|
74
149
|
require 'verbalize'
|
@@ -132,21 +207,21 @@ end
|
|
132
207
|
|
133
208
|
```
|
134
209
|
Warming up --------------------------------------
|
135
|
-
Ruby
|
136
|
-
Verbalize
|
137
|
-
Actionizer
|
138
|
-
Interactor 4.
|
210
|
+
Ruby 63.091k i/100ms
|
211
|
+
Verbalize 40.521k i/100ms
|
212
|
+
Actionizer 5.226k i/100ms
|
213
|
+
Interactor 4.874k i/100ms
|
139
214
|
Calculating -------------------------------------
|
140
|
-
Ruby
|
141
|
-
Verbalize
|
142
|
-
Actionizer
|
143
|
-
Interactor
|
215
|
+
Ruby 751.604k (± 3.0%) i/s - 3.785M in 5.041472s
|
216
|
+
Verbalize 457.598k (± 6.1%) i/s - 2.310M in 5.072488s
|
217
|
+
Actionizer 54.874k (± 3.5%) i/s - 276.978k in 5.054541s
|
218
|
+
Interactor 52.294k (± 3.2%) i/s - 263.196k in 5.038365s
|
144
219
|
|
145
220
|
Comparison:
|
146
|
-
Ruby:
|
147
|
-
Verbalize:
|
148
|
-
Actionizer:
|
149
|
-
Interactor:
|
221
|
+
Ruby: 751604.0 i/s
|
222
|
+
Verbalize: 457597.9 i/s - 1.64x slower
|
223
|
+
Actionizer: 54873.6 i/s - 13.70x slower
|
224
|
+
Interactor: 52293.6 i/s - 14.37x slower
|
150
225
|
|
151
226
|
```
|
152
227
|
|
@@ -155,15 +230,15 @@ Comparison:
|
|
155
230
|
### Happy Path
|
156
231
|
|
157
232
|
When testing positive cases of a `Verbalize::Action`, it is recommended to test using the `call!` class method and
|
158
|
-
assert on the result. This implicitly ensures a successful result, and your tests will fail with a bang! if
|
233
|
+
assert on the result. This implicitly ensures a successful result, and your tests will fail with a bang! if
|
159
234
|
something goes wrong:
|
160
235
|
|
161
236
|
```ruby
|
162
237
|
class MyAction
|
163
238
|
include Verbalize::Action
|
164
|
-
|
239
|
+
|
165
240
|
input :a
|
166
|
-
|
241
|
+
|
167
242
|
def call
|
168
243
|
fail!('#{a} is greater than than 100!') if a >= 100
|
169
244
|
a + 1
|
@@ -178,28 +253,28 @@ end
|
|
178
253
|
|
179
254
|
### Sad Path
|
180
255
|
|
181
|
-
When testing negative cases of a `Verbalize::Action`, it is recommended to test using the `call` non-bang
|
256
|
+
When testing negative cases of a `Verbalize::Action`, it is recommended to test using the `call` non-bang
|
182
257
|
class method which will return a `Verbalize::Failure` on failure.
|
183
258
|
|
184
|
-
Use of `call!` here is not advised as it will result in an exception being thrown. Set assertions on both
|
259
|
+
Use of `call!` here is not advised as it will result in an exception being thrown. Set assertions on both
|
185
260
|
the failure outcome and value:
|
186
261
|
|
187
262
|
```ruby
|
188
263
|
class MyAction
|
189
264
|
include Verbalize::Action
|
190
|
-
|
265
|
+
|
191
266
|
input :a
|
192
|
-
|
267
|
+
|
193
268
|
def call
|
194
269
|
fail!('#{a} is greater than 100!') if a >= 100
|
195
270
|
a + 1
|
196
271
|
end
|
197
272
|
end
|
198
|
-
|
273
|
+
|
199
274
|
# rspec:
|
200
275
|
it 'fails when the input is out of bounds' do
|
201
276
|
result = MyAction.call(a: 1000)
|
202
|
-
|
277
|
+
|
203
278
|
expect(result).to be_failed
|
204
279
|
expect(result.failure).to eq '1000 is greater than 100!'
|
205
280
|
end
|
@@ -208,11 +283,11 @@ end
|
|
208
283
|
### Stubbing Responses
|
209
284
|
|
210
285
|
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
|
286
|
+
you should __always__ stub the `MyAction.perform` class method on the action class being stubbed per the
|
212
287
|
instructions below. __Never__ stub the `call` or `call!` methods directly.
|
213
288
|
|
214
289
|
Stubbing `.perform` will enable `Verbalize` to wrap results correctly for references to either `call` or `call!`.
|
215
|
-
|
290
|
+
|
216
291
|
#### Stubbing Successful Responses
|
217
292
|
|
218
293
|
To simulate a successful response of the `Verbalize::Action` being stubbed, you should stub the `MyAction.perform`
|
@@ -225,7 +300,7 @@ class Foo
|
|
225
300
|
def self.multiply_by(multiple)
|
226
301
|
result = MyAction.call(a: 1)
|
227
302
|
raise "I couldn't do the thing!" if result.failure?
|
228
|
-
|
303
|
+
|
229
304
|
result.value * multiple
|
230
305
|
end
|
231
306
|
end
|
@@ -238,9 +313,9 @@ describe Foo do
|
|
238
313
|
allow(MyAction).to receive(:perform)
|
239
314
|
.with(a: 1)
|
240
315
|
.and_return(123)
|
241
|
-
|
316
|
+
|
242
317
|
result = described_class.multiply_by(100)
|
243
|
-
|
318
|
+
|
244
319
|
expect(result).to eq 12300
|
245
320
|
end
|
246
321
|
end
|
@@ -266,7 +341,7 @@ describe Foo do
|
|
266
341
|
allow(MyAction).to receive(:perform)
|
267
342
|
.with(a: 1)
|
268
343
|
.and_throw(::Verbalize::THROWN_SYMBOL, 'Y U NO!')
|
269
|
-
|
344
|
+
|
270
345
|
expect {
|
271
346
|
described_class.multiply_by(100)
|
272
347
|
}.to raise_error "I couldn't do the thing!"
|
@@ -297,6 +372,13 @@ After checking out the repo, run `bin/setup` to install dependencies. Then, run
|
|
297
372
|
|
298
373
|
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
299
374
|
|
375
|
+
## Releasing
|
376
|
+
|
377
|
+
- Update CHANGELOG.md, and lib/verbalize/version.rb, commit, and push
|
378
|
+
- [Create a new release on github](https://github.com/taylorzr/verbalize/releases/new)
|
379
|
+
- Build the gem version: `gem build verbalize.gemspec`
|
380
|
+
- Push the gem version to rubygems: `gem push verbalize-<VERSION>.gem`
|
381
|
+
|
300
382
|
## Contributing
|
301
383
|
|
302
384
|
Bug reports and pull requests are welcome on GitHub at https://github.com/taylorzr/verbalize.
|
@@ -305,4 +387,3 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/taylor
|
|
305
387
|
## License
|
306
388
|
|
307
389
|
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
308
|
-
|
data/bin/console
CHANGED
@@ -6,9 +6,5 @@ require 'verbalize'
|
|
6
6
|
# You can add fixtures and/or initialization code here to make experimenting
|
7
7
|
# with your gem easier. You can also use a different console, if you like.
|
8
8
|
|
9
|
-
|
10
|
-
|
11
|
-
# Pry.start
|
12
|
-
|
13
|
-
require 'irb'
|
14
|
-
IRB.start
|
9
|
+
require 'pry'
|
10
|
+
Pry.start
|
data/docker-compose.yml
ADDED
data/lib/verbalize/action.rb
CHANGED
@@ -11,13 +11,64 @@ module Verbalize
|
|
11
11
|
throw(THROWN_SYMBOL, failure_value)
|
12
12
|
end
|
13
13
|
|
14
|
+
def action_inputs
|
15
|
+
self.class.inputs.map { |i| [i, self.send(i)] }.to_h
|
16
|
+
end
|
17
|
+
|
14
18
|
def self.included(target)
|
15
19
|
target.extend ClassMethods
|
16
20
|
end
|
17
21
|
|
22
|
+
private
|
23
|
+
|
24
|
+
def __setup(key, value)
|
25
|
+
is_valid = self.class.input_is_valid?(key, value)
|
26
|
+
local_error = self.class.pop_local_error
|
27
|
+
fail!(local_error) if !is_valid && local_error
|
28
|
+
fail! "Input '#{key}' failed validation!" unless is_valid
|
29
|
+
|
30
|
+
instance_variable_set(:"@#{key}", value)
|
31
|
+
end
|
32
|
+
|
18
33
|
module ClassMethods
|
19
|
-
def
|
20
|
-
|
34
|
+
def required_inputs
|
35
|
+
@required_inputs || []
|
36
|
+
end
|
37
|
+
|
38
|
+
def optional_inputs
|
39
|
+
@optional_inputs || []
|
40
|
+
end
|
41
|
+
|
42
|
+
def default_inputs
|
43
|
+
(@defaults || {}).keys
|
44
|
+
end
|
45
|
+
|
46
|
+
def inputs
|
47
|
+
required_inputs + optional_inputs + default_inputs
|
48
|
+
end
|
49
|
+
|
50
|
+
def defaults
|
51
|
+
@defaults
|
52
|
+
end
|
53
|
+
|
54
|
+
def input_validations
|
55
|
+
@input_validations ||= {}
|
56
|
+
end
|
57
|
+
|
58
|
+
def input_is_valid?(input, value)
|
59
|
+
return true unless input_validations.include?(input.to_sym)
|
60
|
+
|
61
|
+
input_validations[input].call(value) == true
|
62
|
+
rescue => e
|
63
|
+
@local_error = e
|
64
|
+
false
|
65
|
+
end
|
66
|
+
|
67
|
+
def pop_local_error
|
68
|
+
return nil unless @local_error
|
69
|
+
@local_error
|
70
|
+
ensure
|
71
|
+
@local_error = nil
|
21
72
|
end
|
22
73
|
|
23
74
|
# Because call/call! are defined when Action.input is called, they would
|
@@ -30,35 +81,81 @@ module Verbalize
|
|
30
81
|
def call!
|
31
82
|
__proxied_call!
|
32
83
|
end
|
84
|
+
alias_method :!, :call!
|
33
85
|
|
34
86
|
private
|
35
87
|
|
36
|
-
def
|
37
|
-
|
88
|
+
def input(*required_keywords, optional: [])
|
89
|
+
@required_inputs = required_keywords
|
90
|
+
optional = Array(optional)
|
91
|
+
@optional_inputs = optional.reject { |kw| kw.is_a?(Hash) }
|
92
|
+
assign_defaults(optional)
|
93
|
+
|
94
|
+
class_eval Build.call(required_inputs, optional_inputs, default_inputs)
|
38
95
|
end
|
39
96
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
# 2. Because #1, meta-programming a simple interface to these proxied
|
45
|
-
# methods is much simpler than meta-programming the full methods
|
46
|
-
def __proxied_call(*args)
|
47
|
-
error = catch(:verbalize_error) do
|
48
|
-
value = perform(*args)
|
49
|
-
return Success.new(value)
|
50
|
-
end
|
97
|
+
def validate(keyword, &block)
|
98
|
+
raise Verbalize::Error, 'Missing block to validate against!' unless block_given?
|
99
|
+
input_validations[keyword.to_sym] = block
|
100
|
+
end
|
51
101
|
|
52
|
-
|
102
|
+
def assign_defaults(optional)
|
103
|
+
@defaults = optional.select { |kw| kw.is_a?(Hash) }.reduce(&:merge)
|
104
|
+
@defaults = (@defaults || {})
|
105
|
+
.map { |k, v| [k, v.respond_to?(:call) ? v : -> { v }] }
|
106
|
+
.to_h
|
53
107
|
end
|
54
108
|
|
55
|
-
|
56
|
-
perform(*args)
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
109
|
+
if RUBY_VERSION < "2.7"
|
110
|
+
def perform(*args)
|
111
|
+
new(*args).send(:call)
|
112
|
+
end
|
113
|
+
|
114
|
+
def __proxied_call(*args)
|
115
|
+
error = catch(:verbalize_error) do
|
116
|
+
value = perform(*args)
|
117
|
+
return Success.new(value)
|
118
|
+
end
|
119
|
+
|
120
|
+
Failure.new(error)
|
121
|
+
end
|
122
|
+
|
123
|
+
def __proxied_call!(*args)
|
124
|
+
perform(*args)
|
125
|
+
rescue UncaughtThrowError => uncaught_throw_error
|
126
|
+
fail_value = uncaught_throw_error.value
|
127
|
+
error = Verbalize::Error.new("Unhandled fail! called with: #{fail_value.inspect}.")
|
128
|
+
error.set_backtrace(uncaught_throw_error.backtrace[2..-1])
|
129
|
+
raise error
|
130
|
+
end
|
131
|
+
else
|
132
|
+
def perform(**args)
|
133
|
+
new(**args).send(:call)
|
134
|
+
end
|
135
|
+
|
136
|
+
# We used __proxied_call/__proxied_call! for 2 reasons:
|
137
|
+
# 1. The declaration of call/call! needs to be explicit so that tools
|
138
|
+
# like rspec-mocks can verify the actions keywords actually
|
139
|
+
# exist when stubbing
|
140
|
+
# 2. Because #1, meta-programming a simple interface to these proxied
|
141
|
+
# methods is much simpler than meta-programming the full methods
|
142
|
+
def __proxied_call(**args)
|
143
|
+
error = catch(:verbalize_error) do
|
144
|
+
value = perform(**args)
|
145
|
+
return Success.new(value)
|
146
|
+
end
|
147
|
+
|
148
|
+
Failure.new(error)
|
149
|
+
end
|
150
|
+
|
151
|
+
def __proxied_call!(**args)
|
152
|
+
perform(**args)
|
153
|
+
rescue UncaughtThrowError => uncaught_throw_error
|
154
|
+
fail_value = uncaught_throw_error.value
|
155
|
+
error = Verbalize::Error.new("Unhandled fail! called with: #{fail_value.inspect}.")
|
156
|
+
error.set_backtrace(uncaught_throw_error.backtrace[2..-1])
|
157
|
+
raise error
|
158
|
+
end
|
62
159
|
end
|
63
160
|
end
|
64
161
|
end
|
data/lib/verbalize/build.rb
CHANGED
@@ -1,22 +1,28 @@
|
|
1
1
|
module Verbalize
|
2
2
|
class Build
|
3
|
-
def self.call(required_keywords = [], optional_keywords = [])
|
4
|
-
new(required_keywords, optional_keywords).call
|
3
|
+
def self.call(required_keywords = [], optional_keywords = [], default_keywords = [])
|
4
|
+
new(required_keywords, optional_keywords, default_keywords).call
|
5
5
|
end
|
6
6
|
|
7
|
-
def initialize(required_keywords, optional_keywords)
|
7
|
+
def initialize(required_keywords, optional_keywords, default_keywords)
|
8
8
|
@required_keywords = required_keywords
|
9
9
|
@optional_keywords = optional_keywords
|
10
|
+
@default_keywords = default_keywords
|
10
11
|
end
|
11
12
|
|
12
13
|
def call
|
14
|
+
# We have to re-alias `!` to `call!` here, otherwise it will be pointing
|
15
|
+
# to the original `call!` method
|
13
16
|
<<-CODE
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
+
class << self
|
18
|
+
def call(#{declaration_arguments_string})
|
19
|
+
__proxied_call(#{forwarding_arguments_string})
|
20
|
+
end
|
17
21
|
|
18
|
-
def
|
19
|
-
|
22
|
+
def call!(#{declaration_arguments_string})
|
23
|
+
__proxied_call!(#{forwarding_arguments_string})
|
24
|
+
end
|
25
|
+
alias_method :!, :call!
|
20
26
|
end
|
21
27
|
|
22
28
|
def initialize(#{declaration_arguments_string})
|
@@ -29,18 +35,19 @@ attr_reader #{attribute_readers_string}
|
|
29
35
|
CODE
|
30
36
|
end
|
31
37
|
|
32
|
-
attr_reader :required_keywords, :optional_keywords
|
38
|
+
attr_reader :required_keywords, :optional_keywords, :default_keywords
|
33
39
|
|
34
40
|
private
|
35
41
|
|
36
42
|
def all_keywords
|
37
|
-
required_keywords + optional_keywords
|
43
|
+
required_keywords + optional_keywords + default_keywords
|
38
44
|
end
|
39
45
|
|
40
46
|
def declaration_arguments_string
|
41
|
-
required_segments
|
42
|
-
optional_segments
|
43
|
-
|
47
|
+
required_segments = required_keywords.map { |kw| "#{kw}:" }
|
48
|
+
optional_segments = optional_keywords.map { |kw| "#{kw}: nil" }
|
49
|
+
default_segments = default_keywords.map { |kw| "#{kw}: self.defaults[:#{kw}].call" }
|
50
|
+
(required_segments + optional_segments + default_segments).join(', ')
|
44
51
|
end
|
45
52
|
|
46
53
|
def forwarding_arguments_string
|
@@ -48,7 +55,9 @@ attr_reader #{attribute_readers_string}
|
|
48
55
|
end
|
49
56
|
|
50
57
|
def initialize_body
|
51
|
-
all_keywords.map
|
58
|
+
all_keywords.map do |keyword|
|
59
|
+
"__setup(:#{keyword}, #{keyword})"
|
60
|
+
end.join("\n ")
|
52
61
|
end
|
53
62
|
|
54
63
|
def attribute_readers_string
|
data/lib/verbalize/version.rb
CHANGED
data/verbalize.gemspec
CHANGED
@@ -21,9 +21,9 @@ Gem::Specification.new do |spec|
|
|
21
21
|
spec.require_paths = ['lib']
|
22
22
|
|
23
23
|
spec.add_development_dependency 'bundler'
|
24
|
-
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rake'
|
25
25
|
spec.add_development_dependency 'rspec'
|
26
26
|
spec.add_development_dependency 'coveralls'
|
27
|
-
spec.add_development_dependency 'rubocop'
|
27
|
+
spec.add_development_dependency 'rubocop'
|
28
28
|
spec.add_development_dependency 'pry'
|
29
29
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: verbalize
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 2.
|
4
|
+
version: 2.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Taylor
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-06-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -28,16 +28,16 @@ dependencies:
|
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- - "
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
33
|
+
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - "
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '
|
40
|
+
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -70,16 +70,16 @@ dependencies:
|
|
70
70
|
name: rubocop
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- -
|
73
|
+
- - ">="
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '0
|
75
|
+
version: '0'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- -
|
80
|
+
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '0
|
82
|
+
version: '0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: pry
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -94,7 +94,7 @@ dependencies:
|
|
94
94
|
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
|
-
description:
|
97
|
+
description:
|
98
98
|
email:
|
99
99
|
- taylorzr@gmail.com
|
100
100
|
executables: []
|
@@ -102,17 +102,20 @@ extensions: []
|
|
102
102
|
extra_rdoc_files: []
|
103
103
|
files:
|
104
104
|
- ".codeclimate.yml"
|
105
|
+
- ".github/dependabot.yml"
|
106
|
+
- ".github/workflows/tests.yml"
|
105
107
|
- ".gitignore"
|
106
108
|
- ".rspec"
|
107
109
|
- ".rubocop.yml"
|
108
|
-
-
|
110
|
+
- CHANGELOG.md
|
111
|
+
- Dockerfile
|
109
112
|
- Gemfile
|
110
113
|
- LICENSE.txt
|
111
114
|
- README.md
|
112
115
|
- Rakefile
|
113
116
|
- bin/console
|
114
117
|
- bin/setup
|
115
|
-
-
|
118
|
+
- docker-compose.yml
|
116
119
|
- lib/verbalize.rb
|
117
120
|
- lib/verbalize/action.rb
|
118
121
|
- lib/verbalize/build.rb
|
@@ -126,7 +129,7 @@ homepage: https://github.com/taylorzr/verbalize
|
|
126
129
|
licenses:
|
127
130
|
- MIT
|
128
131
|
metadata: {}
|
129
|
-
post_install_message:
|
132
|
+
post_install_message:
|
130
133
|
rdoc_options: []
|
131
134
|
require_paths:
|
132
135
|
- lib
|
@@ -141,9 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
141
144
|
- !ruby/object:Gem::Version
|
142
145
|
version: '0'
|
143
146
|
requirements: []
|
144
|
-
|
145
|
-
|
146
|
-
signing_key:
|
147
|
+
rubygems_version: 3.0.3
|
148
|
+
signing_key:
|
147
149
|
specification_version: 4
|
148
150
|
summary: Verb based class pattern
|
149
151
|
test_files: []
|
data/.travis.yml
DELETED
data/circle.yml
DELETED