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

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