service_actor 3.1.3 → 3.2.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 +90 -64
- data/lib/service_actor/base.rb +13 -13
- data/lib/service_actor/collectionable.rb +1 -1
- data/lib/service_actor/conditionable.rb +1 -1
- data/lib/service_actor/core.rb +6 -6
- data/lib/service_actor/nil_checkable.rb +3 -3
- data/lib/service_actor/playable.rb +19 -10
- data/lib/service_actor/result.rb +24 -1
- data/lib/service_actor/type_checkable.rb +3 -3
- data/lib/service_actor/version.rb +1 -1
- data/lib/service_actor.rb +1 -1
- metadata +11 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8bde0ceb526951927f7349b5bd80dc2d6ca036e40e7dbc3ca98bc027f47fbd4c
|
4
|
+
data.tar.gz: cd90e8762fe61eccd643fcdb318ebb27b79a561dbc8075ae4e2c802734ace9f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2cddbccf7794088dc4a25b011cdb1155d0b6e855abd4a83630402ec90d4fe2f6c4c7fa4a0935ddca7faee58e49b2ff3d1f9f99b430c76dcc2990452d06d16ded
|
7
|
+
data.tar.gz: 81444f049effd685780bd4904c3513c7d7adf220c2ecf4ca6a3bf18e077d1b207786f6b85eeb02597e23700bf2a661c3a83f2c4602333bf85c6adf7e810652ef
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# ServiceActor
|
2
2
|
|
3
3
|

|
4
4
|
|
@@ -21,31 +21,37 @@ and controllers thin.
|
|
21
21
|
- [Fail](#fail)
|
22
22
|
- [Play actors in a sequence](#play-actors-in-a-sequence)
|
23
23
|
- [Rollback](#rollback)
|
24
|
-
- [
|
24
|
+
- [Inline actors](#inline-actors)
|
25
25
|
- [Play conditions](#play-conditions)
|
26
26
|
- [Testing](#testing)
|
27
27
|
- [Build your own actor](#build-your-own-actor)
|
28
28
|
- [Influences](#influences)
|
29
29
|
- [Thanks](#thanks)
|
30
|
-
- [Development](#development)
|
31
30
|
- [Contributing](#contributing)
|
32
31
|
- [License](#contributing)
|
33
32
|
|
34
33
|
## Installation
|
35
34
|
|
36
|
-
Add
|
35
|
+
Add the gem to your application’s Gemfile by executing:
|
37
36
|
|
38
|
-
```
|
39
|
-
|
40
|
-
gem 'service_actor'
|
37
|
+
```sh
|
38
|
+
bundle add service_actor
|
41
39
|
```
|
42
40
|
|
43
|
-
|
41
|
+
### Extensions
|
42
|
+
|
43
|
+
For **Rails generators**, you can use the
|
44
44
|
[service_actor-rails](https://github.com/sunny/actor-rails) gem:
|
45
45
|
|
46
|
-
```
|
47
|
-
|
48
|
-
|
46
|
+
```sh
|
47
|
+
bundle add service_actor-rails
|
48
|
+
```
|
49
|
+
|
50
|
+
For **TTY prompts**, you can use the
|
51
|
+
[service_actor-promptable](https://github.com/pboling/service_actor-promptable) gem:
|
52
|
+
|
53
|
+
```sh
|
54
|
+
bundle add service_actor-promptable
|
49
55
|
```
|
50
56
|
|
51
57
|
## Usage
|
@@ -69,9 +75,10 @@ Trigger them in your application with `.call`:
|
|
69
75
|
SendNotification.call # => <ServiceActor::Result…>
|
70
76
|
```
|
71
77
|
|
72
|
-
When called,
|
73
|
-
actors to accept and return multiple arguments. Let
|
74
|
-
and then we
|
78
|
+
When called, an actor returns a result. Reading and writing to this result allows
|
79
|
+
actors to accept and return multiple arguments. Let’s find out how to do that
|
80
|
+
and then we’ll see how to
|
81
|
+
[chain multiple actors togethor](#play-actors-in-a-sequence).
|
75
82
|
|
76
83
|
### Inputs
|
77
84
|
|
@@ -111,8 +118,19 @@ end
|
|
111
118
|
The result you get from calling an actor will include the outputs you set:
|
112
119
|
|
113
120
|
```rb
|
114
|
-
|
115
|
-
|
121
|
+
actor = BuildGreeting.call
|
122
|
+
actor.greeting # => "Have a wonderful day!"
|
123
|
+
```
|
124
|
+
|
125
|
+
For every output there is also a boolean method ending with `?` to test its
|
126
|
+
presence:
|
127
|
+
|
128
|
+
```rb
|
129
|
+
if actor.greeting?
|
130
|
+
puts "Greetings is truthy"
|
131
|
+
else
|
132
|
+
puts "Greetings is falsey"
|
133
|
+
end
|
116
134
|
```
|
117
135
|
|
118
136
|
### Defaults
|
@@ -136,14 +154,14 @@ end
|
|
136
154
|
This lets you call the actor without specifying those keys:
|
137
155
|
|
138
156
|
```rb
|
139
|
-
|
140
|
-
|
157
|
+
actor = BuildGreeting.call(name: "Jim")
|
158
|
+
actor.greeting # => "Have a wonderful week Jim!"
|
141
159
|
```
|
142
160
|
|
143
161
|
If an input does not have a default, it will raise a error:
|
144
162
|
|
145
163
|
```rb
|
146
|
-
|
164
|
+
BuildGreeting.call
|
147
165
|
=> ServiceActor::ArgumentError: Input name on BuildGreeting is missing.
|
148
166
|
```
|
149
167
|
|
@@ -168,7 +186,7 @@ You can also add custom conditions with the name of your choice by using `must`:
|
|
168
186
|
class UpdateAdminUser < Actor
|
169
187
|
input :user,
|
170
188
|
must: {
|
171
|
-
be_an_admin: ->
|
189
|
+
be_an_admin: -> user { user.admin? }
|
172
190
|
}
|
173
191
|
|
174
192
|
# …
|
@@ -207,7 +225,7 @@ class UpdateUser < Actor
|
|
207
225
|
end
|
208
226
|
```
|
209
227
|
|
210
|
-
You may also use strings instead of constants, such as `type:
|
228
|
+
You may also use strings instead of constants, such as `type: "User"`.
|
211
229
|
|
212
230
|
When using a type condition, `allow_nil` defaults to `false`.
|
213
231
|
|
@@ -242,11 +260,11 @@ For example in a Rails controller:
|
|
242
260
|
# app/controllers/users_controller.rb
|
243
261
|
class UsersController < ApplicationController
|
244
262
|
def create
|
245
|
-
|
246
|
-
if
|
247
|
-
redirect_to
|
263
|
+
actor = UpdateUser.result(user: user, attributes: user_attributes)
|
264
|
+
if actor.success?
|
265
|
+
redirect_to actor.user
|
248
266
|
else
|
249
|
-
render :new, notice:
|
267
|
+
render :new, notice: actor.error
|
250
268
|
end
|
251
269
|
end
|
252
270
|
end
|
@@ -263,7 +281,7 @@ actor can use `play` to call other actors:
|
|
263
281
|
```rb
|
264
282
|
class PlaceOrder < Actor
|
265
283
|
play CreateOrder,
|
266
|
-
|
284
|
+
PayOrder,
|
267
285
|
SendOrderConfirmation,
|
268
286
|
NotifyAdmins
|
269
287
|
end
|
@@ -299,26 +317,51 @@ Rollback is only called on the _previous_ actors in `play` and is not called on
|
|
299
317
|
the failing actor itself. Actors should be kept to a single purpose and not have
|
300
318
|
anything to clean up if they call `fail!`.
|
301
319
|
|
302
|
-
###
|
320
|
+
### Inline actors
|
303
321
|
|
304
|
-
|
305
|
-
the shared result
|
322
|
+
For small work or preparing the result set for the next actors, you can create
|
323
|
+
inline actors by using lambdas. Each lambda has access to the shared result. For
|
324
|
+
example:
|
306
325
|
|
307
326
|
```rb
|
308
|
-
class
|
309
|
-
|
327
|
+
class PayOrder < Actor
|
328
|
+
input :order
|
329
|
+
|
330
|
+
play -> actor { actor.order.currency ||= "EUR" },
|
310
331
|
CreatePayment,
|
311
|
-
|
312
|
-
|
332
|
+
UpdateOrderBalance,
|
333
|
+
-> actor { Logger.info("Order #{actor.order.id} paid") }
|
313
334
|
end
|
314
335
|
```
|
315
336
|
|
316
|
-
|
317
|
-
result for the next actors. If you want to do more work before, after or around
|
318
|
-
the whole `play`, you can also override the `call` method. For example:
|
337
|
+
You can also call instance methods. For example:
|
319
338
|
|
320
339
|
```rb
|
321
|
-
class
|
340
|
+
class PayOrder < Actor
|
341
|
+
input :order
|
342
|
+
|
343
|
+
play :assign_default_currency,
|
344
|
+
CreatePayment,
|
345
|
+
UpdateOrderBalance,
|
346
|
+
:log_payment
|
347
|
+
|
348
|
+
private
|
349
|
+
|
350
|
+
def assign_default_currency
|
351
|
+
order.currency ||= "EUR"
|
352
|
+
end
|
353
|
+
|
354
|
+
def log_payment
|
355
|
+
Logger.info("Order #{order.id} paid")
|
356
|
+
end
|
357
|
+
end
|
358
|
+
```
|
359
|
+
|
360
|
+
If you want to do work around the whole actor, you can also override the `call`
|
361
|
+
method. For example:
|
362
|
+
|
363
|
+
```rb
|
364
|
+
class PayOrder < Actor
|
322
365
|
# …
|
323
366
|
|
324
367
|
def call
|
@@ -337,12 +380,10 @@ Actors in a play can be called conditionally:
|
|
337
380
|
class PlaceOrder < Actor
|
338
381
|
play CreateOrder,
|
339
382
|
Pay
|
340
|
-
play NotifyAdmins, if: ->
|
383
|
+
play NotifyAdmins, if: -> actor { actor.order.amount > 42 }
|
341
384
|
end
|
342
385
|
```
|
343
386
|
|
344
|
-
You can use this to trigger an early success.
|
345
|
-
|
346
387
|
### Fail on argument error
|
347
388
|
|
348
389
|
By default, errors on inputs will raise an error, even when using `.result`
|
@@ -392,7 +433,7 @@ Some key differences make Actor unique:
|
|
392
433
|
|
393
434
|
- Does not [hide errors when an actor fails inside another
|
394
435
|
actor](https://github.com/collectiveidea/interactor/issues/170).
|
395
|
-
- Requires you to document
|
436
|
+
- Requires you to document arguments with `input` and `output`.
|
396
437
|
- Defaults to raising errors on failures: actor uses `call` and `result`
|
397
438
|
instead of `call!` and `call`. This way, the _default_ is to raise an error
|
398
439
|
and failures are not hidden away because you forgot to use `!`.
|
@@ -401,7 +442,8 @@ Some key differences make Actor unique:
|
|
401
442
|
`context.foo = `, `fail!` vs `context.fail!`.
|
402
443
|
- Shorter setup syntax: inherit from `< Actor` vs having to `include Interactor`
|
403
444
|
and `include Interactor::Organizer`.
|
404
|
-
- Organizers allow lambdas, being called multiple times,
|
445
|
+
- Organizers allow lambdas, instance methods, being called multiple times,
|
446
|
+
and having conditions.
|
405
447
|
- Allows early success with conditions inside organizers.
|
406
448
|
- No `before`, `after` and `around` hooks, prefer using `play` with lambdas or
|
407
449
|
overriding `call`.
|
@@ -414,33 +456,17 @@ migration.
|
|
414
456
|
Thank you to @nicoolas25, @AnneSottise & @williampollet for the early thoughts
|
415
457
|
and feedback on this gem.
|
416
458
|
|
417
|
-
|
418
|
-
|
419
|
-
## Development
|
459
|
+
Thank you to the wonderful
|
460
|
+
[contributors](https://github.com/sunny/actor/graphs/contributors).
|
420
461
|
|
421
|
-
|
422
|
-
`bin/rake` to run the tests and linting. You can also run `bin/console` for an
|
423
|
-
interactive prompt.
|
424
|
-
|
425
|
-
To release a new version, update the version number in `version.rb`, and in the
|
426
|
-
`CHANGELOG.md`. Update the `README.md` if there are missing segments, make sure
|
427
|
-
tests and linting are pristine by calling `bundle && bin/rake`, then create a
|
428
|
-
commit for this version.
|
429
|
-
|
430
|
-
You can then run `rake release`, which will assign a git tag, push using git,
|
431
|
-
and push the gem to [rubygems.org](https://rubygems.org).
|
462
|
+
Photo by [Lloyd Dirks](https://unsplash.com/photos/4SLz_RCk6kQ).
|
432
463
|
|
433
464
|
## Contributing
|
434
465
|
|
435
|
-
|
436
|
-
[
|
437
|
-
|
438
|
-
This project is intended to be a safe, welcoming space for collaboration, and
|
439
|
-
everyone interacting in the project’s codebase and issue tracker is expected to
|
440
|
-
adhere to the [Contributor Covenant code of
|
441
|
-
conduct](https://github.com/sunny/actor/blob/main/CODE_OF_CONDUCT.md).
|
466
|
+
See
|
467
|
+
[CONTRIBUTING.md](https://github.com/sunny/actor/blob/main/CONTRIBUTING.md).
|
442
468
|
|
443
469
|
## License
|
444
470
|
|
445
471
|
The gem is available as open source under the terms of the
|
446
|
-
[MIT License](https://
|
472
|
+
[MIT License](https://choosealicense.com/licenses/mit/).
|
data/lib/service_actor/base.rb
CHANGED
@@ -1,23 +1,23 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
# Exceptions
|
4
|
-
require
|
5
|
-
require
|
6
|
-
require
|
4
|
+
require "service_actor/error"
|
5
|
+
require "service_actor/failure"
|
6
|
+
require "service_actor/argument_error"
|
7
7
|
|
8
8
|
# Core
|
9
|
-
require
|
10
|
-
require
|
11
|
-
require
|
12
|
-
require
|
9
|
+
require "service_actor/core"
|
10
|
+
require "service_actor/attributable"
|
11
|
+
require "service_actor/playable"
|
12
|
+
require "service_actor/result"
|
13
13
|
|
14
14
|
# Concerns
|
15
|
-
require
|
16
|
-
require
|
17
|
-
require
|
18
|
-
require
|
19
|
-
require
|
20
|
-
require
|
15
|
+
require "service_actor/type_checkable"
|
16
|
+
require "service_actor/nil_checkable"
|
17
|
+
require "service_actor/conditionable"
|
18
|
+
require "service_actor/defaultable"
|
19
|
+
require "service_actor/collectionable"
|
20
|
+
require "service_actor/failable"
|
21
21
|
|
22
22
|
module ServiceActor
|
23
23
|
module Base
|
data/lib/service_actor/core.rb
CHANGED
@@ -9,9 +9,9 @@ module ServiceActor
|
|
9
9
|
module ClassMethods
|
10
10
|
# Call an actor with a given result. Returns the result.
|
11
11
|
#
|
12
|
-
# CreateUser.call(name:
|
13
|
-
def call(
|
14
|
-
result = Result.to_result(
|
12
|
+
# CreateUser.call(name: "Joe")
|
13
|
+
def call(result = nil, **arguments)
|
14
|
+
result = Result.to_result(result).merge!(arguments)
|
15
15
|
new(result)._call
|
16
16
|
result
|
17
17
|
end
|
@@ -19,9 +19,9 @@ module ServiceActor
|
|
19
19
|
# Call an actor with arguments. Returns the result and does not raise on
|
20
20
|
# failure.
|
21
21
|
#
|
22
|
-
# CreateUser.result(name:
|
23
|
-
def result(
|
24
|
-
call(
|
22
|
+
# CreateUser.result(name: "Joe")
|
23
|
+
def result(result = nil, **arguments)
|
24
|
+
call(result, **arguments)
|
25
25
|
rescue Failure => e
|
26
26
|
e.result
|
27
27
|
end
|
@@ -16,11 +16,11 @@ module ServiceActor
|
|
16
16
|
|
17
17
|
module PrependedMethods
|
18
18
|
def _call
|
19
|
-
check_context_for_nil(self.class.inputs, origin:
|
19
|
+
check_context_for_nil(self.class.inputs, origin: "input")
|
20
20
|
|
21
21
|
super
|
22
22
|
|
23
|
-
check_context_for_nil(self.class.outputs, origin:
|
23
|
+
check_context_for_nil(self.class.outputs, origin: "output")
|
24
24
|
end
|
25
25
|
|
26
26
|
private
|
@@ -31,7 +31,7 @@ module ServiceActor
|
|
31
31
|
|
32
32
|
raise ArgumentError,
|
33
33
|
"The #{origin} \"#{name}\" on #{self.class} does not allow " \
|
34
|
-
|
34
|
+
"nil values"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module ServiceActor
|
4
4
|
# Play class method to call a series of actors with the same result. On
|
5
|
-
# failure, calls rollback on
|
5
|
+
# failure, calls rollback on actors that succeeded.
|
6
6
|
#
|
7
7
|
# class CreateUser < Actor
|
8
8
|
# play SaveUser,
|
@@ -16,14 +16,6 @@ module ServiceActor
|
|
16
16
|
end
|
17
17
|
|
18
18
|
module ClassMethods
|
19
|
-
def inherited(child)
|
20
|
-
super
|
21
|
-
|
22
|
-
play_actors.each do |actor|
|
23
|
-
child.play_actors << actor
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
19
|
def play(*actors, **options)
|
28
20
|
actors.each do |actor|
|
29
21
|
play_actors.push({ actor: actor, **options })
|
@@ -33,6 +25,14 @@ module ServiceActor
|
|
33
25
|
def play_actors
|
34
26
|
@play_actors ||= []
|
35
27
|
end
|
28
|
+
|
29
|
+
def inherited(child)
|
30
|
+
super
|
31
|
+
|
32
|
+
play_actors.each do |actor|
|
33
|
+
child.play_actors << actor
|
34
|
+
end
|
35
|
+
end
|
36
36
|
end
|
37
37
|
|
38
38
|
module PrependedMethods
|
@@ -61,6 +61,7 @@ module ServiceActor
|
|
61
61
|
|
62
62
|
def play_actor(actor)
|
63
63
|
play_service_actor(actor) ||
|
64
|
+
play_symbol(actor) ||
|
64
65
|
play_interactor(actor) ||
|
65
66
|
actor.call(result)
|
66
67
|
end
|
@@ -75,9 +76,17 @@ module ServiceActor
|
|
75
76
|
(@played ||= []).unshift(actor)
|
76
77
|
end
|
77
78
|
|
79
|
+
def play_symbol(actor)
|
80
|
+
return unless actor.is_a?(Symbol)
|
81
|
+
|
82
|
+
send(actor)
|
83
|
+
|
84
|
+
true
|
85
|
+
end
|
86
|
+
|
78
87
|
def play_interactor(actor)
|
79
88
|
return unless actor.is_a?(Class)
|
80
|
-
return unless actor.ancestors.map(&:name).include?(
|
89
|
+
return unless actor.ancestors.map(&:name).include?("Interactor")
|
81
90
|
|
82
91
|
result.merge!(actor.call(result).to_h)
|
83
92
|
end
|
data/lib/service_actor/result.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require
|
3
|
+
require "ostruct"
|
4
4
|
|
5
5
|
module ServiceActor
|
6
6
|
# Represents the context of an actor, holding the data from both its inputs
|
@@ -51,5 +51,28 @@ module ServiceActor
|
|
51
51
|
def display
|
52
52
|
to_h.fetch(:display)
|
53
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def respond_to_missing?(method_name, include_private = false)
|
58
|
+
method_name.to_s.end_with?("?") || super
|
59
|
+
end
|
60
|
+
|
61
|
+
def method_missing(symbol, *args)
|
62
|
+
attribute = symbol.to_s.chomp("?")
|
63
|
+
|
64
|
+
if symbol.to_s.end_with?("?") && respond_to?(attribute)
|
65
|
+
define_singleton_method symbol do
|
66
|
+
attribute_value = send(attribute.to_sym)
|
67
|
+
|
68
|
+
# Same as ActiveSupport’s #present?
|
69
|
+
attribute_value.respond_to?(:empty?) ? !attribute_value.empty? : !!attribute_value
|
70
|
+
end
|
71
|
+
|
72
|
+
return send(symbol)
|
73
|
+
end
|
74
|
+
|
75
|
+
super symbol, *args
|
76
|
+
end
|
54
77
|
end
|
55
78
|
end
|
@@ -7,7 +7,7 @@ module ServiceActor
|
|
7
7
|
# Example:
|
8
8
|
#
|
9
9
|
# class ReduceOrderAmount < Actor
|
10
|
-
# input :order, type:
|
10
|
+
# input :order, type: "Order"
|
11
11
|
# input :amount, type: [Integer, Float]
|
12
12
|
# input :bonus_applied, type: [TrueClass FalseClass]
|
13
13
|
# end
|
@@ -18,11 +18,11 @@ module ServiceActor
|
|
18
18
|
|
19
19
|
module PrependedMethods
|
20
20
|
def _call
|
21
|
-
check_type_definitions(self.class.inputs, kind:
|
21
|
+
check_type_definitions(self.class.inputs, kind: "Input")
|
22
22
|
|
23
23
|
super
|
24
24
|
|
25
|
-
check_type_definitions(self.class.outputs, kind:
|
25
|
+
check_type_definitions(self.class.outputs, kind: "Output")
|
26
26
|
end
|
27
27
|
|
28
28
|
private
|
data/lib/service_actor.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: service_actor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Sunny Ripert
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -53,19 +53,25 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name: rubocop
|
56
|
+
name: rubocop-lts
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '12.0'
|
59
62
|
- - ">="
|
60
63
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
64
|
+
version: 12.0.1
|
62
65
|
type: :development
|
63
66
|
prerelease: false
|
64
67
|
version_requirements: !ruby/object:Gem::Requirement
|
65
68
|
requirements:
|
69
|
+
- - "~>"
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '12.0'
|
66
72
|
- - ">="
|
67
73
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
74
|
+
version: 12.0.1
|
69
75
|
- !ruby/object:Gem::Dependency
|
70
76
|
name: rubocop-rspec
|
71
77
|
requirement: !ruby/object:Gem::Requirement
|