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

Improve Ruby coding styles and Lint

Improve Ruby coding styles and Lint

RubyKaigi 2018
http://rubykaigi.org/2018

Avatar for Koichi ITO

Koichi ITO

June 01, 2018
Tweet

More Decks by Koichi ITO

Other Decks in Programming

Transcript

  1.  'SJ Improve Ruby coding style rules and Lint ,PJDIJ*50FTN

    3VCZ,BJHJ 4FOEBJ*OUFSOBUJPOBM$FOUFS)BHJ How do you join social coding?
  2. FTN

  3. -BZPVU%FQBSUNFOU "MJHO"SSBZ .FUBQIFS "MJHO)BTI &MTF"MJHONFOU &NQUZ-JOFT &OE"MJHONFOU &YUSB4QBDJOH *OEFOU"SSBZ -JOU%FQBSUNFOU

    %VQMJDBUF.FUIPET %VQMJDBUFE,FZ &MTF"MJHONFOU 4DSJQU1FSNJTTJPO 6OJpFE*OUFHFS 6OSFBDIBCMF$PEF 6OMFTT"TTJHONFOU .FUSJDT%FQBSUNFOU "CD4J[F #MPDL-FOHUI #MPDL/FTUJOH $MBTT-FOHUI -JOF-FOHUI .FUIPE-FOHUI 1BSBNFUFS-JTUT ʜ
  4. -JTUPGDPQT*DSFBUFE  DBU$)"/(&-0(NEcHSFQLPJDcHSFQJBEEOFX <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA3BJMT3FGVUF.FUIPETADPQ <!LPJD><>  <>

    IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA-JOU&SC/FX"SHVNFOUTADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA-JOU#JH%FDJNBM/FXADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQJTTVFT  "EEOFXA-BZPVU&NQUZ$PNNFOUADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQJTTVFT  "EEOFXA-JOU0SEFSFE.BHJD$PNNFOUTADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQJTTVFT  "EEOFXA4UZMF&YQBOE1BUI"SHVNFOUTADPQ <!LPJD><>
  5. -JTUPGDPQT*DSFBUFE  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA(FNTQFD3FRVJSFE3VCZ7FSTJPOADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM

    "EE OFXA(FNTQFD3FEVOEBOU"TTJHONFOUADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA3BJMT3FEVOEBOU3FDFJWFS*O8JUI0QUJPOTADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQJTTVFT  "EEOFXA-JOU6OOFFEFE3FRVJSF4UBUFNFOUADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA4UZMF4UEFSS1VUTADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA-JOU3FEVOEBOU8JUI0CKFDUADPQ <!LPJD><>
  6. -JTUPGDPQT*DSFBUFE  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA4UZMF.JYJO6TBHFADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM

    "EE OFXA-JOU6SJ&TDBQF6OFTDBQFADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA1FSGPSNBODF6SJ%FGBVMU1BSTFSADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA-JOU6SJ3FHFYQADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA#VOEMFS*OTFDVSF1SPUPDPM4PVSDFADPQ <!LPJD><>  <> IUUQTHJUIVCDPNCCBUTPWSVCPDPQQVMM "EE OFXA-JOU3FEVOEBOU8JUI*OEFYADPQ <!LPJD><>
  7.  'SJ Improve Ruby coding style rules and Lint ,PJDIJ*50FTN

    3VCZ,BJHJ 4FOEBJ*OUFSOBUJPOBM$FOUFS)BHJ How do you join social coding?
  8. w.JOFSP"PLJTDPEJOHTUZMF +"  wIUUQJMPWFSVCZOFUKBSVCZDPEJOHTUZMFIUNM w4IVHP.BFEBTDPEJOHTUZMF +"  wIUUQTTIVHPOFUSVCZDPEFDPOW DPEFDPOWIUNM w3VCZ4UZMF(VJEF

    wIUUQTHJUIVCDPNSVCPDPQIRSVCZTUZMFHVJEF w"OEPUIFSTUZMFT w1FSTPOBMBOE$PNQBOZDPEJOHTUZMFT .BOZTUZMFTJOUIFSFBMXPSME
  9. &3#OFXJO3VCZ % cat example.rb require ‘erb' ERB.new('hi', nil, '-', ‘@output_buffer')

    % ruby example.rb example.rb:3: warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments. example.rb:3: warning: Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: ...) instead. example.rb:3: warning: Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: ...) instead.
  10. &3#OFXJO3VCZ # bad # ERB.new(str, nil, '-', '@output_buffer') # good

    # ERB.new(str, trim_mode: '-', eoutvar:'@output_buffer')
  11. &NVMBUJPOPG3VCP$PQ % rubocop example.rb --only Lint/ErbNewArguments Inspecting 1 file W

    Offenses: example.rb:3:15: W: Lint/ErbNewArguments: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments. ERB.new('hi', nil, '-', '@output_buffer') ^^^ example.rb:3:20: W: Lint/ErbNewArguments: Passing trim_mode with the 3rd argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, trim_mode: '-') instead. ERB.new('hi', nil, '-', '@output_buffer') ^^^ example.rb:3:25: W: Lint/ErbNewArguments: Passing eoutvar with the 4th argument of ERB.new is deprecated. Use keyword argument like ERB.new(str, eoutvar: '@output_buffer') instead. ERB.new('hi', nil, '-', '@output_buffer') ^^^^^^^^^^^^^^^^
  12. SBLFOFX@DPQ % be rake new_cop[Rails/TopLevelInclude] Files created: - lib/rubocop/cop/rails/top_level_include.rb -

    spec/rubocop/cop/rails/ top_level_include_spec.rb File modified: - `require_relative 'rubocop/cop/rails/ top_level_include'` added into lib/rubocop.rb Do 3 steps: 1. Add an entry to the "New features" section in CHANGELOG.md, e.g. "Add new `TopLevel/Include` cop. ([@your_id][])" 2. Add an entry into config/enabled.yml or config/disabled.yml 3. Implement your new cop in the generated file!
  13. 8SJUFFYBNQMFT # TODO: when finished, run `rake generate_cops_documentation` to update

    the docs module RuboCop module Cop module Rails # TODO: Write cop description and example of bad / good code. # # @example # # bad # bad_method() # # # good # bad_method(args) 8SJUFDPQEFTDSJQUJPOBOE FYBNQMFPGCBEHPPE
  14. 8SJUFTQFDT describe RuboCop::Cop::Rails::TopLevelInclude do it 'registers an offense when using

    `#bad_method`' do expect_offense(<<-RUBY.strip_indent) bad_method ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`. RUBY end it 'does not register an offense when using `#good_method`' do expect_no_offenses(<<-RUBY.strip_indent) good_method RUBY end end 8SJUFBCBEDBTFPOUIFAFYQFDU@P⒎FOTFA NFUIPE
  15. 8SJUFTQFDT describe RuboCop::Cop::Rails::TopLevelInclude do it 'registers an offense when using

    `#bad_method`' do expect_offense(<<-RUBY.strip_indent) bad_method ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`. RUBY end it 'does not register an offense when using `#good_method`' do expect_no_offenses(<<-RUBY.strip_indent) good_method RUBY end end 8SJUFBCBEDBTFPOUIFAFYQFDU@P⒎FOTFA NFUIPE 8SJUFBHPPEDBTFPOUIFAFYQFDU@OP@P⒎FOTFTA NFUIPE
  16. 8SJUFTQFDT BHBJO describe RuboCop::Cop::Rails::TopLevelInclude do it 'registers an offense when

    using `#bad_method`' do expect_offense(<<-RUBY.strip_indent) bad_method ^^^^^^^^^^ Use `#good_method` instead of `#bad_method`. RUBY end it 'does not register an offense when using `#good_method`' do expect_no_offenses(<<-RUBY.strip_indent) good_method RUBY end end 8SJUFBCBEDBTFPOUIFAFYQFDU@P⒎FOTFA NFUIPE 8SJUFBHPPEDBTFPOUIFAFYQFDU@OP@P⒎FOTFTA NFUIPE
  17. 3FXSJUFTQFDT describe RuboCop::Cop::Rails::TopLevelInclude do it 'registers an offense when using

    outside class' do expect_offense(<<-RUBY.strip_indent) include ^^^^^^^ `include` is used at the top level. Use inside `class` or `module`. class C end RUBY end 8SJUFBCBEDBTFPOUIFAFYQFDU@P⒎FOTFA NFUIPE
  18. 3FXSJUFTQFDT describe RuboCop::Cop::Rails::TopLevelInclude do it 'registers an offense when using

    outside class' do expect_offense(<<-RUBY.strip_indent) include ^^^^^^^^^ `include` is used at the top level. Use inside `class` or `module`. class C end RUBY end it 'does not register an offense when using inside class' do expect_no_offenses(<<-RUBY.strip_indent) class C include M end RUBY 8SJUFBHPPEDBTFPOUIFAFYQFDU@OP@P⒎FOTFTA NFUIPE
  19. SVCZQBSTF % ruby-parse -e 'include M’ (send nil :include (const

    nil :M)) % ruby-parse -e 'extend M’ (send nil :extend (const nil :M)) % ruby-parse -e 'prepend M’ (send nil :prepend (const nil :M)) (FU4FYQSFTTJPOGSPNSVCZQBSTFDPNNBOE 3VCP$PQJTEFQFOEFOUPO1BSTFSHFN
  20. "CTUSBDU4ZOUBY5SFF % ruby_ast_visualizer -e 'include M’ (send nil :include (const

    nil :M)) Wrote a.png IUUQTHJUIVCDPNLPJDSVCZ@BTU@WJTVBMJ[FS
  21. EFG@OPEF@NBUDIFS def_node_matcher :include_statement, <<-PATTERN (send nil? ${:include :extend :prepend} (const

    nil? _)) PATTERN 3FXSJUFBTOPEFQBUUFSOCBTFEPO4FYQSFTTJPO 'VSUIFSSFBEJOH IUUQTHJUIVCDPNSVCPDPQIRSVCPDPQCMPCNBTUFSMJCSVCPDPQOPEF@QBUUFSOSC
  22. 3VCP$PQ/PEF1BUUFSO (send nil? :include (const nil? _)) (send nil? :extend

    (const nil? _)) (send nil? :prepend (const nil? _)) (send nil? ${:include :extend :prepend} (const nil? _)) 6TFA\AA^A NBUDIFTJODMVEF FYUFOEPSQSFQFOE "OEAA BSCJUSBSZNBUDIJOHDBOCFQFSGPSNFEPOB DBQUVSF 'VSUIFSSFBEJOH IUUQTHJUIVCDPNSVCPDPQIRSVCPDPQCMPCNBTUFSMJCSVCPDPQOPEF@QBUUFSOSC
  23. PO@YYYBEE@PGGFOTF MSG = '`%<statement>s` is used at the top level.'

    \ 'Use inside `class` or `module`.'.freeze def_node_matcher :include_statement, <<-PATTERN (send nil? ${:include :extend :prepend} (const nil? _)) 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 8SJUFFWFOUIBOEMFSAPO@OPEF@OBNFA PSAJOWFTUJHBUFA NFUIPE
  24. 8SJUFDPOpHpMFT Rails/TopLevelInclude: Description: 'Checks that `include`, `extend` and `prepend` exists

    at the top level.' Enabled: true # In this PR, the following setting has been removed Rails/TopLevelInclude: Include: - app/**/*.rb "EEBOFOUSZJOUPDPOpHFOBCMFEZNM PSDPOpHEJTBCMFEZNM "EEBOFOUSZJOUPDPOpHEFGBVMUZNM *GEFGBVMUTFUUJOHJTSFRVJSFE
  25. SBLFHFOFSBUF@DPQT@EPDVNFOUBUJPO % # Write the CHANGELOG.md % be rake generate_cops_documentation

    % be rake # be rake parallel:spec Finished in 39.07 seconds (files took 5.91 seconds to load) 17739 examples, 0 failures, 1 pending # be rake parallel:ascii_spec Finished in 37.04 seconds (files took 5.26 seconds to load) 17739 examples, 0 failures, 1 pending # be rake internal_investigation 1046 files inspected, no offenses detected 8IFOpOJTIFE SVO`rake generate_cops_documentation`UPVQEBUFUIFEPDT
  26. # In this PR, the following setting has been removed

    Rails/TopLevelInclude: Include: - app/**/*.rb $BVTFPGUIFQSPCMFN "EEBOFOUSZJOUPDPOpHEFGBVMUZNM *GEFGBVMUTFUUJOHJTSFRVJSFE *FYQBOEFEUIFTDPQFGSPN3BJMT UP4UZMFCVUUIFJNQMFNFOUBUJPO SFNBJOFEOBSSPX