Slide 1

Slide 1 text

Recommendations for making miscellaneous Custom Cops 2022-10-09 Kaigi on Rails _2022_ new @ydah

Slide 2

Slide 2 text

• Name: Yudai T akada • GitHub: @ydah • T witter: @ydah_ • An Open Source Software programmer. • Software Engineer at ANDPAD, Inc. • RuboCop Contributor. (Create and send patches) • Born and raised in Osaka. • Loves beer and coffee and metal bands 🍻 ☕ 🤘 self.inspect

Slide 3

Slide 3 text

rubocop/rubocop 2022

Slide 4

Slide 4 text

rubocop/rubocop-rspec 2022

Slide 5

Slide 5 text

• Style/ObjectThen • Lint/ConstantOverwrittenInRescue • Lint/NonAtomicFileOperation • Rails/WhereMissing • Rails/FreezeTime • RSpec/ChangeByZero • RSpec/Capybara/SpecificFinders • RSpec/Capybara/SpecificMatcher Add new cops

Slide 6

Slide 6 text

Today’s talk

Slide 7

Slide 7 text

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

Slide 8

Slide 8 text

• A Ruby static code analyzer (a.k.a. linter) and code formatter. • Rubyの静的解析ツール What is RuboCop?

Slide 9

Slide 9 text

• 自分で使う便利ツールとして作っていく • 例: action_argsを使っていないアクションを探す • 良さそうなものはブラッシュアップしてプロダクトに導入したり、RuboCopへパッチを送ったり • 置き場となるリポジトリを作っておくのがおすすめ • 思いついた時にサッと書けて試せる • リポジトリ自体も簡単に作れる “雑” Custom Cop

Slide 10

Slide 10 text

https://github.com/rubocop/ rubocop-extension-generator

Slide 11

Slide 11 text

$ rubocop-extension-generator rubocop-foobar

Slide 12

Slide 12 text

Creating gem 'rubocop-foobar'... create rubocop-foobar/Gemfile create rubocop-foobar/lib/rubocop/foobar.rb create rubocop-foobar/lib/rubocop/foobar/version.rb create rubocop-foobar/rubocop-foobar.gemspec create rubocop-foobar/Rakefile create rubocop-foobar/README.md create rubocop-foobar/bin/console create rubocop-foobar/bin/setup create rubocop-foobar/.gitignore Initializing git repo in /tmp/tmp.Gu7G94wX00/rubocop-foobar Gem 'rubocop-foobar' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html create rubocop-foobar/lib/rubocop-foobar.rb create rubocop-foobar/lib/rubocop/foobar/inject.rb create rubocop-foobar/lib/rubocop/cop/foobar_cops.rb create rubocop-foobar/config/default.yml create rubocop-foobar/spec/spec_helper.rb create rubocop-foobar/.rspec update lib/rubocop/foobar.rb update lib/rubocop/foobar.rb update lib/rubocop/foobar/version.rb update rubocop-foobar.gemspec update rubocop-foobar.gemspec update Rakefile update Gemfile It's done! You can start developing a new extension of RuboCop in rubocop-foobar. For the next step, you can use the cop generator. $ bundle exec rake 'new_cop[Foobar/SuperCoolCopName]'

Slide 13

Slide 13 text

Creating gem 'rubocop-foobar'... create rubocop-foobar/Gemfile create rubocop-foobar/lib/rubocop/foobar.rb create rubocop-foobar/lib/rubocop/foobar/version.rb create rubocop-foobar/rubocop-foobar.gemspec create rubocop-foobar/Rakefile create rubocop-foobar/README.md create rubocop-foobar/bin/console create rubocop-foobar/bin/setup create rubocop-foobar/.gitignore Initializing git repo in /tmp/tmp.Gu7G94wX00/rubocop-foobar Gem 'rubocop-foobar' was successfully created. For more information on making a RubyGem visit https://bundler.io/guides/creating_gem.html create rubocop-foobar/lib/rubocop-foobar.rb create rubocop-foobar/lib/rubocop/foobar/inject.rb create rubocop-foobar/lib/rubocop/cop/foobar_cops.rb create rubocop-foobar/config/default.yml create rubocop-foobar/spec/spec_helper.rb create rubocop-foobar/.rspec update lib/rubocop/foobar.rb update lib/rubocop/foobar.rb update lib/rubocop/foobar/version.rb update rubocop-foobar.gemspec update rubocop-foobar.gemspec update Rakefile update Gemfile It's done! You can start developing a new extension of RuboCop in rubocop-foobar. For the next step, you can use the cop generator. $ bundle exec rake 'new_cop[Foobar/SuperCoolCopName]'

Slide 14

Slide 14 text

$ bundle exec rake 'new_cop[FooBar/CopName]'

Slide 15

Slide 15 text

[create] lib/rubocop/cop/foo_bar/cop_name.rb ★copの実装 [create] spec/rubocop/cop/foo_bar/cop_name_spec.rb ★テストコード [modify] lib/rubocop/cop/foobar_cops.rb - `require_relative 'foo_bar/cop_name'` was injected. [modify] A configuration for the cop is added into config/default.yml. Do 4 steps: 1. Modify the description of FooBar/CopName in config/default.yml 2. Implement your new cop in the generated file! 3. Commit your new cop with a message such as e.g. "Add new `FooBar/CopName` cop" 4. Run `bundle exec rake changelog:new` to generate a changelog entry for your new cop.

Slide 16

Slide 16 text

lib/rubocop/cop/foo_bar/cop_name.rb

Slide 17

Slide 17 text

lib/rubocop/cop/foo_bar/cop_name.rb on_{node_type} は解析時に呼ばれる コールバックメソッド。 雛形の例だと以下を解析すると2回実行される。  bad_method.bad_method $ ruby-parse -e “bad_method.bad_method" (send (send nil :bad_method) :bad_method)

Slide 18

Slide 18 text

lib/rubocop/cop/foo_bar/cop_name.rb on_send を使用する場合に指定する。 メソッド呼び出しがある毎に on_send が実行されるので、 on_send で呼ばれるメソッドを限定する。

Slide 19

Slide 19 text

lib/rubocop/cop/foo_bar/cop_name.rb 第一引数 = メソッド名 第二引数 = ノードパターン としてノードパターンに一致するかを判定する メソッドを定義する。

Slide 20

Slide 20 text

lib/rubocop/cop/foo_bar/cop_name.rb add_offense はノードに対して警告を表示する。 警告の内容はMSGで指定できる。 ɹbad_method ɹ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`.

Slide 21

Slide 21 text

違反としたい場合にのみ add_offense を呼ぶように書き換えれば良い

Slide 22

Slide 22 text

シンプルなものならとても簡単に書ける

Slide 23

Slide 23 text

幸せな Custom Cop ライフを

Slide 24

Slide 24 text

end