Coder Social home page Coder Social logo

rubocop-jp's Introduction

RuboCop Logo


Ruby Style Guide Gem Version Actions Status Test Coverage Maintainability Discord

Role models are important.
-- Officer Alex J. Murphy / RoboCop

RuboCop is a Ruby static code analyzer (a.k.a. linter) and code formatter. Out of the box it will enforce many of the guidelines outlined in the community Ruby Style Guide. Apart from reporting the problems discovered in your code, RuboCop can also automatically fix many of them for you.

RuboCop is extremely flexible and most aspects of its behavior can be tweaked via various configuration options.


Patreon OpenCollective OpenCollective Tidelift

Working on RuboCop is often fun, but it also requires a great deal of time and energy.

Please consider financially supporting its ongoing development.

Installation

RuboCop's installation is pretty standard:

$ gem install rubocop

If you'd rather install RuboCop using bundler, add a line for it in your Gemfile (but set the require option to false, as it is a standalone tool):

gem 'rubocop', require: false

RuboCop is stable between minor versions, both in terms of API and cop configuration. We aim to ease the maintenance of RuboCop extensions and the upgrades between RuboCop releases. All big changes are reserved for major releases. To prevent an unwanted RuboCop update you might want to use a conservative version lock in your Gemfile:

gem 'rubocop', '~> 1.65', require: false

See our versioning policy for further details.

Quickstart

Just type rubocop in a Ruby project's folder and watch the magic happen.

$ cd my/cool/ruby/project
$ rubocop

You can also use this magic in your favorite editor with RuboCop's built-in LSP server.

Documentation

You can read a lot more about RuboCop in its official docs.

Compatibility

RuboCop officially supports the following runtime Ruby implementations:

  • MRI 2.7+
  • JRuby 9.4+

Targets Ruby 2.0+ code analysis.

See the compatibility documentation for further details.

Readme Badge

If you use RuboCop in your project, you can include one of these badges in your readme to let people know that your code is written following the community Ruby Style Guide.

Ruby Style Guide

Ruby Style Guide

Here are the Markdown snippets for the two badges:

[![Ruby Style Guide](https://img.shields.io/badge/code_style-rubocop-brightgreen.svg)](https://github.com/rubocop/rubocop)

[![Ruby Style Guide](https://img.shields.io/badge/code_style-community-brightgreen.svg)](https://rubystyle.guide)

Team

Here's a list of RuboCop's core developers:

See the team page for more details.

Logo

RuboCop's logo was created by Dimiter Petrov. You can find the logo in various formats here.

The logo is licensed under a Creative Commons Attribution-NonCommercial 4.0 International License.

Contributors

Here's a list of all the people who have contributed to the development of RuboCop.

I'm extremely grateful to each and every one of them!

If you'd like to contribute to RuboCop, please take the time to go through our short contribution guidelines.

Converting more of the Ruby Style Guide into RuboCop cops is our top priority right now. Writing a new cop is a great way to dive into RuboCop!

Of course, bug reports and suggestions for improvements are always welcome. GitHub pull requests are even better! :-)

Funding

While RuboCop is free software and will always be, the project would benefit immensely from some funding. Raising a monthly budget of a couple of thousand dollars would make it possible to pay people to work on certain complex features, fund other development related stuff (e.g. hardware, conference trips) and so on. Raising a monthly budget of over $5000 would open the possibility of someone working full-time on the project which would speed up the pace of development significantly.

We welcome both individual and corporate sponsors! We also offer a wide array of funding channels to account for your preferences (although currently Open Collective is our preferred funding platform).

If you're working in a company that's making significant use of RuboCop we'd appreciate it if you suggest to your company to become a RuboCop sponsor.

You can support the development of RuboCop via GitHub Sponsors, Patreon, PayPal, Open Collective and Tidelift .

Note: If doing a sponsorship in the form of donation is problematic for your company from an accounting standpoint, we'd recommend the use of Tidelift, where you can get a support-like subscription instead.

Open Collective for Individuals

Support us with a monthly donation and help us continue our activities. [Become a backer]

Open Collective for Organizations

Become a sponsor and get your logo on our README on GitHub with a link to your site. [Become a sponsor]

Changelog

RuboCop's changelog is available here.

Copyright

Copyright (c) 2012-2024 Bozhidar Batsov. See LICENSE.txt for further details.

rubocop-jp's People

Contributors

koic avatar pocke avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

rubocop-jp's Issues

Layouts/DefEndAlignment Cop で怒られる場合と怒られない場合がある

Layouts/DefEndAlignment Cop の挙動について質問させてください!
gem ruboco-airbnb を継承して使っているのですが、こちらの設定には特におかしいところがなさそうだったので、こちらで質問させていただきました。

https://github.com/airbnb/ruby/tree/master/rubocop-airbnb

<怒られたり怒られなかったりするコード例>

# Warning Layouts/DefEndAlignment end at 6, 2 is not aligned with ApplicationController
# app/controller/some/categories_contriller.rb
class Some::CategoriesController < ApplicationController
  def show
    #..some code...
  end
end

# Not Warning Some Controller
# app/controller/some/products_controller.rb
class Some::ProductsController < ApplicationController
  SOME_CONSTANT = 10
  def show
    # ...some code...
  end
end

.rubocop.yml

inherit_from:
  - .rubocop_airbnb.yml
  - .rubocop_todo.yml

Rails:
  Enabled: true

AllCops:
  TargetRubyVersion: 2.4.1
  Exclude:
    - vendor/bundle/**/*
    - bin/*
    - db/**/*
    - config/**/*
    - Gemfile

rubocop-airbnb のDefEndAlignement の設定箇所

...
Layout/DefEndAlignment:
  Enabled: true
  EnforcedStyleAlignWith: start_of_line
  AutoCorrect: false
...

Cop 対象のコントローラー(some/categories_controller.rb) で class の直下にコードを何か挿入すると怒られなくなります。
(例えば、対象のコントローラーのように定数を入れたり、before_action など入れても怒られない)

他の挙動として

# ApplicationController がトップの定数だと明示すると怒られない
class Some::CategoriesController < ::ApplicationController
  #...
end

ここの挙動と対処の仕方がどうしても理解できず issue を立てさせていただきました。よろしくお願いします!

Gemfile.lock

rails (~> 5.1.3)

rubocop(0.57.2)
rubocop-airbnb (1.5.0)
    rubocop (= 0.57.2)
    rubocop-rspec (= 1.27.0)
rubocop-rspec (1.27.0)
    rubocop (>= 0.56.0)

ruby-version : 2.4.1p111

破壊的メソッドの再代入を検出するCop

foo = foo.concat([bar, baz])

Array#concatは破壊的メソッドなので、再代入する必要はない。
false positiveが気になるけど、Ruby標準と同名で違うインターフェースのメソッドを定義するやつが悪いので、気にしない。

同様の例に、gsub!とかbangが付いたメソッド群もある。

rubocop-jp/issues の README を整備する

目的

  • このレポジトリの意味を明確にする
    • vim-jp/issues を知っていたらなんとなく意味がわかる気がするけど、そうでない人も多いはず
  • Issue に書き込む際の障壁を減らす

書きたいこと

レポジトリの意味

  • 日本語で rubocop の issue を書けるところ
    • 例: 機能要望、バグ報告、使い方に関する質問、など
  • RuboCopの問題について取り組みたい場合に、上がっているIssueに取り組めること
    • ここに上がった問題について取り組んでみたい人がいたら、それを支援したい

書き込む際の障壁を減らす

ISSUE_TEMPLATEがあると良さそう?


そのうち手を付けます

代入文のレイアウトを検出するCop

日本語で書けるということで、こちらに要望を出させていただきます。

RubyMineのコードスタイルの設定
https://www.jetbrains.com/help/ruby/code-style-ruby.html

Align right parts of assignments or hashes
If this checkbox is selected, the assignments and hashes are aligned against values.

というものが有るのですが、これは(Hashと)代入文での右辺値(式部分)のインデントの深さを前後行に合わせるためのものです。

# before
a = 1
bbb = 2

# after
a   = 1
bbb = 1

このようなスタイルの違いをチェックする Cop は現状存在しないように思います。
それによって、RubyMineを使っている開発者と、そうでない開発者の間でスタイルが統一されていません。

既存のものでは Hash 用の Layout/AlignHash が最も近いと思いますが、これと同様に

  • key インデントしない(デフォルト)
     a = 1
     bbb = 2
  • separator 前後に合わせた左辺値のインデントを強制
       a = 1
     bbb = 2
  • table 前後に合わせた右辺値のインデントを強制(RubyMineと同様)
     a   = 1
     bbb = 2

というような設定が出来れば良いと思い、提案いたします。

["foo", "bar"].join("\n") はheredocで書くようにするCop

RuboCop本体のテストコードには、

["foo",
  "bar"].join("\n")

のようなコードが大量にあるが、これは明らかにheredocで書いたほうが簡単だし編集もしやすい(しLineLengthから逃げられる)ので、heredocを使うようにするCopをつくりたい。
ついでにAuto-Correctを実装して既存のコードを一掃したい。

実装はそこそこの手応えがあると思います。
Auto-Correctまで考えると体力が必要になると思います。

`max_by{|x, y| x <=> y}` は `max{|x, y| x <=> y}` では

#1 の逆

実装は比較的簡単だと思う。
注意点として、auto-correctは実装しない or デフォルトでは無効にする必要がある。何故ならば、これを自動的に直してしまうとコードが壊れる可能性があるため。

ディレクトリを遡って .ruby-version ファイルを見つけて欲しい

.ruby-version ファイルがあれば TargetRubyVersion が自動で設定される機能を、大変重宝してます。

が、.ruby-version ファイルが RuboCop を実行したディレクトリに存在しないと、TargetRubyVersion が設定されずに困っています。
具体的には、エディタで Ruby ファイルを編集中に RuboCop を走らせているのですが、その際にパースエラーが発生してしまいます。

.ruby-version ファイルがディレクトリに存在しない場合、ディレクトリを遡って見つけて欲しいです。

こちらにサンプルプロジェクトを用意しました。

/
- .ruby-version
- app/
  - models/
    - player.rb
$ cd app/models/
$ bundle exec rubocop player.rb
Inspecting 1 file
E

Offenses:

player.rb:13:6: E: Lint/Syntax: unexpected token error
(Using Ruby 2.1 parser; configure using TargetRubyVersion parameter, under AllCops)
    b&.strip
     ^^

1 file inspected, 1 offense detected

参考

https://github.com/bbatsov/rubocop/blob/f72860cf9f879d8ecef19b30624d777d8cc3bd80/manual/configuration.md#setting-the-target-ruby-version

FactoryBot(旧:FactoryGirl)アンチパターンを検出することは意味がありますか?

こちらのblog postで紹介されているFactoryBotのアンチパターンを、RuboCopで検出することは意味がありそうでしょうか?

Rails アンチパターン - 錆びついたファクトリー (factory_girl) - アジャイルSEの憂鬱

特に、以下の例で示されているAssociationsのアンチパターンはテスト実行速度に影響があるため、検出できれば有益かなと思いました。

# アンチパターン:build_stubbed なのにレコードが生成される

# bad
FactoryBot.define do
  factory :book do
    author { create(:user) }
    published_at { '2017-04-10' }
  end
end

# good
FactoryBot.define do
  factory :book do
    association :author, factory: :user
    published_at { '2017-04-10' }
  end
end

Metrics/LineLength のより良いデフォルト値を模索したい

統計で殴るのが変更を訴える理由として一番有効そうかなと思っているんですが、
第一報としてこんな感じです。

雑に star 数 1500 以上で .rubocop.yml を持っているプロダクトを
見て回ったところ、以下のような感じになりました。

(いっぱい取りこぼしがあるので雰囲気として掴んでください)
(追試可能なようにコード化していきます……)

max repo
Disabled DavyJonesLocker/client_side_validations
Disabled discourse/discourse
Disabled erikhuda/thor
Disabled fatfreecrm/fat_free_crm
Disabled hanami/hanami
Disabled helpyio/helpy
Disabled intridea/oauth2
Disabled jwt/ruby-jwt
Disabled kpumuk/meta-tags
Disabled lsegal/yard
Disabled mbj/mutant
Disabled michenriksen/gitrob
Disabled middleman/middleman
Disabled mongodb/mongoid
Disabled mroth/lolcommits
Disabled nanoc/nanoc
Disabled neo4jrb/neo4j
Disabled neonichu/ThisCouldBeUsButYouPlaying
Disabled octobox/octobox
Disabled omniauth/omniauth
Disabled prat0318/json_resume
Disabled publify/publify
Disabled rails/rails
Disabled rails/webpacker
Disabled realm/jazzy
Disabled refile/refile
Disabled resque/resque-scheduler
Disabled rest-client/rest-client
Disabled rmosolgo/graphql-ruby
Disabled roidrage/lograge
Disabled rpush/rpush
Disabled ruboto/ruboto
Disabled ruby-grape/grape
Disabled rubygems/rubygems.org
Disabled sensu/sensu
Disabled sferik/rails_admin
Disabled sferik/t
Disabled sferik/twitter
Disabled shakacode/react-webpack-rails-tutorial
Disabled shakacode/react_on_rails
Disabled sharetribe/sharetribe
Disabled shoes/shoes4
Disabled skywinder/github-changelog-generator
Disabled solidusio/solidus
Disabled soundcloud/lhm
Disabled spree/spree
Disabled swanson/stringer
Disabled technicalpickles/homesick
Disabled tenex/rails-assets
Disabled test-kitchen/test-kitchen
Disabled theforeman/foreman
Disabled thoughtbot/administrate
Disabled thoughtbot/gitsh
Disabled tootsuite/mastodon
Disabled toptal/chewy
Disabled troessner/reek
Disabled welaika/wordmove
Disabled zdennis/activerecord-import
9000 jordansissel/fpm
483 hexorx/countries
309 cucumber/cucumber-ruby
279 CocoaPods/CocoaPods
276 ctran/annotate_models
266 jnunemaker/httparty
200 celluloid/celluloid
187 comfy/comfortable-mexican-sofa
186 geokit/geokit
180 rapid7/metasploit-framework
170 intridea/hashie
143 httprb/http
140 dtan4/terraforming
120 Casecommons/pg_search
120 Shopify/bootsnap
120 ambethia/recaptcha
120 athityakumar/colorls
120 binarylogic/authlogic
120 churchio/onebody
120 diaspora/diaspora
120 feedjira/feedjira
120 glebm/i18n-tasks
120 google/google-api-ruby-client
110 galetahub/ckeditor
100 airblade/paper_trail
100 drapergem/draper
100 ffaker/ffaker
90 jekyll/jekyll
80 BBC-News/wraith
80 awesome-print/awesome_print
80 bbatsov/rubocop
80 bkeepers/dotenv
80 chef/chef
80 deivid-rodriguez/byebug
80 deivid-rodriguez/pry-byebug
80 doorkeeper-gem/doorkeeper
80 fnando/browser
80 houndci/hound
80 thoughtbot/bourbon
80 thoughtbot/griddler
80 thoughtbot/guides
80 thoughtbot/scenic
80 vcr/vcr

Open3.capture3({ENV_NAME: bar}, cmd) を検出するCop

何が悪いかと言うと、Open3.capture3の最初の引数に渡されるHashは環境変数になるが、そのkeyはStringでなくてはいけない(Symbolはダメ)。

これを実行するとTypeErrorが出るけど、

/usr/lib/ruby/2.4.0/open3.rb:199:in `spawn': no implicit conversion of Symbol into String (TypeError)
	from /usr/lib/ruby/2.4.0/open3.rb:199:in `popen_run'
	from /usr/lib/ruby/2.4.0/open3.rb:95:in `popen3'
	from /usr/lib/ruby/2.4.0/open3.rb:258:in `capture3'
	from /tmp/tmp.TX9kZKubu5/test.rb:3:in `<main>'

みたいなエラーメッセージで若干分かりづらいので、RuboCopで検出したい。
エラーメッセージから分かる通り、spawnとか他のcaptureXも検出したい。

実装はそこまで難しくないと思う。
ただ、「実行したら必ずエラーが出るのにCopにする必要があるの?」といわれそうな気はする。
私は「このコードをテストで実行してない時でも、Copになっていれば気がつけて便利」と思っているので、追加するべきだと思っています。

gemspec 内で、重複したフィールドがある場合に検出するCop

Gem::Specification.new do |s|
  # name が2回呼ばれているため、何かがおかしい
  s.name = 'rubocop'
  s.name = 'rubocop2'

  # add_runtime_dependency などは何回呼ばれても良い
  s.add_runtime_dependency('parallel', '~> 1.10')
  s.add_runtime_dependency('parser', '>= 2.3.3.1', '< 3.0')
end

実装

末尾が = で終わるメソッドが2回以上呼ばれていたら、警告を追加するように実装すると良いと思います。

ちゃんとやるならば、メソッドのレシーバがGem::Specification.newのブロック引数で定義されていることを見る必要があるかも知れません。

RSpec::ContextWording で 接尾辞でも設定できるようにしたい

https://www.rubydoc.info/gems/rubocop-rspec/RuboCop/Cop/RSpec/ContextWording

# Overview
`context` block descriptions should start with 'when', or 'with'.

Prefixes:
  - when
  - with
  - without
  - if

現状Prefixesしか設定できず、
日本語でrspecを書く場合

context '画面に表示されていないとき'
context '画面に表示されていない場合'

のようにとき場合などのSuffixesの設定ができるようにしたいと思いました。

実装してPRを出そうとしたのですが、
RSpec::ContextWordingの条件の部分は

desctiprion # 'with metadata hash'
prefixes # ['when', 'with']
def bad_prefix?(description)
  !prefixes.include?(description.split.first)
end

https://github.com/rubocop-hq/rubocop-rspec/blob/0442757fb4af570994b37b3e0ca35baeec635eb0/lib/rubocop/cop/rspec/context_wording.rb#L45

desctiprion画面に表示されていない場合のような日本語はsplitできません。

  • Patterns:のようなオプションで正規表現で実装するのがよいのでしょうか
  • 日本語でcontextを書くのを辞めるのがよいのでしょうか
    よろしくおねがいします

offenseに「offenseを無視することが正当であるケース」を入れるフィールドを追加する

たとえば、 querlyには、警告にjustification という項目が存在します。querly公式のサンプルにjustificationsがのってなくてつらいのですが、こんな感じです。

rules:
  - id: com.sideci.find_with_bang
    pattern: "find_by(_) [!conditional]"
    message: find_byは対象のレコードが見つからない場合にnilを返します。find_by!を利用しましょう。
    justification: nilが返ってくることを期待する場合

このようにjustificationがあることで、Lintがfalse positiveを出した場合にユーザーがそれをfalse positiveだと判断できるようになります。
現状ユーザーが「本当にこの警告に従うべきなのか」と思った時に、RuboCopは参考になるような情報をなにも提供していないので、これによって「従わなくても良い」ケースに関してはそう言えるようにしたいと思っています。

https://teratail.com/questions/99932 は、「justificationがあれば質問をせずすぐ解決できた」実際の事例です。こういうことは結構たくさん起きていると思うので、この機能を追加することで迷ってしまう体験を減らしたいなーと思っています

Make new cop aware of no newline at end of file

POSIX におけるテキストファイルの定義に合わせてファイルの最後に改行を入れるようにする Cop があると良いかもしれません (EOF に改行がないときに GitHub のコード diff の最後に表示される赤丸) 。

参考: http://hiroakiuno.hatenablog.com/entry/20070409/p1

一方で Ruby と直接関係のない定義の話なので、RuboCop が持つべき Cop ではなく別のツールで検出するべき問題という考え方もあります。Rails アプリケーション開発を例に挙げても、Ruby 以外で例えば YAML ファイルも検査の対象となるため、殊更 RuboCop の役割ではない気がしてたりします。実用性の観点からアプリケーションで扱うテキストファイルのうち Ruby だけを特別視するのも違うかなと思うためです。

このあたりのご意見ご感想を聞いてみたいです。

Add tests that examples in comments passes the cop's inspection or not.

各Copはコメント内に良いコード例と悪いコード例を持っています。


https://github.com/bbatsov/rubocop/blob/fdb936a8408f7f2192f93bf5bc1978e38c314efe/lib/rubocop/cop/style/attr.rb#L8-L15

      # This cop checks for uses of Module#attr.
      #
      # @example
      #   # bad - creates a single attribute accessor (deprecated in Ruby 1.9)
      #   attr :something, true
      #   attr :one, :two, :three # behaves as attr_reader
      #
      #   # good
      #   attr_accessor :something
      #   attr_reader :one, :two, :three
      #

ところが、これらのコードが本当に「良い例」「悪い例」であるかは検査されていません。つまり、「良い例」と示されている例にRuboCopが警告を出さないこと、「悪い例」と示されている例にRuboCopが警告を出すことは保証されていません。

そのため、これらの例が本当に良い例、悪い例になっているかをテストしたいと思っています。

課題

ちょっと考えただけでこの実現はめんどくさそうなことがわかります。

  • 良いコード例、悪いコード例をうまく切り出す必要がある
    • # bad, # good をセパレータとしてexamplesを切れば実現できそう
  • Copが設定を持っている場合、それを反映しないといけない
    • examplesの書き方が統一されていっているので、統一されたスタイルを前提とすれば不可能ではなさそう
  • 結構ヒューリスティックに# good, # badの判定、設定の判定を行わなければいけないので、メンテしづらく将来的に負債になるのではないか(ドキュメントの信頼性を担保するにはコストが大きすぎるのではないか)

RuboCop 0.53.0 + parser 2.5.0.4 で Lint/Syntax が急に出るようになった

RuboCop のバージョンは変えず parser 2.5.0.4 に変更したところ急に Lint/Syntax が出るようになりました。
parser 2.5.0.3 では発生しません。
parser の issue ッポイですが RuboCop の依存 gem も parser を 2.5.0.3 に固定した方がいいかも? と思いここに書き残しておきます。

$ bundle list | grep rubocop
  * rubocop (0.53.0)
  * rubocop-rspec (1.22.2)
$ bundle list | grep parser
  * parser (2.5.0.4)
# $ cat .rubocop.yml
AllCops:
  TargetRubyVersion: 2.4

けっこうケズってこうなりました。

# $ cat test.rb
class Cake
  def piece
    if true
      cut "#{[]}"
    else
      [].each do |n|
        cut "#{[]}"
      end
    end
  end
end
$ bundle exec rubocop --only=Lint/Syntax test.rb
Inspecting 1 file
E

Offenses:

test.rb:6:15: E: Lint/Syntax: unexpected token kDO_BLOCK
(Using Ruby 2.4 parser; configure using TargetRubyVersion parameter, under AllCops)
      [].each do |n|
              ^^
test.rb:7:13: E: Lint/Syntax: unexpected token tSTRING_BEG
(Using Ruby 2.4 parser; configure using TargetRubyVersion parameter, under AllCops)
        cut "#{[]}"
            ^
test.rb:11:1: E: Lint/Syntax: unexpected token kEND
(Using Ruby 2.4 parser; configure using TargetRubyVersion parameter, under AllCops)
end
^^^

1 file inspected, 3 offenses detected

$ bundle list | grep parser
  * parser (2.5.0.3)
$ bundle exec rubocop --only=Lint/Syntax test.rb
Inspecting 1 file
.

1 file inspected, no offenses detected

Hash のインスタンスに対する map { |k, v| [k, v.foo] }.to_h を transform_values にする Cop

h = { a: 1, b: 2 }
h.map { |k, v| [k, v.to_s] }.to_h

上記のコードは transform_values で置き換えることができます。

h = { a: 1, b: 2 }
h.transform_values(&:to_s)

注意する点

map は Enumerable のメソッド

map メソッドでブロック引数が2つあれば、おそらく Hash のインスタンスだとは思うけど、
確定できないので false positive が発生しそうです。

使える環境

古い Ruby/Rails では使用できないメソッドなので、 Cop を作るときに注意が必要そう。

`max{|x| x.size}` はもしかして`max_by{|x| x.size}` では?

max{|x| x.size}のような、ブロック内で<=>を使っていないmaxがあったら「もしかして max_by」と警告を出すCopがほしい

sort, min も同様

実装は比較的簡単だと思う。
注意点として、auto-correctは実装しない or デフォルトでは無効にする必要がある。何故ならば、これを自動的に直してしまうとコードが壊れる可能性があるため。

`Lint/Void`が、ifの戻り値が使われていない場合に、そのif文の最後の値をVoidだと認識しない。

def foo
  if cond
    foo
    1 # この 1 に対してはRuboCopは警告を出すべきですが、現状は出していません。
  end
  bar
end

実装の難易度は、ちょっと眺めてみないとよくわかりません。まあ、不可能では無いと思います。
ifの他にも、色々なケースで同様のfalse negativeがあるのではないかと思っています(例えば、case-when文など)

`Performance/RangeInclude`を色々直したい。

問題

Performance/RangeIncludeは、Range#include?の代わりにRange#cover?を使用してね、という警告をだすCopです。このCopにはいくつか問題があります。

  • rangeの値がNumberである場合、パフォーマンスにはほとんど差が出ない。
    • 若干cover?の方が速くはあるっぽい
    • これはどこにも記述がない
  • rangeの値がStringである場合、include?cover?では異なった結果が得られる。
    • これはドキュメントには書かれているけど、警告のメッセージには何も書いていない。

そのため、この警告を元にユーザーは間違った修正を行ってしまう可能性があります。

解決方法

range の値の中身によって、警告のメッセージを変えるべきでしょう。

  • Numberの場合「ほとんど差がないよ」と書く?
    • これは書かなくてもいいかも知れない。
  • Stringの場合「挙動が変わるから注意してね」と書く
    • もしくは、そもそも警告を出さなくても良いかも知れない。
  • 値がリテラルではない場合「Stringでは挙動が変わるよ。」などと注意を書く

Note

これだけ聞くとこのCopは無意味なのでは、と思うかも知れませんが、例えばTimeのrangeの場合などはそこそこパフォーマンスに差が出てくるので意味があると言えるでしょう。

require 'benchmark'
Benchmark.bm(20) do |x|
  time1 = Time.new(1994, 2, 2)
  time2 = Time.new(2017, 11, 13)
  time3 = Time.new(1990, 11, 24)
  time4 = Time.new(2020, 8, 16)

  range = 1..100000
  range_time = time1..time2

  x.report('include? Number') do
    10000000.times do
      range.include?(-1)
      range.include?(1)
      range.include?(5667)
      range.include?(100000000)
    end
  end

  x.report('cover? Number') do
    10000000.times do
      range.cover?(-1)
      range.cover?(1)
      range.cover?(5667)
      range.cover?(100000000)
    end
  end

  x.report('include? Time') do
    10000000.times do
      range_time.include?(time1)
      range_time.include?(time3)
      range_time.include?(time4)
    end
  end

  x.report('cover? number') do
    10000000.times do
      range_time.cover?(time1)
      range_time.cover?(time3)
      range_time.cover?(time4)
    end
  end
end
                           user     system      total        real
include? Number        2.640000   0.000000   2.640000 (  2.639529)
cover? Number          2.590000   0.000000   2.590000 (  2.585174)
include? Time          4.260000   0.000000   4.260000 (  4.262342)
cover? number          3.770000   0.000000   3.770000 (  3.770333)

ヒアドキュメント風の勘違いを訂正したい

foo = """
  bar
  baz
"""

を見かけたので、warning を出してあげても良いかなと思った。

けどこういう 3 年に 1 回ぐらいしか見かけないコードを対象に cop 作るの、無駄っぽくてあんまり好きじゃないんだよねぇ。。
別言語 (coffee, elixir) から来た人には便利かもしれない?

(lvasgn :foo
  (dstr
    (str "")
    (dstr
      (str "\n")
      (str "  bar\n")
      (str "  baz\n"))
    (str "")))

0.53 から出力される overrides the same parameter を抑止したい

0.53.0 から同じパラメータを上書きしていると overrides the same parameter と出力されるようになりました。

Exclude, Include については inherit_mode を設定することによって、メッセージが出なくなったのですが、
Metrics の Max パラメータについては inherit_mode を設定してもメッセージが出力されてしまいます。

設定で回避する手段はあるのでしょうか?

rubocop.yml の設定はこのような感じになっています。

inherit_gem:
  rubocop-shared-config: rubocop.yml # 複数プロジェクトで共通。ここに Metrics の推奨 Max 値を設定

inherit_from: .rubocop_todo.yml # ここにプロジェクト固有の Metrics Max 値を設定
inherit_mode:
  override:
    - Max

rubocop を実行すると以下のような出力がされます。

$ bundle exec rubocop
.rubocop.yml: Metrics/AbcSize:Max overrides the same parameter in .rubocop_todo.yml

rubocop のバージョン

$ bundle exec rubocop -V 
0.53.0 (using Parser 2.5.0.2, running on ruby 2.4.3 x86_64-linux)

演算子をドットで呼び出すのを怒るCop

a.[]
a.+ b

Rubyでは演算子もメソッドなのでこういう呼び出し方が出来るが、これは一般的ではないスタイルなのでこのスタイルを書いていたら怒る。

実装は簡単なのかはよくわからない。

注意点

  • a.+(b).something みたいなのは気軽にauto-correctすると死ぬ

Rangeの始点が終点より大きいコードを検出するCop

例えば、以下のようなコードはだいたいバグです。

range = 10..4
range.cover?(n) # nがどんな数値でもfalse

また、実際にバグを引き起こしていたコードとして、次のようなものがありました。

range = Time.zone.now...1.day.ago
range.cover?(foo.nantoka_at)

これもnantoka_atがどのような日付であれ、cover?は必ずfalseを返します。

このようなバグになりうるrangeの使い方を検出するCopがほしいです。

注意点

ただし、以下のようなrangeは始点の方が大きい数ですが普通に使用されます。

"abcde"[2..-1] # => cde
"abcde"[2..-2] # => cd

これに対応するには、終点が負の数になっていたら例外的に許可すればよい気がします。
もしかしたらまだ他にも例外ケースがあるかも知れません。

`Style/StringLiterals` の symbol 版

"foo"のようなリテラルはsingle quoteを使えと怒られるが、:"foo-bar"のようなリテラルは怒られないため、これを怒るCopが必要。

Style/StringLiterals をそのまま持ってくれば動くのかは、よくわからない。

has_manyでthrough optionを使ってる場合のinverse_of optionについて

has_many :foo_users
has_many :foos, through: :foo_users

してる際にRails/InverseOfのcopに怒られるのはfalse positiveなのかしら。
throughの場合にinverse_of option付けるのは不可能だと思うのですけれど、最近のRailsでは出来るようになったんですかね(いやまさか)

  • RuboCop: 0.52.0
  • Ruby: 2.4.3
  • Rails: 5.1.4

RuboCopの誤検出についてあまり詳しくないのでご意見ください・・

全角文字利用時、アラインメントが揃っているのに警告(Layout/ExtraSpacing)が出る

rubocop-0.57.2 環境で(それ以前でも)、以下のような事象が発生します。

# 警告なし
VALID_CONSTANT = [
  ['Japanese is double-byte character set.', '日本語は全角文字です。'],
  ['English is single-byte character set.',  '英語は半角文字です。']
].freeze

# Layout/ExtraSpacing: Unnecessary spacing detected. が発生する
INVALID_CONSTANT = [
  ['日本語は全角文字です。', 'Japanese is double-byte character set.'],
  ['英語は半角文字です。',   'English is single-byte character set.']
].freeze

文字数でカウントしているのか、日本語を利用した場合、スペースによるアラインメントがうまく認識されません。

初心者が .rubocop.yml を簡単に作れるように rubocop --init が欲しい

初心者が .rubocop.yml を作成するのは下記の理由で難しいと思いました。

  • .rubocop.yml の話が rubocop --help や README に記載がない
  • デフォルト値がどうなっているのか分からない
  • 使えるオプションが分からない

設定値は GitHub 上の RuboCop のソースコードを見るしか(たぶん)知る方法がない。

提案

$ rubocop --init で基本的な yml を生成して上げて、基本的な設定項目を列挙して上げたら良いかなと思いました。
最近のRailsの routes.rb だと URL がコメントとして挿入されています。

# For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

GitHub 上の RuboCop の yml へのリンクを挿入してあげると、親切かもしれません。

auto-correctすると要素が消える

-v 0.60.0 で、auto-correct時に要素が消える現象が起きましたので、報告致します。

auto-correct前のソースコード

# frozen_string_literal: true

hoge = Hoge.new(
            { hoge: 'hoge',
              fuga: 'fuga',
              foo: 'this is dummy.'
            })

rubocop -a の出力

Inspecting 1 file
C

Offenses:

test.rb:4:3: C: [Corrected] Style/BracesAroundHashParameters: Redundant curly braces around a hash parameter.
  { hoge: 'hoge', ...
  ^^^^^^^^^^^^^^^
test.rb:4:4: C: [Corrected] Layout/FirstParameterIndentation: Indent the first parameter one step more than the start of the previous line.
   hoge: 'hoge', ...
   ^^^^^^^^^^^^^
test.rb:4:13: C: [Corrected] Layout/FirstParameterIndentation: Indent the first parameter one step more than the start of the previous line.
            { hoge: 'hoge', ...
            ^^^^^^^^^^^^^^^
test.rb:4:13: C: [Corrected] Style/BracesAroundHashParameters: Redundant curly braces around a hash parameter.
            { hoge: 'hoge', ...
            ^^^^^^^^^^^^^^^
test.rb:5:5: C: [Corrected] Layout/AlignHash: Align the elements of a hash literal if they span more than one line.
    fuga: 'fuga',
    ^^^^^^^^^^^^
test.rb:5:17: C: [Corrected] Style/TrailingCommaInArguments: Avoid comma after the last parameter of a method call.
    fuga: 'fuga',
                ^
test.rb:6:1: C: [Corrected] Layout/ClosingParenthesisIndentation: Indent ) to column 1 (not 0)
)
^
test.rb:6:2: C: [Corrected] Layout/ClosingParenthesisIndentation: Indent ) to column 0 (not 1)
 )
 ^
test.rb:6:26: C: [Corrected] Layout/SpaceInsideHashLiteralBraces: Space inside } missing.
    foo: 'this is dummy.'}
                         ^
test.rb:7:13: C: [Corrected] Layout/MultilineHashBraceLayout: Closing hash brace must be on the same line as the last hash element when opening brace is on the same line as the first hash element.
            })
            ^
test.rb:7:14: C: [Corrected] Layout/MultilineMethodCallBraceLayout: Closing method call brace must be on the line after the last argument when opening brace is on a separate line from the first argument.
            })
             ^

1 file inspected, 11 offenses detected, 11 offenses corrected

auto-correct後のソースコード

# frozen_string_literal: true

hoge = Hoge.new(
  hoge: 'hoge',
  fuga: 'fuga'
)

Hoge.new時にキーワード引数ではなくHashで渡しているのがイレギュラーではあると思いますが...

params[:foo].something を怒るCop

# In controller
def index
  params[:foo].something
end

これは、paramsに値が入ってこなかったらエラーになって死ぬ。
なので、params.require(:foo).somethingparams[:foo]&.something になるべき。
(ただしnilに生えているメソッドは呼べる)

実装は多分簡単。

nil に生えているメソッドを呼び出しているケース(例えば、params[:foo].nil?)の対応は、 Lint/SafeNavigationChain とかを見ると良いと思う。 https://github.com/bbatsov/rubocop/blob/245155158db2d4e0d3d0da918d3e7f3bf6291e78/lib/rubocop/cop/lint/safe_navigation_chain.rb#L40
この nil に生えているメソッドのリストをいい感じに共通化したいけど、現状のRuboCopにはCop感をまたがるような設定はあまりいい感じに出来ないので、ちょっとむずかしい。

A new cop for checking eval's arguments have fname and lineno

eval 時の FILE, LINE + 1 を強制する cop ってあったっけ?
@onk
https://twitter.com/onk/status/935350994375868416

Eval族は引数にファイル名、行番号を与えることでスタックトレースのファイル名などをいい感じにすることができます。
https://docs.ruby-lang.org/ja/latest/method/Kernel/m/eval.html
https://docs.ruby-lang.org/ja/latest/method/Module/i/module_eval.html
これを行っていないとスタックトレースがわかりづらくなってしまうため、ファイル名などを渡すように強制するCopがほしいです。

実装は簡単そうですが、いくつか注意点があります。

  • evalclass_eval では引数が違う
    • evalbindingを受け取るため
  • 行番号などを違う形で指定する必要があるケースもある
  • 渡されるソースコードがheredoc なら __LINE__ + 1, 普通の文字列リテラルなら__LINE__を渡す必要がありそう

"マネーフォワード社内PRに見られるRubyの書き方について" をRuboCopで実装する

https://moneyforward.com/engineers_blog/2019/02/05/ruby-code-3/

例えば、次のコードあたりはRuboCopで検出しなさそう && 実装できそうです。
シリーズ記事のようなので、他の記事も参考にすると面白そうですね

# bad
string =~ /\Afixed pattern\z/

# good
string == 'fixed pattern'
# bad
array.select{|s| s =~ /1/}

# good
array.select{|s| s.match?(/1/)}

また、String#split('')String#charsに置き換え可能であるように以前から思っているのですが、なにか反例があるような気がしていて実装できていません。軽く実装を眺めた感じ実装は違うので、エンコーディング周りとかでなにか挙動が変わるのではという不安があります。
Copを実装するとしたら注意がいりそう。

`Lint/Void` で lambda / procを検出する

def foo
  -> () {hogehoge}
  proc {fugafuga}
  lambda {barbar}
  x
end

このlambdaやprocは、実行されないため、Lint/Voidで検出されるべきです。
実装は、そんなに難しくないと思います。 rubocop/rubocop#4858 が入ってから実装に手を付けたほうがいいかも知れない。

chain method後のインデントがおかしいはずなのにRuboCopに怒られない

Summary

I found that broken indents in chain-method after do-end under codes but it has no comment from RuboCop.
chain methodの後のdo-endの中身(code)が壊れてのにRuboCopが検出しないので起票しました。

Problem Summary

This is the code related to Rails.
これがソースコードで、Rails関連のコードです。

models.each do |model|
  model
    .attributes
    .except('id', 'created_at', 'updated_at')
    .reject { |_k, v| v.nil? }
    .each do |key, value|
    name = "#{model.class.to_s.underscore}[#{key}]"

    if value.is_a?(TrueClass) || value.is_a?(FalseClass)
      check(name)
    else
      fill_in(name, with: value)
    end
  end
end

So I think indents is borken because name and each block's indent size is same but it has comment from RuboCop.
I think name variable and if-block is needed more 2 indents. because it is in the each do-end.
btw, I executed auto-correct but it didn't change anything.
each methodとname変数のindent sizeが一緒なので正直見辛いと思いますが、RuboCopには怒られません。
私はchain methodの後でもeachの中身は2個インデントするべきだと思います。
ちなみにauto-correctしても何も変わりませんでした。

Environment information

  • RuboCop: 0.51.0
  • Ruby: 2.4.2p198 (2017-09-14 revision 59899) [x86_64-linux]

a = a を検出するCop

代入の右辺で代入される変数を使用すると、それは必ずnilなのでなんらかの間違いである可能性が高い。
そのため、そのような代入を検出するCopが欲しい

a = a # 右辺のaは常にnil
a = x do
  a # このaは常にnil
end

これは、実装が大変だとおもう(たぶんね)。VariableForceとか見ると答えがあるかも知れないけど、私もよく知らない。

Redundant cbase

A == ::A # Always true

class X
  A == ::A # Sometime false
end

トップレベルであればcbaseは要らないので、それを要らないよねって言うCopが欲しい。

実装は比較的簡単だと思う。トップレベルかどうかの判断が少し手間がいる(例えば、Class.new do ... end の際にどうするべきなのか、とか)と思うけど、考えることはそれくらい?
Auto Correctは実装してしまっても良さそう。

出る警告が Layout/AccessModifierIndentationで正しいのかわからない

以下のようなコードをrubocop -Rで回してみました。

# Test
class Test

  private

    def some_method
    end

    private def another_method
    end
end

すると、private def another_methodの行にLayout/AccessModifierIndentationと警告が出ました。privateの二重指定になっているので、警告が出ること自体に問題があるわけでもないのですが、「インデント位置がおかしい」という問題ではないので、別な警告の形のほうが適切だと思います。

  • バージョン: Rubocop 0.57.1

Rails: change_table に bulk: true のオプションを推奨する Cop が欲しい

Rails のマイグレーションファイルに使われる change_table メソッドに { bulk: true } のオプションをつけることができます。
このオプションを利用すると 1 つの ALTER TABLE クエリにまとめてくれるので特に理由がなければ使った方がいいと思っています。

このオプションは MySQL (ActiveRecord::ConnectionAdapters::AbstractMysqlAdapter) のみサポートされていて、他の Adapter では無視されます

この change_table メソッドに対して {bulk: true} オプションを付けることを推奨するような Cop があるといいんじゃないかなあと思っています。

プロジェクト内で強制するならモンキーパッチで change_table に常にオプション渡す、とかできると思いますが、RuboCop で検知できてもいいかもしれないと思ったので起票してみます。

Rubocopをrequireしたい。

発生している問題

コンソール上で require 'rubocop' をすると、以下の文言が返ってきます。

uninitialized constant RuboCop::AST::Parser (NameError)

やりたいこと

rubocopが吐き出すメッセージをgithubのprのchecksのannotationsにpostしたいので
rubocopのインとアウト部分をRailsアプリ上でカスタマイズしようとしています。

補足

rubocop (0.36.0)
parser 2.6.2.0

よろしくお願いします。

map(&:a).map(&:b) を map { |x| x.a.b } にする Cop

obj.map(&:a).map(&:b)

上記のコードは1回の map に直すことができます。

obj.map { |x| x.a.b }

これは3つ以上の map も同様に適用でき、たぶん Performance に属する Cop になると思います。

注意する点

副作用があるメソッド

最初のメソッドの実行回数により、後続のメソッドの戻り値が変わる場合に false positive が発生します。

# app/models/user.rb
class User
  def join_ranking!
    Ranking.current.users << self
    self
  end

  def current_rank
    Ranking.current.rank_of(self)   
  end
end

users = User.limit(10)
users.map(&:join_ranking!).map(&:current_rank)

これは避けるのが難しいため、デフォルト false にした方が無難かもしれません。

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.