diff --git a/README.md b/README.md index 325e781..b34c385 100644 --- a/README.md +++ b/README.md @@ -96,7 +96,7 @@ name. That seems to be the fairest way to arrange this table. | Python | [flake8](http://flake8.pycqa.org/en/latest/), [mypy](http://mypy-lang.org/), [pylint](https://www.pylint.org/) | | reStructuredText | [proselint](http://proselint.com/)| | RPM spec | [rpmlint](https://github.com/rpm-software-management/rpmlint) | -| Ruby | [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) | +| Ruby | [reek](https://github.com/troessner/reek), [rubocop](https://github.com/bbatsov/rubocop), [ruby](https://www.ruby-lang.org) | | Rust | [rustc](https://www.rust-lang.org/), cargo (see `:help ale-integration-rust` for configuration instructions) | | SASS | [sass-lint](https://www.npmjs.com/package/sass-lint), [stylelint](https://github.com/stylelint/stylelint) | | SCSS | [sass-lint](https://www.npmjs.com/package/sass-lint), [scss-lint](https://github.com/brigade/scss-lint), [stylelint](https://github.com/stylelint/stylelint) | diff --git a/ale_linters/ruby/reek.vim b/ale_linters/ruby/reek.vim new file mode 100644 index 0000000..5f476fb --- /dev/null +++ b/ale_linters/ruby/reek.vim @@ -0,0 +1,53 @@ +" Author: Eddie Lebow https://github.com/elebow +" Description: Reek, a code smell detector for Ruby files + +let g:ale_ruby_reek_show_context = +\ get(g:, 'ale_ruby_reek_show_context', 0) + +let g:ale_ruby_reek_show_wiki_link = +\ get(g:, 'ale_ruby_reek_show_wiki_link', 0) + +function! ale_linters#ruby#reek#Handle(buffer, lines) abort + if len(a:lines) == 0 + return [] + endif + + let l:errors = json_decode(a:lines[0]) + + let l:output = [] + + for l:error in l:errors + for l:location in l:error.lines + call add(l:output, { + \ 'lnum': l:location, + \ 'type': 'W', + \ 'text': s:BuildText(a:buffer, l:error), + \}) + endfor + endfor + + return l:output +endfunction + +function! s:BuildText(buffer, error) abort + let l:text = a:error.smell_type . ':' + + if ale#Var(a:buffer, 'ruby_reek_show_context') + let l:text .= ' ' . a:error.context + endif + + let l:text .= ' ' . a:error.message + + if ale#Var(a:buffer, 'ruby_reek_show_wiki_link') + let l:text .= ' [' . a:error.wiki_link . ']' + endif + + return l:text +endfunction + +call ale#linter#Define('ruby', { +\ 'name': 'reek', +\ 'executable': 'reek', +\ 'command': 'reek -f json --no-progress --no-color', +\ 'callback': 'ale_linters#ruby#reek#Handle', +\}) diff --git a/doc/ale-ruby.txt b/doc/ale-ruby.txt index 77ea734..033da36 100644 --- a/doc/ale-ruby.txt +++ b/doc/ale-ruby.txt @@ -2,6 +2,27 @@ ALE Ruby Integration *ale-ruby-options* +------------------------------------------------------------------------------- +reek *ale-ruby-reek* + +g:ale_ruby_reek_show_context *g:ale_ruby_reek_show_context* + + Type: |Number| + Default: 0 + + Controls whether context is included in the linter message. Defaults to off + because context is usually obvious while viewing a file. + + +g:ale_ruby_reek_show_wiki_link *g:ale_ruby_reek_show_wiki_link* + + Type: |Number| + Default: 0 + + Controls whether linter messages contain a link to an explanatory wiki page + for the type of code smell. Defaults to off to improve readability. + + ------------------------------------------------------------------------------- rubocop *ale-ruby-rubocop* diff --git a/doc/ale.txt b/doc/ale.txt index 8979b1b..8011a21 100644 --- a/doc/ale.txt +++ b/doc/ale.txt @@ -60,6 +60,7 @@ CONTENTS *ale-contents* mypy................................|ale-python-mypy| pylint..............................|ale-python-pylint| ruby..................................|ale-ruby-options| + reek................................|ale-ruby-reek| rubocop.............................|ale-ruby-rubocop| rust..................................|ale-rust-options| cargo...............................|ale-rust-cargo| @@ -155,7 +156,7 @@ The following languages and tools are supported. * reStructuredText: 'proselint' * RPM spec: 'spec' * Rust: 'rustc' (see |ale-integration-rust|) -* Ruby: 'rubocop' +* Ruby: 'reek', 'rubocop' * SASS: 'sasslint', 'stylelint' * SCSS: 'sasslint', 'scsslint', 'stylelint' * Scala: 'scalac' diff --git a/test/handler/test_reek_handler.vader b/test/handler/test_reek_handler.vader new file mode 100644 index 0000000..67ba6f6 --- /dev/null +++ b/test/handler/test_reek_handler.vader @@ -0,0 +1,69 @@ +Before: + runtime ale_linters/ruby/reek.vim + +After: + call ale#linter#Reset() + +Execute(The reek handler should parse JSON correctly, with only context enabled): + let g:ale_ruby_reek_show_context = 1 + let g:ale_ruby_reek_show_wiki_link = 0 + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'text': 'Rule1: Context#method violates rule number one', + \ 'type': 'W', + \ }, + \ { + \ 'lnum': 34, + \ 'text': 'Rule2: Context#method violates rule number two', + \ 'type': 'W', + \ }, + \ { + \ 'lnum': 56, + \ 'text': 'Rule2: Context#method violates rule number two', + \ 'type': 'W', + \ }, + \ ], + \ ale_linters#ruby#reek#Handle(347, [ + \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"},{"context":"Context#method","lines":[34, 56],"message":"violates rule number two","smell_type":"Rule2","source":"/home/user/file.rb","name":"bad code","count":2,"wiki_link":"https://example.com/Rule1.md"}]' + \ ]) + +Execute(The reek handler should parse JSON correctly, with no context or wiki links): + let g:ale_ruby_reek_show_context = 0 + let g:ale_ruby_reek_show_wiki_link = 0 + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'text': 'Rule1: violates rule number one', + \ 'type': 'W', + \ }, + \ ], + \ ale_linters#ruby#reek#Handle(347, [ + \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"}]' + \ ]) + +Execute(The reek handler should parse JSON correctly, with both context and wiki links): + let g:ale_ruby_reek_show_context = 1 + let g:ale_ruby_reek_show_wiki_link = 1 + + AssertEqual + \ [ + \ { + \ 'lnum': 12, + \ 'text': 'Rule1: Context#method violates rule number one [https://example.com/Rule1.md]', + \ 'type': 'W', + \ }, + \ ], + \ ale_linters#ruby#reek#Handle(347, [ + \ '[{"context":"Context#method","lines":[12],"message":"violates rule number one","smell_type":"Rule1","source":"/home/user/file.rb","parameter":"bad parameter","wiki_link":"https://example.com/Rule1.md"}]' + \ ]) + +Execute(The reek handler should parse JSON correctly when there is no output from reek): + AssertEqual + \ [], + \ ale_linters#ruby#reek#Handle(347, [ + \ ])