Skip to content

Commit

Permalink
Merge pull request #538 from Shopify/add-nil-default-value-to-nilable…
Browse files Browse the repository at this point in the history
…-parameters

[Tapioca compiler] Add nil default value to nilable parameters
  • Loading branch information
st0012 authored Jan 28, 2025
2 parents 6e0dcb3 + e42450c commit beef547
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 5 deletions.
18 changes: 17 additions & 1 deletion lib/tapioca/dsl/compilers/job_iteration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,15 @@ class JobIteration < Compiler
extend T::Sig

ConstantType = type_member { { fixed: T.class_of(::JobIteration::Iteration) } }
PARAM_TYPES_IN_ORDER = [
RBI::Param,
RBI::OptParam,
RBI::RestParam,
RBI::KwParam,
RBI::KwOptParam,
RBI::KwRestParam,
RBI::BlockParam,
].freeze

sig { override.void }
def decorate
Expand All @@ -29,7 +38,11 @@ def decorate
expanded_parameters = parameters.flat_map do |typed_param|
if (hash_type = fixed_hash_args[typed_param.param.name.to_sym])
hash_type.types.map do |key, value|
create_kw_param(key.to_s, type: value.to_s)
if value.name.start_with?("T.nilable")
create_kw_opt_param(key.to_s, type: value.to_s, default: "nil")
else
create_kw_param(key.to_s, type: value.to_s)
end
end
else
typed_param
Expand All @@ -39,6 +52,9 @@ def decorate
expanded_parameters = parameters
end

# Sorbet expects optional keyword arguments to be after required keyword arguments.
expanded_parameters.sort_by! { |typed_param| PARAM_TYPES_IN_ORDER.index(typed_param.param.class) }

job.create_method(
"perform_later",
parameters: perform_later_parameters(expanded_parameters, constant_name),
Expand Down
47 changes: 43 additions & 4 deletions test/tapioca/dsl/compilers/job_iteration_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,45 @@ def perform_now(user_id:, name:); end
assert_equal(expected, rbi_for(:NotifyJob))
end

def test_generates_nil_default_value_for_nilable_parameters
add_ruby_file("job.rb", <<~RUBY)
class NotifyJob < ActiveJob::Base
include JobIteration::Iteration
Params = T.type_alias { { user_id: T.nilable(Integer), name: String } }
extend T::Sig
sig { params(params: Params, cursor: T.untyped).returns(T::Array[T.untyped]) }
def build_enumerator(params, cursor:)
# ...
end
end
RUBY

expected = template(<<~RBI)
# typed: strong
class NotifyJob
sig { params(name: ::String, user_id: T.nilable(::Integer)).void }
def perform(name:, user_id: nil); end
class << self
<% if rails_version(">= 7.0") %>
sig { params(name: ::String, user_id: T.nilable(::Integer), block: T.nilable(T.proc.params(job: NotifyJob).void)).returns(T.any(NotifyJob, FalseClass)) }
def perform_later(name:, user_id: nil, &block); end
<% else %>
sig { params(name: ::String, user_id: T.nilable(::Integer)).returns(T.any(NotifyJob, FalseClass)) }
def perform_later(name:, user_id: nil); end
<% end %>
sig { params(name: ::String, user_id: T.nilable(::Integer)).returns(T.any(NilClass, Exception)) }
def perform_now(name:, user_id: nil); end
end
end
RBI
assert_equal(expected, rbi_for(:NotifyJob))
end

def test_generates_correct_rbi_file_for_job_with_build_enumerator_method_with_nested_hash_parameter
add_ruby_file("job.rb", <<~RUBY)
class ResourceType; end
Expand All @@ -297,19 +336,19 @@ def build_enumerator(params, cursor:)
class NotifyJob
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).void }
def perform(shop_id:, resource_types:, locale:, metadata:); end
def perform(shop_id:, resource_types:, locale:, metadata: nil); end
class << self
<% if rails_version(">= 7.0") %>
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String), block: T.nilable(T.proc.params(job: NotifyJob).void)).returns(T.any(NotifyJob, FalseClass)) }
def perform_later(shop_id:, resource_types:, locale:, metadata:, &block); end
def perform_later(shop_id:, resource_types:, locale:, metadata: nil, &block); end
<% else %>
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).returns(T.any(NotifyJob, FalseClass)) }
def perform_later(shop_id:, resource_types:, locale:, metadata:); end
def perform_later(shop_id:, resource_types:, locale:, metadata: nil); end
<% end %>
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).returns(T.any(NilClass, Exception)) }
def perform_now(shop_id:, resource_types:, locale:, metadata:); end
def perform_now(shop_id:, resource_types:, locale:, metadata: nil); end
end
end
RBI
Expand Down

0 comments on commit beef547

Please sign in to comment.