Ale: ALE not working with a locally installed Rubocop

Created on 6 Mar 2018  路  6Comments  路  Source: dense-analysis/ale

Information

VIM version

VIM - Vi IMproved 8.0 (2016 Sep 12, compiled Feb 12 2018 14:37:54)
Included patches: 1-2

Operating System: CentOS 6

:ALEInfo

Current Filetype: ruby
Available Linters: ['brakeman', 'rails_best_practices', 'reek', 'rubocop', 'ruby']
Enabled Linters: ['rubocop', 'ruby']
Linter Variables:
let g:ale_ruby_rubocop_executable = '/export/home/ryanma/.gem/ruby/2.4.0/bin/rubocop'
let g:ale_ruby_rubocop_options = ''
let g:ale_ruby_ruby_executable = 'ruby'
Global Variables:
let g:ale_echo_cursor = 1
let g:ale_echo_msg_error_str = 'Error'
let g:ale_echo_msg_format = '%code: %%s'
let g:ale_echo_msg_warning_str = 'Warning'
let g:ale_enabled = 1
let g:ale_fix_on_save = 0
let g:ale_fixers = {'ruby': ['rubocop']}
let g:ale_keep_list_window_open = 0
let g:ale_lint_delay = 200
let g:ale_lint_on_enter = 1
let g:ale_lint_on_save = 1
let g:ale_lint_on_text_changed = 'always'
let g:ale_linter_aliases = {}
let g:ale_linters = {'ruby': ['ruby', 'rubocop']}
let g:ale_open_list = 0
let g:ale_set_highlights = 1
let g:ale_set_loclist = 1
let g:ale_set_quickfix = 0
let g:ale_set_signs = 1
let g:ale_sign_column_always = 1
let g:ale_sign_error = '>>'
let g:ale_sign_offset = 1000000
let g:ale_sign_warning = '--'
let g:ale_statusline_format = ['%d error(s)', '%d warning(s)', 'OK']
let g:ale_warn_about_trailing_whitespace = 1
Command History:
(executable check - success) /export/home/ryanma/.gem/ruby/2.4.0/bin/rubocop
(finished - exit code 1) ['/bin/bash', '-c', '''/export/home/ryanma/.gem/ruby/2.4.0/bin/rubocop'' --format json --force-exclusion --stdin ''<path_to_file>/config/deploy.rb'' < ''/tmp/vEUIODm/5/deploy.rb''']
<<<NO OUTPUT RETURNED>>>
(executable check - success) ruby
(finished - exit code 0) ['/bin/bash', '-c', '''ruby'' -w -c -T1 ''/tmp/vEUIODm/6/deploy.rb''']
<<<NO OUTPUT RETURNED>>>

What went wrong

ALE with Rubocop seem to be having issues reading the current buffer.

  • Using ruby as a linter works fine, and running /bin/bash -c '''/export/home/ryanma/.gem/ruby/2.4.0/bin/rubocop'' --format json --force-exclusion --stdin ''<path_to_file>/config/deploy.rb'' < ''<path_to_file>/config/deploy.rb''' works and prints out the errors the file has
  • I've double checked that I have read/write permissions in the /tmp/ directory
  • I'm on a slightly customized version of CentOS and my box is disconnected from the internet if that helps shed light on this issue
  • I don't have root permissions on this box and it's a local installation of Rubocop, which is why I'm specifying the specific executable to use, though I have the same issue if I rely on the location of the executable that's added to my $PATH

Reproducing the bug

I'm not entirely sure how to reproduce this, unfortunately. Mostly looking for more help to diagnose the setup

bug

Most helpful comment

@ryanma I was able to fix this issue by setting let g:ale_ruby_rubocop_executable = 'bin/rubocop'. This relies on having a binstub for RuboCop generated. For some reason, let g:ale_ruby_rubocop_executable = 'bundle exec rubocop' does not work.

@w0rp I was poking through https://github.com/w0rp/ale/blob/master/ale_linters/ruby/rubocop.vim, and I think I have identified the issue, at least partially. The issue has to do with how the command is being checked and built.

function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
    let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
    let l:exec_args = l:executable =~? 'bundle$'
    \   ? ' exec rubocop'
    \   : ''

    return ale#Escape(l:executable) . l:exec_args
    \   . ' --format json --force-exclusion '
    \   . ale#Var(a:buffer, 'ruby_rubocop_options')
    \   . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction

Based on this, setting let g:ale_ruby_rubocop_executable = 'bundle' will get bundle exec rubocop to work. RuboCop and rails_best_practices appear to have the same bug with setting bundle as the executable. Reek and Brakeman don't appear to have settings to change the executable.

Ruby gems can be installed at the system level or locally through bundler. System level gems can be executed like normal commands. Locally installed gems can be run via bundle exec <command_name>. If a binstub is generated for the locally installed gem, bin/<command_name> can be used.

I think it would be beneficial to have some auto-detection of if a binstub exists and to use it if present. Additionally/alternatively, it would be beneficial to have a setting to use bundle exec for all Ruby commands. vim-test has some auto-detection and config settings that work similar to this.

Command run by ale_linters#ruby#rubocop#GetCommand with different settings

g:ale_ruby_rubocop_executable not set in vimrc - Works with system install
'rubocop' --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bin/rubocop' - Work with binstub
'bin/rubocop' --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bundle' - works with bundle exec
'bundle' exec rubocop --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bundle exec rubocop' - does not work
'bundle exec rubocop' --format json --force-exclusion  --stdin ''

I'm not that good with vimscript, but I would be willing to try fixing or working with someone to fix this.

All 6 comments

@ryanma Have you tried generating rubocop's binstubs?

From your project directory:

$ bundle binstubs rubocop

Thanks for leaving a comment. I don't use Ruby myself.

@ryanma I was able to fix this issue by setting let g:ale_ruby_rubocop_executable = 'bin/rubocop'. This relies on having a binstub for RuboCop generated. For some reason, let g:ale_ruby_rubocop_executable = 'bundle exec rubocop' does not work.

@w0rp I was poking through https://github.com/w0rp/ale/blob/master/ale_linters/ruby/rubocop.vim, and I think I have identified the issue, at least partially. The issue has to do with how the command is being checked and built.

function! ale_linters#ruby#rubocop#GetCommand(buffer) abort
    let l:executable = ale#handlers#rubocop#GetExecutable(a:buffer)
    let l:exec_args = l:executable =~? 'bundle$'
    \   ? ' exec rubocop'
    \   : ''

    return ale#Escape(l:executable) . l:exec_args
    \   . ' --format json --force-exclusion '
    \   . ale#Var(a:buffer, 'ruby_rubocop_options')
    \   . ' --stdin ' . ale#Escape(expand('#' . a:buffer . ':p'))
endfunction

Based on this, setting let g:ale_ruby_rubocop_executable = 'bundle' will get bundle exec rubocop to work. RuboCop and rails_best_practices appear to have the same bug with setting bundle as the executable. Reek and Brakeman don't appear to have settings to change the executable.

Ruby gems can be installed at the system level or locally through bundler. System level gems can be executed like normal commands. Locally installed gems can be run via bundle exec <command_name>. If a binstub is generated for the locally installed gem, bin/<command_name> can be used.

I think it would be beneficial to have some auto-detection of if a binstub exists and to use it if present. Additionally/alternatively, it would be beneficial to have a setting to use bundle exec for all Ruby commands. vim-test has some auto-detection and config settings that work similar to this.

Command run by ale_linters#ruby#rubocop#GetCommand with different settings

g:ale_ruby_rubocop_executable not set in vimrc - Works with system install
'rubocop' --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bin/rubocop' - Work with binstub
'bin/rubocop' --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bundle' - works with bundle exec
'bundle' exec rubocop --format json --force-exclusion  --stdin ''

let g:ale_ruby_rubocop_executable = 'bundle exec rubocop' - does not work
'bundle exec rubocop' --format json --force-exclusion  --stdin ''

I'm not that good with vimscript, but I would be willing to try fixing or working with someone to fix this.

Okay. Note that vim-test allows _executable options to be commands, but ALE _executable options should be only a path to an executable.

ALE _executable options should be only a path to an executable.

I did not realize that. Now it makes sense why setting let g:ale_ruby_rubocop_executable = 'bundle exec rubocop' does not work.

Looking through the documentation again, the section for rails_best_practices mentions setting the executable to bundle, however the documentation for rubocop does not mention this.

g:ale_ruby_rails_best_practices_executable
                                   g:ale_ruby_rails_best_practices_executable
                                   b:ale_ruby_rails_best_practices_executable
  Type: String
  Default: 'rails_best_practices'

  Override the invoked rails_best_practices binary. Set this to 'bundle' to
  invoke 'bundle exec rails_best_practices'.

I think this can be improved mostly by updating documentation, and by updating Reek and Brakeman to have consistent settings to RuboCop and rails_best_practices.

The rubygems-bundler gem aims to fix this kind of issue: it will make calling foo as bundle exec foo automatic if a Gemfile is present, and otherwise falls back to be the globally installed foo.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

chauncey-garrett picture chauncey-garrett  路  3Comments

kronos29296 picture kronos29296  路  4Comments

sodiumjoe picture sodiumjoe  路  4Comments

plexigras picture plexigras  路  3Comments

glepnir picture glepnir  路  3Comments