activejob-later 2026.10.29.162056
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 +7 -0
- data/LICENSE +21 -0
- data/README.md +88 -0
- data/lib/active_job/perform_later/job.rb +34 -0
- data/lib/active_job/perform_later/macro.rb +59 -0
- data/lib/active_job/perform_later/mixin.rb +32 -0
- data/lib/active_job/perform_later/proxy.rb +59 -0
- data/lib/active_job/perform_later/version.rb +11 -0
- data/lib/active_job/perform_later.rb +123 -0
- data/lib/activejob-later.rb +4 -0
- metadata +65 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 72ac0154c0607d1f6dd6f7cf36e0398062381ab252deab36ee96cfe06c9a3d6d
|
|
4
|
+
data.tar.gz: 42bf415d23c136a6490237a84e6cbb4987b8531fa8ee251715ce724787626467
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 37c9ebf8a59917d4e780c1b6d2b30f33aa42a69d9557c4cf268876ce53bdd83ff67c35897e7c807407588281d17edd53762c98596bb105320c0fb25e561fe724
|
|
7
|
+
data.tar.gz: a8433f560729ebe2514ffc0c0a1325c1fb5b261c85f2ea60e6254407edd91fbdb6df7002fbd3f7c3cdbb4843e1f17420df4da707451b59bee80a6760efb18d93
|
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Fluence
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
# activejob-later
|
|
2
|
+
|
|
3
|
+
Run any method of any class, module or instance in the background through
|
|
4
|
+
Active Job — no dedicated job class needed.
|
|
5
|
+
|
|
6
|
+
```ruby
|
|
7
|
+
Report.perform_later.compute("2026-06")
|
|
8
|
+
Report.perform_later(queue: :low, wait: 10.minutes).compute("2026-06")
|
|
9
|
+
invoice.perform_later.generate_pdf # instances via GlobalID
|
|
10
|
+
Maintenance.perform_later.purge # modules too
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
The direct call (`Report.compute(...)`) stays synchronous and untouched.
|
|
14
|
+
Options are passed straight to `ActiveJob::Base.set` (`queue:`, `wait:`,
|
|
15
|
+
`wait_until:`, `priority:`).
|
|
16
|
+
|
|
17
|
+
## Per-class and per-method job configuration
|
|
18
|
+
|
|
19
|
+
`perform_later` calls go through a generic job by default. Declare a dedicated
|
|
20
|
+
job to use the full Active Job class DSL — `retry_on`, `discard_on`,
|
|
21
|
+
`rescue_from`, `queue_as`, callbacks, and adapter extensions such as
|
|
22
|
+
`limits_concurrency` (Solid Queue):
|
|
23
|
+
|
|
24
|
+
```ruby
|
|
25
|
+
class Report
|
|
26
|
+
perform_later_job do # applies to the whole class
|
|
27
|
+
queue_as :reports
|
|
28
|
+
retry_on Timeout::Error, attempts: 5
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
perform_later_job :compute do # applies to one method only
|
|
32
|
+
limits_concurrency to: 1, key: ->(target, *) { target }
|
|
33
|
+
discard_on ActiveRecord::RecordNotFound
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def self.compute(month)
|
|
37
|
+
# ...
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Job resolution order: method job (`Report::ComputePerformLaterJob`) → class
|
|
43
|
+
job (`Report::PerformLaterJob`) → generic (`ActiveJob::PerformLater::Job`).
|
|
44
|
+
Method jobs inherit the class job, so rules cumulate.
|
|
45
|
+
Declare the class-level `perform_later_job` before the per-method ones — a method job only inherits a class job that already exists at that point.
|
|
46
|
+
|
|
47
|
+
When a class method and an instance method share a name, scope the job:
|
|
48
|
+
|
|
49
|
+
```ruby
|
|
50
|
+
perform_later_job :sync, on: :class do ... end # Report.perform_later.sync
|
|
51
|
+
perform_later_job :sync, on: :instance do ... end # report.perform_later.sync
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
## Building a job without enqueuing it
|
|
55
|
+
|
|
56
|
+
`job_later` takes the same options and returns the job `perform_later` would
|
|
57
|
+
enqueue, without enqueuing it — for APIs that take a job instance, such as
|
|
58
|
+
Solid Queue batch callbacks:
|
|
59
|
+
|
|
60
|
+
```ruby
|
|
61
|
+
SolidQueue::Batch.enqueue(on_finish: import.job_later.finalize!) do
|
|
62
|
+
import.lines.each { |line| line.perform_later.process! }
|
|
63
|
+
end
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Job resolution and the errors below are the same as for `perform_later`.
|
|
67
|
+
|
|
68
|
+
## Configuration
|
|
69
|
+
|
|
70
|
+
```ruby
|
|
71
|
+
ActiveJob::PerformLater.base_job = "ApplicationJob" # default: "ActiveJob::Base"
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Parent class of the jobs generated by `perform_later_job`.
|
|
75
|
+
|
|
76
|
+
## Error behavior
|
|
77
|
+
|
|
78
|
+
- Unknown or private method → `NoMethodError` at enqueue time, not in the worker.
|
|
79
|
+
- Non-serializable instance (no GlobalID, no custom serializer) →
|
|
80
|
+
`ActiveJob::SerializationError` at enqueue time.
|
|
81
|
+
- Target class removed before the job runs → `NameError` at perform.
|
|
82
|
+
- The proxy forwards every method call, so reflective calls like `.class` on the proxy itself enqueue real jobs; `inspect` is the exception (safe to display in a console).
|
|
83
|
+
- String instances are rejected as targets (`ArgumentError`) — a String would be ambiguous with a class reference in the job payload.
|
|
84
|
+
- Passing a block to a proxied call raises `ArgumentError` — blocks cannot be serialized.
|
|
85
|
+
|
|
86
|
+
## Requirements
|
|
87
|
+
|
|
88
|
+
Ruby >= 3.3, activejob >= 7.1.
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveJob
|
|
4
|
+
module PerformLater
|
|
5
|
+
# Shared perform implementation included in every job the gem
|
|
6
|
+
# resolves or generates.
|
|
7
|
+
#
|
|
8
|
+
# @api private
|
|
9
|
+
module JobBehavior
|
|
10
|
+
# Replays the captured call: resolves a class or module reference
|
|
11
|
+
# back to its constant, then public_sends the method.
|
|
12
|
+
#
|
|
13
|
+
# @api private
|
|
14
|
+
# @param target [Object, String] receiver, or class/module name
|
|
15
|
+
# @param method_name [String] method to invoke
|
|
16
|
+
# @param args [Array] positional arguments
|
|
17
|
+
# @param kwargs [Hash] keyword arguments
|
|
18
|
+
# @return [Object] whatever the replayed method returns
|
|
19
|
+
def perform(target, method_name, args, kwargs)
|
|
20
|
+
target = ::Object.const_get(target) if target.is_a?(String)
|
|
21
|
+
target.public_send(method_name, *args, **kwargs)
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
ActiveSupport.on_load(:active_job) do
|
|
28
|
+
# Generic fallback job used when no dedicated job constant matches the
|
|
29
|
+
# enqueued method. Defined in the load hook so {PerformLater.base_job}
|
|
30
|
+
# is only touched once Active Job is actually loaded.
|
|
31
|
+
class ActiveJob::PerformLater::Job < ActiveJob::Base
|
|
32
|
+
include ActiveJob::PerformLater::JobBehavior
|
|
33
|
+
end
|
|
34
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveJob
|
|
4
|
+
module PerformLater
|
|
5
|
+
# `perform_later_job` class macro, mixed into Module.
|
|
6
|
+
module Macro
|
|
7
|
+
# Accepted values for the `on:` scope option.
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
# @return [Array<Symbol, nil>] valid scopes
|
|
11
|
+
VALID_SCOPES = [nil, :class, :instance].freeze
|
|
12
|
+
|
|
13
|
+
# Defines a dedicated job class for `method_name` — or the
|
|
14
|
+
# class-wide `PerformLaterJob` fallback when no name is given —
|
|
15
|
+
# named after {PerformLater.job_const_name} and inheriting from the
|
|
16
|
+
# nearest `PerformLaterJob` or {PerformLater.base_job}.
|
|
17
|
+
#
|
|
18
|
+
# @api public
|
|
19
|
+
# @param method_name [Symbol, nil] method the job is dedicated to;
|
|
20
|
+
# nil declares the class-wide fallback job
|
|
21
|
+
# @param on [Symbol, nil] restrict the job to `:class` or
|
|
22
|
+
# `:instance` calls of `method_name`
|
|
23
|
+
# @yield optional block class_eval'ed inside the generated job
|
|
24
|
+
# (`queue_as`, `retry_on`, ...)
|
|
25
|
+
# @return [Class] the generated job class
|
|
26
|
+
# @raise [ArgumentError] on an invalid scope, a scope without a
|
|
27
|
+
# method name, or an already-defined job constant
|
|
28
|
+
# @example Dedicated job with options
|
|
29
|
+
# class Report
|
|
30
|
+
# perform_later_job :generate, on: :instance do
|
|
31
|
+
# queue_as :reports
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
def perform_later_job(method_name = nil, on: nil, &block)
|
|
35
|
+
unless VALID_SCOPES.include?(on)
|
|
36
|
+
raise ArgumentError, "on: must be :class or :instance, got #{on.inspect}"
|
|
37
|
+
end
|
|
38
|
+
raise ArgumentError, "on: requires a method name" if on && method_name.nil?
|
|
39
|
+
|
|
40
|
+
const_name = PerformLater.job_const_name(method_name, on: on)
|
|
41
|
+
if const_defined?(const_name, false)
|
|
42
|
+
raise ArgumentError, "#{self}::#{const_name} is already defined"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
parent =
|
|
46
|
+
if method_name
|
|
47
|
+
PerformLater.lookup_const(self, "PerformLaterJob") || PerformLater.resolved_base_job
|
|
48
|
+
else
|
|
49
|
+
PerformLater.resolved_base_job
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
job = const_set(const_name, Class.new(parent))
|
|
53
|
+
job.include(JobBehavior)
|
|
54
|
+
job.class_eval(&block) if block
|
|
55
|
+
job
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveJob
|
|
4
|
+
module PerformLater
|
|
5
|
+
# `perform_later` entry point, mixed into Object.
|
|
6
|
+
module Mixin
|
|
7
|
+
# Returns a proxy that enqueues the next method call as an Active
|
|
8
|
+
# Job instead of invoking it.
|
|
9
|
+
#
|
|
10
|
+
# @api public
|
|
11
|
+
# @param options [Hash] Active Job set options (`:queue`, `:wait`,
|
|
12
|
+
# `:wait_until`, `:priority`, ...)
|
|
13
|
+
# @return [Proxy] proxy enqueueing method calls on this receiver
|
|
14
|
+
# @example
|
|
15
|
+
# Newsletter.perform_later(queue: :low).deliver_all
|
|
16
|
+
def perform_later(**options)
|
|
17
|
+
Proxy.new(self, options)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
# Returns a proxy that builds the next method call as an Active Job
|
|
21
|
+
# without enqueuing it, resolved and checked like {#perform_later}.
|
|
22
|
+
#
|
|
23
|
+
# @api public
|
|
24
|
+
# @param options [Hash] Active Job set options (`:queue`, `:wait`,
|
|
25
|
+
# `:wait_until`, `:priority`, ...)
|
|
26
|
+
# @return [Proxy] proxy building jobs for method calls on this receiver
|
|
27
|
+
# @example Hand a call to a Solid Queue batch callback
|
|
28
|
+
# SolidQueue::Batch.enqueue(on_finish: import.job_later.finalize!) { ... }
|
|
29
|
+
def job_later(**options) = Proxy.new(self, options, enqueue: false)
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module ActiveJob
|
|
4
|
+
module PerformLater
|
|
5
|
+
# Intermediate object returned by {Mixin#perform_later} and
|
|
6
|
+
# {Mixin#job_later}: captures the next method call and enqueues — or
|
|
7
|
+
# only builds — it instead of invoking it.
|
|
8
|
+
#
|
|
9
|
+
# @api private
|
|
10
|
+
class Proxy < BasicObject
|
|
11
|
+
# @api private
|
|
12
|
+
# @param target [Object] receiver the call will be replayed on
|
|
13
|
+
# @param options [Hash] Active Job set options
|
|
14
|
+
# @param enqueue [Boolean] false to build the job without enqueuing it
|
|
15
|
+
# @return [Proxy] a new proxy around target
|
|
16
|
+
def initialize(target, options, enqueue: true)
|
|
17
|
+
@target = target
|
|
18
|
+
@options = options
|
|
19
|
+
@enqueue = enqueue
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
# Enqueues — or only builds, for {Mixin#job_later} — `method_name`
|
|
23
|
+
# on the captured target through the job class resolved by
|
|
24
|
+
# {PerformLater.job_for}.
|
|
25
|
+
#
|
|
26
|
+
# @api private
|
|
27
|
+
# @return [ActiveJob::Base] the enqueued, or built, job instance
|
|
28
|
+
# @raise [NoMethodError] when the target does not respond to the
|
|
29
|
+
# method
|
|
30
|
+
# @raise [ArgumentError] when a block is passed — blocks are not
|
|
31
|
+
# serializable
|
|
32
|
+
def method_missing(method_name, *args, **kwargs, &block)
|
|
33
|
+
unless @target.respond_to?(method_name)
|
|
34
|
+
::Kernel.raise ::NoMethodError,
|
|
35
|
+
"undefined method '#{method_name}' for #{@target.inspect} (via perform_later)"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
if block
|
|
39
|
+
::Kernel.raise ::ArgumentError,
|
|
40
|
+
"cannot enqueue '#{method_name}' with a block — blocks are not serializable"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
job = PerformLater.job_for(@target, method_name)
|
|
44
|
+
arguments = [PerformLater.target_ref(@target), method_name.to_s, args, kwargs]
|
|
45
|
+
return job.new(*arguments).set(@options) unless @enqueue
|
|
46
|
+
|
|
47
|
+
job.set(**@options).perform_later(*arguments)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
# Human-readable description of the proxy.
|
|
51
|
+
#
|
|
52
|
+
# @api private
|
|
53
|
+
# @return [String] the captured target and options
|
|
54
|
+
def inspect
|
|
55
|
+
"#<ActiveJob::PerformLater::Proxy target=#{@target.inspect} options=#{@options.inspect}>"
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
end
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_job/perform_later/version"
|
|
4
|
+
require "active_job/perform_later/job"
|
|
5
|
+
require "active_job/perform_later/proxy"
|
|
6
|
+
require "active_job/perform_later/mixin"
|
|
7
|
+
require "active_job/perform_later/macro"
|
|
8
|
+
|
|
9
|
+
module ActiveJob
|
|
10
|
+
# Runs any method of any class or instance in the background, either
|
|
11
|
+
# through ad-hoc {Mixin#perform_later} proxies or through dedicated
|
|
12
|
+
# jobs declared with the {Macro#perform_later_job} macro.
|
|
13
|
+
#
|
|
14
|
+
# @example Enqueue a method call on a model
|
|
15
|
+
# user.perform_later(wait: 5.minutes).send_welcome_email
|
|
16
|
+
module PerformLater
|
|
17
|
+
class << self
|
|
18
|
+
# Sets the job class every generated job inherits from.
|
|
19
|
+
#
|
|
20
|
+
# Accepts a Class, or a String resolved lazily so the constant can
|
|
21
|
+
# be defined after configuration runs (e.g. an autoloaded
|
|
22
|
+
# `ApplicationJob`).
|
|
23
|
+
#
|
|
24
|
+
# @api public
|
|
25
|
+
# @return [Class, String] the new base job
|
|
26
|
+
attr_writer :base_job
|
|
27
|
+
|
|
28
|
+
# The job class (or class name) generated jobs inherit from.
|
|
29
|
+
#
|
|
30
|
+
# @api public
|
|
31
|
+
# @return [Class, String] defaults to `"ActiveJob::Base"`
|
|
32
|
+
def base_job
|
|
33
|
+
@base_job ||= "ActiveJob::Base"
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# Resolves {base_job} to a Class, constantizing it when configured
|
|
37
|
+
# as a String.
|
|
38
|
+
#
|
|
39
|
+
# @api private
|
|
40
|
+
# @return [Class] the job class generated jobs inherit from
|
|
41
|
+
def resolved_base_job
|
|
42
|
+
base_job.is_a?(String) ? Object.const_get(base_job) : base_job
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
# Converts a proxy target into an Active Job serializable reference.
|
|
46
|
+
#
|
|
47
|
+
# Classes and modules are passed by name; any other object is
|
|
48
|
+
# passed as-is and relies on GlobalID (or primitive) serialization.
|
|
49
|
+
#
|
|
50
|
+
# @api private
|
|
51
|
+
# @param target [Object] receiver captured by the proxy
|
|
52
|
+
# @return [Object] the reference given to `perform_later`
|
|
53
|
+
# @raise [ArgumentError] when target is a String or an anonymous
|
|
54
|
+
# class or module
|
|
55
|
+
def target_ref(target)
|
|
56
|
+
if target.is_a?(String)
|
|
57
|
+
raise ArgumentError, "String targets are not supported by perform_later"
|
|
58
|
+
end
|
|
59
|
+
return target unless target.is_a?(Module)
|
|
60
|
+
|
|
61
|
+
target.name || raise(ArgumentError, "cannot perform_later on an anonymous class or module")
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Picks the job class used to enqueue `method_name` on `target`.
|
|
65
|
+
#
|
|
66
|
+
# Looks up, in order: the scope-prefixed constant
|
|
67
|
+
# (`Class…`/`Instance…`), the method-named constant, the class-wide
|
|
68
|
+
# `PerformLaterJob`, then falls back to the generic {Job}.
|
|
69
|
+
#
|
|
70
|
+
# @api private
|
|
71
|
+
# @param target [Object] receiver captured by the proxy
|
|
72
|
+
# @param method_name [Symbol] method being enqueued
|
|
73
|
+
# @return [Class] the Active Job class to enqueue with
|
|
74
|
+
def job_for(target, method_name)
|
|
75
|
+
klass = target.is_a?(Module) ? target : target.class
|
|
76
|
+
scope = target.is_a?(Module) ? :class : :instance
|
|
77
|
+
|
|
78
|
+
[job_const_name(method_name, on: scope),
|
|
79
|
+
job_const_name(method_name),
|
|
80
|
+
"PerformLaterJob"].each do |const_name|
|
|
81
|
+
job = lookup_const(klass, const_name)
|
|
82
|
+
return job if job
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
Job
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# Builds the conventional job constant name for a method.
|
|
89
|
+
#
|
|
90
|
+
# @api private
|
|
91
|
+
# @param method_name [Symbol, String, nil] method the job wraps
|
|
92
|
+
# @param on [Symbol, nil] optional `:class` / `:instance` scope prefix
|
|
93
|
+
# @return [String] e.g. `"SyncPerformLaterJob"`,
|
|
94
|
+
# `"ClassSyncPerformLaterJob"`
|
|
95
|
+
def job_const_name(method_name, on: nil)
|
|
96
|
+
return "PerformLaterJob" if method_name.nil?
|
|
97
|
+
|
|
98
|
+
prefix = on ? ActiveSupport::Inflector.camelize(on.to_s) : ""
|
|
99
|
+
base = ActiveSupport::Inflector.camelize(method_name.to_s.sub(/[?!=]\z/, ""))
|
|
100
|
+
"#{prefix}#{base}PerformLaterJob"
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Finds `const_name` defined directly on `mod` or one of its
|
|
104
|
+
# ancestors, skipping Object so a top-level constant does not leak
|
|
105
|
+
# into every class.
|
|
106
|
+
#
|
|
107
|
+
# @api private
|
|
108
|
+
# @param mod [Module] starting point of the ancestry lookup
|
|
109
|
+
# @param const_name [String] constant name to look up
|
|
110
|
+
# @return [Class, nil] the matching job class, or nil when undefined
|
|
111
|
+
def lookup_const(mod, const_name)
|
|
112
|
+
mod.ancestors.each do |ancestor|
|
|
113
|
+
next if ancestor == Object
|
|
114
|
+
return ancestor.const_get(const_name, false) if ancestor.const_defined?(const_name, false)
|
|
115
|
+
end
|
|
116
|
+
nil
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
Object.include ActiveJob::PerformLater::Mixin
|
|
123
|
+
Module.include ActiveJob::PerformLater::Macro
|
metadata
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: activejob-later
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 2026.10.29.162056
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Jonathan PHILIPPE
|
|
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: '7.1'
|
|
19
|
+
type: :runtime
|
|
20
|
+
prerelease: false
|
|
21
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
22
|
+
requirements:
|
|
23
|
+
- - ">="
|
|
24
|
+
- !ruby/object:Gem::Version
|
|
25
|
+
version: '7.1'
|
|
26
|
+
executables: []
|
|
27
|
+
extensions: []
|
|
28
|
+
extra_rdoc_files: []
|
|
29
|
+
files:
|
|
30
|
+
- LICENSE
|
|
31
|
+
- README.md
|
|
32
|
+
- lib/active_job/perform_later.rb
|
|
33
|
+
- lib/active_job/perform_later/job.rb
|
|
34
|
+
- lib/active_job/perform_later/macro.rb
|
|
35
|
+
- lib/active_job/perform_later/mixin.rb
|
|
36
|
+
- lib/active_job/perform_later/proxy.rb
|
|
37
|
+
- lib/active_job/perform_later/version.rb
|
|
38
|
+
- lib/activejob-later.rb
|
|
39
|
+
homepage: https://github.com/fluence-eu/activejob-later
|
|
40
|
+
licenses:
|
|
41
|
+
- MIT
|
|
42
|
+
metadata:
|
|
43
|
+
homepage_uri: https://github.com/fluence-eu/activejob-later
|
|
44
|
+
source_code_uri: https://github.com/fluence-eu/activejob-later
|
|
45
|
+
changelog_uri: https://github.com/fluence-eu/activejob-later/blob/main/CHANGELOG.md
|
|
46
|
+
github_repo: https://github.com/fluence-eu/activejob-later
|
|
47
|
+
rubygems_mfa_required: 'true'
|
|
48
|
+
rdoc_options: []
|
|
49
|
+
require_paths:
|
|
50
|
+
- lib
|
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '3.3'
|
|
56
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
requirements: []
|
|
62
|
+
rubygems_version: 4.0.20
|
|
63
|
+
specification_version: 4
|
|
64
|
+
summary: Run any method of any class in the background via Active Job
|
|
65
|
+
test_files: []
|