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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 41272ca8c9212dc08dc09beeef481c282656946e182e0c62c72585ecc6cfe658
4
- data.tar.gz: 0dc3c80ab252123291ab7b77a02b22fff1f27dd5bc07eb49ea51dfdbff4310f2
3
+ metadata.gz: ecc8c1b4cd4569bdb9c816f842a90f0dfb1122931adcd9c96d1e2eb8a3799471
4
+ data.tar.gz: 3c1bcc4f69a361ae6a26b635331f6475413fed38bac9a88c7ed45ffea02129eb
5
5
  SHA512:
6
- metadata.gz: fb753c4c3a4282faeefbd254840be186969179e6eaff83320a79e6fd5d2149e4d35acd68f7c38d8bd436e07b233f5e3cebf553c53317576333b83c4b81582dc0
7
- data.tar.gz: 881b3d77f931f890ed68a12b478b7762ea491165e70c4cd61af078eccdeb139c28d9f9eed83406b7fa01927e6b0ea3a07993e0d73ae4c0eede146c6fb124a4aa
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
- This gem consists of two components that enable enhanced Rails functionality in the editor:
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
- 1. A Rack app that automatically exposes APIs when Rails server is running
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
- > There is no need to restart the Ruby LSP every time the Rails server is booted.
64
- > If the server is shut down, the extra features will temporarily disappear and reappear once the server is running again.
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
 
@@ -1,9 +1,6 @@
1
1
  # typed: strict
2
2
  # frozen_string_literal: true
3
3
 
4
- require "sorbet-runtime"
5
- require "pathname"
6
-
7
4
  require "ruby_lsp_rails/version"
8
5
  require "ruby_lsp_rails/railtie"
9
6
 
@@ -3,7 +3,7 @@
3
3
 
4
4
  require "ruby_lsp/addon"
5
5
 
6
- require_relative "rails_client"
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(RailsClient) }
15
+ sig { returns(RunnerClient) }
16
16
  def client
17
- @client ||= T.let(RailsClient.new, T.nilable(RailsClient))
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; end
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
@@ -22,7 +22,7 @@ module RubyLsp
22
22
 
23
23
  sig do
24
24
  params(
25
- client: RailsClient,
25
+ client: RunnerClient,
26
26
  response_builder: ResponseBuilders::Hover,
27
27
  nesting: T::Array[String],
28
28
  index: RubyIndexer::Index,
@@ -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 |app|
15
- # If we start the app with `bin/rails console` then `Rails::Server` is not defined.
16
- if defined?(::Rails::Server) && config.ruby_lsp_rails.server
17
- app.routes.prepend do
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
@@ -3,6 +3,6 @@
3
3
 
4
4
  module RubyLsp
5
5
  module Rails
6
- VERSION = "0.2.10"
6
+ VERSION = "0.3.0"
7
7
  end
8
8
  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.2.10
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-13 00:00:00.000000000 Z
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