From cd8436ef9b1330801f97fad43917561a326b1d87 Mon Sep 17 00:00:00 2001 From: shimaaaji <221018698+simaaaji@users.noreply.github.com> Date: Fri, 7 Nov 2025 14:51:44 +0900 Subject: [PATCH 1/7] Add rbs-inline gem for Ruby type annotations --- Gemfile | 1 + Gemfile.lock | 6 ++++++ 2 files changed, 7 insertions(+) diff --git a/Gemfile b/Gemfile index 58a7a32..d1a8076 100644 --- a/Gemfile +++ b/Gemfile @@ -10,4 +10,5 @@ gem "rake", "~> 13.0" gem "kramdown", "~> 2.5" gem "minitest", "~> 5.16" +gem "rbs-inline", require: false gem "rubocop-rails-omakase" diff --git a/Gemfile.lock b/Gemfile.lock index 6a0c143..39a5f3e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -87,6 +87,11 @@ GEM rb-fsevent (0.11.2) rb-inotify (0.11.1) ffi (~> 1.0) + rbs (3.9.5) + logger + rbs-inline (0.12.0) + prism (>= 0.29) + rbs (>= 3.8.0) rdoc (6.15.1) erb psych (>= 4.0.0) @@ -157,6 +162,7 @@ DEPENDENCIES kramdown (~> 2.5) minitest (~> 5.16) rake (~> 13.0) + rbs-inline (~> 0.12.0) rubocop-rails-omakase BUNDLED WITH From 3b58fea4f4969d786194dd665ccd94d154634b3f Mon Sep 17 00:00:00 2001 From: shimaaaji <221018698+simaaaji@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:06:17 +0900 Subject: [PATCH 2/7] RBS inline for page.rb --- .rubocop.yml | 6 +++++ Gemfile.lock | 2 +- lib/hotpages/page.rb | 18 ++++++++++++-- sig/generated/hotpages/page.rbs | 43 +++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 3 deletions(-) create mode 100644 sig/generated/hotpages/page.rbs diff --git a/.rubocop.yml b/.rubocop.yml index d9125f4..2a9ddf0 100644 --- a/.rubocop.yml +++ b/.rubocop.yml @@ -1,3 +1,9 @@ # Omakase Ruby styling for Rails inherit_gem: rubocop-rails-omakase: rubocop.yml + +Style/LeadingCommentSpace: + AllowGemfileRubyComment: true + AllowRBSInlineAnnotation: true + Exclude: + - '**/*.rbs' diff --git a/Gemfile.lock b/Gemfile.lock index 39a5f3e..9d2a8be 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -162,7 +162,7 @@ DEPENDENCIES kramdown (~> 2.5) minitest (~> 5.16) rake (~> 13.0) - rbs-inline (~> 0.12.0) + rbs-inline rubocop-rails-omakase BUNDLED WITH diff --git a/lib/hotpages/page.rb b/lib/hotpages/page.rb index cee94ef..a1af64d 100644 --- a/lib/hotpages/page.rb +++ b/lib/hotpages/page.rb @@ -1,3 +1,5 @@ +# rbs_inline: enabled + require "forwardable" class Hotpages::Page < Hotpages::PagePathComponent @@ -7,16 +9,19 @@ class Hotpages::Page < Hotpages::PagePathComponent include Hotpages::Helpers class << self + #: (Class) -> void def inherited(subclass) super subclass.layout_path = self.layout_path.dup if self.layout_path end + #: (String) -> String def layout(layout_path) @layout_path = layout_path end - attr_accessor :layout_path + attr_accessor :layout_path #: String + #: () -> void def include_all_site_helpers site.helper_constants.each do |helper_module| next if included_modules.include?(helper_module) @@ -29,7 +34,13 @@ def include_all_site_helpers layout :site # Default layout path, can be overridden by individual pages - attr_reader :base_path, :segments, :name, :site, :config, :template_file_ext, :layout_path + attr_reader :base_path, #: String + :segments, #: Hash[Symbol, String] + :name, #: String? + :site, #: Hotpages::Site + :config, #: Hash[Symbol, untyped] + :template_file_ext, #: String? + :layout_path #: String? def initialize(base_path:, segments: {}, name: nil, template_file_ext: nil, layout: nil) @base_path = base_path @@ -44,13 +55,16 @@ def initialize(base_path:, segments: {}, name: nil, template_file_ext: nil, layo self.class.include_all_site_helpers end + #: (String) -> void def layout(layout_path) @layout_path = layout_path end + #: () -> String def body raise "No template file is found at #{self.class.name} at `/#{site.directory.pages}/#{[ base_path, template_file_ext ].compact.join(".")}`, "\ "please provide body method or template file." end + #: () -> String def body_type = "html.erb" end diff --git a/sig/generated/hotpages/page.rbs b/sig/generated/hotpages/page.rbs new file mode 100644 index 0000000..7ba54a5 --- /dev/null +++ b/sig/generated/hotpages/page.rbs @@ -0,0 +1,43 @@ +# Generated from lib/hotpages/page.rb with RBS::Inline + +class Hotpages::Page < Hotpages::PagePathComponent + include Hotpages::Support::Hooks + + include Hotpages::Helpers + + # : (Class) -> void + def self.inherited: (Class) -> void + + # : (String) -> String + def self.layout: (String) -> String + + attr_accessor layout_path: String + + # : () -> void + def self.include_all_site_helpers: () -> void + + attr_reader base_path: String? + + attr_reader segments: String? + + attr_reader name: String? + + attr_reader site: String? + + attr_reader config: String? + + attr_reader template_file_ext: String? + + attr_reader layout_path: String? + + def initialize: (base_path: untyped, ?segments: untyped, ?name: untyped, ?template_file_ext: untyped, ?layout: untyped) -> untyped + + # : (String) -> void + def layout: (String) -> void + + # : () -> String + def body: () -> String + + # : () -> String + def body_type: () -> String +end From d610082d1af8d30b0311af503bbba7a0d7f04102 Mon Sep 17 00:00:00 2001 From: shimaaaji <221018698+simaaaji@users.noreply.github.com> Date: Fri, 7 Nov 2025 15:21:48 +0900 Subject: [PATCH 3/7] auto generate inline RBS by rbs-trace gem --- lib/hotpages.rb | 3 +++ lib/hotpages/config.rb | 4 ++++ lib/hotpages/extension.rb | 7 +++++++ lib/hotpages/extensions/i18n.rb | 3 +++ lib/hotpages/page.rb | 2 -- lib/hotpages/page/expandable.rb | 1 + lib/hotpages/site.rb | 11 +++++++++++ lib/hotpages/support/cache.rb | 1 + lib/hotpages/support/hooks.rb | 6 ++++++ test/integration/dev_server/test_hot_reloading.rb | 2 ++ test/integration/dev_server/test_serving.rb | 10 ++++++++++ test/integration/site_generator/test_generation.rb | 2 ++ test/lib/hotpages/support/test_cache.rb | 4 ++++ test/lib/hotpages/test_config.rb | 2 ++ test/test_helper.rb | 10 ++++++++++ 15 files changed, 66 insertions(+), 2 deletions(-) diff --git a/lib/hotpages.rb b/lib/hotpages.rb index ba5698a..e4dfd73 100644 --- a/lib/hotpages.rb +++ b/lib/hotpages.rb @@ -36,14 +36,17 @@ def teardown # To add/remove extensions, modify this array before calling Extension.setup # Extensions order is important, because initialization is performed in the order defined # and this affects prepended/included modules' order. + #: () -> Array[untyped] def extensions = @extensions ||= DEFAULT_EXTENSIONS def extensions=(extensions) @extensions = extensions end + #: () -> Hotpages::Config def config = @config ||= Config.defaults attr_accessor :site_class + #: () -> TestSite def site = @site ||= site_class.instance.tap(&:setup) def site_generator = @site_generator ||= SiteGenerator.new(site:) diff --git a/lib/hotpages/config.rb b/lib/hotpages/config.rb index 80f2a0d..63a14eb 100644 --- a/lib/hotpages/config.rb +++ b/lib/hotpages/config.rb @@ -1,5 +1,6 @@ class Hotpages::Config class << self + #: () -> Hotpages::Config def defaults new( assets: new( @@ -30,8 +31,10 @@ def defaults end end + #: (?Hash[untyped, untyped]) -> void def initialize(defaults = {}) = add(**defaults) + #: (**String | (String | Hotpages::Config)? | Integer | String | Hotpages::Config | Hash[untyped, untyped] | Array[untyped] | Array[untyped] | String | Symbol | Hotpages::Config | String | Hash[untyped, untyped] | Hotpages::Config) -> Hotpages::Config def add(**configs) configs.each do |key, value| define_attribute(key, value) @@ -58,6 +61,7 @@ def to_h private + #: (Symbol, (String | Hotpages::Config | Integer | Hash[untyped, untyped] | Array[untyped] | Symbol)?) -> Symbol def define_attribute(name, value) # Do not re-define return if respond_to?(name) diff --git a/lib/hotpages/extension.rb b/lib/hotpages/extension.rb index 6c79e10..88899a1 100644 --- a/lib/hotpages/extension.rb +++ b/lib/hotpages/extension.rb @@ -1,10 +1,12 @@ module Hotpages::Extension class << self + #: (extensions: Array[untyped], config: Hotpages::Config) -> Array[untyped] def setup(extensions:, config:) extensions.each { it.setup(config) } end end + #: (extensions: Array[untyped], config: Hotpages::Config) -> Array[untyped] def setup(config, extension = self) @setup_block.call(Setup.new(config, extension)) end @@ -16,11 +18,13 @@ def extension(&setup_block) end class Setup + #: (Hotpages::Config, Module) -> void def initialize(config, extension) @config = config @extension = extension end + #: (?Module, to: Class | Module) -> Class? def prepend(mod = extension, to:) to.prepend(mod) if mod.const_defined?(:ClassMethods) @@ -28,6 +32,7 @@ def prepend(mod = extension, to:) end end + #: (?Module, to: Class) -> nil def include(mod = extension, to:) to.include(mod) if mod.const_defined?(:ClassMethods) @@ -35,8 +40,10 @@ def include(mod = extension, to:) end end + #: (Module) -> nil def add_helper(helper_mod) = include(helper_mod, to: Hotpages::Page) + #: () -> (Hotpages::Config | Hash[untyped, untyped]) def configure = yield config private diff --git a/lib/hotpages/extensions/i18n.rb b/lib/hotpages/extensions/i18n.rb index 5bc57e7..5f5ed29 100644 --- a/lib/hotpages/extensions/i18n.rb +++ b/lib/hotpages/extensions/i18n.rb @@ -26,6 +26,7 @@ module Site GETTEXT_DOMAIN = "hotpages_site" Gettext = FastGettext + #: () -> String def setup super Gettext.add_text_domain( @@ -45,6 +46,7 @@ def reload def locales = i18n_config.locales def default_locale = i18n_config.default_locale + #: () -> Pathname def locales_path = root.join(i18n_config.locales_directory) def default_locale?(locale) = default_locale.to_s == locale.to_s def locales_without_default = locales.reject { default_locale?(it) } @@ -60,6 +62,7 @@ def with_locale(locale, &block) private + #: () -> Hotpages::Config def i18n_config = config.site.i18n end diff --git a/lib/hotpages/page.rb b/lib/hotpages/page.rb index a1af64d..c829922 100644 --- a/lib/hotpages/page.rb +++ b/lib/hotpages/page.rb @@ -1,5 +1,3 @@ -# rbs_inline: enabled - require "forwardable" class Hotpages::Page < Hotpages::PagePathComponent diff --git a/lib/hotpages/page/expandable.rb b/lib/hotpages/page/expandable.rb index 78b8ba1..175542b 100644 --- a/lib/hotpages/page/expandable.rb +++ b/lib/hotpages/page/expandable.rb @@ -4,6 +4,7 @@ module Hotpages::Page::Expandable EXPANDABLE_PATH_COMPONENT_REGEXP = Hotpages::Page::EXPANDABLE_NAME_REGEXP class << self + #: (Class) -> Class def included(base) base.extend(ClassMethods) end diff --git a/lib/hotpages/site.rb b/lib/hotpages/site.rb index a569b8b..6b70f34 100644 --- a/lib/hotpages/site.rb +++ b/lib/hotpages/site.rb @@ -9,6 +9,7 @@ class Hotpages::Site using Hotpages::Support::StringInflections class << self + #: (Class) -> Pathname def inherited(subclass) Hotpages::Extension.setup( extensions: Hotpages.extensions, @@ -23,12 +24,14 @@ def inherited(subclass) config.site.root = Pathname.new(base_class_location).join("../site") end + #: () -> Hotpages::Config def config = @config ||= Hotpages.config end attr_reader :config define_hook :initialize, only: :after + #: () -> void def initialize run_hooks :initialize do @config = self.class.config @@ -42,6 +45,7 @@ def initialize end end + #: () -> bool def setup loader.setup end @@ -65,6 +69,7 @@ def page_base_class(class_name: config.site.page_base_class_name) class_name.constantize end + #: () -> Array[untyped] def assets_paths = @assets_paths ||= [ assets_path ] def assets(filter_ext = nil) Enumerator.new do |yielder| @@ -89,17 +94,23 @@ module Paths delegate %i[ root directory ] => :site_config + #: () -> Pathname def dist_path = root.join(site_config.dist_path) def pages_path = root.join(directory.pages) + #: () -> Pathname def models_path = root.join(directory.models) def layouts_path = root.join(directory.layouts) + #: () -> Pathname def helpers_path = root.join(directory.helpers) + #: () -> Pathname def assets_path = root.join(directory.assets) + #: () -> Pathname def shared_path = root.join(directory.shared) private + #: () -> Hotpages::Config def site_config = config.site end include Paths diff --git a/lib/hotpages/support/cache.rb b/lib/hotpages/support/cache.rb index 247908a..915fd10 100644 --- a/lib/hotpages/support/cache.rb +++ b/lib/hotpages/support/cache.rb @@ -12,6 +12,7 @@ def content_of(of_version) end class Store < Hash + #: (String, version: Integer) -> String? def fetch(cache_key, version:, &block) self[cache_key]&.content_of(version) || block && diff --git a/lib/hotpages/support/hooks.rb b/lib/hotpages/support/hooks.rb index 9b759b5..02f091f 100644 --- a/lib/hotpages/support/hooks.rb +++ b/lib/hotpages/support/hooks.rb @@ -13,12 +13,14 @@ def in?(*types) = types.include?(type) private_constant :Type class << self + #: (Class) -> Class def included(base) base.extend(ClassMethods) end end module ClassMethods + #: (Class) -> Hash[untyped, untyped] def inherited(subclass) super @@ -28,9 +30,11 @@ def inherited(subclass) end end + #: () -> Hash[untyped, untyped] def hooks = @hooks ||= {} attr_writer :hooks + #: (Symbol, ?only: nil) -> Array[untyped] def define_hook(hook_name, only: nil) Type.all.each do |type| registered_name = type.key(hook_name) @@ -50,6 +54,7 @@ def define_hooks(*hook_names, only: nil) end end + #: (Symbol) -> Zeitwerk::Loader def run_hooks(hook_name, &block) unless self.class.hooks[Type.before.key(hook_name)] raise "Hooks for `#{hook_name}` is not registered." @@ -91,6 +96,7 @@ def run_hooks(hook_name, &block) private + #: (Proc) -> Proc def callable_hook_content(hook_content) case hook_content when Symbol diff --git a/test/integration/dev_server/test_hot_reloading.rb b/test/integration/dev_server/test_hot_reloading.rb index 2be399e..d1b388c 100644 --- a/test/integration/dev_server/test_hot_reloading.rb +++ b/test/integration/dev_server/test_hot_reloading.rb @@ -3,6 +3,7 @@ class TestHotReloading < Minitest::Test @@setup_done = false + #: () -> Integer def setup return if @@setup_done @@ -28,6 +29,7 @@ def setup end end + #: () -> nil def test_sse_broadcasting client_socket = TCPSocket.new("localhost", @@port) diff --git a/test/integration/dev_server/test_serving.rb b/test/integration/dev_server/test_serving.rb index ebbe1e0..24d9412 100644 --- a/test/integration/dev_server/test_serving.rb +++ b/test/integration/dev_server/test_serving.rb @@ -4,6 +4,7 @@ class TestServing < Minitest::Test @@setup_done = false + #: () -> Integer? def setup return if @@setup_done @@ -35,6 +36,7 @@ def setup end end + #: () -> Array[untyped] def test_serves_all_pages Dir.glob(Hotpages.site.dist_path.join("**/*")).each do |file| next if File.directory?(file) @@ -47,12 +49,14 @@ def test_serves_all_pages end end + #: () -> bool def test_serves_404_page_for_non_existent_page uri = URI("http://localhost:#{@@port}/not-exist") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Failed to serve /not-exist" end + #: () -> bool def test_serves_without_file_extension uri = URI("http://localhost:#{@@port}/posts/1/bar/index") res = Net::HTTP.get_response(uri) @@ -60,6 +64,7 @@ def test_serves_without_file_extension assert_page_content "posts/1/bar/index.html", res.body end + #: () -> bool def test_serves_index_without_filename uri = URI("http://localhost:#{@@port}/posts/1/bar/") res = Net::HTTP.get_response(uri) @@ -67,12 +72,14 @@ def test_serves_index_without_filename assert_page_content "posts/1/bar/index.html", res.body end + #: () -> bool def test_not_serves_txt_without_file_extension uri = URI("http://localhost:#{@@port}/robot") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Should not serve /robot.txt without extension" end + #: () -> bool def test_not_serves_ignored_path uri = URI("http://localhost:#{@@port}/products/_page") res = Net::HTTP.get_response(uri) @@ -83,12 +90,14 @@ def test_not_serves_ignored_path assert_equal "404", res.code, "Should not serve /products/_product" end + #: () -> bool def test_not_serves_directory_without_trailing_slash uri = URI("http://localhost:#{@@port}/posts/1/bar") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Should not serve /posts/1/bar without trailing slash" end + #: () -> bool def test_serves_non_html uri = URI("http://localhost:#{@@port}/sitemap.xml") res = Net::HTTP.get_response(uri) @@ -98,6 +107,7 @@ def test_serves_non_html private + #: (String, String) -> bool def assert_page_content(expected_path, actual_content) actual_content = actual_content.force_encoding("UTF-8").encode("UTF-8") expected_content = File.read(Hotpages.site.dist_path.join(expected_path.delete_prefix("/"))) diff --git a/test/integration/site_generator/test_generation.rb b/test/integration/site_generator/test_generation.rb index 08d73c8..31b72c1 100644 --- a/test/integration/site_generator/test_generation.rb +++ b/test/integration/site_generator/test_generation.rb @@ -2,6 +2,7 @@ require "digest" class TestGeneration < Minitest::Test + #: () -> Integer def setup pid = fork do Hotpages.extensions += [ @@ -15,6 +16,7 @@ def setup Process.wait(pid) end + #: () -> Array[untyped] def test_site_generation expected_dist = File.join(__dir__, "../../dist/expected") actual_dist = Hotpages.site.dist_path.to_s diff --git a/test/lib/hotpages/support/test_cache.rb b/test/lib/hotpages/support/test_cache.rb index 3a0f1ab..d6a3f90 100644 --- a/test/lib/hotpages/support/test_cache.rb +++ b/test/lib/hotpages/support/test_cache.rb @@ -6,6 +6,7 @@ class TestCache < Minitest::Test Entry = Hotpages::Support::Cache::Entry Store = Hotpages::Support::Cache::Store + #: () -> bool def test_entry_content_of_with_newer_version entry = Entry.new(version: 2, content: "cached content") @@ -13,12 +14,14 @@ def test_entry_content_of_with_newer_version assert_equal "cached content", entry.content_of(2) end + #: () -> bool def test_entry_content_of_with_older_version entry = Entry.new(version: 1, content: "cached content") assert_nil entry.content_of(2) end + #: () -> bool def test_entry_content_of_with_nil_version entry = Entry.new(version: nil, content: "cached content") @@ -28,6 +31,7 @@ def test_entry_content_of_with_nil_version assert_equal "cached content", entry.content_of(0) end + #: () -> bool def test_store_fetch store = Store.new key = "test cache key" diff --git a/test/lib/hotpages/test_config.rb b/test/lib/hotpages/test_config.rb index 8eb0150..f115e97 100644 --- a/test/lib/hotpages/test_config.rb +++ b/test/lib/hotpages/test_config.rb @@ -3,6 +3,7 @@ class TestConfig < Minitest::Test Config = Hotpages::Config + #: () -> Hotpages::Config def setup @defaults = { foo: "foo", @@ -14,6 +15,7 @@ def setup @config = Hotpages::Config.new(@defaults) end + #: () -> bool def test_singleton_methods assert_respond_to @config, :foo assert_equal "foo", @config.foo diff --git a/test/test_helper.rb b/test/test_helper.rb index b17176b..028568c 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,6 +2,11 @@ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "hotpages" +require "rbs" +require "rbs/trace" + +trace = RBS::Trace.new +trace.enable # Fix the last modified date of the page to prevent failures # during tests due to changes in CI, etc. @@ -24,3 +29,8 @@ class TestSite < Hotpages::Site Minitest.after_run do Hotpages.teardown end + +Minitest.after_run do + trace.disable + trace.save_comments +end From 2a1e1b5bd354075d21d82ee262be5772172e39c2 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:30:03 +0000 Subject: [PATCH 4/7] Initial plan From ae875df6e234ec4418afd570f9b569275a2eb1ae Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:35:55 +0000 Subject: [PATCH 5/7] Remove RBS inline comments from test files Co-authored-by: simaaaji <221018698+simaaaji@users.noreply.github.com> --- test/integration/dev_server/test_hot_reloading.rb | 2 -- test/integration/dev_server/test_serving.rb | 10 ---------- test/integration/site_generator/test_generation.rb | 2 -- test/lib/hotpages/support/test_cache.rb | 4 ---- test/lib/hotpages/test_config.rb | 2 -- test/test_helper.rb | 10 ---------- 6 files changed, 30 deletions(-) diff --git a/test/integration/dev_server/test_hot_reloading.rb b/test/integration/dev_server/test_hot_reloading.rb index d1b388c..2be399e 100644 --- a/test/integration/dev_server/test_hot_reloading.rb +++ b/test/integration/dev_server/test_hot_reloading.rb @@ -3,7 +3,6 @@ class TestHotReloading < Minitest::Test @@setup_done = false - #: () -> Integer def setup return if @@setup_done @@ -29,7 +28,6 @@ def setup end end - #: () -> nil def test_sse_broadcasting client_socket = TCPSocket.new("localhost", @@port) diff --git a/test/integration/dev_server/test_serving.rb b/test/integration/dev_server/test_serving.rb index 24d9412..ebbe1e0 100644 --- a/test/integration/dev_server/test_serving.rb +++ b/test/integration/dev_server/test_serving.rb @@ -4,7 +4,6 @@ class TestServing < Minitest::Test @@setup_done = false - #: () -> Integer? def setup return if @@setup_done @@ -36,7 +35,6 @@ def setup end end - #: () -> Array[untyped] def test_serves_all_pages Dir.glob(Hotpages.site.dist_path.join("**/*")).each do |file| next if File.directory?(file) @@ -49,14 +47,12 @@ def test_serves_all_pages end end - #: () -> bool def test_serves_404_page_for_non_existent_page uri = URI("http://localhost:#{@@port}/not-exist") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Failed to serve /not-exist" end - #: () -> bool def test_serves_without_file_extension uri = URI("http://localhost:#{@@port}/posts/1/bar/index") res = Net::HTTP.get_response(uri) @@ -64,7 +60,6 @@ def test_serves_without_file_extension assert_page_content "posts/1/bar/index.html", res.body end - #: () -> bool def test_serves_index_without_filename uri = URI("http://localhost:#{@@port}/posts/1/bar/") res = Net::HTTP.get_response(uri) @@ -72,14 +67,12 @@ def test_serves_index_without_filename assert_page_content "posts/1/bar/index.html", res.body end - #: () -> bool def test_not_serves_txt_without_file_extension uri = URI("http://localhost:#{@@port}/robot") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Should not serve /robot.txt without extension" end - #: () -> bool def test_not_serves_ignored_path uri = URI("http://localhost:#{@@port}/products/_page") res = Net::HTTP.get_response(uri) @@ -90,14 +83,12 @@ def test_not_serves_ignored_path assert_equal "404", res.code, "Should not serve /products/_product" end - #: () -> bool def test_not_serves_directory_without_trailing_slash uri = URI("http://localhost:#{@@port}/posts/1/bar") res = Net::HTTP.get_response(uri) assert_equal "404", res.code, "Should not serve /posts/1/bar without trailing slash" end - #: () -> bool def test_serves_non_html uri = URI("http://localhost:#{@@port}/sitemap.xml") res = Net::HTTP.get_response(uri) @@ -107,7 +98,6 @@ def test_serves_non_html private - #: (String, String) -> bool def assert_page_content(expected_path, actual_content) actual_content = actual_content.force_encoding("UTF-8").encode("UTF-8") expected_content = File.read(Hotpages.site.dist_path.join(expected_path.delete_prefix("/"))) diff --git a/test/integration/site_generator/test_generation.rb b/test/integration/site_generator/test_generation.rb index 31b72c1..08d73c8 100644 --- a/test/integration/site_generator/test_generation.rb +++ b/test/integration/site_generator/test_generation.rb @@ -2,7 +2,6 @@ require "digest" class TestGeneration < Minitest::Test - #: () -> Integer def setup pid = fork do Hotpages.extensions += [ @@ -16,7 +15,6 @@ def setup Process.wait(pid) end - #: () -> Array[untyped] def test_site_generation expected_dist = File.join(__dir__, "../../dist/expected") actual_dist = Hotpages.site.dist_path.to_s diff --git a/test/lib/hotpages/support/test_cache.rb b/test/lib/hotpages/support/test_cache.rb index d6a3f90..3a0f1ab 100644 --- a/test/lib/hotpages/support/test_cache.rb +++ b/test/lib/hotpages/support/test_cache.rb @@ -6,7 +6,6 @@ class TestCache < Minitest::Test Entry = Hotpages::Support::Cache::Entry Store = Hotpages::Support::Cache::Store - #: () -> bool def test_entry_content_of_with_newer_version entry = Entry.new(version: 2, content: "cached content") @@ -14,14 +13,12 @@ def test_entry_content_of_with_newer_version assert_equal "cached content", entry.content_of(2) end - #: () -> bool def test_entry_content_of_with_older_version entry = Entry.new(version: 1, content: "cached content") assert_nil entry.content_of(2) end - #: () -> bool def test_entry_content_of_with_nil_version entry = Entry.new(version: nil, content: "cached content") @@ -31,7 +28,6 @@ def test_entry_content_of_with_nil_version assert_equal "cached content", entry.content_of(0) end - #: () -> bool def test_store_fetch store = Store.new key = "test cache key" diff --git a/test/lib/hotpages/test_config.rb b/test/lib/hotpages/test_config.rb index f115e97..8eb0150 100644 --- a/test/lib/hotpages/test_config.rb +++ b/test/lib/hotpages/test_config.rb @@ -3,7 +3,6 @@ class TestConfig < Minitest::Test Config = Hotpages::Config - #: () -> Hotpages::Config def setup @defaults = { foo: "foo", @@ -15,7 +14,6 @@ def setup @config = Hotpages::Config.new(@defaults) end - #: () -> bool def test_singleton_methods assert_respond_to @config, :foo assert_equal "foo", @config.foo diff --git a/test/test_helper.rb b/test/test_helper.rb index 028568c..b17176b 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -2,11 +2,6 @@ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "hotpages" -require "rbs" -require "rbs/trace" - -trace = RBS::Trace.new -trace.enable # Fix the last modified date of the page to prevent failures # during tests due to changes in CI, etc. @@ -29,8 +24,3 @@ class TestSite < Hotpages::Site Minitest.after_run do Hotpages.teardown end - -Minitest.after_run do - trace.disable - trace.save_comments -end From a5c3317ea75a6bbbd681685da3951efad077c091 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:36:30 +0000 Subject: [PATCH 6/7] Add sorbet and sorbet-runtime gems for type checking Co-authored-by: simaaaji <221018698+simaaaji@users.noreply.github.com> --- Gemfile | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Gemfile b/Gemfile index d1a8076..f325dcd 100644 --- a/Gemfile +++ b/Gemfile @@ -11,4 +11,6 @@ gem "kramdown", "~> 2.5" gem "minitest", "~> 5.16" gem "rbs-inline", require: false +gem "sorbet", require: false +gem "sorbet-runtime" gem "rubocop-rails-omakase" From 60752f5f3276eb20713f0f392ab22cecaf94b1eb Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Fri, 7 Nov 2025 06:38:39 +0000 Subject: [PATCH 7/7] Configure Sorbet for type checking with RBS inline Co-authored-by: simaaaji <221018698+simaaaji@users.noreply.github.com> --- TYPE_CHECKING.md | 36 ++++++++++++++++++++++++++++++++++++ sorbet/config | 4 ++++ 2 files changed, 40 insertions(+) create mode 100644 TYPE_CHECKING.md create mode 100644 sorbet/config diff --git a/TYPE_CHECKING.md b/TYPE_CHECKING.md new file mode 100644 index 0000000..1184c48 --- /dev/null +++ b/TYPE_CHECKING.md @@ -0,0 +1,36 @@ +# Type Checking with RBS Inline and Sorbet + +This project uses a combination of RBS inline annotations and Sorbet for type checking. + +## RBS Inline + +Type annotations in the `lib/` directory use RBS inline format with `#:` comments. + +To generate RBS files from inline annotations: +```bash +bundle exec rbs-inline lib --output sig/generated +``` + +## Sorbet + +The Sorbet gem is available for additional type checking capabilities. + +### Setup + +Initialize Sorbet (if not already done): +```bash +bundle exec srb init +``` + +### Type Checking + +Run Sorbet type checker: +```bash +bundle exec srb tc +``` + +## Workflow + +1. Write code with RBS inline annotations in `lib/` files +2. Generate RBS files: `bundle exec rbs-inline lib --output sig/generated` +3. Run type checking as needed with Sorbet diff --git a/sorbet/config b/sorbet/config new file mode 100644 index 0000000..6266ba7 --- /dev/null +++ b/sorbet/config @@ -0,0 +1,4 @@ +--dir +. +--ignore=/test/ +--ignore=/sig/