active_job-performs 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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7850f0de3bce1b5668903aa8d5144c3eb220fb4655013fc0ed4424357215627d
4
+ data.tar.gz: b13c325e25d4f470bed021bcf4d1bc302c04953d9bb287389d532d0df1327a5d
5
+ SHA512:
6
+ metadata.gz: 9790fdd3cd0812abd555f46cd3f295be1a4ed9fd5843ed4b0563fd61cf5b8c069c881f1373dae8ac2d130f3f9bddb6bc4bdf46a0f95c88ab8b5da5a98829a391
7
+ data.tar.gz: 659b0e1cdb12cf76f91df7f158800c71573866b132db1ed215bdced87bf72e837da7b96c1e6641b39abb6c4db35e5450bab52a4e9f7d5d04e375b5a1e8c5272b
data/CHANGELOG.md ADDED
@@ -0,0 +1,5 @@
1
+ ## [Unreleased]
2
+
3
+ ## [0.1.0] - 2022-09-27
4
+
5
+ - Initial release
data/Gemfile ADDED
@@ -0,0 +1,11 @@
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"
data/Gemfile.lock ADDED
@@ -0,0 +1,42 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ active_job-performs (0.1.0)
5
+ activejob (>= 6.1)
6
+
7
+ GEM
8
+ remote: https://rubygems.org/
9
+ specs:
10
+ activejob (7.0.4)
11
+ activesupport (= 7.0.4)
12
+ globalid (>= 0.3.6)
13
+ activesupport (7.0.4)
14
+ concurrent-ruby (~> 1.0, >= 1.0.2)
15
+ i18n (>= 1.6, < 2)
16
+ minitest (>= 5.1)
17
+ tzinfo (~> 2.0)
18
+ concurrent-ruby (1.1.10)
19
+ globalid (1.0.0)
20
+ activesupport (>= 5.0)
21
+ i18n (1.12.0)
22
+ concurrent-ruby (~> 1.0)
23
+ minitest (5.16.3)
24
+ minitest-sprint (1.2.2)
25
+ path_expander (~> 1.1)
26
+ path_expander (1.1.1)
27
+ rake (13.0.6)
28
+ tzinfo (2.0.5)
29
+ concurrent-ruby (~> 1.0)
30
+
31
+ PLATFORMS
32
+ arm64-darwin-20
33
+ x86_64-linux
34
+
35
+ DEPENDENCIES
36
+ active_job-performs!
37
+ minitest (~> 5.0)
38
+ minitest-sprint
39
+ rake (~> 13.0)
40
+
41
+ BUNDLED WITH
42
+ 2.3.21
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,164 @@
1
+ # ActiveJob::Performs
2
+
3
+ `ActiveJob::Performs` adds the `performs` macro to set up jobs by convention.
4
+
5
+ ## Usage with `include GlobalID::Identification` objects
6
+
7
+ `ActiveJob::Performs` works with any object that has `include GlobalID::Identification` and responds to that interface.
8
+
9
+ `ActiveRecord::Base` implements this, so here's how that looks:
10
+
11
+ ```ruby
12
+ class Post < ActiveRecord::Base
13
+ extend ActiveJob::Performs # We technically auto-extend ActiveRecord::Base, but other object hierarchies need this.
14
+
15
+ # `performs` builds a `Post::PublishJob` and routes configs over to it.
16
+ performs :publish, queue_as: :important, discard_on: SomeError do
17
+ retry_on TimeoutError, wait: :exponentially_longer
18
+ end
19
+
20
+ def publish
21
+
22
+ end
23
+ end
24
+ ```
25
+
26
+ Here's what `performs` generates under the hood:
27
+
28
+ ```ruby
29
+ class Post < ActiveRecord::Base
30
+ # We setup a general Job class that's shared between method jobs.
31
+ class Job < ApplicationJob; end
32
+
33
+ # Individual method jobs inherit from the `Post::Job` defined above.
34
+ class PublishJob < Job
35
+ queue_as :important
36
+ discard_on SomeError
37
+ retry_on TimeoutError, wait: :exponentially_longer
38
+
39
+ # We generate `perform` passing in the `post` and calling `publish` on it.
40
+ def perform(post, *arguments, **options)
41
+ post.publish(*arguments, **options)
42
+ end
43
+ end
44
+
45
+ # We generate `publish_later` to wrap the job execution.
46
+ def publish_later(*arguments, **options)
47
+ PublishJob.perform_later(self, *arguments, **options)
48
+ end
49
+
50
+ def publish
51
+
52
+ end
53
+ end
54
+ ```
55
+
56
+ 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:
57
+
58
+ ```ruby
59
+ class Post < ActiveRecord::Base
60
+ performs queue_as: :important
61
+ performs :publish
62
+ performs :retract
63
+
64
+ def publish
65
+
66
+ end
67
+
68
+ def retract(reason:)
69
+
70
+ end
71
+ end
72
+ ```
73
+
74
+ Which would then become:
75
+
76
+ ```ruby
77
+ class Post < ActiveRecord::Base
78
+ class Job < ApplicationJob
79
+ queue_as :important
80
+ end
81
+
82
+ class PublishJob < Job
83
+
84
+ end
85
+
86
+ class RetractJob < Job
87
+
88
+ end
89
+
90
+
91
+ end
92
+ ```
93
+
94
+ ### Usage with ActiveRecord::AssociatedObject
95
+
96
+ The [`ActiveRecord::AssociatedObject`](https://github.com/kaspth/active_record-associated_object) gem also implements `GlobalID::Identification`, so you can do this too:
97
+
98
+ ```ruby
99
+ class Post::Publisher < ActiveRecord::AssociatedObject
100
+ extend ActiveJob::Performs # We technically auto-extend ActiveRecord::AssociatedObject, but other object hierarchies need this.
101
+
102
+ performs queue_as: :important
103
+ performs :publish
104
+ performs :retract
105
+
106
+ def publish
107
+
108
+ end
109
+
110
+ def retract(reason:)
111
+
112
+ end
113
+ end
114
+ ```
115
+
116
+ ### Passing `wait` to `performs`
117
+
118
+ If there's a job you want to defer, `performs` can set it for each invocation:
119
+
120
+ ```ruby
121
+ class Post < ActiveRecord::Base
122
+ mattr_reader :config, default: Rails.application.config_for(:posts)
123
+
124
+ performs :social_media_boost, wait: config.social_media_boost_after
125
+ performs :social_media_boost, wait: 5.minutes # Alternatively, this works too.
126
+
127
+ # Additionally, a block can be passed to have access to the `post`:
128
+ performs :social_media_boost, wait: -> post { post.social_media_boost_grace_period }
129
+ end
130
+ ```
131
+
132
+ Now, `social_media_boost_later` can be called immediately, but automatically run after the grace period.
133
+
134
+ `wait_until` is also supported:
135
+
136
+ ```ruby
137
+ class Post < ActiveRecord::Base
138
+ performs :publish, wait_until: -> post { Date.tomorrow.noon if post.graceful? }
139
+ end
140
+ ```
141
+
142
+ ## Installation
143
+
144
+ Install the gem and add to the application's Gemfile by executing:
145
+
146
+ $ bundle add active_job-performs
147
+
148
+ If bundler is not being used to manage dependencies, install the gem by executing:
149
+
150
+ $ gem install active_job-performs
151
+
152
+ ## Development
153
+
154
+ 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.
155
+
156
+ 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).
157
+
158
+ ## Contributing
159
+
160
+ Bug reports and pull requests are welcome on GitHub at https://github.com/kaspth/active_job-performs.
161
+
162
+ ## License
163
+
164
+ 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,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/active_job/performs/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "active_job-performs"
7
+ spec.version = ActiveJob::Performs::VERSION
8
+ spec.authors = ["Kasper Timm Hansen"]
9
+ spec.email = ["hey@kaspth.com"]
10
+
11
+ spec.summary = "ActiveJob::Performs adds the `performs` macro to set up jobs by convention."
12
+ spec.homepage = "https://github.com/kaspth/active_job-performs"
13
+ spec.license = "MIT"
14
+ spec.required_ruby_version = ">= 3.0.0"
15
+
16
+ spec.metadata["homepage_uri"] = spec.homepage
17
+ spec.metadata["source_code_uri"] = spec.homepage
18
+ spec.metadata["changelog_uri"] = "#{spec.homepage}/blob/main/CHANGELOG.md"
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(__dir__) do
23
+ `git ls-files -z`.split("\x0").reject do |f|
24
+ (f == __FILE__) || f.match(%r{\A(?:(?:bin|test|spec|features)/|\.(?:git|travis|circleci)|appveyor)})
25
+ end
26
+ end
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_dependency "activejob", ">= 6.1"
30
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveJob
4
+ module Performs
5
+ VERSION = "0.1.0"
6
+ end
7
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "performs/version"
4
+
5
+ module ActiveJob; end
6
+ module ActiveJob::Performs
7
+ module Waiting
8
+ def Proc(value)
9
+ value.respond_to?(:call) ? value : proc { value }
10
+ end unless Kernel.respond_to?(:Proc) # Optimistically assume Ruby gets this and it'll work fine.
11
+
12
+ def wait(value = nil)
13
+ @wait = Proc(value) if value
14
+ @wait
15
+ end
16
+
17
+ def wait_until(value = nil)
18
+ @wait_until = Proc(value) if value
19
+ @wait_until
20
+ end
21
+
22
+ def scoped_by_wait(record)
23
+ if waits = { wait: wait&.call(record), wait_until: wait_until&.call(record) }.compact and waits.any?
24
+ set(waits)
25
+ else
26
+ self
27
+ end
28
+ end
29
+ end
30
+
31
+ def performs(method = nil, **configs, &block)
32
+ @job ||= safe_define("Job") { ApplicationJob }.tap { _1.extend Waiting }
33
+
34
+ if method.nil?
35
+ apply_performs_to(@job, **configs, &block)
36
+ else
37
+ job = safe_define("#{method}_job".classify) { @job }
38
+ apply_performs_to(job, **configs, &block)
39
+
40
+ job.class_eval <<~RUBY, __FILE__, __LINE__ + 1 unless job.instance_method(:perform).owner == job
41
+ def perform(object, *arguments, **options)
42
+ object.#{method}(*arguments, **options)
43
+ end
44
+ RUBY
45
+
46
+ class_eval <<~RUBY, __FILE__, __LINE__ + 1
47
+ def #{method}_later(*arguments, **options)
48
+ #{job}.scoped_by_wait(self).perform_later(self, *arguments, **options)
49
+ end
50
+ RUBY
51
+ end
52
+ end
53
+
54
+ private
55
+ def safe_define(name)
56
+ name.safe_constantize || const_set(name, Class.new(yield))
57
+ end
58
+
59
+ def apply_performs_to(job_class, **configs, &block)
60
+ configs.each { job_class.public_send(_1, _2) }
61
+ job_class.class_exec(&block) if block_given?
62
+ end
63
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: active_job-performs
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Kasper Timm Hansen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-09-27 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: '6.1'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '6.1'
27
+ description:
28
+ email:
29
+ - hey@kaspth.com
30
+ executables: []
31
+ extensions: []
32
+ extra_rdoc_files: []
33
+ files:
34
+ - CHANGELOG.md
35
+ - Gemfile
36
+ - Gemfile.lock
37
+ - LICENSE.txt
38
+ - README.md
39
+ - Rakefile
40
+ - active_job-performs.gemspec
41
+ - lib/active_job/performs.rb
42
+ - lib/active_job/performs/version.rb
43
+ homepage: https://github.com/kaspth/active_job-performs
44
+ licenses:
45
+ - MIT
46
+ metadata:
47
+ homepage_uri: https://github.com/kaspth/active_job-performs
48
+ source_code_uri: https://github.com/kaspth/active_job-performs
49
+ changelog_uri: https://github.com/kaspth/active_job-performs/blob/main/CHANGELOG.md
50
+ post_install_message:
51
+ rdoc_options: []
52
+ require_paths:
53
+ - lib
54
+ required_ruby_version: !ruby/object:Gem::Requirement
55
+ requirements:
56
+ - - ">="
57
+ - !ruby/object:Gem::Version
58
+ version: 3.0.0
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: '0'
64
+ requirements: []
65
+ rubygems_version: 3.3.21
66
+ signing_key:
67
+ specification_version: 4
68
+ summary: ActiveJob::Performs adds the `performs` macro to set up jobs by convention.
69
+ test_files: []