From c10907df58018dced5769cf6edbb432c08a30b52 Mon Sep 17 00:00:00 2001 From: Vinicius Stock Date: Tue, 23 Jun 2026 12:11:09 -0400 Subject: [PATCH] Allow skipping abstract method translation --- lib/spoom/rbs.rb | 7 +- .../base_translator.rb | 2 + .../rbs_comments_to_sorbet_sigs/options.rb | 8 +- rbi/spoom.rbi | 14 +++- .../rbs_comments_to_sorbet_sigs_test.rb | 82 ++++++++++++++++++- 5 files changed, 104 insertions(+), 9 deletions(-) diff --git a/lib/spoom/rbs.rb b/lib/spoom/rbs.rb index 7ba02e67..44ee94a5 100644 --- a/lib/spoom/rbs.rb +++ b/lib/spoom/rbs.rb @@ -68,7 +68,12 @@ def initialize(string, location) end end - class Annotation < Comment; end + class Annotation < Comment + #: () -> bool + def abstract? + @string == "@abstract" + end + end class Signature < Comment # Locations of the `#|` continuation comment lines that make up a multiline signature, diff --git a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/base_translator.rb b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/base_translator.rb index a036dc97..fc00498b 100644 --- a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/base_translator.rb +++ b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/base_translator.rb @@ -25,6 +25,7 @@ def initialize( end #: Integer? @overloads_strategy = options.overloads_strategy #: Symbol + @translate_abstract_methods = options.translate_abstract_methods #: bool @type_translator = RBI::RBS::TypeTranslator.new #: RBI::RBS::TypeTranslator end @@ -141,6 +142,7 @@ def visit_attr(node) def rewrite_def(def_node, comments) return if comments.empty? return if comments.signatures.empty? + return if !@translate_abstract_methods && comments.method_annotations.any?(&:abstract?) signatures = apply_overloads_strategy( comments.signatures, diff --git a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/options.rb b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/options.rb index e3a0c773..7e2a696a 100644 --- a/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/options.rb +++ b/lib/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs/options.rb @@ -47,13 +47,18 @@ class Options #: BaseRBIFormat attr_reader :output_format + #: bool + attr_reader :translate_abstract_methods + #: ( #| ?overloads_strategy: Symbol, #| ?output_format: BaseRBIFormat, + #| ?translate_abstract_methods: bool, #| ) -> void def initialize( overloads_strategy: :translate_all, - output_format: HumanReadableRBIFormat.default + output_format: HumanReadableRBIFormat.default, + translate_abstract_methods: true ) unless ALLOWED_OVERLOAD_STRATEGIES.include?(overloads_strategy) raise ArgumentError, "Unknown overloads_strategy: #{overloads_strategy.inspect}. " \ @@ -62,6 +67,7 @@ def initialize( @overloads_strategy = overloads_strategy @output_format = output_format + @translate_abstract_methods = translate_abstract_methods freeze end diff --git a/rbi/spoom.rbi b/rbi/spoom.rbi index 28155c41..254e5f03 100644 --- a/rbi/spoom.rbi +++ b/rbi/spoom.rbi @@ -2578,7 +2578,11 @@ end module Spoom::PrismTypes; end Spoom::PrismTypes::AnyScopeNode = T.type_alias { T.any(::Prism::ClassNode, ::Prism::ModuleNode, ::Prism::SingletonClassNode) } module Spoom::RBS; end -class Spoom::RBS::Annotation < ::Spoom::RBS::Comment; end + +class Spoom::RBS::Annotation < ::Spoom::RBS::Comment + sig { returns(T::Boolean) } + def abstract?; end +end class Spoom::RBS::Comment sig { params(string: ::String, location: ::Prism::Location).void } @@ -3209,10 +3213,11 @@ class Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::Options sig do params( overloads_strategy: ::Symbol, - output_format: ::Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::BaseRBIFormat + output_format: ::Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::BaseRBIFormat, + translate_abstract_methods: T::Boolean ).void end - def initialize(overloads_strategy: T.unsafe(nil), output_format: T.unsafe(nil)); end + def initialize(overloads_strategy: T.unsafe(nil), output_format: T.unsafe(nil), translate_abstract_methods: T.unsafe(nil)); end sig { returns(::Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::BaseRBIFormat) } def output_format; end @@ -3220,6 +3225,9 @@ class Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::Options sig { returns(::Symbol) } def overloads_strategy; end + sig { returns(T::Boolean) } + def translate_abstract_methods; end + class << self sig { returns(::Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::Options) } def default; end diff --git a/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb b/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb index 3afa852b..398c08a5 100644 --- a/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb +++ b/test/spoom/sorbet/translate/rbs_comments_to_sorbet_sigs_test.rb @@ -147,6 +147,66 @@ def bar; end ) end + def test_translate_to_rbi_skipping_abstract_methods + assert_rewrites_rbs( + from: <<~RUBY, + # @abstract + class Foo + # @abstract + #: -> String + def bar; end + end + + # @abstract + module Baz + # @abstract + #: -> String + def qux; end + end + RUBY + + to_pretty_format_for_humans: <<~RUBY, + class Foo + extend T::Helpers + + abstract! + + # @abstract + #: -> String + def bar; end + end + + module Baz + extend T::Helpers + + abstract! + + # @abstract + #: -> String + def qux; end + end + RUBY + + to_line_matched_format_for_machines: <<~RUBY, + # RBS_REWRITTEN_ANNOTATION: @abstract + class Foo; extend T::Helpers; abstract! + # @abstract + #: -> String + def bar; end + end + + # RBS_REWRITTEN_ANNOTATION: @abstract + module Baz; extend T::Helpers; abstract! + # @abstract + #: -> String + def qux; end + end + RUBY + + translate_abstract_methods: false, + ) + end + def test_translate_to_rbi_method_sigs_without_runtime assert_rewrites_rbs( from: <<~RUBY, @@ -1280,13 +1340,23 @@ def foo; end private - #: (String, ?max_line_length: Integer?, ?overloads_strategy: Symbol) -> String - def rbs_comments_to_sorbet_sigs(ruby_contents, max_line_length: nil, overloads_strategy: :translate_all) + #: (String, + #| ?max_line_length: Integer?, + #| ?overloads_strategy: Symbol, + #| ?translate_abstract_methods: bool + #| ) -> String + def rbs_comments_to_sorbet_sigs( + ruby_contents, + max_line_length: nil, + overloads_strategy: :translate_all, + translate_abstract_methods: true + ) RBSCommentsToSorbetSigs::HumanReadableTranslator.new( ruby_contents, file: "test.rb", options: RBSCommentsToSorbetSigs::Options.new( overloads_strategy:, + translate_abstract_methods:, output_format: RBSCommentsToSorbetSigs::HumanReadableRBIFormat.new( max_line_length:, ), @@ -1299,14 +1369,16 @@ def rbs_comments_to_sorbet_sigs(ruby_contents, max_line_length: nil, overloads_s #| to_pretty_format_for_humans: String, #| to_line_matched_format_for_machines: String | Symbol, #| ?max_line_length: Integer?, - #| ?overloads_strategy: Symbol + #| ?overloads_strategy: Symbol, + #| ?translate_abstract_methods: bool #| ) -> void def assert_rewrites_rbs( from:, to_pretty_format_for_humans:, to_line_matched_format_for_machines:, max_line_length: nil, - overloads_strategy: :translate_all + overloads_strategy: :translate_all, + translate_abstract_methods: true ) source_with_rbs = from expected_pretty_format = to_pretty_format_for_humans @@ -1317,6 +1389,7 @@ def assert_rewrites_rbs( source_with_rbs, max_line_length:, overloads_strategy:, + translate_abstract_methods:, ) assert_equal(expected_pretty_format, rewritten_output) @@ -1347,6 +1420,7 @@ def assert_rewrites_rbs( file: "test.rb", options: RBSCommentsToSorbetSigs::Options.new( overloads_strategy:, + translate_abstract_methods:, output_format: RBSCommentsToSorbetSigs::LineMatchedRBIFormat.default, ), ).rewrite