ruby-lsp-rails 0.3.2 → 0.3.4

Sign up to get free protection for your applications and to get access to all the features.
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