ruby-lsp-rails 0.2.10 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +6 -7
- data/lib/ruby-lsp-rails.rb +0 -3
- data/lib/ruby_lsp/ruby_lsp_rails/addon.rb +7 -7
- data/lib/ruby_lsp/ruby_lsp_rails/hover.rb +1 -1
- data/lib/ruby_lsp_rails/railtie.rb +4 -21
- data/lib/ruby_lsp_rails/version.rb +1 -1
- metadata +2 -4
- data/lib/ruby_lsp/ruby_lsp_rails/rails_client.rb +0 -77
- data/lib/ruby_lsp_rails/rack_app.rb +0 -58
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ecc8c1b4cd4569bdb9c816f842a90f0dfb1122931adcd9c96d1e2eb8a3799471
|
4
|
+
data.tar.gz: 3c1bcc4f69a361ae6a26b635331f6475413fed38bac9a88c7ed45ffea02129eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: eff545775dfa463c99b301a94ab450070f683d3f70a3c974683ac1b311a53d10da57acbd051a6fd0e4c8b005629c1d18bd8d61e33c94548e2fcf2b22b70df606
|
7
|
+
data.tar.gz: 927c991dc2d499be19c626b4a64cfcc11064f2bbadad41abb71ebea13e1e33592810c7fe6135393d7a1c2140d760e8518eee085d3a2d596942af5e031ff8f272
|
data/README.md
CHANGED
@@ -52,16 +52,15 @@ See the [documentation](https://shopify.github.io/ruby-lsp-rails) for more in-de
|
|
52
52
|
|
53
53
|
## How It Works
|
54
54
|
|
55
|
-
|
55
|
+
When Ruby LSP Rails starts, it spawns a `rails runner` instance which runs
|
56
|
+
`[server.rb](https://github.com/Shopify/ruby-lsp-rails/blob/main/lib/ruby_lsp/ruby_lsp_rails/server.rb)`.
|
57
|
+
The addon communicates with this process over a pipe (i.e. `stdin` and `stdout`) to fetch runtime information about the application.
|
56
58
|
|
57
|
-
|
58
|
-
1. A Ruby LSP addon that connects to the exposed APIs to fetch runtime information from the Rails server
|
59
|
-
|
60
|
-
This is why the Rails server needs to be running for some features to work.
|
59
|
+
When extension is stopped (e.g. by quitting the editor), the server instance is shut down.
|
61
60
|
|
62
61
|
> [!NOTE]
|
63
|
-
>
|
64
|
-
>
|
62
|
+
> Prior to v0.3, `ruby-lsp-rails` used a different approach which involved mounting a Rack application within the Rails app.
|
63
|
+
> That approach was brittle and susceptible to the application's configuration, such as routing and middleware.
|
65
64
|
|
66
65
|
## Contributing
|
67
66
|
|
data/lib/ruby-lsp-rails.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require "ruby_lsp/addon"
|
5
5
|
|
6
|
-
require_relative "
|
6
|
+
require_relative "runner_client"
|
7
7
|
require_relative "hover"
|
8
8
|
require_relative "code_lens"
|
9
9
|
|
@@ -12,18 +12,18 @@ module RubyLsp
|
|
12
12
|
class Addon < ::RubyLsp::Addon
|
13
13
|
extend T::Sig
|
14
14
|
|
15
|
-
sig { returns(
|
15
|
+
sig { returns(RunnerClient) }
|
16
16
|
def client
|
17
|
-
@client ||= T.let(
|
17
|
+
@client ||= T.let(RunnerClient.new, T.nilable(RunnerClient))
|
18
18
|
end
|
19
19
|
|
20
20
|
sig { override.params(message_queue: Thread::Queue).void }
|
21
|
-
def activate(message_queue)
|
22
|
-
client.check_if_server_is_running!
|
23
|
-
end
|
21
|
+
def activate(message_queue); end
|
24
22
|
|
25
23
|
sig { override.void }
|
26
|
-
def deactivate
|
24
|
+
def deactivate
|
25
|
+
client.shutdown
|
26
|
+
end
|
27
27
|
|
28
28
|
# Creates a new CodeLens listener. This method is invoked on every CodeLens request
|
29
29
|
sig do
|
@@ -2,34 +2,17 @@
|
|
2
2
|
# frozen_string_literal: true
|
3
3
|
|
4
4
|
require "rails"
|
5
|
-
require "ruby_lsp_rails/rack_app"
|
6
5
|
|
7
6
|
module RubyLsp
|
8
7
|
module Rails
|
9
8
|
class Railtie < ::Rails::Railtie
|
10
9
|
config.ruby_lsp_rails = ActiveSupport::OrderedOptions.new
|
11
|
-
config.ruby_lsp_rails.server = true
|
12
10
|
|
13
11
|
initializer "ruby_lsp_rails.setup" do |_app|
|
14
|
-
config.after_initialize do |
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
T.bind(self, ActionDispatch::Routing::Mapper)
|
19
|
-
mount(RackApp.new => RackApp::BASE_PATH)
|
20
|
-
end
|
21
|
-
|
22
|
-
ssl_enable, host, port = ::Rails::Server::Options.new.parse!(ARGV).values_at(:SSLEnable, :Host, :Port)
|
23
|
-
app_uri = "#{ssl_enable ? "https" : "http"}://#{host}:#{port}"
|
24
|
-
app_uri_path = ::Rails.root.join("tmp", "app_uri.txt")
|
25
|
-
app_uri_path.write(app_uri)
|
26
|
-
|
27
|
-
at_exit do
|
28
|
-
# The app_uri.txt file should only exist when the server is running. The addon uses its presence to
|
29
|
-
# report if the server is running or not. If the server is not running, some of the addon features
|
30
|
-
# will not be available.
|
31
|
-
File.delete(app_uri_path) if File.exist?(app_uri_path)
|
32
|
-
end
|
12
|
+
config.after_initialize do |_app|
|
13
|
+
unless config.ruby_lsp_rails.server.nil?
|
14
|
+
ActiveSupport::Deprecation.new.warn("The `ruby_lsp_rails.server` configuration option is no longer " \
|
15
|
+
"needed and will be removed in a future release.")
|
33
16
|
end
|
34
17
|
end
|
35
18
|
end
|
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.
|
4
|
+
version: 0.3.0
|
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-
|
11
|
+
date: 2024-02-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: actionpack
|
@@ -100,11 +100,9 @@ files:
|
|
100
100
|
- lib/ruby_lsp/ruby_lsp_rails/addon.rb
|
101
101
|
- lib/ruby_lsp/ruby_lsp_rails/code_lens.rb
|
102
102
|
- lib/ruby_lsp/ruby_lsp_rails/hover.rb
|
103
|
-
- lib/ruby_lsp/ruby_lsp_rails/rails_client.rb
|
104
103
|
- lib/ruby_lsp/ruby_lsp_rails/runner_client.rb
|
105
104
|
- lib/ruby_lsp/ruby_lsp_rails/server.rb
|
106
105
|
- lib/ruby_lsp/ruby_lsp_rails/support/rails_document_client.rb
|
107
|
-
- lib/ruby_lsp_rails/rack_app.rb
|
108
106
|
- lib/ruby_lsp_rails/railtie.rb
|
109
107
|
- lib/ruby_lsp_rails/version.rb
|
110
108
|
- lib/tasks/ruby_lsp_rails_tasks.rake
|
@@ -1,77 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require "net/http"
|
5
|
-
|
6
|
-
module RubyLsp
|
7
|
-
module Rails
|
8
|
-
class RailsClient
|
9
|
-
class ServerAddressUnknown < StandardError; end
|
10
|
-
|
11
|
-
extend T::Sig
|
12
|
-
|
13
|
-
SERVER_NOT_RUNNING_MESSAGE = "Rails server is not running. " \
|
14
|
-
"To get Rails features in the editor, boot the Rails server"
|
15
|
-
|
16
|
-
sig { returns(Pathname) }
|
17
|
-
attr_reader :root
|
18
|
-
|
19
|
-
sig { void }
|
20
|
-
def initialize
|
21
|
-
project_root = T.let(Bundler.with_unbundled_env { Bundler.default_gemfile }.dirname, Pathname)
|
22
|
-
dummy_path = project_root.join("test", "dummy")
|
23
|
-
|
24
|
-
@root = T.let(dummy_path.exist? ? dummy_path : project_root, Pathname)
|
25
|
-
app_uri_path = @root.join("tmp", "app_uri.txt")
|
26
|
-
|
27
|
-
if app_uri_path.exist?
|
28
|
-
url = URI(app_uri_path.read.chomp)
|
29
|
-
|
30
|
-
@ssl = T.let(url.scheme == "https", T::Boolean)
|
31
|
-
@address = T.let(
|
32
|
-
[url.host, url.path].reject { |component| component.nil? || component.empty? }.join("/"),
|
33
|
-
T.nilable(String),
|
34
|
-
)
|
35
|
-
@port = T.let(T.must(url.port).to_i, Integer)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
sig { params(name: String).returns(T.nilable(T::Hash[Symbol, T.untyped])) }
|
40
|
-
def model(name)
|
41
|
-
response = request("models/#{name}")
|
42
|
-
return unless response.code == "200"
|
43
|
-
|
44
|
-
JSON.parse(response.body.chomp, symbolize_names: true)
|
45
|
-
rescue Errno::ECONNREFUSED,
|
46
|
-
Errno::EADDRNOTAVAIL,
|
47
|
-
Errno::ECONNRESET,
|
48
|
-
Net::ReadTimeout,
|
49
|
-
Net::OpenTimeout,
|
50
|
-
ServerAddressUnknown
|
51
|
-
nil
|
52
|
-
end
|
53
|
-
|
54
|
-
sig { void }
|
55
|
-
def check_if_server_is_running!
|
56
|
-
request("activate", 0.2)
|
57
|
-
rescue Errno::ECONNREFUSED, Errno::EADDRNOTAVAIL, Errno::ECONNRESET, ServerAddressUnknown
|
58
|
-
warn(SERVER_NOT_RUNNING_MESSAGE)
|
59
|
-
rescue Net::ReadTimeout, Net::OpenTimeout
|
60
|
-
# If the server is running, but the initial request is taking too long, we don't want to block the
|
61
|
-
# initialization of the Ruby LSP
|
62
|
-
end
|
63
|
-
|
64
|
-
private
|
65
|
-
|
66
|
-
sig { params(path: String, timeout: T.nilable(Float)).returns(Net::HTTPResponse) }
|
67
|
-
def request(path, timeout = nil)
|
68
|
-
raise ServerAddressUnknown unless @address
|
69
|
-
|
70
|
-
http = Net::HTTP.new(@address, @port)
|
71
|
-
http.use_ssl = @ssl
|
72
|
-
http.read_timeout = timeout if timeout
|
73
|
-
http.get("/ruby_lsp_rails/#{path}")
|
74
|
-
end
|
75
|
-
end
|
76
|
-
end
|
77
|
-
end
|
@@ -1,58 +0,0 @@
|
|
1
|
-
# typed: strict
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
module RubyLsp
|
5
|
-
module Rails
|
6
|
-
class RackApp
|
7
|
-
extend T::Sig
|
8
|
-
|
9
|
-
BASE_PATH = "/ruby_lsp_rails/"
|
10
|
-
|
11
|
-
sig { params(env: T::Hash[T.untyped, T.untyped]).returns(T::Array[T.untyped]) }
|
12
|
-
def call(env)
|
13
|
-
request = ActionDispatch::Request.new(env)
|
14
|
-
path = request.path
|
15
|
-
|
16
|
-
route, argument = path.delete_prefix(BASE_PATH).split("/")
|
17
|
-
|
18
|
-
case route
|
19
|
-
when "activate"
|
20
|
-
[200, { "Content-Type" => "application/json" }, []]
|
21
|
-
when "models"
|
22
|
-
resolve_database_info_from_model(argument)
|
23
|
-
else
|
24
|
-
not_found
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
private
|
29
|
-
|
30
|
-
sig { params(model_name: String).returns(T::Array[T.untyped]) }
|
31
|
-
def resolve_database_info_from_model(model_name)
|
32
|
-
const = ActiveSupport::Inflector.safe_constantize(model_name)
|
33
|
-
|
34
|
-
if const && const < ActiveRecord::Base && !const.abstract_class?
|
35
|
-
begin
|
36
|
-
schema_file = ActiveRecord::Tasks::DatabaseTasks.schema_dump_path(const.connection.pool.db_config)
|
37
|
-
rescue => e
|
38
|
-
warn("Could not locate schema: #{e.message}")
|
39
|
-
end
|
40
|
-
|
41
|
-
body = JSON.dump({
|
42
|
-
columns: const.columns.map { |column| [column.name, column.type] },
|
43
|
-
schema_file: schema_file,
|
44
|
-
})
|
45
|
-
|
46
|
-
[200, { "Content-Type" => "application/json" }, [body]]
|
47
|
-
else
|
48
|
-
not_found
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
sig { returns(T::Array[T.untyped]) }
|
53
|
-
def not_found
|
54
|
-
[404, { "Content-Type" => "text/plain" }, ["Not Found"]]
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|