diff --git a/Gemfile b/Gemfile index b675eef4..0dd4c42c 100644 --- a/Gemfile +++ b/Gemfile @@ -23,3 +23,6 @@ gem 'mocha' gem 'rubocop', '~> 0.77.0' gem 'yard' gem 'rake' + +# for unit testing optional sorbet support +gem 'sorbet-runtime' diff --git a/lib/job-iteration/iteration.rb b/lib/job-iteration/iteration.rb index 83862da3..b53fc749 100644 --- a/lib/job-iteration/iteration.rb +++ b/lib/job-iteration/iteration.rb @@ -176,7 +176,7 @@ def assert_implements_methods! end if respond_to?(:build_enumerator, true) - parameters = method(:build_enumerator).parameters + parameters = method_parameters(:build_enumerator) unless valid_cursor_parameter?(parameters) raise ArgumentError, "Iteration job (#{self.class}) #build_enumerator " \ "expects the keyword argument `cursor`" @@ -187,6 +187,17 @@ def assert_implements_methods! end end + def method_parameters(method_name) + method = method(method_name) + + if defined?(T::Private::Methods) + signature = T::Private::Methods.signature_for_method(method) + method = signature.method if signature + end + + method.parameters + end + def iteration_instrumentation_tags { job_class: self.class.name } end diff --git a/test/unit/iteration_test.rb b/test/unit/iteration_test.rb index 3a810c57..7668a3a5 100644 --- a/test/unit/iteration_test.rb +++ b/test/unit/iteration_test.rb @@ -1,6 +1,7 @@ # frozen_string_literal: true require "test_helper" +require "sorbet-runtime" class JobIterationTest < IterationUnitTest class JobWithNoMethods < ActiveJob::Base @@ -17,6 +18,20 @@ def each_iteration(*) end end + class JobWithRightMethodsButWithSorbetSignatures < ActiveJob::Base + extend T::Sig + include JobIteration::Iteration + + sig { params(_params: T.untyped, cursor: T.untyped).returns(T::Enumerator[T.untyped]) } + def build_enumerator(_params, cursor:) + enumerator_builder.build_times_enumerator(2, cursor: cursor) + end + + sig { params(product: T.untyped, params: T.untyped).void } + def each_iteration(product, params) + end + end + class JobWithRightMethodsButMissingCursorKeywordArgument < ActiveJob::Base include JobIteration::Iteration def build_enumerator(params, cursor) @@ -53,6 +68,11 @@ def test_jobs_that_define_build_enumerator_and_each_iteration_will_not_raise work_one_job end + def test_jobs_that_define_build_enumerator_and_each_iteration_with_sigs_will_not_raise + push(JobWithRightMethodsButWithSorbetSignatures, 'walrus' => 'best') + work_one_job + end + def test_jobs_that_pass_splat_argument_to_build_enumerator_will_not_raise push(JobWithRightMethodsUsingSplatInTheArguments, {}) work_one_job