Skip to content

Commit

Permalink
Introduce CLI command to translate RBI sigs to RBS
Browse files Browse the repository at this point in the history
Signed-off-by: Alexandre Terrasa <[email protected]>
  • Loading branch information
Morriar committed Dec 9, 2024
1 parent 8120ec8 commit 1ab57d1
Show file tree
Hide file tree
Showing 3 changed files with 174 additions and 0 deletions.
4 changes: 4 additions & 0 deletions lib/spoom/cli/srb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
require_relative "srb/bump"
require_relative "srb/coverage"
require_relative "srb/lsp"
require_relative "srb/sigs"
require_relative "srb/tc"

module Spoom
Expand All @@ -19,6 +20,9 @@ class Main < Thor
desc "bump", "Change Sorbet sigils from one strictness to another when no errors"
subcommand "bump", Spoom::Cli::Srb::Bump

desc "sigs", "Translate signatures from/to RBI and RBS"
subcommand "sigs", Spoom::Cli::Srb::Sigs

desc "tc", "Run typechecking with advanced options"
subcommand "tc", Spoom::Cli::Srb::Tc
end
Expand Down
59 changes: 59 additions & 0 deletions lib/spoom/cli/srb/sigs.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
# typed: true
# frozen_string_literal: true

require "spoom/sorbet/translate_sigs"

module Spoom
module Cli
module Srb
class Sigs < Thor
include Helper

desc "translate", "Translate signatures from/to RBI and RBS"
option :from, type: :string, aliases: :f, desc: "From format", enum: ["rbi"], default: "rbi"
option :to, type: :string, aliases: :t, desc: "To format", enum: ["rbs"], default: "rbs"
def translate(*paths)
from = options[:from]
to = options[:to]
paths << "." if paths.empty?

files = paths.flat_map do |path|
if File.file?(path)
[path]
else
Dir.glob("#{path}/**/*.rb")
end
end

if files.empty?
say_error("No files to translate")
exit(1)
end

say("Translating signatures from `#{from}` to `#{to}` " \
"in `#{files.size}` file#{files.size == 1 ? "" : "s"}...\n\n")

translated_files = T.let(0, Integer)

files.each do |file|
contents = File.read(file)
contents = Spoom::Sorbet::TranslateSigs.rbi_to_rbs(contents)
File.write(file, contents)
translated_files += 1
rescue RBI::Error => error
say_warning("Can't parse #{file}: #{error.message}")
next
end

say("Translated signatures in `#{translated_files}` file#{translated_files == 1 ? "" : "s"}.")
end

no_commands do
def pluralize(word, count)
count == 1 ? word : "#{word}s"
end
end
end
end
end
end
111 changes: 111 additions & 0 deletions test/spoom/cli/srb/sigs_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# typed: true
# frozen_string_literal: true

require "test_with_project"

module Spoom
module Cli
module Srb
class SigsTest < TestWithProject
def setup
@project.bundle_install!
end

def test_only_supports_translation_from_rbi
result = @project.spoom("srb sigs translate --from rbs")

assert_equal(<<~ERR, result.err)
Expected '--from' to be one of rbi; got rbs
ERR
refute(result.status)
end

def test_only_supports_translation_to_rbs
result = @project.spoom("srb sigs translate --to rbi")

assert_equal(<<~ERR, result.err)
Expected '--to' to be one of rbs; got rbi
ERR
refute(result.status)
end

def test_no_files
result = @project.spoom("srb sigs translate --no-color")

assert_equal(<<~OUT, result.err)
Error: No files to translate
OUT
refute(result.status)
end

def test_only_selected_files
@project.write!("a/file1.rb", <<~RB)
sig { void }
def foo; end
RB

@project.write!("a/file2.rb", <<~RB)
sig { void }
def foo; end
RB

@project.write!("b/file1.rb", <<~RB)
sig { void }
def foo; end
RB

result = @project.spoom("srb sigs translate --no-color a/file1.rb b/")

assert_empty(result.err)
assert_equal(<<~OUT, result.out)
Translating signatures from `rbi` to `rbs` in `2` files...
Translated signatures in `2` files.
OUT
assert(result.status)

assert_equal(<<~RB, @project.read("a/file1.rb"))
#: -> void
def foo; end
RB

assert_equal(<<~RB, @project.read("a/file2.rb"))
sig { void }
def foo; end
RB

assert_equal(<<~RB, @project.read("b/file1.rb"))
#: -> void
def foo; end
RB
end

def test_encoding_support
path = @project.absolute_path_to("file.rb")
File.write(path, <<~RB, encoding: Encoding::ISO8859_1)
# Some content with accentuated characters: éàèù
sig { void }
def foo; end
RB

result = @project.spoom("srb sigs translate --no-color --encoding ISO-8859-1")

assert_empty(result.err)
assert_equal(<<~OUT, result.out)
Translating signatures from `rbi` to `rbs` in `1` file...
Translated signatures in `1` file.
OUT
assert(result.status)

contents = File.read(path, encoding: Encoding::ISO8859_1)
assert_equal(<<~RB.encode(Encoding::ISO8859_1), contents)
# Some content with accentuated characters: éàèù
#: -> void
def foo; end
RB
end
end
end
end
end

0 comments on commit 1ab57d1

Please sign in to comment.