ruby-lsp-rails 0.3.2 → 0.3.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 7b68f8a0b2e4d7d4fa32aa2712865dea5c4734c86aa6a490c2a7ace718e3405a
4
- data.tar.gz: a146d2ff4091073a9517147dffd3f5326337b947563ed39848d3a823662b5fdc
3
+ metadata.gz: 463c37a3e7c9fef9c7b5433d2ef9519f41a29867a0089fe6508fc701a6cf1871
4
+ data.tar.gz: 0f3e7a164235e85b610f9e0855a0d57e9a25125999ff1c15ed31acc54880cad2
5
5
  SHA512:
6
- metadata.gz: 8902056649daff38b9c6e73231ecc0fb55485d4789d52b9dbf92afe4983104082a959b242b1a9f898d3697344663a678da952b0c0a4f76db026ef07c4744fe52
7
- data.tar.gz: 7550880a0a82da99734d38178c5aa47a1909b1787f2070bbf960f2b70ea177a3dd330484428b220de10d3d511a93b7f87a736dfbaf5c47bd12c50f547da15858
6
+ metadata.gz: 85cbe926939cac7051877d168de8164099265329ccb0cbe4ff6dbe9d1508ae64ce52b168a816d6cd538c79c384f04a1873654b692c98592cb032bc9c1470f318
7
+ data.tar.gz: c1023803f769de1d701788a85e17906b9626aa9fee89a7d36cabb849826ca68021c00402d8a3d7043cb3128ac7966195fb9ef5b0714109fff96ad907359d7ed5
data/README.md CHANGED
@@ -7,37 +7,27 @@ Ruby LSP Rails is a [Ruby LSP](https://github.com/Shopify/ruby-lsp) addon for ex
7
7
 
8
8
  ## Installation
9
9
 
10
- To install, add the following line to your application's Gemfile:
10
+ If you haven't already done so, you'll need to first [set up Ruby LSP](https://github.com/Shopify/ruby-lsp#usage).
11
11
 
12
- ```ruby
13
- # Gemfile
14
- group :development do
15
- gem "ruby-lsp-rails"
16
- end
17
- ```
12
+ As of v0.3.0, Ruby LSP will automatically include the Ruby LSP Rails addon in its custom bundle when a Rails app is detected.
13
+ There is no need to add the gem to your bundle.
18
14
 
19
- ## Usage
15
+ ## Features
20
16
 
21
- ### Hover to reveal ActiveRecord schema
17
+ * Hover over an ActiveRecord model to reveal its schema.
18
+ * Run or debug a test by clicking on the code lens which appears above the test class, or an individual test.
19
+ * Navigate to associations, validations, callbacks and test cases using your editor's "Go to Symbol" feature, or outline view.
20
+ * Jump to the definition of callbacks using your editor's "Go to Definition" feature.
22
21
 
23
- 1. Start your Rails server
24
- 1. Hover over an ActiveRecord model to see its details
25
-
26
- ### Documentation
22
+ ## Documentation
27
23
 
28
24
  See the [documentation](https://shopify.github.io/ruby-lsp-rails) for more in-depth details about the
29
25
  [supported features](https://shopify.github.io/ruby-lsp-rails/RubyLsp/Rails.html).
30
26
 
31
- ### Running Tests
32
-
33
- 1. Open a test which inherits from `ActiveSupport::TestCase` or one of its descendants, such as `ActionDispatch::IntegrationTest`.
34
- 2. Click on the "Run", "Run in Terminal" or "Debug" code lens which appears above the test class, or an individual test.
35
-
36
- > [!NOTE]
37
- > When using the Test Explorer view, if your code contains a statement to pause execution (e.g. `debugger`) it will
38
- > cause the test runner to hang.
27
+ ## How Runtime Introspection Works
39
28
 
40
- ## How It Works
29
+ LSP tooling is typically based on static analysis, but `ruby-lsp-rails` actually communicates with your Rails app for
30
+ some features.
41
31
 
42
32
  When Ruby LSP Rails starts, it spawns a `rails runner` instance which runs
43
33
  [`server.rb`](https://github.com/Shopify/ruby-lsp-rails/blob/main/lib/ruby_lsp/ruby_lsp_rails/server.rb).
@@ -46,7 +36,7 @@ The addon communicates with this process over a pipe (i.e. `stdin` and `stdout`)
46
36
  When extension is stopped (e.g. by quitting the editor), the server instance is shut down.
47
37
 
48
38
  > [!NOTE]
49
- > Prior to v0.3, `ruby-lsp-rails` used a different approach which involved mounting a Rack application within the Rails app.
39
+ > Prior to v0.3.0, `ruby-lsp-rails` used a different approach which involved mounting a Rack application within the Rails app.
50
40
  > That approach was brittle and susceptible to the application's configuration, such as routing and middleware.
51
41
 
52
42
  ## Contributing
data/Rakefile CHANGED
@@ -23,6 +23,7 @@ RDoc::Task.new do |rdoc|
23
23
  rdoc.rdoc_files.include("*.md", "lib/**/*.rb")
24
24
  rdoc.rdoc_dir = "docs"
25
25
  rdoc.markup = "markdown"
26
+ rdoc.generator = "snapper"
26
27
  rdoc.options.push("--copy-files", "misc")
27
28
  rdoc.options.push("--copy-files", "LICENSE.txt")
28
29
  end
@@ -9,6 +9,8 @@ module RubyLsp
9
9
  #
10
10
  # - [Hover](rdoc-ref:RubyLsp::Rails::Hover)
11
11
  # - [CodeLens](rdoc-ref:RubyLsp::Rails::CodeLens)
12
+ # - [DocumentSymbol](rdoc-ref:RubyLsp::Rails::DocumentSymbol)
13
+ # - [Definition](rdoc-ref:RubyLsp::Rails::Definition)
12
14
  module Rails
13
15
  end
14
16
  end
@@ -4,10 +4,12 @@
4
4
  require "ruby_lsp/addon"
5
5
 
6
6
  require_relative "support/active_support_test_case_helper"
7
+ require_relative "support/callbacks"
7
8
  require_relative "runner_client"
8
9
  require_relative "hover"
9
10
  require_relative "code_lens"
10
11
  require_relative "document_symbol"
12
+ require_relative "definition"
11
13
 
12
14
  module RubyLsp
13
15
  module Rails
@@ -23,8 +25,10 @@ module RubyLsp
23
25
  @client = T.let(NullClient.new, RunnerClient)
24
26
  end
25
27
 
26
- sig { override.params(message_queue: Thread::Queue).void }
27
- def activate(message_queue)
28
+ sig { override.params(global_state: GlobalState, message_queue: Thread::Queue).void }
29
+ def activate(global_state, message_queue)
30
+ @global_state = T.let(global_state, T.nilable(RubyLsp::GlobalState))
31
+ $stderr.puts("Activating Ruby LSP Rails addon v#{VERSION}")
28
32
  # Start booting the real client in a background thread. Until this completes, the client will be a NullClient
29
33
  Thread.new { @client = RunnerClient.create_client }
30
34
  end
@@ -43,6 +47,8 @@ module RubyLsp
43
47
  ).void
44
48
  end
45
49
  def create_code_lens_listener(response_builder, uri, dispatcher)
50
+ return unless T.must(@global_state).test_library == "rails"
51
+
46
52
  CodeLens.new(response_builder, uri, dispatcher)
47
53
  end
48
54
 
@@ -50,12 +56,11 @@ module RubyLsp
50
56
  override.params(
51
57
  response_builder: ResponseBuilders::Hover,
52
58
  nesting: T::Array[String],
53
- index: RubyIndexer::Index,
54
59
  dispatcher: Prism::Dispatcher,
55
60
  ).void
56
61
  end
57
- def create_hover_listener(response_builder, nesting, index, dispatcher)
58
- Hover.new(@client, response_builder, nesting, index, dispatcher)
62
+ def create_hover_listener(response_builder, nesting, dispatcher)
63
+ Hover.new(@client, response_builder, nesting, T.must(@global_state), dispatcher)
59
64
  end
60
65
 
61
66
  sig do
@@ -68,6 +73,28 @@ module RubyLsp
68
73
  DocumentSymbol.new(response_builder, dispatcher)
69
74
  end
70
75
 
76
+ sig do
77
+ override.params(
78
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
79
+ uri: URI::Generic,
80
+ nesting: T::Array[String],
81
+ dispatcher: Prism::Dispatcher,
82
+ ).void
83
+ end
84
+ def create_definition_listener(response_builder, uri, nesting, dispatcher)
85
+ index = T.must(@global_state).index
86
+ Definition.new(response_builder, nesting, index, dispatcher)
87
+ end
88
+
89
+ sig { params(changes: T::Array[{ uri: String, type: Integer }]).void }
90
+ def workspace_did_change_watched_files(changes)
91
+ if changes.any? do |change|
92
+ change[:uri].end_with?("db/schema.rb") || change[:uri].end_with?("structure.sql")
93
+ end
94
+ @client.trigger_reload
95
+ end
96
+ end
97
+
71
98
  sig { override.returns(String) }
72
99
  def name
73
100
  "Ruby LSP Rails"
@@ -12,7 +12,9 @@ module RubyLsp
12
12
  #
13
13
  # The
14
14
  # [code lens](https://microsoft.github.io/language-server-protocol/specification#textDocument_codeLens)
15
- # request informs the editor of runnable commands such as tests
15
+ # request informs the editor of runnable commands such as tests.
16
+ # It's available for tests which inherit from `ActiveSupport::TestCase` or one of its descendants, such as
17
+ # `ActionDispatch::IntegrationTest`.
16
18
  #
17
19
  # # Example:
18
20
  #
@@ -32,6 +34,9 @@ module RubyLsp
32
34
  # ````
33
35
  #
34
36
  # The code lenses will be displayed above the class and above each test method.
37
+ #
38
+ # Note: When using the Test Explorer view, if your code contains a statement to pause execution (e.g. `debugger`) it
39
+ # will cause the test runner to hang.
35
40
  class CodeLens
36
41
  extend T::Sig
37
42
  include Requests::Support::Common
@@ -0,0 +1,87 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Rails
6
+ # ![Definition demo](../../definition.gif)
7
+ #
8
+ # The [definition
9
+ # request](https://microsoft.github.io/language-server-protocol/specification#textDocument_definition) jumps to the
10
+ # definition of the symbol under the cursor.
11
+ #
12
+ # Currently supported targets:
13
+ # - Callbacks
14
+ #
15
+ # # Example
16
+ #
17
+ # ```ruby
18
+ # before_action :foo # <- Go to definition on this symbol will jump to the method if it is defined in the same class
19
+ # ```
20
+ class Definition
21
+ extend T::Sig
22
+ include Requests::Support::Common
23
+
24
+ sig do
25
+ params(
26
+ response_builder: ResponseBuilders::CollectionResponseBuilder[Interface::Location],
27
+ nesting: T::Array[String],
28
+ index: RubyIndexer::Index,
29
+ dispatcher: Prism::Dispatcher,
30
+ ).void
31
+ end
32
+ def initialize(response_builder, nesting, index, dispatcher)
33
+ @response_builder = response_builder
34
+ @nesting = nesting
35
+ @index = index
36
+
37
+ dispatcher.register(self, :on_call_node_enter)
38
+ end
39
+
40
+ sig { params(node: Prism::CallNode).void }
41
+ def on_call_node_enter(node)
42
+ return unless self_receiver?(node)
43
+
44
+ message = node.message
45
+
46
+ return unless message && Support::Callbacks::ALL.include?(message)
47
+
48
+ arguments = node.arguments&.arguments
49
+ return unless arguments&.any?
50
+
51
+ arguments.each do |argument|
52
+ name = case argument
53
+ when Prism::SymbolNode
54
+ argument.value
55
+ when Prism::StringNode
56
+ argument.content
57
+ end
58
+
59
+ next unless name
60
+
61
+ collect_definitions(name)
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ sig { params(name: String).void }
68
+ def collect_definitions(name)
69
+ methods = @index.resolve_method(name, @nesting.join("::"))
70
+ return unless methods
71
+
72
+ methods.each do |target_method|
73
+ location = target_method.location
74
+ file_path = target_method.file_path
75
+
76
+ @response_builder << Interface::Location.new(
77
+ uri: URI::Generic.from_path(path: file_path).to_s,
78
+ range: Interface::Range.new(
79
+ start: Interface::Position.new(line: location.start_line - 1, character: location.start_column),
80
+ end: Interface::Position.new(line: location.end_line - 1, character: location.end_column),
81
+ ),
82
+ )
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -6,7 +6,8 @@ module RubyLsp
6
6
  # ![Document Symbol demo](../../document_symbol.gif)
7
7
  #
8
8
  # The [document symbol](https://microsoft.github.io/language-server-protocol/specification#textDocument_documentSymbol)
9
- # request allows users to navigate between ActiveSupport test cases with VS Code's "Go to Symbol" feature.
9
+ # request allows users to navigate between associations, validations, callbacks and ActiveSupport test cases with
10
+ # VS Code's "Go to Symbol" feature.
10
11
  class DocumentSymbol
11
12
  extend T::Sig
12
13
  include Requests::Support::Common
@@ -28,13 +29,161 @@ module RubyLsp
28
29
  def on_call_node_enter(node)
29
30
  content = extract_test_case_name(node)
30
31
 
31
- return unless content
32
+ if content
33
+ append_document_symbol(
34
+ name: content,
35
+ selection_range: range_from_node(node),
36
+ range: range_from_node(node),
37
+ )
38
+ end
32
39
 
40
+ receiver = node.receiver
41
+ return if receiver && !receiver.is_a?(Prism::SelfNode)
42
+
43
+ message = node.message
44
+ case message
45
+ when *Support::Callbacks::ALL, "validate"
46
+ handle_all_arg_types(node, T.must(message))
47
+ when "validates", "validates!", "validates_each", "belongs_to", "has_one", "has_many", "has_and_belongs_to_many"
48
+ handle_symbol_and_string_arg_types(node, T.must(message))
49
+ when "validates_with"
50
+ handle_class_arg_types(node, T.must(message))
51
+ end
52
+ end
53
+
54
+ private
55
+
56
+ sig { params(node: Prism::CallNode, message: String).void }
57
+ def handle_all_arg_types(node, message)
58
+ block = node.block
59
+
60
+ if block
61
+ append_document_symbol(
62
+ name: "#{message} <anonymous>",
63
+ range: range_from_location(node.location),
64
+ selection_range: range_from_location(block.location),
65
+ )
66
+ return
67
+ end
68
+
69
+ arguments = node.arguments&.arguments
70
+ return unless arguments&.any?
71
+
72
+ arguments.each do |argument|
73
+ case argument
74
+ when Prism::SymbolNode
75
+ name = argument.value
76
+ next unless name
77
+
78
+ append_document_symbol(
79
+ name: "#{message} :#{name}",
80
+ range: range_from_location(argument.location),
81
+ selection_range: range_from_location(T.must(argument.value_loc)),
82
+ )
83
+ when Prism::StringNode
84
+ name = argument.content
85
+ next if name.empty?
86
+
87
+ append_document_symbol(
88
+ name: "#{message} :#{name}",
89
+ range: range_from_location(argument.location),
90
+ selection_range: range_from_location(argument.content_loc),
91
+ )
92
+ when Prism::LambdaNode
93
+ append_document_symbol(
94
+ name: "#{message} <anonymous>",
95
+ range: range_from_location(node.location),
96
+ selection_range: range_from_location(argument.location),
97
+ )
98
+ when Prism::CallNode
99
+ next unless argument.name == :new
100
+
101
+ arg_receiver = argument.receiver
102
+
103
+ name = arg_receiver.full_name if arg_receiver.is_a?(Prism::ConstantReadNode) ||
104
+ arg_receiver.is_a?(Prism::ConstantPathNode)
105
+ next unless name
106
+
107
+ append_document_symbol(
108
+ name: "#{message} #{name}",
109
+ range: range_from_location(argument.location),
110
+ selection_range: range_from_location(argument.location),
111
+ )
112
+ when Prism::ConstantReadNode, Prism::ConstantPathNode
113
+ name = argument.full_name
114
+ next if name.empty?
115
+
116
+ append_document_symbol(
117
+ name: "#{message} #{name}",
118
+ range: range_from_location(argument.location),
119
+ selection_range: range_from_location(argument.location),
120
+ )
121
+ end
122
+ end
123
+ end
124
+
125
+ sig { params(node: Prism::CallNode, message: String).void }
126
+ def handle_symbol_and_string_arg_types(node, message)
127
+ arguments = node.arguments&.arguments
128
+ return unless arguments&.any?
129
+
130
+ arguments.each do |argument|
131
+ case argument
132
+ when Prism::SymbolNode
133
+ name = argument.value
134
+ next unless name
135
+
136
+ append_document_symbol(
137
+ name: "#{message} :#{name}",
138
+ range: range_from_location(argument.location),
139
+ selection_range: range_from_location(T.must(argument.value_loc)),
140
+ )
141
+ when Prism::StringNode
142
+ name = argument.content
143
+ next if name.empty?
144
+
145
+ append_document_symbol(
146
+ name: "#{message} :#{name}",
147
+ range: range_from_location(argument.location),
148
+ selection_range: range_from_location(argument.content_loc),
149
+ )
150
+ end
151
+ end
152
+ end
153
+
154
+ sig { params(node: Prism::CallNode, message: String).void }
155
+ def handle_class_arg_types(node, message)
156
+ arguments = node.arguments&.arguments
157
+ return unless arguments&.any?
158
+
159
+ arguments.each do |argument|
160
+ case argument
161
+ when Prism::ConstantReadNode, Prism::ConstantPathNode
162
+ name = argument.full_name
163
+ next if name.empty?
164
+
165
+ append_document_symbol(
166
+ name: "#{message} #{name}",
167
+ range: range_from_location(argument.location),
168
+ selection_range: range_from_location(argument.location),
169
+ )
170
+ end
171
+ end
172
+ end
173
+
174
+ sig do
175
+ params(
176
+ name: String,
177
+ range: RubyLsp::Interface::Range,
178
+ selection_range: RubyLsp::Interface::Range,
179
+ ).void
180
+ end
181
+ def append_document_symbol(name:, range:, selection_range:)
33
182
  @response_builder.last.children << RubyLsp::Interface::DocumentSymbol.new(
34
- name: content,
35
- kind: LanguageServer::Protocol::Constant::SymbolKind::METHOD,
36
- selection_range: range_from_node(node),
37
- range: range_from_node(node),
183
+ name: name,
184
+ kind: RubyLsp::Constant::SymbolKind::METHOD,
185
+ range: range,
186
+ selection_range: selection_range,
38
187
  )
39
188
  end
40
189
  end
@@ -25,15 +25,15 @@ module RubyLsp
25
25
  client: RunnerClient,
26
26
  response_builder: ResponseBuilders::Hover,
27
27
  nesting: T::Array[String],
28
- index: RubyIndexer::Index,
28
+ global_state: GlobalState,
29
29
  dispatcher: Prism::Dispatcher,
30
30
  ).void
31
31
  end
32
- def initialize(client, response_builder, nesting, index, dispatcher)
32
+ def initialize(client, response_builder, nesting, global_state, dispatcher)
33
33
  @client = client
34
34
  @response_builder = response_builder
35
35
  @nesting = nesting
36
- @index = index
36
+ @index = T.let(global_state.index, RubyIndexer::Index)
37
37
  dispatcher.register(self, :on_constant_path_node_enter, :on_constant_read_node_enter, :on_call_node_enter)
38
38
  end
39
39
 
@@ -12,16 +12,27 @@ module RubyLsp
12
12
 
13
13
  sig { returns(RunnerClient) }
14
14
  def create_client
15
- new
15
+ if File.exist?("bin/rails")
16
+ new
17
+ else
18
+ $stderr.puts(<<~MSG)
19
+ Ruby LSP Rails failed to locate bin/rails in the current directory: #{Dir.pwd}"
20
+ MSG
21
+ $stderr.puts("Server dependent features will not be available")
22
+ NullClient.new
23
+ end
16
24
  rescue Errno::ENOENT, StandardError => e # rubocop:disable Lint/ShadowedException
17
- warn("Ruby LSP Rails failed to initialize server: #{e.message}\n#{e.backtrace&.join("\n")}")
18
- warn("Server dependent features will not be available")
25
+ $stderr.puts("Ruby LSP Rails failed to initialize server: #{e.message}\n#{e.backtrace&.join("\n")}")
26
+ $stderr.puts("Server dependent features will not be available")
19
27
  NullClient.new
20
28
  end
21
29
  end
22
30
 
23
31
  class InitializationError < StandardError; end
24
32
  class IncompleteMessageError < StandardError; end
33
+ class EmptyMessageError < StandardError; end
34
+
35
+ MAX_RETRIES = 5
25
36
 
26
37
  extend T::Sig
27
38
 
@@ -50,14 +61,23 @@ module RubyLsp
50
61
  @stdin.binmode # for Windows compatibility
51
62
  @stdout.binmode # for Windows compatibility
52
63
 
53
- warn("Ruby LSP Rails booting server")
54
- read_response
55
- warn("Finished booting Ruby LSP Rails server")
64
+ $stderr.puts("Ruby LSP Rails booting server")
65
+ count = 0
66
+
67
+ begin
68
+ count += 1
69
+ read_response
70
+ rescue EmptyMessageError
71
+ $stderr.puts("Ruby LSP Rails is retrying initialize (#{count})")
72
+ retry if count < MAX_RETRIES
73
+ end
74
+
75
+ $stderr.puts("Finished booting Ruby LSP Rails server")
56
76
 
57
77
  unless ENV["RAILS_ENV"] == "test"
58
78
  at_exit do
59
79
  if @wait_thread.alive?
60
- warn("Ruby LSP Rails is force killing the server")
80
+ $stderr.puts("Ruby LSP Rails is force killing the server")
61
81
  sleep(0.5) # give the server a bit of time if we already issued a shutdown notification
62
82
  Process.kill(T.must(Signal.list["TERM"]), @wait_thread.pid)
63
83
  end
@@ -71,13 +91,22 @@ module RubyLsp
71
91
  def model(name)
72
92
  make_request("model", name: name)
73
93
  rescue IncompleteMessageError
74
- warn("Ruby LSP Rails failed to get model information: #{@stderr.read}")
94
+ $stderr.puts("Ruby LSP Rails failed to get model information: #{@stderr.read}")
95
+ nil
96
+ end
97
+
98
+ sig { void }
99
+ def trigger_reload
100
+ $stderr.puts("Reloading Rails application")
101
+ send_notification("reload")
102
+ rescue IncompleteMessageError
103
+ $stderr.puts("Ruby LSP Rails failed to trigger reload")
75
104
  nil
76
105
  end
77
106
 
78
107
  sig { void }
79
108
  def shutdown
80
- warn("Ruby LSP Rails shutting down server")
109
+ $stderr.puts("Ruby LSP Rails shutting down server")
81
110
  send_message("shutdown")
82
111
  sleep(0.5) # give the server a bit of time to shutdown
83
112
  [@stdin, @stdout, @stderr].each(&:close)
@@ -117,11 +146,14 @@ module RubyLsp
117
146
  headers = @stdout.gets("\r\n\r\n")
118
147
  raise IncompleteMessageError unless headers
119
148
 
120
- raw_response = @stdout.read(headers[/Content-Length: (\d+)/i, 1].to_i)
149
+ content_length = headers[/Content-Length: (\d+)/i, 1].to_i
150
+ raise EmptyMessageError if content_length.zero?
151
+
152
+ raw_response = @stdout.read(content_length)
121
153
  response = JSON.parse(T.must(raw_response), symbolize_names: true)
122
154
 
123
155
  if response[:error]
124
- warn("Ruby LSP Rails error: " + response[:error])
156
+ $stderr.puts("Ruby LSP Rails error: " + response[:error])
125
157
  return
126
158
  end
127
159
 
@@ -57,16 +57,19 @@ module RubyLsp
57
57
  sig do
58
58
  params(
59
59
  request: String,
60
- params: T::Hash[Symbol, T.untyped],
60
+ params: T.nilable(T::Hash[Symbol, T.untyped]),
61
61
  ).returns(T.any(Object, T::Hash[Symbol, T.untyped]))
62
62
  end
63
- def execute(request, params = {})
63
+ def execute(request, params)
64
64
  case request
65
65
  when "shutdown"
66
66
  @running = false
67
67
  VOID
68
68
  when "model"
69
- resolve_database_info_from_model(params.fetch(:name))
69
+ resolve_database_info_from_model(T.must(params).fetch(:name))
70
+ when "reload"
71
+ ::Rails.application.reloader.reload!
72
+ VOID
70
73
  else
71
74
  VOID
72
75
  end
@@ -11,8 +11,6 @@ module RubyLsp
11
11
  message_value = node.message
12
12
  return unless message_value == "test" || message_value == "it"
13
13
 
14
- return unless node.arguments
15
-
16
14
  arguments = node.arguments&.arguments
17
15
  return unless arguments&.any?
18
16
 
@@ -0,0 +1,67 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module RubyLsp
5
+ module Rails
6
+ module Support
7
+ module Callbacks
8
+ MODELS = T.let(
9
+ [
10
+ "before_validation",
11
+ "after_validation",
12
+ "before_save",
13
+ "around_save",
14
+ "after_save",
15
+ "before_create",
16
+ "around_create",
17
+ "after_create",
18
+ "after_commit",
19
+ "after_rollback",
20
+ "before_update",
21
+ "around_update",
22
+ "after_update",
23
+ "before_destroy",
24
+ "around_destroy",
25
+ "after_destroy",
26
+ "after_initialize",
27
+ "after_find",
28
+ "after_touch",
29
+ ].freeze,
30
+ T::Array[String],
31
+ )
32
+
33
+ CONTROLLERS = T.let(
34
+ [
35
+ "after_action",
36
+ "append_after_action",
37
+ "append_around_action",
38
+ "append_before_action",
39
+ "around_action",
40
+ "before_action",
41
+ "prepend_after_action",
42
+ "prepend_around_action",
43
+ "prepend_before_action",
44
+ "skip_after_action",
45
+ "skip_around_action",
46
+ "skip_before_action",
47
+ ].freeze,
48
+ T::Array[String],
49
+ )
50
+
51
+ JOBS = T.let(
52
+ [
53
+ "after_enqueue",
54
+ "after_perform",
55
+ "around_enqueue",
56
+ "around_perform",
57
+ "before_enqueue",
58
+ "before_perform",
59
+ ].freeze,
60
+ T::Array[String],
61
+ )
62
+
63
+ ALL = T.let((MODELS + CONTROLLERS + JOBS).freeze, T::Array[String])
64
+ end
65
+ end
66
+ end
67
+ end
@@ -66,7 +66,7 @@ module RubyLsp
66
66
  private def build_search_index
67
67
  return unless RAILTIES_VERSION
68
68
 
69
- warn("Fetching Rails Documents...")
69
+ $stderr.puts("Fetching Rails Documents...")
70
70
 
71
71
  response = Net::HTTP.get_response(URI("#{RAILS_DOC_HOST}/v#{RAILTIES_VERSION}/js/search_index.js"))
72
72
 
@@ -79,13 +79,13 @@ module RubyLsp
79
79
  response = Net::HTTP.get_response(URI("#{RAILS_DOC_HOST}/js/search_index.js"))
80
80
  response.body if response.is_a?(Net::HTTPSuccess)
81
81
  else
82
- warn("Response failed: #{response.inspect}")
82
+ $stderr.puts("Response failed: #{response.inspect}")
83
83
  nil
84
84
  end
85
85
 
86
86
  process_search_index(body) if body
87
87
  rescue StandardError => e
88
- warn("Exception occurred when fetching Rails document index: #{e.inspect}")
88
+ $stderr.puts("Exception occurred when fetching Rails document index: #{e.inspect}")
89
89
  end
90
90
 
91
91
  sig { params(js: String).returns(T::Hash[String, T::Array[T::Hash[Symbol, String]]]) }
@@ -3,6 +3,6 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Rails
6
- VERSION = "0.3.2"
6
+ VERSION = "0.3.4"
7
7
  end
8
8
  end
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  # desc "Explaining what the task does"
3
4
  # task :ruby_lsp_rails do
4
5
  # # Task goes here
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lsp-rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.2
4
+ version: 0.3.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Shopify
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-02-29 00:00:00.000000000 Z
11
+ date: 2024-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -58,20 +58,20 @@ dependencies:
58
58
  requirements:
59
59
  - - ">="
60
60
  - !ruby/object:Gem::Version
61
- version: 0.14.2
61
+ version: 0.16.0
62
62
  - - "<"
63
63
  - !ruby/object:Gem::Version
64
- version: 0.15.0
64
+ version: 0.17.0
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
68
68
  requirements:
69
69
  - - ">="
70
70
  - !ruby/object:Gem::Version
71
- version: 0.14.2
71
+ version: 0.16.0
72
72
  - - "<"
73
73
  - !ruby/object:Gem::Version
74
- version: 0.15.0
74
+ version: 0.17.0
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: sorbet-runtime
77
77
  requirement: !ruby/object:Gem::Requirement
@@ -99,11 +99,13 @@ files:
99
99
  - lib/ruby-lsp-rails.rb
100
100
  - lib/ruby_lsp/ruby_lsp_rails/addon.rb
101
101
  - lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
102
+ - lib/ruby_lsp/ruby_lsp_rails/definition.rb
102
103
  - lib/ruby_lsp/ruby_lsp_rails/document_symbol.rb
103
104
  - lib/ruby_lsp/ruby_lsp_rails/hover.rb
104
105
  - lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
105
106
  - lib/ruby_lsp/ruby_lsp_rails/server.rb
106
107
  - lib/ruby_lsp/ruby_lsp_rails/support/active_support_test_case_helper.rb
108
+ - lib/ruby_lsp/ruby_lsp_rails/support/callbacks.rb
107
109
  - lib/ruby_lsp/ruby_lsp_rails/support/rails_document_client.rb
108
110
  - lib/ruby_lsp_rails/railtie.rb
109
111
  - lib/ruby_lsp_rails/version.rb
@@ -124,14 +126,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
124
126
  requirements:
125
127
  - - ">="
126
128
  - !ruby/object:Gem::Version
127
- version: '0'
129
+ version: 3.0.0
128
130
  required_rubygems_version: !ruby/object:Gem::Requirement
129
131
  requirements:
130
132
  - - ">="
131
133
  - !ruby/object:Gem::Version
132
134
  version: '0'
133
135
  requirements: []
134
- rubygems_version: 3.5.6
136
+ rubygems_version: 3.5.7
135
137
  signing_key:
136
138
  specification_version: 4
137
139
  summary: A Ruby LSP addon for Rails