Skip to content

Commit beef547

Browse files
authored
Merge pull request #538 from Shopify/add-nil-default-value-to-nilable-parameters
[Tapioca compiler] Add nil default value to nilable parameters
2 parents 6e0dcb3 + e42450c commit beef547

File tree

2 files changed

+60
-5
lines changed

2 files changed

+60
-5
lines changed

lib/tapioca/dsl/compilers/job_iteration.rb

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,15 @@ class JobIteration < Compiler
1010
extend T::Sig
1111

1212
ConstantType = type_member { { fixed: T.class_of(::JobIteration::Iteration) } }
13+
PARAM_TYPES_IN_ORDER = [
14+
RBI::Param,
15+
RBI::OptParam,
16+
RBI::RestParam,
17+
RBI::KwParam,
18+
RBI::KwOptParam,
19+
RBI::KwRestParam,
20+
RBI::BlockParam,
21+
].freeze
1322

1423
sig { override.void }
1524
def decorate
@@ -29,7 +38,11 @@ def decorate
2938
expanded_parameters = parameters.flat_map do |typed_param|
3039
if (hash_type = fixed_hash_args[typed_param.param.name.to_sym])
3140
hash_type.types.map do |key, value|
32-
create_kw_param(key.to_s, type: value.to_s)
41+
if value.name.start_with?("T.nilable")
42+
create_kw_opt_param(key.to_s, type: value.to_s, default: "nil")
43+
else
44+
create_kw_param(key.to_s, type: value.to_s)
45+
end
3346
end
3447
else
3548
typed_param
@@ -39,6 +52,9 @@ def decorate
3952
expanded_parameters = parameters
4053
end
4154

55+
# Sorbet expects optional keyword arguments to be after required keyword arguments.
56+
expanded_parameters.sort_by! { |typed_param| PARAM_TYPES_IN_ORDER.index(typed_param.param.class) }
57+
4258
job.create_method(
4359
"perform_later",
4460
parameters: perform_later_parameters(expanded_parameters, constant_name),

test/tapioca/dsl/compilers/job_iteration_test.rb

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,45 @@ def perform_now(user_id:, name:); end
271271
assert_equal(expected, rbi_for(:NotifyJob))
272272
end
273273

274+
def test_generates_nil_default_value_for_nilable_parameters
275+
add_ruby_file("job.rb", <<~RUBY)
276+
class NotifyJob < ActiveJob::Base
277+
include JobIteration::Iteration
278+
279+
Params = T.type_alias { { user_id: T.nilable(Integer), name: String } }
280+
281+
extend T::Sig
282+
sig { params(params: Params, cursor: T.untyped).returns(T::Array[T.untyped]) }
283+
def build_enumerator(params, cursor:)
284+
# ...
285+
end
286+
end
287+
RUBY
288+
289+
expected = template(<<~RBI)
290+
# typed: strong
291+
292+
class NotifyJob
293+
sig { params(name: ::String, user_id: T.nilable(::Integer)).void }
294+
def perform(name:, user_id: nil); end
295+
296+
class << self
297+
<% if rails_version(">= 7.0") %>
298+
sig { params(name: ::String, user_id: T.nilable(::Integer), block: T.nilable(T.proc.params(job: NotifyJob).void)).returns(T.any(NotifyJob, FalseClass)) }
299+
def perform_later(name:, user_id: nil, &block); end
300+
<% else %>
301+
sig { params(name: ::String, user_id: T.nilable(::Integer)).returns(T.any(NotifyJob, FalseClass)) }
302+
def perform_later(name:, user_id: nil); end
303+
<% end %>
304+
305+
sig { params(name: ::String, user_id: T.nilable(::Integer)).returns(T.any(NilClass, Exception)) }
306+
def perform_now(name:, user_id: nil); end
307+
end
308+
end
309+
RBI
310+
assert_equal(expected, rbi_for(:NotifyJob))
311+
end
312+
274313
def test_generates_correct_rbi_file_for_job_with_build_enumerator_method_with_nested_hash_parameter
275314
add_ruby_file("job.rb", <<~RUBY)
276315
class ResourceType; end
@@ -297,19 +336,19 @@ def build_enumerator(params, cursor:)
297336
298337
class NotifyJob
299338
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).void }
300-
def perform(shop_id:, resource_types:, locale:, metadata:); end
339+
def perform(shop_id:, resource_types:, locale:, metadata: nil); end
301340
302341
class << self
303342
<% if rails_version(">= 7.0") %>
304343
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)) }
305-
def perform_later(shop_id:, resource_types:, locale:, metadata:, &block); end
344+
def perform_later(shop_id:, resource_types:, locale:, metadata: nil, &block); end
306345
<% else %>
307346
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).returns(T.any(NotifyJob, FalseClass)) }
308-
def perform_later(shop_id:, resource_types:, locale:, metadata:); end
347+
def perform_later(shop_id:, resource_types:, locale:, metadata: nil); end
309348
<% end %>
310349
311350
sig { params(shop_id: ::Integer, resource_types: T::Array[::ResourceType], locale: ::Locale, metadata: T.nilable(::String)).returns(T.any(NilClass, Exception)) }
312-
def perform_now(shop_id:, resource_types:, locale:, metadata:); end
351+
def perform_now(shop_id:, resource_types:, locale:, metadata: nil); end
313352
end
314353
end
315354
RBI

0 commit comments

Comments
 (0)