active_interaction-extras 0.2.1 → 1.0.2
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 +5 -5
- data/.github/workflows/ci.yml +35 -0
- data/CHANGELOG.md +29 -0
- data/README.md +168 -14
- data/Rakefile +9 -1
- data/active_interaction-extras.gemspec +11 -8
- data/lib/active_interaction/extras.rb +24 -2
- data/lib/active_interaction/extras/active_job.rb +25 -3
- data/lib/active_interaction/extras/all.rb +4 -1
- data/lib/active_interaction/extras/filter_alias.rb +18 -0
- data/lib/active_interaction/extras/filter_extensions.rb +2 -0
- data/lib/active_interaction/extras/filter_extensions/hash_auto_strip.rb +25 -0
- data/lib/active_interaction/extras/filter_extensions/object_classes.rb +47 -0
- data/lib/active_interaction/extras/filter_extensions/timezone_support.rb +16 -0
- data/lib/active_interaction/extras/filters/anything_filter.rb +9 -0
- data/lib/active_interaction/extras/filters/uuid_filter.rb +15 -0
- data/lib/active_interaction/extras/jobs/core.rb +32 -0
- data/lib/active_interaction/extras/locale/en.yml +5 -0
- data/lib/active_interaction/extras/model_fields.rb +5 -1
- data/lib/active_interaction/extras/rspec.rb +2 -0
- data/lib/active_interaction/extras/sidekiq.rb +61 -3
- data/lib/active_interaction/extras/strong_params.rb +1 -1
- data/lib/active_interaction/extras/transaction.rb +14 -19
- data/lib/active_interaction/extras/version.rb +1 -1
- metadata +37 -26
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 388877d30b968d835dd575246ce422c76869152aa48e5c5d092d77b43f35764f
|
|
4
|
+
data.tar.gz: da305c4468eaacca6ec6cf9a5c81f7bec3b2cceee1cd1e295fe06d654bdd8ea4
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c93f2d6aefa7015c27b34ec33c18d26c912099e85894987a9bbaca137cd52d3ff40842f9343a2c4ca3d4b79ef7bf672a03f8f328e0aaddf94943907a19c2db40
|
|
7
|
+
data.tar.gz: 69756c3fd8da5ac3e9bbbc209b8c4b7456b99c1203161f3df5cb15e7c0b2f1a40eb258b1b61663f4fc5fba2b5d639c97c2a6c516ae71ac5d588d42c8df674e41
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
|
2
|
+
# They are provided by a third-party and are governed by
|
|
3
|
+
# separate terms of service, privacy policy, and support
|
|
4
|
+
# documentation.
|
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
|
7
|
+
|
|
8
|
+
name: Tests
|
|
9
|
+
|
|
10
|
+
on:
|
|
11
|
+
push:
|
|
12
|
+
branches: [ master ]
|
|
13
|
+
pull_request:
|
|
14
|
+
branches: [ master ]
|
|
15
|
+
|
|
16
|
+
jobs:
|
|
17
|
+
test:
|
|
18
|
+
|
|
19
|
+
runs-on: ubuntu-latest
|
|
20
|
+
strategy:
|
|
21
|
+
matrix:
|
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
|
23
|
+
|
|
24
|
+
steps:
|
|
25
|
+
- uses: actions/checkout@v2
|
|
26
|
+
- name: Set up Ruby
|
|
27
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
|
28
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
|
29
|
+
# uses: ruby/setup-ruby@v1
|
|
30
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
|
31
|
+
with:
|
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
|
34
|
+
- name: Run tests
|
|
35
|
+
run: bundle exec rake
|
data/CHANGELOG.md
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# Change Log
|
|
2
|
+
All notable changes to this project will be documented in this file.
|
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [1.0.2] - 2021-07-07
|
|
8
|
+
|
|
9
|
+
- Requires active_interaction v4.0.2 or higher
|
|
10
|
+
- Fixed `run_in_transaction!` to rollback when interaction finished with errors
|
|
11
|
+
|
|
12
|
+
## [1.0.1] - 2021-05-13
|
|
13
|
+
|
|
14
|
+
- Fix `run_in_transaction` in ruby 3 [#8](https://github.com/antulik/active_interaction-extras/pull/8)
|
|
15
|
+
|
|
16
|
+
## [1.0.0] - 2021-05-12
|
|
17
|
+
|
|
18
|
+
- Requires active_interaction v4
|
|
19
|
+
- New filters: `anything` and `uuid`
|
|
20
|
+
- New filter extensions
|
|
21
|
+
- object: support for multiple classes
|
|
22
|
+
- hash: disable auto strip when no keys are listed
|
|
23
|
+
- New extension:
|
|
24
|
+
- filter alias
|
|
25
|
+
- Changed `transaction` extension
|
|
26
|
+
- It requires new transaction by default
|
|
27
|
+
- Include order is important now
|
|
28
|
+
- Removed `active_interaction-active_job` gem dependency
|
|
29
|
+
- Added changelog
|
data/README.md
CHANGED
|
@@ -1,26 +1,115 @@
|
|
|
1
1
|
# ActiveInteraction::Extras
|
|
2
2
|
|
|
3
|
+
[](https://badge.fury.io/rb/active_interaction-extras) 
|
|
4
|
+
|
|
3
5
|
This gem contains the collection of useful extensions to [active_interaction](https://github.com/AaronLasseigne/active_interaction) gem.
|
|
4
6
|
|
|
7
|
+
- [Installation](#installation)
|
|
8
|
+
- [Basic Usage](#basic-usage)
|
|
9
|
+
- [Filters](#filters)
|
|
10
|
+
- [Anything](#anything)
|
|
11
|
+
- [UUID](#uuid)
|
|
12
|
+
- [Filter Extensions](#filter-extensions)
|
|
13
|
+
- [Hash: auto strip](#hash-auto-strip)
|
|
14
|
+
- [Object: multiple classes](#object-multiple-classes)
|
|
15
|
+
- [Extensions](#extensions)
|
|
16
|
+
- [Filter alias](#filter-alias)
|
|
17
|
+
- [Halt](#halt)
|
|
18
|
+
- [ModelFields](#modelfields)
|
|
19
|
+
- [RunCallback](#runcallback)
|
|
20
|
+
- [StrongParams](#strongparams)
|
|
21
|
+
- [Transaction](#transaction)
|
|
22
|
+
- [Jobs](#jobs)
|
|
23
|
+
- [ActiveJob](#activejob)
|
|
24
|
+
- [Sidekiq](#sidekiq)
|
|
25
|
+
- [RSpec](#rspec)
|
|
26
|
+
|
|
5
27
|
## Installation
|
|
6
28
|
|
|
7
29
|
```ruby
|
|
8
30
|
gem 'active_interaction-extras'
|
|
9
31
|
```
|
|
10
32
|
|
|
11
|
-
## Usage
|
|
12
|
-
|
|
13
|
-
### All
|
|
33
|
+
## Basic Usage
|
|
14
34
|
|
|
15
35
|
```ruby
|
|
36
|
+
# app/services/application_interaction.rb
|
|
16
37
|
class ApplicationInteraction < ActiveInteraction::Base
|
|
17
38
|
include ActiveInteraction::Extras::All
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Filters
|
|
43
|
+
|
|
44
|
+
These new filters are added automatically when gem is loaded.
|
|
45
|
+
|
|
46
|
+
### Anything
|
|
47
|
+
|
|
48
|
+
Anything filter accepts as you guest it - anything.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
class Service < ActiveInteraction::Base
|
|
52
|
+
anything :model
|
|
53
|
+
end
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### UUID
|
|
57
|
+
|
|
58
|
+
```ruby
|
|
59
|
+
class Service < ActiveInteraction::Base
|
|
60
|
+
uuid :id
|
|
61
|
+
end
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Filter Extensions
|
|
65
|
+
|
|
66
|
+
You can load all filter extensions with:
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
# config/initializers/active_interaction.rb
|
|
70
|
+
require 'active_interaction/extras/filter_extensions'
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Hash: auto strip
|
|
74
|
+
|
|
75
|
+
This small extensions allows to accept full hashes without explicit `strip` option.
|
|
76
|
+
|
|
77
|
+
```ruby
|
|
78
|
+
class Service < ActiveInteraction::Base
|
|
79
|
+
hash :options_a, strip: false # (Before) Accept all keys
|
|
80
|
+
|
|
81
|
+
hash :options_b # (After) Accept all keys
|
|
82
|
+
|
|
83
|
+
hash :options_c do # (Before and After) Accept only specified keys
|
|
84
|
+
string :name
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Object: multiple classes
|
|
90
|
+
|
|
91
|
+
This extension allows using `object` filter with multiple classes.
|
|
92
|
+
|
|
93
|
+
```ruby
|
|
94
|
+
class Service < ActiveInteraction::Base
|
|
95
|
+
object :user, class: [User, AdminUser]
|
|
96
|
+
end
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
## Extensions
|
|
101
|
+
|
|
102
|
+
### Filter Alias
|
|
103
|
+
|
|
104
|
+
```ruby
|
|
105
|
+
class Service < ActiveInteraction::Base
|
|
106
|
+
include ActiveInteraction::Extras::FilterAlias
|
|
107
|
+
|
|
108
|
+
hash :params, as: :user_attributes
|
|
109
|
+
|
|
110
|
+
def execute
|
|
111
|
+
user_attributes == params # => true
|
|
112
|
+
end
|
|
24
113
|
end
|
|
25
114
|
```
|
|
26
115
|
|
|
@@ -50,7 +139,7 @@ end
|
|
|
50
139
|
class UserForm < ActiveInteraction::Base
|
|
51
140
|
include ActiveInteraction::Extras::ModelFields
|
|
52
141
|
|
|
53
|
-
|
|
142
|
+
anything :user
|
|
54
143
|
|
|
55
144
|
model_fields(:user) do
|
|
56
145
|
string :first_name
|
|
@@ -96,7 +185,6 @@ end
|
|
|
96
185
|
|
|
97
186
|
### StrongParams
|
|
98
187
|
|
|
99
|
-
|
|
100
188
|
```ruby
|
|
101
189
|
class UpdateUserForm < ActiveInteraction::Base
|
|
102
190
|
include ActiveInteraction::Extras::StrongParams
|
|
@@ -120,6 +208,14 @@ form_params = ActionController::Parameters.new(
|
|
|
120
208
|
)
|
|
121
209
|
|
|
122
210
|
Service.run(params: form_params)
|
|
211
|
+
|
|
212
|
+
# OR
|
|
213
|
+
form_params = ActionController::Parameters.new(
|
|
214
|
+
first_name: 'Allowed',
|
|
215
|
+
last_name: 'Not allowed',
|
|
216
|
+
)
|
|
217
|
+
|
|
218
|
+
Service.run(form_params: form_params)
|
|
123
219
|
```
|
|
124
220
|
|
|
125
221
|
### Transaction
|
|
@@ -141,6 +237,10 @@ UpdateUserForm.run
|
|
|
141
237
|
Comment.count # => 0
|
|
142
238
|
```
|
|
143
239
|
|
|
240
|
+
## Jobs
|
|
241
|
+
|
|
242
|
+
You no longer need to create a separate Job class for the each interaction. This Job extension automatically converts interactions to background jobs. By convention each interaction will have a nested `Job` class which will be inherited from the parent interaction `Job` class (e.g. `ApplicationInteraction::Job`).
|
|
243
|
+
|
|
144
244
|
### ActiveJob
|
|
145
245
|
|
|
146
246
|
```ruby
|
|
@@ -161,10 +261,15 @@ class DoubleService < ApplicationInteraction
|
|
|
161
261
|
end
|
|
162
262
|
|
|
163
263
|
DoubleService.delay.run(x: 2) # queues to run in background
|
|
264
|
+
DoubleService.delay(queue: 'low_priority', wait: 1.minute).run(x: 2)
|
|
164
265
|
```
|
|
165
266
|
|
|
267
|
+
In ActiveJob mode `delay` method accepts anything ActiveJob `set` [method](https://edgeapi.rubyonrails.org/classes/ActiveJob/Core/ClassMethods.html#method-i-set) does. (`wait`, `wait_until`, `queue`, `priority`)
|
|
268
|
+
|
|
166
269
|
### Sidekiq
|
|
167
270
|
|
|
271
|
+
You can use sidekiq directly if you need more control. Sidekiq integration comes with default GlobalID support.
|
|
272
|
+
|
|
168
273
|
```ruby
|
|
169
274
|
class ApplicationInteraction < ActiveInteraction::Base
|
|
170
275
|
include ActiveInteraction::Extras::Sidekiq
|
|
@@ -177,7 +282,7 @@ end
|
|
|
177
282
|
|
|
178
283
|
class DoubleService < ApplicationInteraction
|
|
179
284
|
job do
|
|
180
|
-
sidekiq_options retry: 1
|
|
285
|
+
sidekiq_options retry: 1 # configure sidekiq options
|
|
181
286
|
end
|
|
182
287
|
|
|
183
288
|
integer :x
|
|
@@ -188,9 +293,53 @@ class DoubleService < ApplicationInteraction
|
|
|
188
293
|
end
|
|
189
294
|
|
|
190
295
|
DoubleService.delay.run(x: 2) # queues to run in background
|
|
296
|
+
DoubleService.delay(queue: 'low_priority', wait: 1.minute).run(x: 2)
|
|
191
297
|
```
|
|
192
298
|
|
|
193
|
-
|
|
299
|
+
In Sidekiq mode `delay` method accepts anything sidekiq `set` [method](https://github.com/mperham/sidekiq/wiki/Advanced-Options#workers) does (`queue`, `retry`, `backtrace`, etc). Plus two additional `wait` and `wait_until`.
|
|
300
|
+
|
|
301
|
+
```ruby
|
|
302
|
+
# Advance usage: retry based on given params
|
|
303
|
+
class DoubleService < ApplicationInteraction
|
|
304
|
+
job do
|
|
305
|
+
sidekiq_options(retry: ->(job) {
|
|
306
|
+
params = deserialize_active_job_args(job)
|
|
307
|
+
params[:x]
|
|
308
|
+
})
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
integer :x
|
|
312
|
+
|
|
313
|
+
def execute
|
|
314
|
+
x + x
|
|
315
|
+
end
|
|
316
|
+
end
|
|
317
|
+
```
|
|
318
|
+
|
|
319
|
+
```ruby
|
|
320
|
+
# Advance usage: Rescue the job but not service
|
|
321
|
+
class DoubleService < ApplicationInteraction
|
|
322
|
+
job do
|
|
323
|
+
def perform(*args)
|
|
324
|
+
super
|
|
325
|
+
rescue StandardError => e
|
|
326
|
+
params = deserialize_active_job_args(args)
|
|
327
|
+
params[:x]
|
|
328
|
+
end
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
integer :x
|
|
332
|
+
|
|
333
|
+
def execute
|
|
334
|
+
raise
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
DoubleService.run # => RuntimeError
|
|
339
|
+
DoubleService.delay.perform_now(x: 2) # => returns 2
|
|
340
|
+
```
|
|
341
|
+
|
|
342
|
+
## Rspec
|
|
194
343
|
|
|
195
344
|
```ruby
|
|
196
345
|
class SomeService < ActiveInteraction::Base
|
|
@@ -219,7 +368,7 @@ RSpec.describe SomeService do
|
|
|
219
368
|
|
|
220
369
|
# expect_to_run / expect_not_to_run / expect_to_not_run
|
|
221
370
|
# expect_to_execute
|
|
222
|
-
# expect_to_delay_run / expect_to_not_run_delayed
|
|
371
|
+
# expect_to_delay_run / expect_not_to_run_delayed / expect_to_not_run_delayed
|
|
223
372
|
# expect_to_delay_execute
|
|
224
373
|
end
|
|
225
374
|
end
|
|
@@ -239,6 +388,11 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/antuli
|
|
|
239
388
|
|
|
240
389
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
|
241
390
|
|
|
391
|
+
## Credits
|
|
392
|
+
|
|
393
|
+
* ActiveInteraction::Extras is brought to you by [Anton Katunin](https://github.com/antulik) and was originally built at [CarNextDoor](https://www.carnextdoor.com.au/).
|
|
394
|
+
* Further improvements to this gem brought to you by [Anton Katunin](https://github.com/antulik) once again and the [Split Payments team](https://github.com/splitpayments/split).
|
|
395
|
+
|
|
242
396
|
## Code of Conduct
|
|
243
397
|
|
|
244
398
|
Everyone interacting in the ActiveInteraction::Extras project’s codebases, issue trackers, chat rooms and mailing lists is expected to follow the [code of conduct](https://github.com/antulik/active_interaction-extras/blob/master/CODE_OF_CONDUCT.md).
|
data/Rakefile
CHANGED
|
@@ -9,10 +9,13 @@ Gem::Specification.new do |spec|
|
|
|
9
9
|
spec.authors = ["Anton Katunin"]
|
|
10
10
|
spec.email = ["antulik@gmail.com"]
|
|
11
11
|
|
|
12
|
-
spec.summary = %q{
|
|
13
|
-
spec.description = %q{
|
|
14
|
-
spec.homepage = "https://github.com/antulik/
|
|
12
|
+
spec.summary = %q{Extensions for active_interaction gem}
|
|
13
|
+
spec.description = %q{Extensions for active_interaction gem}
|
|
14
|
+
spec.homepage = "https://github.com/antulik/active_interaction-extras"
|
|
15
15
|
spec.license = "MIT"
|
|
16
|
+
spec.metadata = {
|
|
17
|
+
"changelog_uri" => "https://github.com/antulik/active_interaction-extras/blob/master/CHANGELOG.md",
|
|
18
|
+
}
|
|
16
19
|
|
|
17
20
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
|
18
21
|
f.match(%r{^(test|spec|features)/})
|
|
@@ -21,11 +24,11 @@ Gem::Specification.new do |spec|
|
|
|
21
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
|
22
25
|
spec.require_paths = ["lib"]
|
|
23
26
|
|
|
24
|
-
spec.add_dependency "active_interaction", ">=
|
|
25
|
-
spec.add_dependency "
|
|
26
|
-
spec.add_development_dependency "bundler", "~>
|
|
27
|
-
spec.add_development_dependency "rake", "
|
|
27
|
+
spec.add_dependency "active_interaction", ">= 4.0.2"
|
|
28
|
+
spec.add_dependency "rails", ">= 6.0"
|
|
29
|
+
spec.add_development_dependency "bundler", "~> 2.2"
|
|
30
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
|
28
31
|
spec.add_development_dependency "rspec", "~> 3.7"
|
|
29
|
-
spec.add_development_dependency "rails", ">= 4.0"
|
|
30
32
|
spec.add_development_dependency "pry"
|
|
33
|
+
spec.add_development_dependency "sqlite3"
|
|
31
34
|
end
|
|
@@ -5,18 +5,40 @@ require 'active_interaction'
|
|
|
5
5
|
|
|
6
6
|
module ActiveInteraction
|
|
7
7
|
module Extras
|
|
8
|
+
module Filters
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
module FilterExtensions
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
module Jobs
|
|
15
|
+
autoload(:Core, "active_interaction/extras/jobs/core")
|
|
16
|
+
end
|
|
8
17
|
|
|
9
18
|
autoload(:All, "active_interaction/extras/all")
|
|
10
19
|
|
|
20
|
+
autoload(:FilterAlias, "active_interaction/extras/filter_alias")
|
|
11
21
|
autoload(:Halt, "active_interaction/extras/halt")
|
|
12
22
|
autoload(:ModelFields, "active_interaction/extras/model_fields")
|
|
13
23
|
autoload(:RunCallback, "active_interaction/extras/run_callback")
|
|
14
24
|
autoload(:StrongParams, "active_interaction/extras/strong_params")
|
|
15
25
|
autoload(:Transaction, "active_interaction/extras/transaction")
|
|
16
26
|
|
|
27
|
+
autoload(:TimezoneSupport, "active_interaction/extras/timezone_support")
|
|
28
|
+
autoload(:Rspec, "active_interaction/extras/rspec")
|
|
29
|
+
|
|
17
30
|
autoload(:ActiveJob, "active_interaction/extras/active_job")
|
|
18
31
|
autoload(:Sidekiq, "active_interaction/extras/sidekiq")
|
|
19
|
-
|
|
20
|
-
autoload(:Rspec, "active_interaction/extras/rspec")
|
|
21
32
|
end
|
|
22
33
|
end
|
|
34
|
+
|
|
35
|
+
require 'active_interaction/extras/filters/anything_filter'
|
|
36
|
+
require 'active_interaction/extras/filters/uuid_filter'
|
|
37
|
+
|
|
38
|
+
I18n.load_path.unshift(
|
|
39
|
+
*Dir.glob(
|
|
40
|
+
File.expand_path(
|
|
41
|
+
File.join(%w[extras locale *.yml]), File.dirname(__FILE__)
|
|
42
|
+
)
|
|
43
|
+
)
|
|
44
|
+
)
|
|
@@ -1,13 +1,35 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'active_job'
|
|
2
2
|
|
|
3
3
|
module ActiveInteraction::Extras::ActiveJob
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
-
include ActiveInteraction::
|
|
6
|
+
include ActiveInteraction::Extras::Jobs::Core
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def configured_job_class
|
|
10
|
+
ConfiguredJob
|
|
11
|
+
end
|
|
12
|
+
end
|
|
7
13
|
|
|
8
14
|
module Perform
|
|
9
15
|
extend ActiveSupport::Concern
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
def perform(*args)
|
|
18
|
+
if self.class.respond_to?(:module_parent)
|
|
19
|
+
self.class.module_parent.run!(*args)
|
|
20
|
+
else
|
|
21
|
+
self.class.parent.run!(*args)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
class ConfiguredJob < ::ActiveJob::ConfiguredJob
|
|
27
|
+
def run(*args)
|
|
28
|
+
perform_later(*args)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def run!(*args)
|
|
32
|
+
perform_later(*args)
|
|
33
|
+
end
|
|
12
34
|
end
|
|
13
35
|
end
|
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
module ActiveInteraction::Extras::All
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
+
# order dependant, include first so around callback includes other modules
|
|
5
|
+
include ActiveInteraction::Extras::Transaction
|
|
6
|
+
|
|
7
|
+
include ActiveInteraction::Extras::FilterAlias
|
|
4
8
|
include ActiveInteraction::Extras::Halt
|
|
5
9
|
include ActiveInteraction::Extras::ModelFields
|
|
6
10
|
include ActiveInteraction::Extras::RunCallback
|
|
7
11
|
include ActiveInteraction::Extras::StrongParams
|
|
8
|
-
include ActiveInteraction::Extras::Transaction
|
|
9
12
|
end
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add :as option, which is a read alias to filter
|
|
4
|
+
# hash :params, as: :account_attributes
|
|
5
|
+
#
|
|
6
|
+
module ActiveInteraction::Extras::FilterAlias
|
|
7
|
+
extend ActiveSupport::Concern
|
|
8
|
+
|
|
9
|
+
class_methods do
|
|
10
|
+
def initialize_filter(filter)
|
|
11
|
+
super.tap do
|
|
12
|
+
if filter.options[:as]
|
|
13
|
+
alias_method filter.options[:as], filter.name
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# If hash specified without structure automatically accept full hash
|
|
4
|
+
#
|
|
5
|
+
# @example Accept all keys
|
|
6
|
+
# hash :options
|
|
7
|
+
#
|
|
8
|
+
# @example Accept only specified keys
|
|
9
|
+
# hash :options do
|
|
10
|
+
# string :name
|
|
11
|
+
# end
|
|
12
|
+
#
|
|
13
|
+
# @example Accept all keys
|
|
14
|
+
# hash :options, strip: false do
|
|
15
|
+
# string :name
|
|
16
|
+
# end
|
|
17
|
+
#
|
|
18
|
+
module ActiveInteraction::Extras::FilterExtensions::HashAutoStrip
|
|
19
|
+
def initialize(*)
|
|
20
|
+
super
|
|
21
|
+
options[:strip] = false if !block_given? && !options.key?(:strip)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
ActiveInteraction::HashFilter.prepend(ActiveInteraction::Extras::FilterExtensions::HashAutoStrip)
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Add support for polymorphic objects
|
|
4
|
+
# object :account, class: [Account, AnyoneAccount]
|
|
5
|
+
#
|
|
6
|
+
module ActiveInteraction::Extras::FilterExtensions::ObjectClasses
|
|
7
|
+
def class_list
|
|
8
|
+
class_names.map do |klass_name|
|
|
9
|
+
case klass_name
|
|
10
|
+
when Class
|
|
11
|
+
klass_name
|
|
12
|
+
else
|
|
13
|
+
begin
|
|
14
|
+
Object.const_get(klass_name.to_s.camelize)
|
|
15
|
+
rescue NameError
|
|
16
|
+
raise ActiveInteraction::InvalidNameError, "class #{klass_name.inspect} does not exist"
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def klass
|
|
23
|
+
if polymorphic?
|
|
24
|
+
class_list.first
|
|
25
|
+
else
|
|
26
|
+
super
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def matches?(value)
|
|
31
|
+
if polymorphic?
|
|
32
|
+
class_list.any? { |klass| value.class <= klass }
|
|
33
|
+
else
|
|
34
|
+
super
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def class_names
|
|
39
|
+
options.fetch(:class, name)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def polymorphic?
|
|
43
|
+
class_names.is_a? Array
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
ActiveInteraction::ObjectFilter.prepend(ActiveInteraction::Extras::FilterExtensions::ObjectClasses)
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# Implementation inspired by
|
|
4
|
+
# https://github.com/AaronLasseigne/active_interaction/blob/c9d5608c3b8aab23d463f99c832b2ac5139911de/lib/active_interaction/filters/abstract_date_time_filter.rb#L42
|
|
5
|
+
module ActiveInteraction::Extras::FilterExtensions::TimezoneSupport
|
|
6
|
+
def convert_string(value)
|
|
7
|
+
if time_with_zone?
|
|
8
|
+
Time.zone.parse(value) ||
|
|
9
|
+
raise(ArgumentError, "no time information in #{value.inspect}")
|
|
10
|
+
else
|
|
11
|
+
super
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
ActiveInteraction::TimeFilter.include(ActiveInteraction::Extras::FilterExtensions::TimezoneSupport)
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
class ActiveInteraction::Extras::Filters::UUIDFilter < ActiveInteraction::StringFilter
|
|
4
|
+
register :uuid
|
|
5
|
+
|
|
6
|
+
REGEX = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i.freeze
|
|
7
|
+
|
|
8
|
+
def matches?(value)
|
|
9
|
+
super && REGEX.match?(value)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def convert(value)
|
|
13
|
+
super&.presence
|
|
14
|
+
end
|
|
15
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
module ActiveInteraction::Extras::Jobs::Core
|
|
2
|
+
extend ActiveSupport::Concern
|
|
3
|
+
|
|
4
|
+
class_methods do
|
|
5
|
+
def define_job_class(klass)
|
|
6
|
+
unless const_defined?(:Job, false)
|
|
7
|
+
const_set(:Job, Class.new(klass))
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def job(&block)
|
|
12
|
+
job_class.class_exec(&block)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def job_class
|
|
16
|
+
const_get(:Job, false)
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
def inherited(subclass)
|
|
20
|
+
super
|
|
21
|
+
subclass.define_job_class(job_class)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def delay(options = {})
|
|
25
|
+
configured_job_class.new(job_class, options)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def configured_job_class
|
|
29
|
+
raise NotImplementedError
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -46,6 +46,10 @@ module ActiveInteraction::Extras::ModelFields
|
|
|
46
46
|
alias file custom_filter_attribute
|
|
47
47
|
alias boolean custom_filter_attribute
|
|
48
48
|
alias array custom_filter_attribute
|
|
49
|
+
alias record custom_filter_attribute
|
|
50
|
+
|
|
51
|
+
alias anything custom_filter_attribute
|
|
52
|
+
alias uuid custom_filter_attribute
|
|
49
53
|
end
|
|
50
54
|
|
|
51
55
|
# checks if value was given to the service and the value is different from
|
|
@@ -64,7 +68,7 @@ module ActiveInteraction::Extras::ModelFields
|
|
|
64
68
|
end
|
|
65
69
|
|
|
66
70
|
# overwritten to pre-populate model fields
|
|
67
|
-
def
|
|
71
|
+
def populate_filters_and_inputs(_inputs)
|
|
68
72
|
super.tap do
|
|
69
73
|
self.class.filters.each do |name, filter|
|
|
70
74
|
next if given?(name)
|
|
@@ -1,13 +1,71 @@
|
|
|
1
|
-
require '
|
|
1
|
+
require 'active_job'
|
|
2
2
|
|
|
3
3
|
module ActiveInteraction::Extras::Sidekiq
|
|
4
4
|
extend ActiveSupport::Concern
|
|
5
5
|
|
|
6
|
-
include ActiveInteraction::
|
|
6
|
+
include ActiveInteraction::Extras::Jobs::Core
|
|
7
|
+
|
|
8
|
+
class_methods do
|
|
9
|
+
def configured_job_class
|
|
10
|
+
ConfiguredJob
|
|
11
|
+
end
|
|
12
|
+
end
|
|
7
13
|
|
|
8
14
|
module Perform
|
|
9
15
|
extend ActiveSupport::Concern
|
|
10
16
|
|
|
11
|
-
|
|
17
|
+
class_methods do
|
|
18
|
+
def deserialize_active_job_args(serialized_job)
|
|
19
|
+
ActiveJob::Arguments.deserialize(serialized_job['args']).first&.with_indifferent_access || {}
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def perform_later(*args)
|
|
23
|
+
ConfiguredJob.new(self).perform_later(*args)
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def perform(*args)
|
|
28
|
+
# support for sidekiq encrypted params
|
|
29
|
+
if args.length > 1 && args[0].nil?
|
|
30
|
+
args.shift
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
args = ActiveJob::Arguments.deserialize(args)
|
|
34
|
+
if self.class.respond_to?(:module_parent)
|
|
35
|
+
self.class.module_parent.run!(*args)
|
|
36
|
+
else
|
|
37
|
+
self.class.parent.run!(*args)
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def deserialize_active_job_args(job_arguments)
|
|
42
|
+
ActiveJob::Arguments.deserialize(job_arguments).first&.with_indifferent_access || {}
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
class ConfiguredJob < ::ActiveJob::ConfiguredJob
|
|
47
|
+
def perform_now(*args)
|
|
48
|
+
@job_class.run!(*args)
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def perform_later(*args)
|
|
52
|
+
args = ActiveJob::Arguments.serialize(args)
|
|
53
|
+
scope = @job_class.set(@options.except(:wait, :wait_until))
|
|
54
|
+
|
|
55
|
+
if @job_class.sidekiq_options['encrypt']
|
|
56
|
+
args.prepend(nil)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if @options[:wait]
|
|
60
|
+
scope.perform_in @options[:wait], *args
|
|
61
|
+
elsif @options[:wait_until]
|
|
62
|
+
scope.perform_at @options[:wait_until], *args
|
|
63
|
+
else
|
|
64
|
+
scope.perform_async *args
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
alias_method :run!, :perform_later
|
|
69
|
+
alias_method :run, :perform_later
|
|
12
70
|
end
|
|
13
71
|
end
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
module ActiveInteraction::Extras::StrongParams
|
|
2
2
|
extend ActiveSupport::Concern
|
|
3
3
|
|
|
4
|
-
def
|
|
4
|
+
def initialize(inputs = {})
|
|
5
5
|
# TODO: whitelist :params and :form_params, so they could not be used as filters
|
|
6
6
|
return super if self.class.filters.key?(:params) || self.class.filters.key?(:form_params)
|
|
7
7
|
|
|
@@ -1,32 +1,27 @@
|
|
|
1
|
+
# Add transaction wrapper
|
|
2
|
+
# run_in_transaction!
|
|
3
|
+
# skip_run_in_transaction!
|
|
1
4
|
module ActiveInteraction::Extras::Transaction
|
|
2
5
|
extend ActiveSupport::Concern
|
|
3
6
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
# errors added by compose method are merged after execute,
|
|
11
|
-
# so we need to check return type ourselves
|
|
12
|
-
#
|
|
13
|
-
# see ActiveInteraction::Runnable#run
|
|
14
|
-
if result_or_errors.is_a?(ActiveInteraction::Errors) && result_or_errors.any?
|
|
15
|
-
raise ActiveRecord::Rollback
|
|
7
|
+
included do
|
|
8
|
+
class_attribute :run_in_transaction_options
|
|
9
|
+
set_callback :execute, :around, ->(_interaction, block) {
|
|
10
|
+
ActiveRecord::Base.transaction(**run_in_transaction_options) do
|
|
11
|
+
block.call
|
|
12
|
+
raise ActiveRecord::Rollback if _interaction.errors.any?
|
|
16
13
|
end
|
|
17
|
-
|
|
18
|
-
raise ActiveRecord::Rollback if errors.any?
|
|
19
|
-
end
|
|
20
|
-
result_or_errors
|
|
14
|
+
}, if: :run_in_transaction_options
|
|
21
15
|
end
|
|
22
16
|
|
|
23
17
|
class_methods do
|
|
24
|
-
|
|
25
|
-
|
|
18
|
+
# https://pragtob.wordpress.com/2017/12/12/surprises-with-nested-transactions-rollbacks-and-activerecord/
|
|
19
|
+
def run_in_transaction!(requires_new: true)
|
|
20
|
+
self.run_in_transaction_options = {requires_new: requires_new}
|
|
26
21
|
end
|
|
27
22
|
|
|
28
23
|
def skip_run_in_transaction!
|
|
29
|
-
|
|
24
|
+
self.run_in_transaction_options = nil
|
|
30
25
|
end
|
|
31
26
|
end
|
|
32
27
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: active_interaction-extras
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.2
|
|
4
|
+
version: 1.0.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Anton Katunin
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2021-07-07 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: active_interaction
|
|
@@ -16,56 +16,56 @@ dependencies:
|
|
|
16
16
|
requirements:
|
|
17
17
|
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
|
-
version:
|
|
19
|
+
version: 4.0.2
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
24
|
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
|
-
version:
|
|
26
|
+
version: 4.0.2
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
28
|
-
name:
|
|
28
|
+
name: rails
|
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
|
30
30
|
requirements:
|
|
31
31
|
- - ">="
|
|
32
32
|
- !ruby/object:Gem::Version
|
|
33
|
-
version: '0'
|
|
33
|
+
version: '6.0'
|
|
34
34
|
type: :runtime
|
|
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: '0'
|
|
40
|
+
version: '6.0'
|
|
41
41
|
- !ruby/object:Gem::Dependency
|
|
42
42
|
name: bundler
|
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
|
44
44
|
requirements:
|
|
45
45
|
- - "~>"
|
|
46
46
|
- !ruby/object:Gem::Version
|
|
47
|
-
version: '
|
|
47
|
+
version: '2.2'
|
|
48
48
|
type: :development
|
|
49
49
|
prerelease: false
|
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
|
51
51
|
requirements:
|
|
52
52
|
- - "~>"
|
|
53
53
|
- !ruby/object:Gem::Version
|
|
54
|
-
version: '
|
|
54
|
+
version: '2.2'
|
|
55
55
|
- !ruby/object:Gem::Dependency
|
|
56
56
|
name: rake
|
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
|
58
58
|
requirements:
|
|
59
|
-
- - "
|
|
59
|
+
- - ">="
|
|
60
60
|
- !ruby/object:Gem::Version
|
|
61
|
-
version:
|
|
61
|
+
version: 12.3.3
|
|
62
62
|
type: :development
|
|
63
63
|
prerelease: false
|
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
65
65
|
requirements:
|
|
66
|
-
- - "
|
|
66
|
+
- - ">="
|
|
67
67
|
- !ruby/object:Gem::Version
|
|
68
|
-
version:
|
|
68
|
+
version: 12.3.3
|
|
69
69
|
- !ruby/object:Gem::Dependency
|
|
70
70
|
name: rspec
|
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -81,21 +81,21 @@ dependencies:
|
|
|
81
81
|
- !ruby/object:Gem::Version
|
|
82
82
|
version: '3.7'
|
|
83
83
|
- !ruby/object:Gem::Dependency
|
|
84
|
-
name:
|
|
84
|
+
name: pry
|
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
|
86
86
|
requirements:
|
|
87
87
|
- - ">="
|
|
88
88
|
- !ruby/object:Gem::Version
|
|
89
|
-
version: '
|
|
89
|
+
version: '0'
|
|
90
90
|
type: :development
|
|
91
91
|
prerelease: false
|
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
|
93
93
|
requirements:
|
|
94
94
|
- - ">="
|
|
95
95
|
- !ruby/object:Gem::Version
|
|
96
|
-
version: '
|
|
96
|
+
version: '0'
|
|
97
97
|
- !ruby/object:Gem::Dependency
|
|
98
|
-
name:
|
|
98
|
+
name: sqlite3
|
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
|
100
100
|
requirements:
|
|
101
101
|
- - ">="
|
|
@@ -108,15 +108,17 @@ dependencies:
|
|
|
108
108
|
- - ">="
|
|
109
109
|
- !ruby/object:Gem::Version
|
|
110
110
|
version: '0'
|
|
111
|
-
description:
|
|
111
|
+
description: Extensions for active_interaction gem
|
|
112
112
|
email:
|
|
113
113
|
- antulik@gmail.com
|
|
114
114
|
executables: []
|
|
115
115
|
extensions: []
|
|
116
116
|
extra_rdoc_files: []
|
|
117
117
|
files:
|
|
118
|
+
- ".github/workflows/ci.yml"
|
|
118
119
|
- ".gitignore"
|
|
119
120
|
- ".rspec"
|
|
121
|
+
- CHANGELOG.md
|
|
120
122
|
- CODE_OF_CONDUCT.md
|
|
121
123
|
- Gemfile
|
|
122
124
|
- LICENSE.txt
|
|
@@ -128,7 +130,16 @@ files:
|
|
|
128
130
|
- lib/active_interaction/extras.rb
|
|
129
131
|
- lib/active_interaction/extras/active_job.rb
|
|
130
132
|
- lib/active_interaction/extras/all.rb
|
|
133
|
+
- lib/active_interaction/extras/filter_alias.rb
|
|
134
|
+
- lib/active_interaction/extras/filter_extensions.rb
|
|
135
|
+
- lib/active_interaction/extras/filter_extensions/hash_auto_strip.rb
|
|
136
|
+
- lib/active_interaction/extras/filter_extensions/object_classes.rb
|
|
137
|
+
- lib/active_interaction/extras/filter_extensions/timezone_support.rb
|
|
138
|
+
- lib/active_interaction/extras/filters/anything_filter.rb
|
|
139
|
+
- lib/active_interaction/extras/filters/uuid_filter.rb
|
|
131
140
|
- lib/active_interaction/extras/halt.rb
|
|
141
|
+
- lib/active_interaction/extras/jobs/core.rb
|
|
142
|
+
- lib/active_interaction/extras/locale/en.yml
|
|
132
143
|
- lib/active_interaction/extras/model_fields.rb
|
|
133
144
|
- lib/active_interaction/extras/rspec.rb
|
|
134
145
|
- lib/active_interaction/extras/run_callback.rb
|
|
@@ -136,11 +147,12 @@ files:
|
|
|
136
147
|
- lib/active_interaction/extras/strong_params.rb
|
|
137
148
|
- lib/active_interaction/extras/transaction.rb
|
|
138
149
|
- lib/active_interaction/extras/version.rb
|
|
139
|
-
homepage: https://github.com/antulik/
|
|
150
|
+
homepage: https://github.com/antulik/active_interaction-extras
|
|
140
151
|
licenses:
|
|
141
152
|
- MIT
|
|
142
|
-
metadata:
|
|
143
|
-
|
|
153
|
+
metadata:
|
|
154
|
+
changelog_uri: https://github.com/antulik/active_interaction-extras/blob/master/CHANGELOG.md
|
|
155
|
+
post_install_message:
|
|
144
156
|
rdoc_options: []
|
|
145
157
|
require_paths:
|
|
146
158
|
- lib
|
|
@@ -155,9 +167,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
155
167
|
- !ruby/object:Gem::Version
|
|
156
168
|
version: '0'
|
|
157
169
|
requirements: []
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
signing_key:
|
|
170
|
+
rubygems_version: 3.1.4
|
|
171
|
+
signing_key:
|
|
161
172
|
specification_version: 4
|
|
162
|
-
summary:
|
|
173
|
+
summary: Extensions for active_interaction gem
|
|
163
174
|
test_files: []
|