Skip to content

Commit 47169fe

Browse files
committed
Add rubocop integration
1 parent ab8998d commit 47169fe

File tree

6 files changed

+106
-1
lines changed

6 files changed

+106
-1
lines changed

Dockerfile.development

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ RUN mkdir /app /vendor && chown -R ruby:ruby /app /vendor
88
ENV LANG=C.UTF-8 \
99
BUNDLE_PATH=/vendor/bundle/$RUBY_VERSION \
1010
BUNDLE_JOBS=4
11+
ENV PATH=$PATH:/vendor/bundle/$RUBY_VERSION/bin
1112

1213
USER ruby
1314
WORKDIR /app

bin/setup

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,5 @@ IFS=$'\n\t'
44
set -vx
55

66
bundle install
7+
8+
# Do any other automated setup that you need to do here

lib/language_server.rb

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
require "language_server/logger"
33
require "language_server/protocol"
44
require "language_server/linter/ruby_wc"
5+
require "language_server/linter/rubocop"
56
require "language_server/completion_provider/rcodetools"
67
require "language_server/completion_provider/ad_hoc"
78
require "language_server/definition_provider/ad_hoc"
@@ -90,11 +91,13 @@ def on(method, &callback)
9091

9192
on :"textDocument/didChange" do |request:, notifier:, file_store:, project:|
9293
uri = request[:params][:textDocument][:uri]
94+
filePath = uri.match(/^file:\/\/(.*\.rb)/)[1]
9395
text = request[:params][:contentChanges][0][:text]
9496
file_store.cache(uri, text)
9597
project.recalculate_result(uri)
98+
diagnostics = (Linter::Rubocop.new(filePath).call + Linter::RubyWC.new(text).call).flatten
9699

97-
diagnostics = Linter::RubyWC.new(text).call.map do |error|
100+
diagnostics = diagnostics.map do |error|
98101
Protocol::Interface::Diagnostic.new(
99102
message: error.message,
100103
severity: error.warning? ? Protocol::Constant::DiagnosticSeverity::WARNING : Protocol::Constant::DiagnosticSeverity::ERROR,
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
require "open3"
2+
3+
module LanguageServer
4+
module Linter
5+
class Rubocop
6+
def initialize(path, config_path="")
7+
@path = path
8+
@config_path = config_path
9+
end
10+
11+
def call
12+
Bundler.with_clean_env do
13+
command = "rubocop #{@path} --format json --force-exclusion"
14+
command += " --config #{@config_path}" if @config_path != ""
15+
o, err, _ = Open3.capture3(command)
16+
return [Error.new(line_num: 0, message: err, type: 'error')] if err != ""
17+
JSON
18+
.parse(o)['files'].map { |v| v['offenses'] }
19+
.flatten
20+
.map { |v| Error.new(line_num: v['location']['line'].to_i - 1, message: v['message'], type: convert_type(v['severity'])) }
21+
end
22+
end
23+
24+
private
25+
26+
def convert_type(type)
27+
case type
28+
when 'refactor' then 'warning'
29+
when 'convention' then 'warning'
30+
when 'warning' then 'warning'
31+
when 'error' then 'error'
32+
when 'fatal' then 'error'
33+
end
34+
end
35+
36+
end
37+
end
38+
end

test/fixtures/rubocop.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
AllCops:
2+
DisabledByDefault: true
3+
4+
Lint/UselessAssignment:
5+
Enabled: true
6+
StringLiterals:
7+
EnforcedStyle: single_quotes
Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
require 'test_helper'
2+
3+
module LanguageServer::Linter
4+
class RubocopTest < Minitest::Test
5+
def setup
6+
@config_path = File.expand_path('./../../../fixtures/rubocop.yml', __FILE__)
7+
end
8+
9+
def test_fatal_error
10+
file = Tempfile.open(['bar_', '.rb']) do |v|
11+
v.puts 'require "foo'
12+
v
13+
end
14+
15+
actual = Rubocop.new(file.path, @config_path).call
16+
17+
assert do
18+
actual == [
19+
Error.new(
20+
line_num: 0,
21+
message: "unterminated string meets end of file\n(Using Ruby 2.1 parser; configure using `TargetRubyVersion` parameter, under `AllCops`)",
22+
type: 'error'
23+
)
24+
]
25+
end
26+
end
27+
28+
def test_warning_error
29+
file = Tempfile.open(['bar_', '.rb']) do |v|
30+
v.puts "a = 'a'"
31+
v
32+
end
33+
34+
actual = Rubocop.new(file.path, @config_path).call
35+
36+
assert do
37+
actual.first == Error.new(line_num: 0, message: "Useless assignment to variable - `a`.", type: 'warning')
38+
end
39+
end
40+
41+
def test_convention_error
42+
file = Tempfile.open(['bar_', '.rb']) do |v|
43+
v.puts 'require "foo"'
44+
v
45+
end
46+
47+
actual = Rubocop.new(file.path, @config_path).call
48+
49+
assert do
50+
actual.first == Error.new(line_num: 0, message: "Prefer single-quoted strings when you don't need string interpolation or special symbols.", type: 'warning')
51+
end
52+
end
53+
end
54+
end

0 commit comments

Comments
 (0)