LoginSignup
1
1

More than 5 years have passed since last update.

【Otemachi.rb#12】Atomでrubocop-auto-correctを使う際の注意点

Last updated at Posted at 2018-12-11
1 / 34

自己紹介

堀崎誠治


事の始まり

Otemachi.rb #10でボッチ演算子を知ったので使ってみたところ、rubocop-auto-correctが反応しなくなった。


rubocop-auto-correct

Atomの拡張機能。
Atom上でrubocopを-aオプションで実行してくれる。
(ファイル保存時に実行する設定もできる)


期待する動作

ok.png


実際の動作

ng.png


無反応。。


設定を変更して情報を増やす

スクリーンショット 2018-12-11 13.33.02.png
⬇️
スクリーンショット 2018-12-11 13.33.23.png


スクリーンショット 2018-12-11 13.33.53.png


Ruby2.2で動作してる
(ボッチ演算子は2.3から)


RubocopのRubyバージョン特定方法

rubocopがrubyのバージョンを特定する優先順位は以下のとおり。

.rubocop.ymlのTargetRubyVersion の値 >
.ruby-versionの値 >
Gemfile.lockのRubyバージョンの値 >
デフォルト値(2.2)


当時の環境

  • .rubocop.ymlなし
$ ls .rubocop.yml ~/.rubocop.yml
ls: .rubocop.yml: No such file or directory
ls: /Users/user/.rubocop.yml: No such file or directory
  • .ruby-veversionあり
$ cat .ruby-version
2.3.1
  • Gemfile.lockにrubyのバージョン指定なし
$ grep -A 1 "RUBY VERSION" Gemfile.lock | wc -l
       0

手動で実行してみる

$ rubocop -a sample.rb
Inspecting 1 file
C

Offenses:

sample.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
def sample(sample_arg)
^

1 file inspected, 1 offense detected, 1 offense corrected

手動なら動くので、拡張機能での実行時との差分を詰めていく


rubocop-auto-correctの実装

rubocop-auto-correct/lib/rubocop-auto-correct.coffee
  autoCorrectBuffer: (editor)  ->
    buffer = editor.getBuffer()

    tempFilePath = @makeTempFile("rubocop.rb")
    fs.writeFileSync(tempFilePath, buffer.getText())

    rubocopCommand = @rubocopCommand()
    command = rubocopCommand[0]
    args = rubocopCommand[1]
      .concat(['-a', tempFilePath])
      .concat(@rubocopConfigPath(buffer.getPath()))

    which command, (err) =>
      return @rubocopNotFoundError() if (err)
      rubocop = spawnSync(command, args, { encoding: 'utf-8', timeout: 5000 })


ログを埋め込んでみる

    args = rubocopCommand[1]
      .concat(['-a', tempFilePath])
      .concat(@rubocopConfigPath(buffer.getPath()))

//ログ埋め込み
    console.log (command + " " + args.join(" "))

実行されたコマンド

  • rubocop.ymlなし

/Users/user/.anyenv/envs/rbenv/shims/rubocop --format json -a /var/folders/09/xr1wrst90lb_295d2pprm6f80000gn/T/d-118916-6808-ed0mea.2qqbj/rubocop.rb

  • rubocop.ymlあり

/Users/user/.anyenv/envs/rbenv/versions/2.5.1/bin/rubocop --format json -a /var/folders/09/xr1wrst90lb_295d2pprm6f80000gn/T/d-1181111-42791-1nbrcij.sdpz/rubocop.rb --config /Users/user/develop/work/qiita/rubocop_auto/.rubocop.yml

  • HOMEディレクトリにのみ.rubocop.ymlあり

/Users/user/.anyenv/envs/rbenv/versions/2.5.1/bin/rubocop --format json -a /var/folders/09/xr1wrst90lb_295d2pprm6f80000gn/T/d-1181111-42791-qw10yv.5336/rubocop.rb --config /Users/user/.rubocop.yml


Rubocopの実装

rubocop/lib/rubocop/config.rb
    def target_ruby_version
      @target_ruby_version ||=
        if for_all_cops['TargetRubyVersion']
          @target_ruby_version_source = :rubocop_yml


          for_all_cops['TargetRubyVersion']
        elsif target_ruby_version_from_version_file
          @target_ruby_version_source = :ruby_version_file


          target_ruby_version_from_version_file
        elsif target_ruby_version_from_bundler_lock_file
          @target_ruby_version_source = :bundler_lock_file


          target_ruby_version_from_bundler_lock_file
        else
          DEFAULT_RUBY_VERSION
        end
    end

rubocop/lib/rubocop/config.rb
    def target_ruby_version_from_version_file
      file = ruby_version_file
      return unless file && File.file?(file)


      @target_ruby_version_from_version_file ||=
        File.read(file).match(/\A(ruby-)?(?<version>\d+\.\d+)/) do |md|
          md[:version].to_f
        end
    end
rubocop/lib/rubocop/config.rb
    def ruby_version_file
      @ruby_version_file ||=
        find_file_upwards(RUBY_VERSION_FILENAME, base_dir_for_path_parameters)
    end

rubocop/lib/rubocop/config.rb
    def ruby_version_file
      @ruby_version_file ||=
        find_file_upwards(RUBY_VERSION_FILENAME, base_dir_for_path_parameters)
    end

rubocop/lib/rubocop/config.rb
    # Paths specified in configuration files starting with .rubocop are
    # relative to the directory where that file is. Paths in other config files
    # are relative to the current directory. This is so that paths in
    # config/default.yml, for example, are not relative to RuboCop's config
    # directory since that wouldn't work.
    def base_dir_for_path_parameters
      @base_dir_for_path_parameters ||=
        if File.basename(loaded_path).start_with?('.rubocop') &&
           loaded_path != File.join(Dir.home, ConfigLoader::DOTFILE)
          File.expand_path(File.dirname(loaded_path))
        else
          Dir.pwd
        end
    end


ログを仕込んでみる

rubocop/lib/rubocop/config.rb
        File.open("/Users/user/rubocop_auto.out", "a") {|f|
          f.puts "Dir.pwd: #{Dir.pwd}"
        }


結果

/Users/user/rubocop_auto.out
Dir.pwd: /

rootディレクトリから実行されていたので設定ファイルが見つけられていなかった


あれ?


File.basename(loaded_path).start_with?('.rubocop')

.rubocopで始まるファイルさえあればいい


$ wc -l .rubocop.yml
       0 .rubocop.yml
$ cat .ruby-version
2.3.1

ok.png


動いた!


調査結果

ファイル 結果 ファイル 結果
1 .rubocop.yml 6 1+3
2 ~/.rubocop.yml × 7 1+4
3 .ruby-version × 8 1+5
4 ~/.ruby-version × 9 2+3 ×
5 Gemfile.lock × 10 2+4 ×
11 2+5 ×

※6~11の.rubocop.ymlは空ファイル


まとめ

  • --configオプションを指定しない場合はカレントディレクトリからファイルを探す。
  • atomから見たカレントディレクトリはrootディレクトリ。
  • プロジェクトディレクトリに.rubocop.ymlを配置する以外の手段は不可。
  • 拡張機能側で~/.rubocop.ymlを探してコマンドに渡しているがコマンド側で受け付けていない。(コマンド側の動きが変わった?)
  • rbenvを使っているならtouch .rubocop.ymlするだけで使える。
  • とはいえデフォルト設定ではrubocopの指摘は厳しいので.rubocop.ymlは設定したほうがいい。

参考

  • RuboCopが静的解析のRubyバージョンを決める流れ

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1