-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Initial implementation based on a combination of:
- https://github.com/standardrb/standard/pull/630/files - https://github.com/castwide/solargraph-reek/blob/master/lib/solargraph-reek.rb
- Loading branch information
Showing
9 changed files
with
280 additions
and
54 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'bundler/setup' | ||
require 'sorbet-runtime' | ||
require 'ruby_lsp/addon' | ||
require 'ruby_lsp/base_server' | ||
require 'ruby_lsp/server' | ||
require 'uri' | ||
require_relative 'runner' | ||
|
||
module RubyLsp | ||
module Reek | ||
# Implements the RubyLsp::Addon interface to provide Reek linter support to Ruby LSP. | ||
class Addon < ::RubyLsp::Addon | ||
def initializer | ||
@runner = nil | ||
end | ||
|
||
# @return [String] The name of the addon. | ||
def name | ||
'Reek: Code smell detector for Ruby' | ||
end | ||
|
||
# @param global_state [GlobalState] The global state of the Ruby LSP server. | ||
# @param outgoing_queue [Thread::Queue] The outgoing message queue of the Ruby LSP server. | ||
def activate(global_state, message_queue) | ||
warn "Activating Reek Ruby LSP addon v#{::RubyLsp::Reek::VERSION}" | ||
@runner = Runner.new | ||
global_state.register_formatter('reek', @runner) | ||
register_additional_file_watchers(global_state, message_queue) | ||
warn "Initialized Reek Ruby LSP addon v#{::RubyLsp::Reek::VERSION}" | ||
end | ||
|
||
# @return [nil] | ||
def deactivate | ||
@runner = nil | ||
end | ||
|
||
# @param global_state [GlobalState] The global state of the Ruby LSP server. | ||
# @param outgoing_queue [Thread::Queue] The outgoing message queue of the Ruby LSP server. | ||
def register_additional_file_watchers(global_state, message_queue) | ||
return unless global_state.supports_watching_files | ||
|
||
message_queue << Request.new( | ||
id: 'reek-file-watcher', | ||
method: 'client/registerCapability', | ||
params: Interface::RegistrationParams.new( | ||
registrations: [ | ||
Interface::Registration.new( | ||
id: 'workspace/didChangeWatchedFilesReek', | ||
method: 'workspace/didChangeWatchedFiles', | ||
register_options: Interface::DidChangeWatchedFilesRegistrationOptions.new( | ||
watchers: [ | ||
Interface::FileSystemWatcher.new( | ||
glob_pattern: '**/.reek.yml', | ||
kind: Constant::WatchKind::CREATE | Constant::WatchKind::CHANGE | Constant::WatchKind::DELETE | ||
) | ||
] | ||
) | ||
) | ||
] | ||
) | ||
) | ||
end | ||
|
||
# @param changes [Array<Hash>] The changes to the watched files. | ||
def workspace_did_change_watched_files(changes) | ||
return unless changes.any? { |change| change[:uri].end_with?('.reek.yml') } | ||
|
||
@runner.init! | ||
warn "Re-initialized Reek Ruby LSP addon v#{::RubyLsp::Reek::VERSION} due to .reek.yml file change" | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
# frozen_string_literal: true | ||
|
||
require 'reek' | ||
|
||
module RubyLsp | ||
module Reek | ||
# Implements Ruby LSP Formatter interface: specifically run_diagnostic | ||
class Runner | ||
include RubyLsp::Requests::Support::Formatter | ||
|
||
def initialize | ||
@config = ::Reek::Configuration::AppConfiguration.from_default_path | ||
end | ||
|
||
# We are not implementing this method, but it is required by the interface | ||
# | ||
# @param uri [String] The URI of the document to format. | ||
# @param document [RubyLsp::Interface::TextDocumentItem] The document to format. | ||
# @return [String] The formatted document. | ||
def run_formatting(_uri, document) | ||
document.source | ||
end | ||
|
||
# @param uri [String] The URI of the document to run diagnostics on. | ||
# @param document [RubyLsp::Interface::TextDocumentItem] The document to run diagnostics on. | ||
def run_diagnostic(uri, document) | ||
return [] if config.path_excluded?(Pathname.new(uri.path)) | ||
|
||
examiner = ::Reek::Examiner.new(document.source, configuration: config) | ||
examiner.smells.map { |w| warning_to_diagnostic(w) } | ||
end | ||
|
||
private | ||
|
||
attr_reader :config | ||
|
||
# @param warning [Reek::SmellWarning] The warning to convert to a diagnostic. | ||
# @return [RubyLsp::Interface::Diagnostic] The diagnostic. | ||
def warning_to_diagnostic(warning) | ||
::RubyLsp::Interface::Diagnostic.new( | ||
range: ::RubyLsp::Interface::Range.new( | ||
start: ::RubyLsp::Interface::Position.new( | ||
line: warning.lines.first - 1, | ||
character: 0 | ||
), | ||
end: ::RubyLsp::Interface::Position.new( | ||
line: warning.lines.last - 1, | ||
character: 0 | ||
) | ||
), | ||
severity: Constant::DiagnosticSeverity::WARNING, | ||
code: warning.smell_type, | ||
code_description: ::RubyLsp::Interface::CodeDescription.new(href: warning.explanatory_link), | ||
source: 'Reek', | ||
message: warning.message | ||
) | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,6 +2,6 @@ | |
|
||
module RubyLsp | ||
module Reek | ||
VERSION = "0.1.0" | ||
VERSION = '0.1.0' | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,45 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative "lib/ruby_lsp/reek/version" | ||
require_relative 'lib/ruby_lsp/reek/version' | ||
|
||
Gem::Specification.new do |spec| | ||
spec.name = "ruby-lsp-reek" | ||
spec.name = 'ruby-lsp-reek' | ||
spec.version = RubyLsp::Reek::VERSION | ||
spec.authors = ["Iain Gray"] | ||
spec.email = ["[email protected]"] | ||
spec.authors = ['Iain Gray'] | ||
spec.email = ['[email protected]'] | ||
|
||
spec.summary = 'Ruby LSP Reek' | ||
spec.description = 'An addon for Ruby LSP that enables linting with reek' | ||
spec.homepage = 'https://github.com/igray/ruby-lsp-reek' | ||
spec.license = "MIT" | ||
spec.license = 'MIT' | ||
spec.required_ruby_version = Gem::Requirement.new('>= 2.5.0') | ||
|
||
spec.metadata["allowed_push_host"] = "https://rubygems.org" | ||
spec.metadata["homepage_uri"] = spec.homepage | ||
spec.metadata["source_code_uri"] = spec.homepage | ||
spec.metadata["changelog_uri"] = spec.homepage | ||
spec.metadata['allowed_push_host'] = 'https://rubygems.org' | ||
spec.metadata['homepage_uri'] = spec.homepage | ||
spec.metadata['source_code_uri'] = spec.homepage | ||
spec.metadata['changelog_uri'] = spec.homepage | ||
|
||
spec.files = Dir.chdir(__dir__) do | ||
`git ls-files -z`.split("\x0").reject do |f| | ||
(File.expand_path(f) == __FILE__) || | ||
f.start_with?(*%w[bin/ test/ .git Gemfile]) | ||
end | ||
end | ||
spec.bindir = "exe" | ||
spec.bindir = 'exe' | ||
spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) } | ||
spec.require_paths = ["lib"] | ||
spec.require_paths = ['lib'] | ||
|
||
spec.add_dependency("ruby-lsp", ">= 0.12.0") | ||
spec.add_dependency("reek", ">= 5.0") | ||
spec.add_dependency('reek', '>= 5.0') | ||
spec.add_dependency('ruby-lsp', '>= 0.12.0') | ||
spec.add_dependency('sorbet-runtime', '>= 0.5.5685') | ||
|
||
# For more information and examples about making a new gem, check out our | ||
# guide at: https://bundler.io/guides/creating_gem.html | ||
spec.add_development_dependency "bundler", "~> 2.4" | ||
spec.add_development_dependency "minitest", "~> 5.20" | ||
spec.add_development_dependency "rake", "~> 13.1" | ||
spec.add_development_dependency "standard", "~> 1.31" | ||
spec.add_development_dependency "rubocop-minitest", "~> 0.35" | ||
spec.add_development_dependency "rubocop-rake", "~> 0.6" | ||
spec.add_development_dependency 'bundler', '~> 2.4' | ||
spec.add_development_dependency 'minitest', '~> 5.20' | ||
spec.add_development_dependency 'pry', '~> 0.14' | ||
spec.add_development_dependency 'rake', '~> 13.1' | ||
spec.add_development_dependency 'rubocop-minitest', '~> 0.35' | ||
spec.add_development_dependency 'rubocop-rake', '~> 0.6' | ||
spec.add_development_dependency 'standard', '~> 1.31' | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,116 @@ | ||
$LOAD_PATH.unshift(File.expand_path('../lib', __dir__)) | ||
|
||
require 'bundler/setup' | ||
require 'minitest/autorun' | ||
require 'sorbet-runtime' | ||
require 'core_ext/uri' | ||
require 'language_server-protocol' | ||
require 'ruby_indexer/ruby_indexer' | ||
require 'ruby_lsp/addon' | ||
require 'ruby_lsp/base_server' | ||
require 'ruby_lsp/server' | ||
require 'ruby_lsp/requests' | ||
require 'ruby_lsp/utils' | ||
require 'ruby_lsp/store' | ||
require 'ruby_lsp/document' | ||
require 'ruby_lsp/global_state' | ||
require 'ruby_lsp/ruby_document' | ||
require 'ruby_lsp/type_inferrer' | ||
require 'prism' | ||
require 'pry' | ||
require 'ruby_lsp/reek/addon' | ||
|
||
class RubyLspAddonTest < Minitest::Test | ||
def setup | ||
@addon = RubyLsp::Reek::Addon.new | ||
super | ||
end | ||
|
||
def test_name | ||
assert_equal 'Reek: Code smell detector for Ruby', @addon.name | ||
end | ||
|
||
def test_diagnostic | ||
source = <<~RUBY | ||
def foo | ||
s = 'hello' | ||
puts s | ||
end | ||
RUBY | ||
with_server(source, 'simple.rb') do |server, uri| | ||
server.process_message( | ||
id: 2, | ||
method: 'textDocument/diagnostic', | ||
params: { | ||
textDocument: { | ||
uri: | ||
} | ||
} | ||
) | ||
|
||
result = server.pop_response | ||
|
||
assert_instance_of(RubyLsp::Result, result) | ||
assert_equal 'full', result.response.kind | ||
assert_equal 1, result.response.items.size | ||
item = result.response.items.first | ||
assert_equal({ line: 1, character: 0 }, item.range.start.to_hash) | ||
assert_equal({ line: 1, character: 0 }, item.range.end.to_hash) | ||
assert_equal RubyLsp::Constant::DiagnosticSeverity::WARNING, item.severity | ||
assert_equal 'UncommunicativeVariableName', item.code | ||
assert_equal( | ||
'https://github.com/troessner/reek/blob/v6.3.0/docs/Uncommunicative-Variable-Name.md', | ||
item.code_description.href | ||
) | ||
assert_equal 'Reek', item.source | ||
assert_equal("has the variable name 's'", item.message) | ||
end | ||
end | ||
|
||
private | ||
|
||
# Lifted from here, because we need to override the formatter to "standard" in the test helper: | ||
# https://github.com/Shopify/ruby-lsp/blob/4c1906172add4d5c39c35d3396aa29c768bfb898/lib/ruby_lsp/test_helper.rb#L20 | ||
def with_server( | ||
source = nil, | ||
path = 'fake.rb', | ||
pwd: 'test/fixture/ruby_lsp', | ||
stub_no_typechecker: false, | ||
load_addons: true, | ||
&block | ||
) | ||
Dir.chdir pwd do | ||
server = RubyLsp::Server.new(test_mode: true) | ||
uri = Kernel.URI(File.join(server.global_state.workspace_path, path)) | ||
server.global_state.instance_variable_set(:@linters, ['reek']) | ||
server.global_state.stubs(:typechecker).returns(false) if stub_no_typechecker | ||
|
||
if source | ||
server.process_message( | ||
{ | ||
method: 'textDocument/didOpen', | ||
params: { | ||
textDocument: { | ||
uri:, | ||
text: source, | ||
version: 1 | ||
} | ||
} | ||
} | ||
) | ||
end | ||
|
||
server.global_state.index.index_single( | ||
RubyIndexer::IndexablePath.new(nil, uri.to_standardized_path), | ||
source | ||
) | ||
server.load_addons if load_addons | ||
block.call(server, uri) | ||
end | ||
ensure | ||
if load_addons | ||
RubyLsp::Addon.addons.each(&:deactivate) | ||
RubyLsp::Addon.addons.clear | ||
end | ||
end | ||
end |
This file was deleted.
Oops, something went wrong.