Skip to content

Commit 14f083a

Browse files
committed
Do not update RBS file if the signature nothing changed
At present, steep detect the file change via its timestamp. To avoid unnecessary type check, this adds FileWriter class which updates the RBS file only if its content has changed. ref: pocke/rbs_rails#346
1 parent 640be1d commit 14f083a

File tree

5 files changed

+110
-3
lines changed

5 files changed

+110
-3
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
"readlines",
2323
"rmtree",
2424
"rubocop",
25-
"Takeshi"
25+
"Takeshi",
26+
"utime"
2627
],
2728
"rbs-helper.rbs-inline-on-save": true,
2829
"rbs-helper.rbs-inline-signature-directory": "sig/"

lib/ruby_lsp/rbs_rails/addon.rb

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
require "language_server-protocol"
44
require "ruby_lsp/addon"
55

6+
require_relative "file_writer"
67
require_relative "logger"
78

89
module RubyLsp
@@ -125,7 +126,7 @@ def generate_path_helpers_signature #: void
125126
rbs_path.dirname.mkpath
126127

127128
sig = ::RbsRails::PathHelpers.generate
128-
rbs_path.write sig
129+
FileWriter.new(rbs_path).write sig
129130
logger.info("Updated RBS signature: #{rbs_path}")
130131
end
131132

@@ -139,7 +140,7 @@ def generate_signature0(klass) #: void
139140
rbs_path.dirname.mkpath
140141

141142
sig = ::RbsRails::ActiveRecord.class_to_rbs(klass)
142-
rbs_path.write sig
143+
FileWriter.new(rbs_path).write sig
143144
logger.info("Updated RBS signature: #{rbs_path}")
144145
end
145146

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# frozen_string_literal: true
2+
3+
module RubyLsp
4+
module RbsRails
5+
# To avoid unnecessary type reloading by type checkers and other utilities,
6+
# FileWriter modifies the target file only if its content has been changed.
7+
#
8+
# See https://github.com/pocke/rbs_rails/pull/346
9+
class FileWriter
10+
attr_reader :path #: Pathname
11+
12+
# @rbs path: Pathname
13+
def initialize(path) #: void
14+
@path = path
15+
end
16+
17+
def write(content) #: void
18+
original_content = begin
19+
path.read
20+
rescue StandardError
21+
nil
22+
end
23+
24+
return unless original_content != content
25+
26+
path.write(content)
27+
end
28+
end
29+
end
30+
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# Generated from lib/ruby_lsp/rbs_rails/file_writer.rb with RBS::Inline
2+
3+
module RubyLsp
4+
module RbsRails
5+
# To avoid unnecessary type reloading by type checkers and other utilities,
6+
# FileWriter modifies the target file only if its content has been changed.
7+
#
8+
# See https://github.com/pocke/rbs_rails/pull/346
9+
class FileWriter
10+
attr_reader path: Pathname
11+
12+
# @rbs path: Pathname
13+
def initialize: (Pathname path) -> void
14+
15+
def write: (untyped content) -> void
16+
end
17+
end
18+
end

spec/rbs_rails/file_writer_spec.rb

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
RSpec.describe RubyLsp::RbsRails::FileWriter do
2+
describe "#write" do
3+
subject { file_writer.write(content) }
4+
5+
after do
6+
tmpdir.rmtree
7+
end
8+
9+
let(:file_writer) { RubyLsp::RbsRails::FileWriter.new(path) }
10+
let(:path) { tmpdir / "test_file.rbs" }
11+
let(:tmpdir) { Pathname.new(Dir.mktmpdir("file_writer_test")) }
12+
13+
context "when the file does not exist" do
14+
it "creates the file with the given content" do
15+
expect(path).not_to exist
16+
17+
file_writer.write("class NewClass; end")
18+
19+
expect(path).to exist
20+
expect(path.read).to eq("class NewClass; end")
21+
end
22+
end
23+
24+
context "when the file exists" do
25+
before do
26+
path.write(old_content)
27+
end
28+
29+
let(:old_content) { "class ExistingClass; end" }
30+
31+
context "when the content is different" do
32+
it "updates the file with the new content" do
33+
file_writer.write("class NewClass; end")
34+
35+
expect(path).to exist
36+
expect(path.read).to eq("class NewClass; end")
37+
end
38+
end
39+
40+
context "when the content is the same" do
41+
before do
42+
path.utime(mtime, mtime)
43+
end
44+
45+
let(:mtime) { Time.now - 60 }
46+
47+
it "does not modify the file" do
48+
file_writer.write(old_content)
49+
50+
expect(path).to exist
51+
expect(path.read).to eq(old_content)
52+
expect(path.mtime).to eq(mtime)
53+
end
54+
end
55+
end
56+
end
57+
end

0 commit comments

Comments
 (0)