performs 0.3.4

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 58f4522465e497385cd7d88c3b8bf68eb83505addcbfc23024b4af4c7d21e855
4
+ data.tar.gz: d446c5a77683f7c6e5c757fcdfabecd80a0556f46fd5fc247107a38077f1e6fd
5
+ SHA512:
6
+ metadata.gz: a1af1460078f19f76d980701f9ab0f3cf09c567e291e54399f8ed7b6580373e2de8d29db08b42d4aeaabf0ee5ca135d0670538f95b508b6affa50c4e3803d6b6
7
+ data.tar.gz: f29b84a433c8b9ce582353af9b79f7b624f7686b93c210b30065ad10fd92f7412df1c355482f44ee8fc07b1a145db8075b5ce0069b08d9570954067db9ef93d8
data/CHANGELOG.md ADDED
@@ -0,0 +1,44 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.3.4] - 2025-11-28
4
+
5
+ - Breaking change. `performs` return only the later method, not an array.
6
+
7
+ ## [0.2.0] - 2023-01-12
8
+
9
+ - Supports `private performs :some_method`
10
+
11
+ Which then generates a private `some_method_later` method.
12
+
13
+ This was already technically supported but a test was added to declare it expected.
14
+
15
+ - Support method suffixes ! and ?
16
+
17
+ You can call `performs :some_method!` and have `some_method_later!` generated. Same for `?`.
18
+
19
+ - Support `performs` on private methods
20
+
21
+ Method jobs will now call methods with `send`, in case you only want to expose the generated later method to the outside world.
22
+
23
+ ```ruby
24
+ class Post < ActiveRecord::Base
25
+ performs :something_low_level
26
+
27
+ private
28
+
29
+ # We don't want other objects to call this, they should always use the generated later method.
30
+ def something_low_level
31
+ # …
32
+ end
33
+ end
34
+ ```
35
+
36
+ Here, the generated `Post#something_low_level_later` is public and available but can still call into the immediate version of `something_low_level`.
37
+
38
+ ## [0.1.1] - 2022-09-27
39
+
40
+ - Fixed: extend ActiveRecord::Base with ActiveJob::Performs as the README says.
41
+
42
+ ## [0.1.0] - 2022-09-27
43
+
44
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ source "https://rubygems.org"
4
+
5
+ # Specify your gem's dependencies in active_job-performs.gemspec
6
+ gemspec
7
+
8
+ gem "rake", "~> 13.0"
9
+
10
+ gem "minitest", "~> 5.0"
11
+ gem "minitest-sprint"
12
+
13
+ gem "debug"
14
+
15
+ # Fetch latest Active Job to test `ActiveJob.perform_all_later`
16
+ gem "activejob", ">= 7.1"
17
+ gem "activerecord", ">= 7.1"
18
+
19
+ gem "sqlite3", "~> 1.4"
data/Gemfile.lock ADDED
@@ -0,0 +1,79 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_job-performs (0.3.3)
5
+ activejob (>= 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activejob (7.1.3.4)
11
+ activesupport (= 7.1.3.4)
12
+ globalid (>= 0.3.6)
13
+ activemodel (7.1.3.4)
14
+ activesupport (= 7.1.3.4)
15
+ activerecord (7.1.3.4)
16
+ activemodel (= 7.1.3.4)
17
+ activesupport (= 7.1.3.4)
18
+ timeout (>= 0.4.0)
19
+ activesupport (7.1.3.4)
20
+ base64
21
+ bigdecimal
22
+ concurrent-ruby (~> 1.0, >= 1.0.2)
23
+ connection_pool (>= 2.2.5)
24
+ drb
25
+ i18n (>= 1.6, < 2)
26
+ minitest (>= 5.1)
27
+ mutex_m
28
+ tzinfo (~> 2.0)
29
+ base64 (0.2.0)
30
+ bigdecimal (3.1.8)
31
+ concurrent-ruby (1.3.3)
32
+ connection_pool (2.4.1)
33
+ debug (1.9.2)
34
+ irb (~> 1.10)
35
+ reline (>= 0.3.8)
36
+ drb (2.2.1)
37
+ globalid (1.2.1)
38
+ activesupport (>= 6.1)
39
+ i18n (1.14.5)
40
+ concurrent-ruby (~> 1.0)
41
+ io-console (0.7.2)
42
+ irb (1.13.2)
43
+ rdoc (>= 4.0.0)
44
+ reline (>= 0.4.2)
45
+ minitest (5.24.0)
46
+ minitest-sprint (1.2.2)
47
+ path_expander (~> 1.1)
48
+ mutex_m (0.2.0)
49
+ path_expander (1.1.1)
50
+ psych (5.1.2)
51
+ stringio
52
+ rake (13.2.1)
53
+ rdoc (6.7.0)
54
+ psych (>= 4.0.0)
55
+ reline (0.5.9)
56
+ io-console (~> 0.5)
57
+ sqlite3 (1.7.3-arm64-darwin)
58
+ sqlite3 (1.7.3-x86_64-linux)
59
+ stringio (3.1.1)
60
+ timeout (0.4.1)
61
+ tzinfo (2.0.6)
62
+ concurrent-ruby (~> 1.0)
63
+
64
+ PLATFORMS
65
+ arm64-darwin
66
+ x86_64-linux
67
+
68
+ DEPENDENCIES
69
+ active_job-performs!
70
+ activejob (>= 7.1)
71
+ activerecord (>= 7.1)
72
+ debug
73
+ minitest (~> 5.0)
74
+ minitest-sprint
75
+ rake (~> 13.0)
76
+ sqlite3 (~> 1.4)
77
+
78
+ BUNDLED WITH
79
+ 2.5.14
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 Kasper Timm Hansen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,345 @@
1
+ # ActiveJob::Performs
2
+
3
+ `ActiveJob::Performs` adds a `performs` class method to make the model + job loop vastly more conventional. You use it like this:
4
+
5
+ ```ruby
6
+ class Post < ApplicationRecord
7
+ performs :publish
8
+ # Or `performs def publish`!
9
+
10
+ def publish
11
+ # Some logic to publish a post
12
+ end
13
+ end
14
+ ```
15
+
16
+ Here's what `performs` generates under the hood:
17
+
18
+ ```ruby
19
+ class Post < ApplicationRecord
20
+ class Job < ApplicationJob; end # We build a general Job class to share configuration between method jobs.
21
+
22
+ # Individual method jobs inherit from the `Post::Job` defined above.
23
+ class PublishJob < Job
24
+ # We generate the required `perform` method passing in the `post` and calling `publish` on it.
25
+ def perform(post, *, **) = post.publish(*, **)
26
+ end
27
+
28
+ # On Rails 7.1+, where `ActiveJob.perform_all_later` exists, we also generate
29
+ # a bulk method to enqueue many jobs at once. So you can do this:
30
+ #
31
+ # Post.unpublished.in_batches.each(&:publish_later_bulk)
32
+ def self.publish_later_bulk(set = all)
33
+ ActiveJob.perform_all_later set.map { PublishJob.new(_1) }
34
+ end
35
+
36
+ # We generate `publish_later` to wrap the job execution forwarding arguments and options.
37
+ def publish_later(*, **) = PublishJob.perform_later(self, *, **)
38
+
39
+ def publish
40
+ # Some logic to publish a post.
41
+ end
42
+ end
43
+ ```
44
+
45
+ ## Benefits
46
+
47
+ 1. Conventional Jobs: they'll now mostly call instance methods like `publish_later` -> `publish`.
48
+ 1. Follows Rails' internal conventions: this borrows from `ActionMailbox::InboundEmail#process_later` calling `process` and `ActionMailer::Base#deliver_later` calling `deliver`.
49
+ 1. Clarity & less guess work: the `_later` methods standardize how you call jobs throughout your app, so you can instantly tell what's happening.
50
+ 1. Less tedium: getting an instance method run in the background is just now a `performs` call with some potential configuration.
51
+ 1. Fewer files to manage: you don't have to dig up something in `app/jobs` just to learn almost nothing from the boilerplate in there.
52
+ 1. Remaining jobs stand out: `app/jobs` is way lighter, so any jobs in there that don't fit the `performs` pattern now stand out way more.
53
+ 1. More consolidated logic: sometimes Job classes house model-level logic, but now it's all the way out in `app/jobs` instead of `app/models`, huh?
54
+
55
+ > [!TIP]
56
+ > On that last point, `performs` does put more logic back within your Active Records, so if you need further encapsulation to prevent them growing too large, consider checking out [active_record-associated_object](https://github.com/kaspth/active_record-associated_object).
57
+
58
+ ### Used in production & praise from people
59
+
60
+ The https://www.rubyevents.org team uses `ActiveJob::Performs` quite a bit:
61
+
62
+ - [See `performs` calls in RubyEvents](https://github.com/search?q=repo%3Arubyevents%2Frubyevents+performs+language%3ARuby&type=code&l=Ruby)
63
+
64
+
65
+ Here's what [@claudiob](https://github.com/claudiob) had to say after using `ActiveJob::Performs`:
66
+
67
+ > I’ve been using active_job-performs for the last month and I love it love it love it!!
68
+ >
69
+ > Your thought process behind it is so thorough. I have a bunch of jobs now attached to models and my app/jobs folder… is empty!!
70
+ >
71
+ > This saves me a lot of mental hoops, I don’t have to switch between files anymore, everything is self-contained. Thank you!!!
72
+
73
+ From [@andycroll](https://github.com/andycroll) in a [writeup](https://andycroll.com/ruby/launching-usingrails) about launching [UsingRails](https://usingrails.com):
74
+
75
+ > I’ve also adopted a couple of gems—with exceptional Rails-level taste and author pedigree—that I hadn’t used in anger before, including `active_job-performs` from Kasper […]. Would recommend both.
76
+
77
+ And [@nshki](https://github.com/nshki) after trying it:
78
+
79
+ > Spent some time playing with [@kaspth](https://github.com/kaspth)'s [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) and `ActiveJob::Performs` and wow! The conventions these gems put in place help simplify a codebase drastically. I particularly love `ActiveJob::Performs`—it helped me refactor out all `ApplicationJob` classes I had and keep important context in the right domain model.
80
+
81
+ ## Usage
82
+ ### with `ActiveRecord::Base` & other `GlobalID::Identification` objects
83
+
84
+ `ActiveJob::Performs` works with any object that has `include GlobalID::Identification` and responds to that interface.
85
+
86
+ `ActiveRecord::Base` implements this, so here's how that looks:
87
+
88
+ ```ruby
89
+ class Post < ActiveRecord::Base
90
+ extend ActiveJob::Performs # We technically auto-extend ActiveRecord::Base, but other object hierarchies need this.
91
+
92
+ # `performs` builds a `Post::PublishJob` and routes configs over to it.
93
+ performs :publish, queue_adapter: :sidekiq, queue_as: :important, discard_on: SomeError do
94
+ retry_on TimeoutError, wait: :polynomially_longer
95
+ end
96
+
97
+ def publish
98
+
99
+ end
100
+ end
101
+ ```
102
+
103
+ Here's what `performs` generates under the hood:
104
+
105
+ ```ruby
106
+ class Post < ActiveRecord::Base
107
+ # We setup a general Job class that's shared between method jobs.
108
+ class Job < ApplicationJob; end
109
+
110
+ # Individual method jobs inherit from the `Post::Job` defined above.
111
+ class PublishJob < Job
112
+ self.queue_adapter = :sidekiq
113
+ queue_as :important
114
+ discard_on SomeError
115
+ retry_on TimeoutError, wait: :polynomially_longer
116
+
117
+ # We generate `perform` passing in the `post` and calling `publish` on it.
118
+ def perform(post, *arguments, **options)
119
+ post.publish(*arguments, **options)
120
+ end
121
+ end
122
+
123
+ # On Rails 7.1, where `ActiveJob.perform_all_later` exists, we also generate
124
+ # a bulk method to enqueue many jobs at once. So you can do this:
125
+ #
126
+ # Post.unpublished.in_batches.each(&:publish_later_bulk)
127
+ #
128
+ # Or pass in a subset of posts as an argument:
129
+ #
130
+ # Post.publish_later_bulk Post.unpublished
131
+ def self.publish_later_bulk(set = all)
132
+ ActiveJob.perform_all_later set.map { PublishJob.new(_1) }
133
+ end
134
+
135
+ # We generate `publish_later` to wrap the job execution.
136
+ def publish_later(*arguments, **options)
137
+ PublishJob.perform_later(self, *arguments, **options)
138
+ end
139
+
140
+ def publish
141
+
142
+ end
143
+ end
144
+ ```
145
+
146
+ > [!NOTE]
147
+ > We prefer & call `{name}=` setter methods, but fall back to getters. That's how we support `self.queue_adapter=`, but also `queue_as` which is not configured via `queue_as=`.
148
+
149
+ We generate the `Post::Job` class above to share configuration between method level jobs. E.g. if you had a `retract` method that was setup very similar, you could do:
150
+
151
+ ```ruby
152
+ class Post < ActiveRecord::Base
153
+ performs queue_as: :important
154
+ performs :publish
155
+ performs :retract
156
+
157
+ def publish
158
+
159
+ end
160
+
161
+ def retract(reason:)
162
+
163
+ end
164
+ end
165
+ ```
166
+
167
+ Which would then become:
168
+
169
+ ```ruby
170
+ class Post < ActiveRecord::Base
171
+ class Job < ApplicationJob
172
+ queue_as :important
173
+ end
174
+
175
+ class PublishJob < Job
176
+
177
+ end
178
+
179
+ class RetractJob < Job
180
+
181
+ end
182
+
183
+
184
+ end
185
+ ```
186
+
187
+ #### Establishing patterns across your app
188
+
189
+ If there's an Active Record method that you'd like any model to be able to run from a background job, you can set them up in your `ApplicationRecord`:
190
+
191
+ ```ruby
192
+ class ApplicationRecord < ActiveRecord::Base
193
+ self.abstract_class = true
194
+
195
+ # We're passing specific queues for monitoring, but you may not need or want them.
196
+ performs :touch, queue_as: "active_record.touch"
197
+ performs :update, queue_as: "active_record.update"
198
+ performs :destroy, queue_as: "active_record.destroy"
199
+ end
200
+ ```
201
+
202
+ Then a model could now run things like:
203
+
204
+ ```ruby
205
+ record.touch_later
206
+ record.touch_later :reminded_at, time: 5.minutes.from_now # Pass supported arguments to `touch`
207
+
208
+ record.update_later reminded_at: 1.year.ago
209
+
210
+ # Particularly handy to use on a record with many `dependent: :destroy` associations.
211
+ # Plus if anything fails, the transaction will rollback and the job fails, so you can retry it later!
212
+ record.destroy_later
213
+ ```
214
+
215
+ You may not want this for `touch` and `update`, and maybe you'd rather architect your system in such a way that they don't have so many side-effects, but having the option can be handy!
216
+
217
+ Also, I haven't tested all the Active Record methods, so please file an issue if you encounter any.
218
+
219
+ #### Method suffixes
220
+
221
+ `ActiveJob::Performs` supports Ruby's stylistic method suffixes, i.e. ? and ! respectively.
222
+
223
+ ```ruby
224
+ class Post < ActiveRecord::Base
225
+ performs :publish! # Generates `publish_later!` which calls `publish!`.
226
+ performs :retract? # Generates `retract_later?` which calls `retract?`.
227
+
228
+ def publish!
229
+
230
+ end
231
+
232
+ def retract?
233
+
234
+ end
235
+ end
236
+ ```
237
+
238
+ #### Private methods
239
+
240
+ `ActiveJob::Performs` also works with private methods in case you only want to expose the generated `_later` method.
241
+
242
+ ```ruby
243
+ class Post < ActiveRecord::Base
244
+ performs :publish # Generates the public `publish_later` instance method.
245
+
246
+ # Private implementation, only call `publish_later` please!
247
+ private def publish
248
+
249
+ end
250
+ end
251
+ ```
252
+
253
+ Additionally, in case the job is meant to be internal to the object, `performs :some_method` returns `:some_method_later` which you can pass to `private`.
254
+
255
+ E.g. `private performs :some_method` will generate a private `some_method_later` method.
256
+
257
+ #### Overriding the generated instance `_later` method
258
+
259
+ The instance level `_later` methods, like `publish_later` above, are generated into an included module. So in case you have a condition where you'd like to prevent the enqueue, you can override the method and call `super`:
260
+
261
+ ```ruby
262
+ class Post < ApplicationRecord
263
+ performs def publish
264
+ # …
265
+ end
266
+ def publish_later = some_condition? && super
267
+ end
268
+ ```
269
+
270
+ ### Usage with `ActiveRecord::AssociatedObject`
271
+
272
+ The [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) gem also implements `GlobalID::Identification`, so you use `performs` exactly like you would on Active Records:
273
+
274
+ ```ruby
275
+ class Post::Publisher < ActiveRecord::AssociatedObject
276
+ extend ActiveJob::Performs # We technically auto-extend ActiveRecord::AssociatedObject, but other object hierarchies need this.
277
+
278
+ performs queue_as: :important
279
+ performs :publish
280
+ performs :retract
281
+
282
+ def publish
283
+
284
+ end
285
+
286
+ def retract(reason:)
287
+
288
+ end
289
+ end
290
+ ```
291
+
292
+ > [!NOTE]
293
+ > There's one difference with Active Record: you must pass in a set to `_later_bulk` methods. Like so:
294
+ >
295
+ > `Post::Publisher.publish_later_bulk Post::Publisher.first(10)`
296
+
297
+ ### Passing `wait` to `performs`
298
+
299
+ If there's a job you want to defer, `performs` can set it for each invocation:
300
+
301
+ ```ruby
302
+ class Post < ActiveRecord::Base
303
+ mattr_reader :config, default: Rails.application.config_for(:posts)
304
+
305
+ performs :social_media_boost, wait: config.social_media_boost_after
306
+ performs :social_media_boost, wait: 5.minutes # Alternatively, this works too.
307
+
308
+ # Additionally, a block can be passed to have access to the `post`:
309
+ performs :social_media_boost, wait: -> post { post.social_media_boost_grace_period }
310
+ end
311
+ ```
312
+
313
+ Now, `social_media_boost_later` can be called immediately, but automatically run after the grace period.
314
+
315
+ `wait_until` is also supported:
316
+
317
+ ```ruby
318
+ class Post < ActiveRecord::Base
319
+ performs :publish, wait_until: -> post { Date.tomorrow.noon if post.graceful? }
320
+ end
321
+ ```
322
+
323
+ ## Installation
324
+
325
+ Install the gem and add to the application's Gemfile by executing:
326
+
327
+ $ bundle add active_job-performs
328
+
329
+ If bundler is not being used to manage dependencies, install the gem by executing:
330
+
331
+ $ gem install active_job-performs
332
+
333
+ ## Development
334
+
335
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
336
+
337
+ 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 the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
338
+
339
+ ## Contributing
340
+
341
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kaspth/active_job-performs.
342
+
343
+ ## License
344
+
345
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "bundler/gem_tasks"
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJob
4
+ module Performs
5
+ VERSION = "0.3.4"
6
+ end
7
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "performs/version"
4
+
5
+ module ActiveJob; end
6
+ module ActiveJob::Performs
7
+ module Waiting
8
+ attr_reader :wait, :wait_until
9
+
10
+ def wait=(value)
11
+ @wait = value.respond_to?(:call) ? value : proc { value }
12
+ end
13
+
14
+ def wait_until=(value)
15
+ @wait_until = value.respond_to?(:call) ? value : proc { value }
16
+ end
17
+
18
+ def scoped_by_wait(record)
19
+ if waits = { wait: wait&.call(record), wait_until: wait_until&.call(record) }.compact and waits.any?
20
+ set(waits)
21
+ else
22
+ self
23
+ end
24
+ end
25
+ end
26
+
27
+ def performs(method = nil, **configs, &block)
28
+ @job ||= safe_define("Job") { ApplicationJob }.tap { _1.extend Waiting }
29
+
30
+ if method.nil?
31
+ apply_performs_to(@job, **configs, &block)
32
+ else
33
+ method = method.to_s.dup
34
+ suffix = $1 if method.gsub!(/([!?])$/, "")
35
+
36
+ job = safe_define("#{method}_job".classify) { @job }
37
+ apply_performs_to(job, **configs, &block)
38
+
39
+ job.class_eval <<~RUBY, __FILE__, __LINE__ + 1 unless job.instance_method(:perform).owner == job
40
+ def perform(object, *arguments, **options)
41
+ object.send(:#{method}#{suffix}, *arguments, **options)
42
+ end
43
+ RUBY
44
+
45
+ if ActiveJob.respond_to?(:perform_all_later)
46
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
47
+ def self.#{method}_later_bulk#{suffix}(set#{" = all" if respond_to?(:all)})
48
+ ActiveJob.perform_all_later set.map { #{job}.scoped_by_wait(_1).new(_1) }
49
+ end
50
+ RUBY
51
+ end
52
+
53
+ performs_later_methods.class_eval <<~RUBY, __FILE__, __LINE__ + 1
54
+ def #{method}_later#{suffix}(*arguments, **options)
55
+ #{job}.scoped_by_wait(self).perform_later(self, *arguments, **options)
56
+ end
57
+ RUBY
58
+
59
+ :"#{method}_later#{suffix}"
60
+ end
61
+ end
62
+
63
+ private
64
+ def safe_define(name)
65
+ name.safe_constantize || const_set(name, Class.new(yield))
66
+ end
67
+
68
+ def apply_performs_to(job, **configs, &block)
69
+ job.class_exec(&block) if block_given?
70
+
71
+ configs.each do |name, value|
72
+ name = "#{name}=".then.find { job.respond_to? _1 } || name
73
+ job.public_send name, value
74
+ end
75
+ end
76
+
77
+ def performs_later_methods
78
+ @performs_later_methods ||= Module.new.tap { include _1 }
79
+ end
80
+ end
81
+
82
+ ActiveSupport.on_load(:active_record) { extend ActiveJob::Performs }
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: performs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.4
5
+ platform: ruby
6
+ authors:
7
+ - Kasper Timm Hansen
8
+ bindir: bin
9
+ cert_chain: []
10
+ date: 1980-01-02 00:00:00.000000000 Z
11
+ dependencies:
12
+ - !ruby/object:Gem::Dependency
13
+ name: activejob
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: '6.1'
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: '6.1'
26
+ email:
27
+ - hey@kaspth.com
28
+ executables: []
29
+ extensions: []
30
+ extra_rdoc_files: []
31
+ files:
32
+ - CHANGELOG.md
33
+ - Gemfile
34
+ - Gemfile.lock
35
+ - LICENSE.txt
36
+ - README.md
37
+ - Rakefile
38
+ - lib/active_job/performs.rb
39
+ - lib/active_job/performs/version.rb
40
+ homepage: https://github.com/claudiob/active_job-performs
41
+ licenses:
42
+ - MIT
43
+ metadata:
44
+ homepage_uri: https://github.com/claudiob/active_job-performs
45
+ source_code_uri: https://github.com/claudiob/active_job-performs
46
+ changelog_uri: https://github.com/claudiob/active_job-performs/blob/main/CHANGELOG.md
47
+ rdoc_options: []
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: 3.0.0
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: '0'
60
+ requirements: []
61
+ rubygems_version: 3.6.9
62
+ specification_version: 4
63
+ summary: ActiveJob::Performs adds the `performs` macro to set up jobs by convention.
64
+ test_files: []