-
Notifications
You must be signed in to change notification settings - Fork 111
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Generator for ActiveJob::Base descendants
Need this to properly type `perform_later` and `perform_now` methods, as their arguments change based on the signature of the `perform` method.
- Loading branch information
Showing
4 changed files
with
201 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,71 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
require "parlour" | ||
|
||
begin | ||
require "active_job" | ||
rescue LoadError | ||
return | ||
end | ||
|
||
module Tapioca | ||
module Compilers | ||
module Dsl | ||
# `Tapioca::Compilers::Dsl::ActiveJob` generates RBI files for subclasses of | ||
# [`ActiveJob::Base`](https://api.rubyonrails.org/classes/ActiveJob/Base.html). | ||
# | ||
# For example, with the following `ActiveJob` subclass: | ||
# | ||
# ~~~rb | ||
# class NotifyUserJob < ActiveJob::Base | ||
# def perform(user) | ||
# # ... | ||
# end | ||
# end | ||
# ~~~ | ||
# | ||
# this generator will produce the RBI file `notify_user_job.rbi` with the following content: | ||
# | ||
# ~~~rbi | ||
# # notify_user_job.rbi | ||
# # typed: true | ||
# class NotifyUserJob | ||
# sig { params(user: T.untyped).returns(T.attached_class) } | ||
# def self.perform_later(user); end | ||
# | ||
# sig { params(user: T.untyped).returns(T.attached_class) } | ||
# def self.perform_now(user); end | ||
# end | ||
# ~~~ | ||
class ActiveJob < Base | ||
extend T::Sig | ||
|
||
sig { override.params(root: Parlour::RbiGenerator::Namespace, constant: T.class_of(::ActiveJob::Base)).void } | ||
def decorate(root, constant) | ||
root.path(constant) do |job| | ||
next unless constant.instance_methods(false).include?(:perform) | ||
|
||
method = constant.instance_method(:perform) | ||
parameters = compile_method_parameters_to_parlour(method) | ||
|
||
%w[perform_later perform_now].each do |name| | ||
create_method( | ||
job, | ||
name, | ||
parameters: parameters, | ||
return_type: "T.attached_class", | ||
class_method: true | ||
) | ||
end | ||
end | ||
end | ||
|
||
sig { override.returns(T::Enumerable[Module]) } | ||
def gather_constants | ||
::ActiveJob::Base.descendants | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
## ActiveJob | ||
|
||
`Tapioca::Compilers::Dsl::ActiveJob` generates RBI files for subclasses of | ||
[`ActiveJob::Base`](https://api.rubyonrails.org/classes/ActiveJob/Base.html). | ||
|
||
For example, with the following `ActiveJob` subclass: | ||
|
||
~~~rb | ||
class NotifyUserJob < ActiveJob::Base | ||
def perform(user) | ||
# ... | ||
end | ||
end | ||
~~~ | ||
|
||
this generator will produce the RBI file `notify_user_job.rbi` with the following content: | ||
|
||
~~~rbi | ||
# notify_user_job.rbi | ||
# typed: true | ||
class NotifyUserJob | ||
sig { params(user: T.untyped).returns(T.attached_class) } | ||
def self.perform_later(user); end | ||
|
||
sig { params(user: T.untyped).returns(T.attached_class) } | ||
def self.perform_now(user); end | ||
end | ||
~~~ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
require "spec_helper" | ||
|
||
class Tapioca::Compilers::Dsl::ActiveJobSpec < DslSpec | ||
describe("#initialize") do | ||
it("gathers no constants if there are no ActiveJob subclasses") do | ||
assert_empty(gathered_constants) | ||
end | ||
|
||
it("gathers only ActiveJob subclasses") do | ||
add_ruby_file("content.rb", <<~RUBY) | ||
class NotifyJob < ActiveJob::Base | ||
end | ||
class User | ||
end | ||
RUBY | ||
|
||
assert_equal(["NotifyJob"], gathered_constants) | ||
end | ||
|
||
it("gathers subclasses of ActiveJob subclasses") do | ||
add_ruby_file("content.rb", <<~RUBY) | ||
class NotifyJob < ActiveJob::Base | ||
end | ||
class SecondaryNotifyJob < NotifyJob | ||
end | ||
RUBY | ||
|
||
assert_equal(["NotifyJob", "SecondaryNotifyJob"], gathered_constants) | ||
end | ||
end | ||
|
||
describe("#decorate") do | ||
it("generates empty RBI file if there is no perform method") do | ||
add_ruby_file("job.rb", <<~RUBY) | ||
class NotifyJob < ActiveJob::Base | ||
end | ||
RUBY | ||
|
||
expected = <<~RBI | ||
# typed: strong | ||
class NotifyJob | ||
end | ||
RBI | ||
|
||
assert_equal(expected, rbi_for(:NotifyJob)) | ||
end | ||
|
||
it("generates correct RBI file for subclass with methods") do | ||
add_ruby_file("job.rb", <<~RUBY) | ||
class NotifyJob < ActiveJob::Base | ||
def perform(user_id) | ||
# ... | ||
end | ||
end | ||
RUBY | ||
|
||
expected = <<~RBI | ||
# typed: strong | ||
class NotifyJob | ||
sig { params(user_id: T.untyped).returns(T.attached_class) } | ||
def self.perform_later(user_id); end | ||
sig { params(user_id: T.untyped).returns(T.attached_class) } | ||
def self.perform_now(user_id); end | ||
end | ||
RBI | ||
|
||
assert_equal(expected, rbi_for(:NotifyJob)) | ||
end | ||
|
||
it("generates correct RBI file for subclass with method signatures") do | ||
add_ruby_file("job.rb", <<~RUBY) | ||
class NotifyJob < ActiveJob::Base | ||
extend T::Sig | ||
sig { params(user_id: Integer).void } | ||
def perform(user_id) | ||
# ... | ||
end | ||
end | ||
RUBY | ||
|
||
expected = <<~RBI | ||
# typed: strong | ||
class NotifyJob | ||
sig { params(user_id: Integer).returns(T.attached_class) } | ||
def self.perform_later(user_id); end | ||
sig { params(user_id: Integer).returns(T.attached_class) } | ||
def self.perform_now(user_id); end | ||
end | ||
RBI | ||
|
||
assert_equal(expected, rbi_for(:NotifyJob)) | ||
end | ||
end | ||
end |