Skip RBS rewriter when file does not contain RBS syntax#917
Conversation
82e90b7 to
07a9394
Compare
| RB | ||
| end | ||
|
|
||
| def test_should_rewrite_returns_true_for_supported_typed_sigils |
There was a problem hiding this comment.
Two more cases to test:
-
Don't trigger if
# typed: trueexists later in the file. This is unlikely, but it's a performance improvement to ensure we're not scanning through the whole file -
Trigger if there's multiple magic comments, but
typedisn't first:# frozen_string_literal: true # typed: true
There was a problem hiding this comment.
Don't trigger if # typed: true exists later in the file
Good call! I updated to only check for the typed marker in the magic comments block
07a9394 to
47118ab
Compare
cf00c3f to
d3125ac
Compare
| next if new_contents == contents | ||
|
|
||
| File.write(file, new_contents) | ||
| transformed_count += 1 |
There was a problem hiding this comment.
This will only count changed files in the Translated signatures in <x> files. message, but I'm happy to drop the commit if we want to leave as is
When a file is not typed or contains no RBS comment syntax, we can skip running the RBS rewriter on it Co-authored-by: Matt Kubej <matt.kubej@shopify.com>
d3125ac to
f25aa67
Compare
| class RBSCommentsToSorbetSigs < Translator | ||
| include Spoom::RBS::ExtractRBSComments | ||
|
|
||
| magic_comments = /\A(?:\s*#[^\n]*\n)*/ |
There was a problem hiding this comment.
Grabs the magic comments block, considered here as everything up until the first non-comment, non-empty line
paracycle
left a comment
There was a problem hiding this comment.
Shouldn't all this logic be encapsulated inside the RBSCommentsToSorbetSigs class, which already stores the ruby_contents as an ivar, and wouldn't need to pass it to a should_rewrite? method. The downside is just an extra object allocation only to return the same contents, but I think that's fine.
| #: (String source) -> bool | ||
| def should_rewrite?(source) | ||
| source.match?(TYPED_FILE_PATTERN) && source.match?(RBS_REWRITE_PATTERN) | ||
| end |
There was a problem hiding this comment.
To what Ufuk was saying, maybe we can add a rewrite class method:
| end | |
| end | |
| #: (String ruby_contents, file: String, ?max_line_length: Integer?) -> String | |
| def rewrite(ruby_contents, file:, max_line_length: nil) | |
| # fast path, skip parsing/visiting if there's no RBS syntax at all | |
| return ruby_contents if should_rewrite?(ruby_contents) | |
| new(ruby_contents, file:, max_line_length:).rewrite | |
| end |
amomchilov
left a comment
There was a problem hiding this comment.
Few small points, but it's shaping up!
| "# @overridable", | ||
| "# @without_runtime", | ||
| ].freeze #: Array[String] | ||
| RBS_REWRITE_PATTERN = Regexp.union(["#:", "#|"] + RBS_ANNOTATION_MARKERS).freeze #: Regexp |
There was a problem hiding this comment.
tiny opt:
| RBS_REWRITE_PATTERN = Regexp.union(["#:", "#|"] + RBS_ANNOTATION_MARKERS).freeze #: Regexp | |
| RBS_REWRITE_PATTERN = Regexp.union(["#:", "#|", *RBS_ANNOTATION_MARKERS]).freeze #: Regexp |
Spares one allocation :)
require "bundler/inline"
gemfile do
source "https://rubygems.org"
gem "benchmark-memory"
end
a = [3, 4, 5]
Benchmark.memory do |x|
x.report(" +") { [1, 2] + a }
x.report("splat") { [1, 2, *a] }
x.compare!
end
# Calculating -------------
# + 120.000 memsize
# 2.000 objects
# splat 208.000 memsize
# 1.000 objects|
|
||
| class << self | ||
| #: (String source) -> bool | ||
| def should_rewrite?(source) |
There was a problem hiding this comment.
if this is going to be public API, perhaps contains_rbs_syntax? would be more clear to callers
| end | ||
| end | ||
|
|
||
| def test_calls_new_for_files_with_rbs_syntax |
There was a problem hiding this comment.
eh, I don't think this is a useful test. it's implied from the other more end-to-endy tests.
| #{marker} | ||
| class Foo; end | ||
| RB | ||
| marker, |
There was a problem hiding this comment.
| marker, | |
| "#should_rewrite? should return true for files containing #{marker}", |
| "# @sealed", | ||
| "# @final", | ||
| "# @requires_ancestor:", | ||
| "# @override", |
There was a problem hiding this comment.
I think you can just move these here and remove the next test
| "# @override", | |
| "# @override", | |
| "# @override(allow_incompatible: true)", | |
| "# @override(allow_incompatible: false)", | |
| "# @override(allow_incompatible: :visibility)", |
| end | ||
| end | ||
|
|
||
| def test_should_rewrite_returns_false_for_files_without_rbs_syntax |
There was a problem hiding this comment.
Can you please reorder these, so related tests are better grouped together?
E.g. the def test_should_rewrite_returns_false_when_the_file_is_not_typed should be in this area, where the other test_should_rewrite_returns_false_for_ tests are
| end | ||
| end | ||
|
|
||
| Spoom::Sorbet::Translate::RBSCommentsToSorbetSigs::RBS_ANNOTATION_MARKERS = T.let(T.unsafe(nil), Array) |
There was a problem hiding this comment.
Let's mark these with private_constant where they're defined, so we don't expose them to the public.
If a file does not contain typed file markers (ex
# typed: true) or RBS syntax we can skip attempting to translate it. If a file has not been rewritten we can exclude it from the count of translated files