Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RuboCop Under a Microscope

Koichi ITO
November 18, 2022

RuboCop Under a Microscope

Lint Night #1
https://lintnight.connpass.com/event/263931/

Koichi ITO

November 18, 2022
Tweet

More Decks by Koichi ITO

Other Decks in Programming

Transcript

  1. 5IFpSTUDPNNJU % git log -p --reverse commit afbead34db54506c12a21dbd4ce04fada0f8b9a4 Author: Bozhidar

    Batsov <[email protected]> Date: Sat Apr 21 13:06:42 2012 +0300 Initial commit to rubocop. --- .document | 5 +++++ .gitignore | 49 +++++++++++++++++++++++++++++++++++++++ ++++++++++ .rspec | 1 + Gemfile | 16 ++++++++++++++++ LICENSE.txt | 20 ++++++++++++++++++++ README.rdoc | 19 +++++++++++++++++++ Rakefile | 45 +++++++++++++++++++++++++++++++++++++++ ++++++ features/rubocop.feature | 9 +++++++++ features/step_definitions/rubocop_steps.rb | 0 features/support/env.rb | 13 +++++++++++++
  2. 5IFpSTUDPNNJU % git log -p --reverse commit afbead34db54506c12a21dbd4ce04fada0f8b9a4 Author: Bozhidar

    Batsov <[email protected]> Date: Sat Apr 21 13:06:42 2012 +0300 Initial commit to rubocop. --- .document | 5 +++++ .gitignore | 49 +++++++++++++++++++++++++++++++++++++++ ++++++++++ .rspec | 1 + Gemfile | 16 ++++++++++++++++ LICENSE.txt | 20 ++++++++++++++++++++ README.rdoc | 19 +++++++++++++++++++ Rakefile | 45 +++++++++++++++++++++++++++++++++++++++ ++++++ features/rubocop.feature | 9 +++++++++ features/step_definitions/rubocop_steps.rb | 0 features/support/env.rb | 13 +++++++++++++ 👈
  3. .F

  4. ߏจղੳͱͦͷઌ ੩తղੳ 3VCP$PQ 1PMZpMM 3VCZ/FYU τϥϯεύΠϥ 0QBM ߏจղੳ 1BSTFS 3VCZίʔυ

    "45 ݹ͍ϥϯλΠϜ 3VCZίʔυ +BWB4DSJQUίʔυ ੩తղੳޙͷमਖ਼ 3VCZίʔυ 1SPDFTTFE4PVSDF
  5. % cd ghq/github.com/whitequark/parser % bundle exec rake generate # Generate

    the Ragel lexer and Racc parser (snip) % ls lib/parser/ all.rb macruby.rb ruby22.y ruby32.rb ast macruby.y ruby23.rb ruby32.y base.rb max_numparam_stack.rb ruby23.y rubymotion.rb builders messages.rb ruby24.rb rubymotion.y clobbering_error.rb meta.rb ruby24.y runner color.rb rewriter.rb ruby25.rb runner.rb context.rb ruby18.rb ruby25.y source current.rb ruby18.y ruby26.rb static_environment.rb current_arg_stack.rb ruby19.rb ruby26.y syntax_error.rb deprecation.rb ruby19.y ruby27.rb tree_rewriter.rb diagnostic ruby20.rb ruby27.y variables_stack.rb diagnostic.rb ruby20.y ruby30.rb version.rb lexer ruby21.rb ruby30.y lexer.rb ruby21.y ruby31.rb lexer.rl ruby22.rb ruby31.y Z͔Β SC͕ੜ੒͞ΕΔ
  6. SVCZQBSTFW SVCZQBSTFCBTFEPOQBSTFSWFSTJPO SVCZQBSTFFDBTFQBUUFSOJO\B ^UIFOUSVF FOE DBTFNBUDI TFOEOJMQBUUFSO

    JOQBUUFSO IBTIQBUUFSO QBJS TZNB JOU OJM USVF OJM SVCZQBSTFW SVCZQBSTFCBTFEPOQBSTFSWFSTJPO SVCZQBSTFFDBTFQBUUFSOJO\B^UIFOUSVF FOE DBTFNBUDI TFOEOJMQBUUFSO JOQBUUFSO IBTIQBUUFSO QBJS TZNB JOU OJM USVF OJM ߏจΤϥʔʹͳΒͣॲཧͰ͖Δ ΧϯϚ͕͋ͬͯ΋ͳͯ͘΋"45͸ಉ͡
  7. require 'rubocop-ast' RuboCop::AST::ProcessedSource.new( 'puts "hello"', 3.1 ) 3VCP$PQ"451SPDFTTFE4PVSDF w ྫ͑͹"45͸ιʔείϝϯτΛදݱͤͣɺ

    ॲཧ͍ͯ͠Διʔείʔυͦͷ΋ͷͷ৘ใΛ ද͢ͷ͕1SPDFTTFE4PVSDFΦϒδΣΫτͰ͢ w 1SPDFTTFE4PVSDF͸ޙड़͢Δ$PQ ϧʔϧ࣮૷ ͔Β΋ΞΫηεՄೳͳΦϒδΣΫτͰ͢
  8. require 'rubocop-ast' ast = RuboCop::AST::ProcessedSource.new( 'puts "hello"', 3.1 ).ast #=>s(:send,

    nil, :puts, s(:str, "hello")) ast.class 3VCP$PQ"451SPDFTTFE4PVSDFBTU
  9. require 'rubocop-ast' ast = RuboCop::AST::ProcessedSource.new( 'puts "hello"', 3.1 ).ast #=>s(:send,

    nil, :puts, s(:str, "hello")) ast.class #=> RuboCop::AST::SendNode ast.class <= RuboCop::AST::Node # true 3VCP$PQ"454FOE/PEF
  10. ast.class #=> RuboCop::AST::SendNode ast.source #=> "puts \"hello\"" ast.location.line #=> 1

    ast.loc.line #=> 1 ast.loc.column #=> 0 ast.loc.last_column #=> 12 ast.loc.source_range #=> ast.method_name #=> :puts ast.first_argument.basic_literal? #=> true 3VCP$PQ"454FOE/PEF
  11. 3VCP$PQ"455SBWFSTBM require 'rubocop-ast' include RuboCop::AST::Traversal # Event handler for `send`

    node def on_send(node) puts node.source end walk(ast) #=> puts "hello"
  12. 3VCP$PQ"455SBWFSTBM require 'rubocop-ast' include RuboCop::AST::Traversal # Event handler for `send`

    node def on_send(node) puts node.source end walk(ast) XBML BTU ͸ຊฤͰͷݤͰ͢💡
  13. 3VCP$PQઃܭུ֓ 3VOOFS 5FBN 3FHJTUSZ $PQ#BTF NPCJMJ[F DPQ@DMBTTFT %FQU$VTUPN$PQ OFX DPEF

    SVCZ@WFSTJPO OFX FOBCMFE $PNNJTTJPOFS JOWFTUJHBUF QSPDFTTFE@TPVSDF "455SBWFSTBM XBML BTU NJYJO JOWFTUJHBUF QSPDFTTFE@TPVSDF "45 1SPDFTTFE4PVSDF OFX OFX DPQT PO@YYY DBMMCBDL EFMFHBUFNFUIPET
  14. 3VCP$PQઃܭུ֓ 3VOOFS 5FBN 3FHJTUSZ $PQ#BTF NPCJMJ[F DPQ@DMBTTFT %FQU$VTUPN$PQ OFX DPEF

    SVCZ@WFSTJPO OFX FOBCMFE $PNNJTTJPOFS JOWFTUJHBUF QSPDFTTFE@TPVSDF "455SBWFSTBM XBML BTU NJYJO JOWFTUJHBUF QSPDFTTFE@TPVSDF "45 1SPDFTTFE4PVSDF OFX OFX DPQT ৭ͳ͠3VCP$PQϥϯλΠϜ 3VCP$PQ"45 ϧʔϧ֦ுϙΠϯτ PO@YYY DBMMCBDL EFMFHBUFNFUIPET
  15. 3VCP$PQઃܭུ֓ ࠶ܝ 3VOOFS 5FBN 3FHJTUSZ $PQ#BTF NPCJMJ[F DPQ@DMBTTFT %FQU$VTUPN$PQ OFX

    DPEF SVCZ@WFSTJPO OFX FOBCMFE $PNNJTTJPOFS JOWFTUJHBUF QSPDFTTFE@TPVSDF "455SBWFSTBM XBML BTU NJYJO JOWFTUJHBUF QSPDFTTFE@TPVSDF "45 1SPDFTTFE4PVSDF OFX OFX DPQT ৭ͳ͠3VCP$PQϥϯλΠϜ 3VCP$PQ"45 ϧʔϧ֦ுϙΠϯτ PO@YYY DBMMCBDL EFMFHBUFNFUIPET
  16. module Cop module Style class MixinUsage < Base MSG =

    '`%<statement>s` is used at the top level.' \ 'Use inside `class` or `module`.'.freeze RESTRICT_ON_SEND = %i[include extend prepend].freeze def_node_matcher :include_statement, <<~PATTERN (send nil? ${:include :extend :prepend} const) PATTERN def on_send(node) return unless (statement = include_statement(node)) return unless top_level_node?(node) add_offense(node, message: format(MSG, statement: statement)) end $PQ ϧʔϧ ͷ࣮૷ྫ
  17. 4VQQPSUNBUSJY W

    ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ❌ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ❌ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ❌ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ❌ ❌ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ ✅ "OBMZTJT3VCZWFSTJPOT TargetRubyVersionJOSVCPDPQZNM 3VOUJNF3VCZWFSTJPOT ruby -v