jobify 0.1.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 +7 -0
- data/.rubocop.yml +24 -0
- data/CHANGELOG.md +10 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +62 -0
- data/LICENSE.txt +21 -0
- data/README.md +133 -0
- data/Rakefile +16 -0
- data/lib/jobify/version.rb +5 -0
- data/lib/jobify.rb +133 -0
- data/sig/jobify.rbs +4 -0
- metadata +86 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: aa64c39d98c548e4f10f34c979871bf027a20f551b9b17d4c6961ea4288a7896
|
4
|
+
data.tar.gz: 784be3e225ff0a7405d315d799bb8b8d30e612fd5bc8a8b0fb765302c6099cd0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f04966afa10e6d96dd9dbf6cb728d654c46bf3041bfbca4048dde85eb134894288b5e57a3642ff114f67a820fa8189853b97f692bc22a6ce4b7901a8d43ea84e
|
7
|
+
data.tar.gz: a6a86a55a01e7c465722ae779b9e6466c579a4731c074635d821b73ebbde7dc2ed453e0d52269149aa8d79561a08e8c3143905ff6e900986681913d7348fbaef
|
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
AllCops:
|
2
|
+
TargetRubyVersion: 2.6
|
3
|
+
Exclude:
|
4
|
+
- 'test/*'
|
5
|
+
|
6
|
+
Style/StringLiterals:
|
7
|
+
Enabled: true
|
8
|
+
EnforcedStyle: double_quotes
|
9
|
+
|
10
|
+
Style/StringLiteralsInInterpolation:
|
11
|
+
Enabled: true
|
12
|
+
EnforcedStyle: double_quotes
|
13
|
+
|
14
|
+
Metrics/BlockLength:
|
15
|
+
Max: 120
|
16
|
+
|
17
|
+
Metrics/AbcSize:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
Metrics/MethodLength:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Layout/LineLength:
|
24
|
+
Max: 150
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
# Changelog
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
5
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
|
+
|
7
|
+
## [Unreleased]
|
8
|
+
|
9
|
+
## [0.1.0] - 2022-10-25
|
10
|
+
- Initial release
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
jobify (0.1.0)
|
5
|
+
activejob
|
6
|
+
activesupport
|
7
|
+
|
8
|
+
GEM
|
9
|
+
remote: https://rubygems.org/
|
10
|
+
specs:
|
11
|
+
activejob (7.0.4)
|
12
|
+
activesupport (= 7.0.4)
|
13
|
+
globalid (>= 0.3.6)
|
14
|
+
activesupport (7.0.4)
|
15
|
+
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
+
i18n (>= 1.6, < 2)
|
17
|
+
minitest (>= 5.1)
|
18
|
+
tzinfo (~> 2.0)
|
19
|
+
ast (2.4.2)
|
20
|
+
concurrent-ruby (1.1.10)
|
21
|
+
globalid (1.0.0)
|
22
|
+
activesupport (>= 5.0)
|
23
|
+
i18n (1.12.0)
|
24
|
+
concurrent-ruby (~> 1.0)
|
25
|
+
json (2.6.2)
|
26
|
+
minitest (5.16.3)
|
27
|
+
parallel (1.22.1)
|
28
|
+
parser (3.1.2.1)
|
29
|
+
ast (~> 2.4.1)
|
30
|
+
rainbow (3.1.1)
|
31
|
+
rake (13.0.6)
|
32
|
+
regexp_parser (2.6.0)
|
33
|
+
rexml (3.2.5)
|
34
|
+
rubocop (1.37.0)
|
35
|
+
json (~> 2.3)
|
36
|
+
parallel (~> 1.10)
|
37
|
+
parser (>= 3.1.2.1)
|
38
|
+
rainbow (>= 2.2.2, < 4.0)
|
39
|
+
regexp_parser (>= 1.8, < 3.0)
|
40
|
+
rexml (>= 3.2.5, < 4.0)
|
41
|
+
rubocop-ast (>= 1.22.0, < 2.0)
|
42
|
+
ruby-progressbar (~> 1.7)
|
43
|
+
unicode-display_width (>= 1.4.0, < 3.0)
|
44
|
+
rubocop-ast (1.23.0)
|
45
|
+
parser (>= 3.1.1.0)
|
46
|
+
ruby-progressbar (1.11.0)
|
47
|
+
tzinfo (2.0.5)
|
48
|
+
concurrent-ruby (~> 1.0)
|
49
|
+
unicode-display_width (2.3.0)
|
50
|
+
|
51
|
+
PLATFORMS
|
52
|
+
x86_64-darwin-20
|
53
|
+
x86_64-linux
|
54
|
+
|
55
|
+
DEPENDENCIES
|
56
|
+
jobify!
|
57
|
+
minitest (~> 5.0)
|
58
|
+
rake (~> 13.0)
|
59
|
+
rubocop (~> 1.21)
|
60
|
+
|
61
|
+
BUNDLED WITH
|
62
|
+
2.3.14
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2022 Søren Houen
|
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,133 @@
|
|
1
|
+
# Jobify
|
2
|
+
|
3
|
+
Run any method as a background job with `perform_my_method_later`. Works with both instance and class methods.
|
4
|
+
|
5
|
+
## Why?
|
6
|
+
|
7
|
+
I think we as Rails developers are not using background processing as much as we could / should.
|
8
|
+
|
9
|
+
I believe this is largely because of 3 things:
|
10
|
+
|
11
|
+
- The extra work required to create a new MyTinyJob class
|
12
|
+
- The added complexity from moving code away from its natural and cohesive location in the project and into app/jobs
|
13
|
+
- The extra work required to _maintain_ a tiny MyTinyJob class
|
14
|
+
|
15
|
+
In short, the activation energy to use background jobs is too high.
|
16
|
+
|
17
|
+
Jobify lowers the activation energy to `jobify :my_method` to generate an activejob job class, and calling `perform_my_method_later`
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
```
|
22
|
+
class SomeClass
|
23
|
+
include Jobify
|
24
|
+
|
25
|
+
def self.my_method(arg1, kw_arg:)
|
26
|
+
puts "...#{arg1} #{kw_arg}'s which would be handy to do async..."
|
27
|
+
end
|
28
|
+
jobify :my_method
|
29
|
+
end
|
30
|
+
|
31
|
+
SomeClass.perform_my_method_later(42, kw_arg: 'flum')
|
32
|
+
```
|
33
|
+
|
34
|
+
Output:
|
35
|
+
|
36
|
+
```
|
37
|
+
[ActiveJob] Enqueued SomeClass::JobifyClassMethod_my_method_Job (Job ID: 8fc2ca69-cb31-4f73-a908-e98acb8a2832) to Async(default) with arguments: 42, {:kw_arg=>"flum"}
|
38
|
+
[ActiveJob] [SomeClass::JobifyClassMethod_my_method_Job] [8fc2ca69-cb31-4f73-a908-e98acb8a2832] Performing SomeClass::JobifyClassMethod_my_method_Job (Job ID: 8fc2ca69-cb31-4f73-a908-e98acb8a2832) from Async(default) enqueued at 2022-10-25T19:11:46Z with arguments: 42, {:kw_arg=>"flum"}
|
39
|
+
=>
|
40
|
+
#<SomeClass::JobifyClassMethod_my_method_Job:0x00007fee638d9cb8
|
41
|
+
@arguments=[42, {:kw_arg=>"flum"}],
|
42
|
+
@exception_executions={},
|
43
|
+
@executions=0,
|
44
|
+
@job_id="8fc2ca69-cb31-4f73-a908-e98acb8a2832",
|
45
|
+
@priority=nil,
|
46
|
+
@provider_job_id="8dc0614f-a229-4648-9308-4e6add9f666c",
|
47
|
+
@queue_name="default",
|
48
|
+
@successfully_enqueued=true,
|
49
|
+
@timezone=nil>
|
50
|
+
...42 flum's which would be handy to do async...
|
51
|
+
[ActiveJob] [SomeClass::JobifyClassMethod_my_method_Job] [8fc2ca69-cb31-4f73-a908-e98acb8a2832] Performed SomeClass::JobifyClassMethod_my_method_Job (Job ID: 8fc2ca69-cb31-4f73-a908-e98acb8a2832) from Async(default) in 4.57ms
|
52
|
+
```
|
53
|
+
|
54
|
+
### Features
|
55
|
+
|
56
|
+
- Jobifies class methods
|
57
|
+
- Jobifies instance methods
|
58
|
+
- Verifies correct arguments are given when enqueing a job
|
59
|
+
- Small overhead added: 0.06 ms boot and 0.1ms on perform
|
60
|
+
- Override perform_xyz_later method with whatever name you prefer (eg. `jobify :my_method, name: :my_method_async`)
|
61
|
+
|
62
|
+
### Instance methods
|
63
|
+
|
64
|
+
Instance methods work out of the box if your class inherits from `ApplicationRecord` or `ActiveRecord::Base`
|
65
|
+
|
66
|
+
If your class does not inherit from these it must supply `#id` and `.find(id)` methods to use `jobify` on
|
67
|
+
instance methods.
|
68
|
+
|
69
|
+
### How it works
|
70
|
+
Calling `jobify :my_method` will declare two things:
|
71
|
+
- A new activejob job class as subclass of the class where it is called. This class `#perform` method will call the original method using `public_send`.
|
72
|
+
- A `perform_my_method_later` method, which will perform the job later.
|
73
|
+
- `perform_my_method_later` will raise unless given the same arguments as `my_method`.
|
74
|
+
|
75
|
+
#### Instance methods
|
76
|
+
Jobifying instance methods work by adding a special id keyword argument to `JobifyInstanceMethod_xyz_Job#perform`:
|
77
|
+
|
78
|
+
- When called, `#perform_xyz_later` gets the id of the instance via `instance#id`.
|
79
|
+
- The id is passed to the jobs `#perform` method as extra argument (`:__jobify__record_id`).
|
80
|
+
- `#perform` method uses this to find the record and then run the instance method on the record.
|
81
|
+
|
82
|
+
## Installation
|
83
|
+
|
84
|
+
Install the gem and add to the application's Gemfile by executing:
|
85
|
+
|
86
|
+
$ bundle add jobify
|
87
|
+
|
88
|
+
If bundler is not being used to manage dependencies, install the gem by executing:
|
89
|
+
|
90
|
+
$ gem install jobify
|
91
|
+
|
92
|
+
### Overhead
|
93
|
+
|
94
|
+
Benchmarks from running on a 2020 i7 Macbook Pro:
|
95
|
+
|
96
|
+
(Generate benchmarks by running `BENCHMARK=10_000 rake test` where env BENCHMARK is the number of iterations to run)
|
97
|
+
```
|
98
|
+
Benchmark boot: 0.058 ms on avg of 100000 iterations
|
99
|
+
Benchmark perform: 0.228 ms on avg of 100000 iterations
|
100
|
+
Benchmark perform_control: 0.128 ms on avg of 100000 iterations
|
101
|
+
```
|
102
|
+
|
103
|
+
**Boot overhead:**
|
104
|
+
|
105
|
+
Jobify adds ~ 0.06 ms avg overhead per call.
|
106
|
+
So if you used `jobify :something` 100 times in your code, you would add ~ 6 ms overhead to boot time.
|
107
|
+
|
108
|
+
**Run job overhead**
|
109
|
+
|
110
|
+
Jobify adds ~ 0.1 ms overhead to running a job. Performing via jobify takes ~ 0.23 ms versus ~ 0.13 ms for normal
|
111
|
+
ActiveJob execution.
|
112
|
+
For all but the most massively-scheduled-all-the-time jobs, this should be fine.
|
113
|
+
|
114
|
+
## Development
|
115
|
+
|
116
|
+
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can
|
117
|
+
also run `bin/console` for an interactive prompt that will allow you to experiment.
|
118
|
+
|
119
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the
|
120
|
+
version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version,
|
121
|
+
push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
|
122
|
+
|
123
|
+
### TODO
|
124
|
+
- Allow to add options to `jobify`, eg. `queue_as: :default`
|
125
|
+
- Allow to add global options, eg queue_as, prefix:, suffix:
|
126
|
+
|
127
|
+
## Contributing
|
128
|
+
|
129
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/houen/jobify.
|
130
|
+
|
131
|
+
## License
|
132
|
+
|
133
|
+
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,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require "rake/testtask"
|
5
|
+
|
6
|
+
Rake::TestTask.new(:test) do |t|
|
7
|
+
t.libs << "test"
|
8
|
+
t.libs << "lib"
|
9
|
+
t.test_files = FileList["test/**/test_*.rb"]
|
10
|
+
end
|
11
|
+
|
12
|
+
require "rubocop/rake_task"
|
13
|
+
|
14
|
+
RuboCop::RakeTask.new
|
15
|
+
|
16
|
+
task default: %i[test rubocop]
|
data/lib/jobify.rb
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "jobify/version"
|
4
|
+
|
5
|
+
require "active_support"
|
6
|
+
require "active_job"
|
7
|
+
|
8
|
+
class MissingArgument < ArgumentError; end
|
9
|
+
|
10
|
+
class MissingKeywordArgument < ArgumentError; end
|
11
|
+
|
12
|
+
# Include to allow running any method as a background job automatically
|
13
|
+
module Jobify
|
14
|
+
extend ActiveSupport::Concern
|
15
|
+
|
16
|
+
ID_ARG_NAME = :__jobify__record_id
|
17
|
+
|
18
|
+
included do
|
19
|
+
@jobified_methods = {
|
20
|
+
instance: {},
|
21
|
+
singleton: {}
|
22
|
+
}
|
23
|
+
|
24
|
+
def self.jobify(method_name, job_method_name: "perform_#{method_name}_later")
|
25
|
+
raise "method name cannot be blank" if method_name.blank?
|
26
|
+
|
27
|
+
method_name = method_name.to_s
|
28
|
+
|
29
|
+
if method_defined?(method_name) && !@jobified_methods[:instance][method_name]
|
30
|
+
# Instance method
|
31
|
+
params = instance_method(method_name).parameters
|
32
|
+
_define_job_class(method_name, job_method_name, params, false)
|
33
|
+
@jobified_methods[:instance][method_name] = true
|
34
|
+
elsif respond_to?(method_name) && !@jobified_methods[:singleton][method_name]
|
35
|
+
# Singleton method (Class method)
|
36
|
+
params = method(method_name).parameters
|
37
|
+
_define_job_class(method_name, job_method_name, params, true)
|
38
|
+
@jobified_methods[:singleton][method_name] = true
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def self._define_job_class(method_name, job_method_name, params, singleton_method)
|
43
|
+
job_class_name = singleton_method ? "JobifyClassMethod_#{method_name}_Job" : "JobifyInstanceMethod_#{method_name}_Job"
|
44
|
+
parent_class = defined?(ApplicationJob) ? ApplicationJob : ActiveJob::Base
|
45
|
+
job_class = Class.new(parent_class)
|
46
|
+
caller_class = self
|
47
|
+
const_set(job_class_name, job_class)
|
48
|
+
|
49
|
+
# Define perform method on job class
|
50
|
+
if singleton_method
|
51
|
+
singleton__define_job_perform_method(job_class, caller_class, method_name)
|
52
|
+
singleton__define_job_enqueue_method(job_class, job_method_name, params)
|
53
|
+
else
|
54
|
+
instance__define_job_perform_method(job_class, caller_class, method_name)
|
55
|
+
instance__define_job_enqueue_method(job_class, job_method_name, params)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.singleton__define_job_perform_method(job_class, caller_class, method_name)
|
60
|
+
job_class.define_method(:perform) do |*args, **kw_args|
|
61
|
+
if kw_args.empty?
|
62
|
+
caller_class.public_send(method_name, *args)
|
63
|
+
else
|
64
|
+
caller_class.public_send(method_name, *args, **kw_args)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.singleton__define_job_enqueue_method(job_class, job_method_name, params)
|
70
|
+
define_singleton_method(job_method_name) do |*args, **kw_args|
|
71
|
+
req_args = params.filter_map { _1[0] == :req ? _1[1] : nil }
|
72
|
+
req_kw_args = params.filter_map { _1[0] == :keyreq ? _1[1] : nil }
|
73
|
+
|
74
|
+
ensure_required_kw_args_present!(req_kw_args, kw_args)
|
75
|
+
ensure_all_args_present!(req_args, args)
|
76
|
+
|
77
|
+
if kw_args.empty?
|
78
|
+
job_class.perform_later(*args)
|
79
|
+
else
|
80
|
+
job_class.perform_later(*args, **kw_args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.instance__define_job_perform_method(job_class, caller_class, method_name)
|
86
|
+
job_class.define_method(:perform) do |*args, **kw_args|
|
87
|
+
id = kw_args.delete(ID_ARG_NAME)
|
88
|
+
raise "Something has gone wrong. Record id is required" unless id
|
89
|
+
|
90
|
+
record = caller_class.find(id)
|
91
|
+
record.public_send(method_name, *args, **kw_args)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def self.instance__define_job_enqueue_method(job_class, job_method_name, params)
|
96
|
+
define_method(job_method_name) do |*args, **kw_args|
|
97
|
+
req_args = params.filter_map { _1[0] == :req ? _1[1] : nil }
|
98
|
+
req_kw_args = params.filter_map { _1[0] == :keyreq ? _1[1] : nil }
|
99
|
+
self.class.ensure_required_kw_args_present!(req_kw_args, kw_args)
|
100
|
+
self.class.ensure_all_args_present!(req_args, args)
|
101
|
+
|
102
|
+
# Instance method adds
|
103
|
+
kw_args[ID_ARG_NAME] = id
|
104
|
+
job_class.perform_later(*args, **kw_args)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
def self.ensure_required_kw_args_present!(req_kw_args, kw_args)
|
109
|
+
req_kw_args.each do |key|
|
110
|
+
next if kw_args.key?(key)
|
111
|
+
|
112
|
+
raise ::MissingKeywordArgument, "Missing require keyword argument `#{key}`"
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
def self.ensure_all_args_present!(req_args, args)
|
117
|
+
num_args_required = req_args.size
|
118
|
+
num_args_given = args.size
|
119
|
+
|
120
|
+
return if num_args_given >= num_args_required
|
121
|
+
|
122
|
+
raise ::MissingArgument, "Not enough arguments. Method expects #{num_args_required}. Got #{num_args_given}"
|
123
|
+
end
|
124
|
+
|
125
|
+
def ensure_required_kw_args_present!(req_kw_args, kw_args)
|
126
|
+
self.class.ensure_required_kw_args_present!(req_kw_args, kw_args)
|
127
|
+
end
|
128
|
+
|
129
|
+
def ensure_all_args_present!(req_args, args)
|
130
|
+
self.class.ensure_all_args_present!(req_args, args)
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
data/sig/jobify.rbs
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jobify
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Søren Houen
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2022-10-26 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activejob
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
description:
|
42
|
+
email:
|
43
|
+
- s@houen.net
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- ".rubocop.yml"
|
49
|
+
- CHANGELOG.md
|
50
|
+
- Gemfile
|
51
|
+
- Gemfile.lock
|
52
|
+
- LICENSE.txt
|
53
|
+
- README.md
|
54
|
+
- Rakefile
|
55
|
+
- lib/jobify.rb
|
56
|
+
- lib/jobify/version.rb
|
57
|
+
- sig/jobify.rbs
|
58
|
+
homepage: https://github.com/houen/jobify
|
59
|
+
licenses:
|
60
|
+
- MIT
|
61
|
+
metadata:
|
62
|
+
allowed_push_host: https://rubygems.org
|
63
|
+
homepage_uri: https://github.com/houen/jobify
|
64
|
+
source_code_uri: https://github.com/houen/jobify
|
65
|
+
changelog_uri: https://github.com/houen/jobify/CHANGELOG.md
|
66
|
+
post_install_message:
|
67
|
+
rdoc_options: []
|
68
|
+
require_paths:
|
69
|
+
- lib
|
70
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
71
|
+
requirements:
|
72
|
+
- - ">="
|
73
|
+
- !ruby/object:Gem::Version
|
74
|
+
version: 2.6.0
|
75
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
requirements: []
|
81
|
+
rubygems_version: 3.2.32
|
82
|
+
signing_key:
|
83
|
+
specification_version: 4
|
84
|
+
summary: Turn any method into a background job (`jobify :hello_world` generates `def
|
85
|
+
hello_world_job`
|
86
|
+
test_files: []
|