From 29590174abae9eeade0c2986c8dcf967630f3e34 Mon Sep 17 00:00:00 2001 From: Takeshi KOMIYA Date: Sun, 31 Aug 2025 12:59:36 +0900 Subject: [PATCH] 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. --- lib/rbs_rails/cli.rb | 4 +- lib/rbs_rails/util.rb | 2 + lib/rbs_rails/util/file_writer.rb | 22 +++++++++++ sig/rbs_rails/util/file_writer.rbs | 16 ++++++++ sig/rbs_rails/utils/file_writer.rbs | 4 ++ test/rbs_rails/util/file_writer_test.rb | 49 +++++++++++++++++++++++++ 6 files changed, 95 insertions(+), 2 deletions(-) create mode 100644 lib/rbs_rails/util/file_writer.rb create mode 100644 sig/rbs_rails/util/file_writer.rbs create mode 100644 sig/rbs_rails/utils/file_writer.rbs create mode 100644 test/rbs_rails/util/file_writer_test.rb diff --git a/lib/rbs_rails/cli.rb b/lib/rbs_rails/cli.rb index 952ae726..b0d2bbdc 100644 --- a/lib/rbs_rails/cli.rb +++ b/lib/rbs_rails/cli.rb @@ -126,7 +126,7 @@ def generate_single_model(klass, dep_builder) #: bool path.dirname.mkpath sig = RbsRails::ActiveRecord.class_to_rbs(klass, dependencies: dep_builder.deps) - path.write sig + Util::FileWriter.new(path).write sig dep_builder.done << klass.name true @@ -137,7 +137,7 @@ def generate_path_helpers #: void path.dirname.mkpath sig = RbsRails::PathHelpers.generate - path.write sig + Util::FileWriter.new(path).write sig end def create_option_parser #: OptionParser diff --git a/lib/rbs_rails/util.rb b/lib/rbs_rails/util.rb index b6b6509c..24979c77 100644 --- a/lib/rbs_rails/util.rb +++ b/lib/rbs_rails/util.rb @@ -1,3 +1,5 @@ +require_relative 'util/file_writer' + module RbsRails module Util MODULE_NAME = Module.instance_method(:name) #: UnboundMethod diff --git a/lib/rbs_rails/util/file_writer.rb b/lib/rbs_rails/util/file_writer.rb new file mode 100644 index 00000000..e6e3c4a0 --- /dev/null +++ b/lib/rbs_rails/util/file_writer.rb @@ -0,0 +1,22 @@ +module RbsRails + module Util + # To avoid unnecessary type reloading by type checkers and other utilities, + # FileWriter modifies the target file only if its content has been changed. + class FileWriter + attr_reader :path #: Pathname + + # @rbs path: Pathname + def initialize(path) #: void + @path = path + end + + def write(content) #: void + original_content = path.read rescue nil + + if original_content != content + path.write(content) + end + end + end + end +end diff --git a/sig/rbs_rails/util/file_writer.rbs b/sig/rbs_rails/util/file_writer.rbs new file mode 100644 index 00000000..89bf12a3 --- /dev/null +++ b/sig/rbs_rails/util/file_writer.rbs @@ -0,0 +1,16 @@ +# Generated from lib/rbs_rails/util/file_writer.rb with RBS::Inline + +module RbsRails + module Util + # To avoid unnecessary type reloading by type checkers and other utilities, + # FileWriter modifies the target file only if its content has been changed. + class FileWriter + attr_reader path: Pathname + + # @rbs path: Pathname + def initialize: (Pathname path) -> void + + def write: (untyped content) -> void + end + end +end diff --git a/sig/rbs_rails/utils/file_writer.rbs b/sig/rbs_rails/utils/file_writer.rbs new file mode 100644 index 00000000..0a3ce7d2 --- /dev/null +++ b/sig/rbs_rails/utils/file_writer.rbs @@ -0,0 +1,4 @@ +# Generated from lib/rbs_rails/utils/file_writer.rb with RBS::Inline + +module RbsRails +end diff --git a/test/rbs_rails/util/file_writer_test.rb b/test/rbs_rails/util/file_writer_test.rb new file mode 100644 index 00000000..4c523636 --- /dev/null +++ b/test/rbs_rails/util/file_writer_test.rb @@ -0,0 +1,49 @@ +require 'test_helper' +require 'tmpdir' +require_relative '../../../lib/rbs_rails/util/file_writer' + +class FileWriterTest < Minitest::Test + def setup + @temp_dir = Pathname.new(Dir.mktmpdir('file_writer_test')) + end + + def teardown + FileUtils.rm_rf(@temp_dir) if @temp_dir + end + + def test_write_on_file_not_found + file_path = @temp_dir / 'non_existent_file.rbs' + file_writer = RbsRails::Util::FileWriter.new(file_path) + + file_writer.write("content") + + assert file_path.exist? + assert_equal "content", file_path.read + end + + def test_write_on_changed + file_path = @temp_dir / 'test_file.rbs' + file_path.write("old content") + + file_writer = RbsRails::Util::FileWriter.new(file_path) + + file_writer.write("new content") + + assert_equal "new content", file_path.read + end + + def test_write_on_not_changed + content = "unchanged content" + mtime = Time.now - 10 + + file_path = @temp_dir / 'test_file.rbs' + file_path.write(content) + file_path.utime(mtime, mtime) + + file_writer = RbsRails::Util::FileWriter.new(file_path) + file_writer.write(content) + + assert_equal content, file_path.read + assert_equal mtime, file_path.mtime + end +end