-
Notifications
You must be signed in to change notification settings - Fork 154
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve detection for rails as the testing framework #2161
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,8 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
require "ruby_lsp/listeners/rails_app" | ||
|
||
module RubyLsp | ||
class GlobalState | ||
extend T::Sig | ||
|
@@ -133,9 +135,9 @@ def detect_test_library(dependencies) | |
"rspec" | ||
# A Rails app may have a dependency on minitest, but we would instead want to use the Rails test runner provided | ||
# by ruby-lsp-rails. A Rails app doesn't need to depend on the rails gem itself, individual components like | ||
# activestorage may be added to the gemfile so that other components aren't downloaded. Check for the presence | ||
# of bin/rails to support these cases. | ||
elsif bin_rails_present | ||
# activestorage may be added to the gemfile so that other components aren't downloaded. Check for inheritance of | ||
# `Rails::Application` in config/application.rb to support these cases. | ||
elsif rails_app? | ||
"rails" | ||
# NOTE: Intentionally ends with $ to avoid mis-matching minitest-reporters, etc. in a Rails app. | ||
elsif dependencies.any?(/^minitest$/) | ||
|
@@ -166,8 +168,24 @@ def detect_typechecker(dependencies) | |
end | ||
|
||
sig { returns(T::Boolean) } | ||
def bin_rails_present | ||
File.exist?(File.join(workspace_path, "bin/rails")) | ||
def rails_app? | ||
config = rails_app_config | ||
return false unless config | ||
|
||
result = Prism.parse(config) | ||
return false unless result | ||
|
||
dispatcher = Prism::Dispatcher.new | ||
listener = Listeners::RailsApp.new(dispatcher) | ||
dispatcher.dispatch(result.value) | ||
|
||
listener.rails_app | ||
end | ||
|
||
sig { returns(T.nilable(String)) } | ||
def rails_app_config | ||
path = File.join(workspace_path, "config/application.rb") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm wondering if it's possible that the file is not right there, but would be nested deeper? I'm not too familiar with the different way people configure their project in relation with the workspace. At the same time, it might be best to stay with the simple solution. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's possible in theory for it to be in other locations, but would be very unusual, so I don't think we should worry about that. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. (and we already require that the Rails app is at the root of a workspace, so that's not a concern). |
||
File.read(path) if File.exist?(path) | ||
end | ||
|
||
sig { returns(T::Boolean) } | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
# typed: strict | ||
# frozen_string_literal: true | ||
|
||
module RubyLsp | ||
module Listeners | ||
class RailsApp | ||
extend T::Sig | ||
|
||
sig { returns(T::Boolean) } | ||
attr_reader :rails_app | ||
|
||
sig { params(dispatcher: Prism::Dispatcher).void } | ||
def initialize(dispatcher) | ||
@rails_app = T.let(false, T::Boolean) | ||
dispatcher.register(self, :on_class_node_enter) | ||
end | ||
|
||
sig { params(node: Prism::ClassNode).void } | ||
def on_class_node_enter(node) | ||
superclass = node.superclass | ||
case superclass | ||
when Prism::ConstantPathNode | ||
@rails_app = true if superclass.full_name == "Rails::Application" | ||
end | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would probably have done it with a simple regex, but your solution looks much cleaner 👌🏼