Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for ActiveSupport classes in Sidekiq::Worker methods #2104

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 17 additions & 2 deletions lib/tapioca/dsl/compilers/sidekiq_worker.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ module Compilers
# def self.perform_in(interval, customer_id); end
# end
# ~~~
#
# If your project uses `ActiveSupport` as well, then the compiler will automatically add its classes
# as accepted values for the `interval` parameter:
# * `self.perform_at` will also accept a `ActiveSupport::TimeWithZone` value
# * `self.perform_in` will also accept a `ActiveSupport::Duration` value
class SidekiqWorker < Compiler
extend T::Sig

Expand All @@ -53,12 +58,22 @@ def decorate
# `perform_at` and is just an alias for `perform_in` so both methods technically
# accept a datetime, time, or numeric but we're typing them differently so they
# semantically make sense.
at_return_type = if defined?(ActiveSupport::TimeWithZone)
"T.any(DateTime, Time, ActiveSupport::TimeWithZone)"
else
"T.any(DateTime, Time)"
end
at_params = [
create_param("interval", type: "T.any(DateTime, Time)"),
create_param("interval", type: at_return_type),
*async_params,
]
in_return_type = if defined?(ActiveSupport::Duration)
"T.any(Numeric, ActiveSupport::Duration)"
else
"Numeric"
end
in_params = [
create_param("interval", type: "Numeric"),
create_param("interval", type: in_return_type),
*async_params,
]

Expand Down
5 changes: 5 additions & 0 deletions manual/compiler_sidekiqworker.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,8 @@ class NotifierWorker
def self.perform_in(interval, customer_id); end
end
~~~

If your project uses `ActiveSupport` as well, then the compiler will automatically add its classes
as accepted values for the `interval` parameter:
* `self.perform_at` will also accept a `ActiveSupport::TimeWithZone` value
* `self.perform_in` will also accept a `ActiveSupport::Duration` value
45 changes: 45 additions & 0 deletions spec/tapioca/dsl/compilers/sidekiq_worker_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,22 @@ module Tapioca
module Dsl
module Compilers
class SidekiqWorkerSpec < ::DslSpec
include Tapioca::Helpers::Test::Isolation

describe "Tapioca::Dsl::Compilers::SidekiqWorker" do
sig { void }
def before_setup
require "sidekiq"
# We need to undefine and unload `ActiveSupport` so that the test object
# space is as clean as possible.
#
# This is inside a `before` block instead of a `before(:all)` block because
# it looks like `before(:all)` blocks run in the parent process, but we don't
# want to mess with the object space of the parent process.
if defined?(::ActiveSupport)
Object.send(:remove_const, :ActiveSupport) # rubocop:disable RSpec/RemoveConst
$LOADED_FEATURES.delete_if { |path| path.include?("active_support") }
end
end

describe "initialize" do
Expand Down Expand Up @@ -80,6 +92,39 @@ def perform_in(interval, customer_id); end
assert_equal(expected, rbi_for(:NotifierWorker))
end

it "generates correct RBI file for class with perform method when ActiveSupport is defined" do
add_ruby_file("mailer.rb", <<~RUBY)
require "active_support"
require "active_support/time_with_zone"

class NotifierWorker
include Sidekiq::Worker
def perform(customer_id)
# ...
end
end
RUBY

expected = <<~RBI
# typed: strong

class NotifierWorker
class << self
sig { params(customer_id: T.untyped).returns(String) }
def perform_async(customer_id); end

sig { params(interval: T.any(DateTime, Time, ActiveSupport::TimeWithZone), customer_id: T.untyped).returns(String) }
def perform_at(interval, customer_id); end

sig { params(interval: T.any(Numeric, ActiveSupport::Duration), customer_id: T.untyped).returns(String) }
def perform_in(interval, customer_id); end
end
end
RBI

assert_equal(expected, rbi_for(:NotifierWorker))
end

it "generates correct RBI file for class with perform method with signature" do
add_ruby_file("mailer.rb", <<~RUBY)
class NotifierWorker
Expand Down
Loading