ruby-lsp-rails 0.2.10 → 0.3.0
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 +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
|