Skip to content

Commit

Permalink
Run URL helpers compiler when routes are modified
Browse files Browse the repository at this point in the history
  • Loading branch information
vinistock committed Jan 23, 2025
1 parent f248f83 commit f707030
Show file tree
Hide file tree
Showing 3 changed files with 94 additions and 39 deletions.
26 changes: 20 additions & 6 deletions lib/ruby_lsp/tapioca/addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -79,11 +79,18 @@ def workspace_did_change_watched_files(changes)
return unless T.must(@global_state).enabled_feature?(:tapiocaAddon)
return unless @rails_runner_client # Client is not ready

has_route_change = T.let(false, T::Boolean)

constants = changes.flat_map do |change|
path = URI(change[:uri]).to_standardized_path
next if path.end_with?("_test.rb", "_spec.rb")
next unless file_updated?(change, path)

if File.basename(path) == "routes.rb"
has_route_change = true
next
end

entries = T.must(@index).entries_for(change[:uri])
next unless entries

Expand All @@ -92,14 +99,21 @@ def workspace_did_change_watched_files(changes)
end
end.compact

return if constants.empty?
return if constants.empty? && !has_route_change

@rails_runner_client.trigger_reload
@rails_runner_client.delegate_notification(
server_addon_name: "Tapioca",
request_name: "dsl",
constants: constants,
)

if has_route_change
@rails_runner_client.delegate_notification(server_addon_name: "Tapioca", request_name: "route_dsl")
end

if constants.any?
@rails_runner_client.delegate_notification(
server_addon_name: "Tapioca",
request_name: "dsl",
constants: constants,
)
end
end

private
Expand Down
10 changes: 7 additions & 3 deletions lib/ruby_lsp/tapioca/server_addon.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true

require "tapioca/internal"
require "tapioca/dsl/compilers/url_helpers"

module RubyLsp
module Tapioca
Expand All @@ -22,17 +23,20 @@ def execute(request, params)
halt_upon_load_error: false,
).load_dsl_extensions_and_compilers
when "dsl"
fork { dsl(params[:constants]) }
when "route_dsl"
fork do
dsl(params)
constants = ::Tapioca::Dsl::Compilers::UrlHelpers.gather_constants
dsl(constants.map(&:name))
end
end
end

private

def dsl(params)
def dsl(constants)
load("tapioca/cli.rb") # Reload the CLI to reset thor defaults between requests
::Tapioca::Cli.start(["dsl", "--lsp_addon", "--workers=1"] + params[:constants])
::Tapioca::Cli.start(["dsl", "--lsp_addon", "--workers=1"] + constants)
end
end
end
Expand Down
97 changes: 67 additions & 30 deletions spec/tapioca/addon_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,78 @@

require "spec_helper"
require "language_server-protocol"
require "ruby_lsp/utils"
require "ruby_lsp/ruby_lsp_rails/runner_client"
require "ruby_lsp/internal"
require "ruby_lsp/ruby_lsp_rails/addon"
require "ruby_lsp/tapioca/addon"
require "minitest/hooks"

module RubyLsp
module Tapioca
class AddonSpec < Minitest::HooksSpec
# The approach here is based on tests within the Ruby LSP Rails gem

# TODO: Replace with `before(:all)` once Sorbet understands it
def initialize(*args)
super(*T.unsafe(args))
@outgoing_queue = Thread::Queue.new
@client = T.let(
FileUtils.chdir("spec/dummy") do
RubyLsp::Rails::RunnerClient.new(@outgoing_queue)
end,
RubyLsp::Rails::RunnerClient,
it "generates DSL RBIs for a given constant" do
create_client
@client.delegate_notification(
server_addon_name: "Tapioca",
request_name: "dsl",
constants: ["NotifyUserJob"],
)
shutdown_client

assert_path_exists("spec/dummy/sorbet/rbi/dsl/notify_user_job.rbi")
ensure
FileUtils.rm_r("spec/dummy/sorbet/rbi")
end

it "triggers route DSL generation if routes.rb is modified" do
create_client

File.write("spec/dummy/config/routes.rb", <<~RUBY)
Rails.application.routes.draw do
root "home#index"
end
RUBY

global_state = RubyLsp::GlobalState.new
global_state.apply_options({
initializationOptions: {
enabledFeatureFlags: {
tapiocaAddon: true,
},
},
})

addon = Addon.new
addon.instance_variable_set(:@rails_runner_client, @client)
addon.instance_variable_set(:@global_state, global_state)
addon.instance_variable_set(:@index, global_state.index)
addon.instance_variable_set(:@outgoing_queue, @outgoing_queue)

addon.workspace_did_change_watched_files([{
uri: "file://#{Dir.pwd}/spec/dummy/config/routes.rb",
type: Constant::FileChangeType::CREATED,
}])

shutdown_client
assert_path_exists("spec/dummy/sorbet/rbi/dsl/generated_url_helpers_module.rbi")
assert_path_exists("spec/dummy/sorbet/rbi/dsl/generated_path_helpers_module.rbi")

assert_match("root_url", File.read("spec/dummy/sorbet/rbi/dsl/generated_url_helpers_module.rbi"))
assert_match("root_path", File.read("spec/dummy/sorbet/rbi/dsl/generated_path_helpers_module.rbi"))
ensure
FileUtils.rm_r("spec/dummy/sorbet/rbi")
FileUtils.rm("spec/dummy/config/routes.rb")
end

private

# Starts a new client
def create_client
@outgoing_queue = Thread::Queue.new
@client = FileUtils.chdir("spec/dummy") do
RubyLsp::Rails::RunnerClient.new(@outgoing_queue)
end

addon_path = File.expand_path("lib/ruby_lsp/tapioca/server_addon.rb")
@client.register_server_addon(File.expand_path(addon_path))
Expand All @@ -32,30 +85,14 @@ def initialize(*args)
)
end

after(:all) do
# Triggers shutdown and waits for it to complete
def shutdown_client
@client.shutdown
@client.instance_variable_get(:@wait_thread).join

assert_predicate(@client, :stopped?)
@outgoing_queue.close
end

it "generates DSL RBIs for a given constant" do
@client.delegate_notification(
server_addon_name: "Tapioca",
request_name: "dsl",
constants: ["NotifyUserJob"],
)

begin
Timeout.timeout(10) do
sleep(1) until File.exist?("spec/dummy/sorbet/rbi/dsl/notify_user_job.rbi")
end
rescue Timeout::Error
flunk("RBI file was not generated")
end
ensure
FileUtils.rm_rf("spec/dummy/sorbet/rbi")
end
end
end
end

0 comments on commit f707030

Please sign in to comment.