Breaking Change

023b04c98f39cc041293d780352432ff?s=47 Koichi ITO
December 14, 2019

Breaking Change

023b04c98f39cc041293d780352432ff?s=128

Koichi ITO

December 14, 2019
Tweet

Transcript

  1. #SFBLJOH$IBOHF <ഁյతมߋ> $MPTJOH,FZOPUF גࣜձࣾ%3&$0. !LPJD&4. *OD  4BU ฏ੒3VCZձٞ

  2. !LPJD,PJDIJ*50 w 3VCP$PQ$PNNJUUFS w "30SBDMFFOIBODFE BEBQUFS$PNNJUUFS w $PNNVOJUZ.BOBHFS BU&4. *OD

  3. 8SJUF 3FWJFX $PEF&WFSZ%BZ

  4. None
  5. None
  6. #VOEMFS 1SZ 34QFD 3VCP$PQ CZFCVH 3VCZ,BJHJ %3&$0.͞Μϒʔεʹͯ

  7. None
  8. 044ίϛϡχςΟͱͷڞੜΛࢧԉ Support coexistence with OSS community

  9. ͋ͱ͸෼͔Γ·͢Ͷʁ ࠾༻ ೥Ҏ্ͷ3BJMTΞϓϦ։ൃͷ࣮੷&4. l3BJMT044Λ௨͡੒௕͍ͨ͠ϓϩάϥϚʔz @koicまでどうぞ

  10. IUUQTIFJTFJSCHJUIVCJPLBJHJ

  11. IUUQTIFJTFJSCHJUIVCJPLBJHJ

  12. #SFBLJOH$IBOHF <ഁյతมߋ> $MPTJOH,FZOPUF גࣜձࣾ%3&$0. ,PJDIJ*50&4. *OD  4BU ฏ੒3VCZձٞ

  13. ͜ͷߨԋͰಘΒΕΔ͔΋͠Εͳ͍͜ͱ w ςετͱCVOEMFVQEBUFͷॏཁ ੑͷ࠶ೝࣝ w 3VCP$PQͷࣼΊ্ͷ࢖͍ํ w ࢲ͔Βݟͨ044ͷੈք؍ w ഁյతมߋͷͨΊʹ͋ͳ͕ͨͰ͖Δ

    ͔΋͠Εͳ͍͜ͱ
  14. w ഁյతมߋͱ͸Կ͔ʁ w ެ෍ࡁΈΠϯλϑΣʔεΛ࢖͏ w ඇਪ঑ܯࠂόʔδϣϯΛܦ༝͢Δ w ഁյతมߋΛ৐Γӽ͑Δ w ΦʔϓϯιʔείϛϡχςΟ

    ΞδΣϯμ
  15. ഁյతมߋ ͱ͸Կ͔ʁ

  16. CVHTSVCZMBOHPSHJTTVFT 3FBMLFZXPSEBSHVNFOU

  17. IUUQTXXXSVCZMBOHPSHKBOFXTSVCZQSFWJFXSFMFBTFE

  18. None
  19. To be continued…

  20. CVHTSVCZMBOHPSHJTTVFT 3FHFYQ\NBUDI NBUDI ^XJUIBOJMBSHVNFOUBSF EFQSFDBUFEBOEXJMMSBJTFB5ZQF&SSPSJO3VCZ

  21. ҆ఆ൛ͷ3VCZ[ % rbenv shell 2.6.5 && ruby -e 'p /re/.match?(nil)'

    false
  22. ։ൃ൛ͷ3VCZ % rbenv shell 2.6.5 && ruby -e 'p /re/.match?(nil)'

    false % rbenv shell 2.7.0-preview2 && ruby -e 'p /re/.match? (nil)' Traceback (most recent call last): 1: from -e:1:in `<main>' -e:1:in `match?': no implicit conversion of nil into String (TypeError) QSFWJFX
  23. ։ൃ൛ͷ3VCZ % rbenv shell 2.6.5 && ruby -e 'p /re/.match?(nil)'

    false % rbenv shell 2.7.0-preview2 && ruby -e 'p /re/.match? (nil)' Traceback (most recent call last): 1: from -e:1:in `<main>' -e:1:in `match?': no implicit conversion of nil into String (TypeError) % rbenv shell 2.7.0-preview3 && ruby -e 'p /re/.match? (nil)' -e:1: warning: given argument is nil; this will raise a TypeError in the next release false QSFWJFX
  24. IUUQTCMPHBHJMFFTNDPKQFOUSZSBJMTPTTQBUDINFFUVQ ύονձͰ΋࿩୊ʹ

  25. IUUQTUXJUUFSDPNLBNJQPTUBUVT

  26. IUUQTUXJUUFSDPNLBNJQPTUBUVT

  27. IUUQTUXJUUFSDPNOBMTITUBUVT

  28. IUUQTUXJUUFSDPNZVLJIJSP@NBU[TUBUVT

  29. IUUQTCVHTSVCZMBOHPSHJTTVFT 3FWFSU

  30. ഁյతมߋ ͱ͸Կ͔ʁ

  31. w CVOEMFVQEBUFޙ w 3VCZͷόʔδϣϯΛ͋͛ͨޙ w ͦͷ΄͔ϛυϧ΢ΣΞΛߋ৽ͨ͠ޙ ར༻ίʔυ΁ͷޙํޓ׵Λͳ͘͢มߋ ҎલͱҟͳΔ݁ՌΛҾ͖ى͜͠͏Δมߋ ‑

  32. w ެ։͞Εͨ"1*ͷ໊લ͕มΘΔ w ެ։͞Εͨ"1*ͷҾ਺͕มΘΔ w ެ։͞Εͨ"1*ͷ໭Γ஋͕มΘΔ w ެ։͞Εͨ"1*ͷৼΔ෣͍͕มΘΔ w όάpYͱඇޓ׵มߋ͸ظ଴ͷҧ͍

    ͲΜͳഁյతมߋ͕͋Δͷ͔ʁ
  33. ެ։"1* ඇެ։"1*

  34. %FQFOEPO 1VCMJTIFE"1* 公開APIへの依存

  35. IUUQTCMJLJKBHJUIVCJP1VCMJTIFE*OUFSGBDF

  36. 0CKFDU0SJFOUFE 1SPHSBNJOH

  37. ŠŠŠŠŠŠŠŠŠŠ҆ఆʹґଘͤΑ SDP: Stable Dependency Principle

  38. w ιϑτ΢ΣΞ͸มԽ͠ଓ͚Δ w ҆ఆͨ͠"1*ͱෆ҆ఆͳ"1*͕͋Δ w ઃܭ͸׬શʹݻఆͰ͖ͳ͍ͨΊɺෆ ҆ఆΛڐ͢࢓૊Έ͕ඞཁ w ෆ҆ఆͳ"1*͕ѱ͍ͷͰ͸ͳ͘ɺෆ ҆ఆͳ"1*ʹґଘ͢Δͷ͕ѱ͍͜ͱ

    4%1҆ఆґଘͷ๏ଇ
  39. w ಺෦తͳ"1*ͱ໌ࣔ͞Ε͍ͯΔ"1* ͸࢖Θͳ͍ w 3BJMTʹ͓͍ͯ͸ϝιουίϝϯτ ͕͋ΔEPDʹ൓ө͞ΕΔϝιου͕ ެ։"1*ͱͳΔ w ඇެ։"1*ʹґଘ͢ΔͱͲ͏ͳΔʁ 3VCZ3VCZPO3BJMT

  40. %FQFOEPO *OUFSOBM"1* ⾮公開APIへの依存

  41. 8JUIHSFBUQPXFS DPNFTHSFBU SFTQPOTJCJMJUZ ⼤いなる⼒には⼤いなる責任が伴う

  42. MTFHBMZBSE SVCZ@QBSTFSSCBEEWPJE@TUNUUPJOTFSU@DPNNFOUT MPPQ

  43. SVCZSVCZ!FGCDB

  44. 3FNPWFBOJOUFSOBM"1* ಺෦"1* શ࡟আ

  45. SFRVJSFFSSPS ಺෦"1*

  46. ಺෦"1*΁ͷґଘΛճආ͢Δ

  47. SBJMTSBJMT 3FNPWFVTFMFTT A.JHSBUPSTDIFNB@NJHSBUJPOT@UBCMF@OBNFA

  48. ಺෦"1*

  49. ಺෦"1* 3BJMTͰ͸ϝιουίϝϯτ͕ه͞Ε͍ͯͳ͍΋ͷ͸ඇެ։ "1*ͱ͍͏ѻ͍ͱͳ͍ͬͯΔ

  50. ࡟আࡁ"1* ͷஔ׵

  51. % ag 'Migrator\.schema_migrations_table_name' `ghq root` HIR؅ཧͷMPDBMSFQPΛ۲ࢗ͠ݕࡧ Ͳ͏ͩΖ͏ʁ

  52. % ag 'Migrator\.schema_migrations_table_name' `ghq root` HIR؅ཧͷMPDBMSFQPΛ۲ࢗ͠ݕࡧ ݁Ռͱ͍͔ͯͭ͘͠ώοτͨ͠ ‑

  53. ಺෦"1*΁ͷґଘͷ࣮ྫ IUUQTHJUIVCDPNFTNJODBEIPRQVMM

  54. ಺෦"1*΁ͷґଘͷ࣮ྫ IUUQTHJUIVCDPNBNBUTVEBEBUBCBTF@SFXJOEFSQVMM

  55. w ಺෦"1*͸ϥΠϒϥϦఏڙऀ͕࣮૷ ʹԠͯ͡มߋ͠͏Δ w ͭ·Γಥવͦͷ"1*͕ͳ͘ͳͬͯ /P.FUIPE&SSPS͕ى͖ΔͳͲ w ྫ͑͹3BJMTΛΞοϓσʔτͨ͠Β ະରԠґଘ(FNͰΤϥʔ͕ى͖Δ %PO`UEFQFOEPOJOUFSOBM"1*

  56. ඇਪ঑ܯࠂͷఏҊ͕͞ΕΔ 削除の前に⾮推奨警告しませんか。 バックリ ンクに⽰された多くのGemが使⽤してる。

  57. w ຊདྷ͸಺෦"1*ʹґଘ͢Δͷ͕ྑ͘ ͳ͍͕ɺใࠂ݅਺͕ͦΕͳΓʹ͋ͬ ͨͱϝϯςφʔʹײ͡ΒΕͨ໛༷ w ͓ͦΒ͔͘ͳΓಛघέʔε w ҰํͰެ։"1*΁ͷมߋ͸Ϣʔβʔ ӨڹΛߟྀ͢΂͖ ඇਪ঑ܯࠂ

  58. ඇਪ঑ܯࠂͷ௥Ճ IUUQTHJUIVCDPNSBJMTSBJMTQVMM

  59. ඇਪ঑ܯࠂʹΑΔઆ໌ IUUQTHJUIVCDPNKSVCZBDUJWFSFDPSEKECDBEBQUFSQVMM

  60. w ॲཧܥ΍ϥΠϒϥϦ͕ܯࠂΛग़͍ͯ ΔόʔδϣϯΛܦ༝ͯ͠ɺܯࠂΛ௵ ͔ͯ͠Β࣍ͷόʔδϣϯʹ্͛Δ w ͳΔ΂͘ϋΠδϟϯϓΛආ͚Δ w ೔ࠒ͔ΒCVOEMFVQEBUFΛ͠ ͯɺςετΛ࣮ߦ͢Δ ΞϓϦέʔγϣϯ։ൃऀͷᅂΈ

  61. ഁյతมߋ ͱ͸Կ͔ʁ ෼͔Γ· ͔ͨ͠ʁ

  62. w ͦ΋ͦ΋ιϑτ΢ΣΞ։ൃ͸೉͍͠ w ΋ͬͱ࢖͍΍͍ͩ͢Ζ͏ઃܭ͕͋Ε ͹ɺͰ͖Ε͹ͦ͏͍ͨ͠ ᷤ౻  w ιϑτ΢ΣΞ͸ਓ͕࡞͍ͬͯΔ w

    ͭ·Γެ։"1*Ͱ΋ᷤ౻ͷ຤ɺഁյ ͞ΕΔ ͢Δ ͜ͱ͕͋Δ ެ։"1*Λ࢖͑͹໰୊͸ى͖ͳ͍ʁ
  63. 'BLFS #SFBLJOH$IBOHF #Z&YBNQMF

  64. None
  65. w ͋Δ೔ɺ3BJMTΞϓϦέʔγϣϯΛ CVOEMFVQEBUFͯ͠ςετΛ࣮ ߦͨ͠ΒಥવͷΤϥʔ͕ى͖Δ 'BLFSͰى͖ͨഁյతมߋ

  66. 'BLFSZ[ Faker::Address.zip_code('NY') # => "25771"

  67. 'BLFS[ Faker::Address.zip_code('NY') % bundle exec ruby example.rb Traceback (most recent

    call last): 1: from example.rb:3:in `<main>' /Users/koic/.rbenv/versions/2.6.3/lib/ruby/gems/ 2.6.0/gems/faker-2.1.2/lib/faker/default/ address.rb:32:in `zip_code': wrong number of arguments (given 1, expected 0) (ArgumentError)
  68. 'BLFS[ ղܾ൛ -Faker::Address.zip_code('NY') +Faker::Address.zip_code(state_abbreviation: 'NY') LXBSHT ʹ͢Δ

  69. w ࣗ෼ͷ৔߹͸ॳखʹHFNEJGGΛ࢖ͬ ͯࠩ෼Λ֬ೝͨ͠Γɺίϛοτϝοηʔ δʹ࢒ͨ͠Γ͍ͯ͠ΔͷͰͦͷϦϯΫ ΛݟΔ VQTUSFBNͷࠩ෼ΛݟΔ % gemdiff (snip) faker:

    2.8.1 > 2.8.0 https://github.com/faker-ruby/faker/compare/ v2.8.0...v2.8.1
  70. มߋཤྺͱ ͍͏ཏ਑൫ IUUQKBXJLJQFEJBPSHXJLJ&""&""&##&&##"NFEJB'JMF$BOUJOP1MBOJTQIFSFQOH IUUQTHJUIVCDPNGBLFSSVCZGBLFSCMPC W$)"/(&-0(NEJNQPSUBOUOPUF

  71. None
  72. "1*

  73. w "SHVNFOU&SSPS͸ݪҼͱͯ͠෼͔ Γ΍͍͕͢ɺͲͷΑ͏ͳҾ਺͕ਖ਼͍͠ ͔෼͔Βͳ͔ͬͨ w QPTJUJPOBMҾ਺͔ΒΩʔϫʔυҾ਺΁ ͷมߋͰΩʔϫʔυ͕͙͢ʹ෼͔Βͳ ͔ͬͨ w "1*ͷҾ਺෼

    ໰୊఺
  74. w ࣗ෼͕౿Μͩ໘౗ͳ͜ͱ͸ɺଞͷਓ ʹͱͬͯ΋໘౗͔΋͠Εͳ͍ w (FNͷଟ͘͸3VCZͰॻ͔Ε͍ͯ Δ w ύονΛૹΔͷʹࢧোͷ͋ΔϥΠη ϯεʹग़ձͬͨ͜ͱ͕ͳ͍ ෆศͩͱࢥͬͨΒఏҊ͢Ε͹ྑ͍

  75. w ΞοϓάϨʔυޙͷ࣮ߦ࣌Ͱ͙͢ʹ Τϥʔʹ͢ΔͷͰ͸ͳ͘ɺઌʹͲͷ Α͏ͳΠϯλϑΣʔεʹมΘΔͷ͔ ܯࠂΛग़͢ ղܾҊͱͯ͠ߟ͑ͨ͜ͱ

  76. GBLFSSVCZGBLFS "EEXBSOGPSQPTJUJPOBMBSHVNFOUTXIFOVTJOH 'BLFS

  77. $POUFYU Կނඞཁ͔

  78. )PX ࣮૷ϙΠϯτ

  79. .FSJU ͲΜͳಘ͕

  80. &YBNQMF ࣮ྫ

  81. ίʔυEJGG جຊతͳมߋ ޓ׵*'ͷఏڙ

  82. ίʔυEJGG جຊతͳมߋ چ"1*΁ͷܯࠂ

  83. ίʔυEJGG جຊతͳมߋ w legacy_sourceͱͯ͠ݩͷҾ਺Ͱ΋ ड͚ೖΕΔΑ͏ʹ͢Δ w legacy_source͕౉͞Εͨ৔߹͸ܯ ࠂΛදࣔͯ͠ɺͦͷ஋Λ༏ઌͯ͠࢖͏

  84. ͦΕΛ"1*

  85. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end "1*෼ͷରԠͱ͸
  86. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end ϝιου໊ "1*෼ͷରԠͱ͸
  87. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end Ҿ਺໊ "1*෼ͷରԠͱ͸
  88. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end Ҿ਺ͷ਺ "1*෼ͷରԠͱ͸
  89. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end σϑΥϧτ஋ "1*෼ͷରԠͱ͸
  90. def saying(legacy_source = NOT_GIVEN, source: nil) if legacy_source != NOT_GIVEN

    warn_with_uplevel 'Passing `source` with the \ 1st argument of `Dune.saying` is deprecated. \ Use keyword argument like \ `Dune.saying(source: ...)` instead.', uplevel: 1 source = legacy_source end end ܯࠂจ "1*෼ͷରԠͱ͸
  91. "1* ख࡞ۀ͸ ͭΒ͍

  92. ୡਓϓϩάϥϚʔ΁ͷجૅٕज़ ςεςΟϯά %FWFMPQFS5FTUJOH ࣗಈԽ 1SPKFDU"VUPNBUJPO όʔδϣϯ؅ཧ 7FSTJPO$POUSPM

  93. None
  94. w LXBSHTʹมΘΔલͷ'BLFSͷίϛο τϋογϡΛखʹೖΕΔ w खݩͷ'BLFSϦϙδτϦΛͦͷόʔδϣ ϯʹ໭͢ w 'BLFSελΠϧ΁ͷҠߦΠϯλϑΣʔ εʹBVUPDPSSFDU͢Δ$PQΛ࡞Δ w

    'BLFSʹ$PQΛద༻ͨ͠ύονΛૹΔ ͜ͷඇਪ঑ܯࠂΛ࡞ΔͨΊߦͬͨ͜ͱ
  95. w LXBSHTʹมΘΔલͷ'BLFSͷίϛο τϋογϡΛखʹೖΕΔ w खݩͷ'BLFSϦϙδτϦΛͦͷόʔδϣ ϯʹ໭͢ w 'BLFSελΠϧ΁ͷҠߦΠϯλϑΣʔ εʹBVUPDPSSFDU͢Δ$PQΛ࡞Δ w

    'BLFSʹ$PQΛద༻ͨ͠ύονΛૹΔ ͜ͷඇਪ঑ܯࠂΛ࡞ΔͨΊߦͬͨ͜ͱ
  96. w 3VCP$PQ͸ظ଴͍ͯ͠ͳ͍ελΠ ϧͷίʔυΛظ଴͍ͯ͠Δίʔυʹ ࣗಈमਖ਼͢ΔػೳΛඋ͍͑ͯΔ w 3VCP$PQ͕ఏڙ͍ͯ͠Δ$PQΫ ϥεΛܧঝ͢Δ͜ͱͰΦϦδφϧͷ $PQΛ࡞Δ͜ͱ͕Ͱ͖Δ 3VCP$PQ͓͞Β͍

  97. w ϩʔΧϧϦϙδτϦͷΈͷϒϥϯν Ͱॻ͖ͳ͙ͬͨ΋ͷΛൃ۷͠·ͨ͠ w ͲΜͳҠߦεΫϦϓτΛॻ͍͍ͯͨ ͷ͔ൈਮͯ͠งғؾΛ఻͑·͢ w ϝϯςφϯεΛ΄΅ߟ͍͑ͯͳ͍ɺ γϣοτͷίʔυʹͯޚ༰ࣻئ ΦϒδΣΫτࢦ޲lεΫϦϓτzݴޠ

  98. ԶDPQ͕ظ଴͢Δ࢓༷ # bad # def email( # name: nil, #

    separators: nil # ) # # good # def email( # legacy_name = NOT_GIVEN, # legacy_separators = NOT_GIVEN, # name: nil, # separators: nil # ) ΩʔϫʔυҾ਺ͷΈ Ͱߏ੒͞Ε͍ͯΔ
  99. CBEέʔεΛଊ͑Δ࣮૷ྫ class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all?

    {|argument| argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end
  100. CBEέʔεΛଊ͑Δ࣮૷ྫ class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all?

    {|argument| argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end EFGϊʔυͷॲཧ
  101. CBEέʔεΛଊ͑Δ࣮૷ྫ class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all?

    {|argument| argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end ܯࠂΛग़͢"1*
  102. CBEέʔεΛଊ͑Δ࣮૷ྫ class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all?

    {|argument| argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end ܯࠂ͠ͳ͍৚݅
  103. CBEέʔεΛଊ͑Δ࣮૷ྫ class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all?

    {|argument| argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end ܯࠂ͠ͳ͍৚݅ ϊʔυͷλΠϓ % ruby-parse -e 'def do_something(foo:, bar: 1); end' (def :do_something (args (kwarg :foo) (kwoptarg :bar (int 1))) nil)
  104. class BreakingChangeArguments < Cop def on_def(node) return unless node.arguments.all? {|argument|

    argument.kwarg_type? || argument.kwoptarg_type? } node.arguments.reverse_each do |argument| message = format( MSG, name: argument.children.first ) add_offense(argument, message: message) end end end ܯࠂ͠ͳ͍৚݅ % ruby-parse -e 'def do_something(foo:, bar: 1); end' (def :do_something (args (kwarg :foo) (kwoptarg :bar (int 1))) nil) CBEέʔεΛଊ͑Δ࣮૷ྫ ϊʔυͷλΠϓ
  105. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  def autocorrect(node) kwarg = node.children.first argument_index = node.parent.parent.arguments.map

    {|argument| argument.children.first }.index(kwarg) + 1 index = case argument_index when 1; '1st' when 2; '2nd' when 3; '3rd' else "#{argument_index}th" end
  106. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  def autocorrect(node) kwarg = node.children.first argument_index = node.parent.parent.arguments.map

    {|argument| argument.children.first }.index(kwarg) + 1 index = case argument_index when 1; '1st' when 2; '2nd' when 3; '3rd' else "#{argument_index}th" end ࣗಈमਖ਼ ΁ͷίʔϧόοΫ ఆٛ
  107. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  def autocorrect(node) kwarg = node.children.first argument_index = node.parent.parent.arguments.map

    {|argument| argument.children.first }.index(kwarg) + 1 index = case argument_index when 1; '1st' when 2; '2nd' when 3; '3rd' else "#{argument_index}th" end LXBSHͷ ϊʔυ
  108. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  def autocorrect(node) kwarg = node.children.first argument_index = node.parent.parent.arguments.map

    {|argument| argument.children.first }.index(kwarg) + 1 index = case argument_index when 1; '1st' when 2; '2nd' when 3; '3rd' else "#{argument_index}th" end LXBSHͷ Ҿ਺Ґஔ
  109. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  legacy_argument = "legacy_#{kwarg}" class_name = find_class_name(node) method_name =

    node.parent.parent.method_name condition += <<-RUBY if #{legacy_argument} != NOT_GIVEN warn_with_uplevel 'Passing `#{kwarg}` with the #{index} argument of `#{class_name}.#{method_name}` is deprecated. Use keyword argument like `#{class_name}.#{method_name} (#{kwarg}: ...)` instead.', uplevel: 1 #{kwarg} = #{legacy_argument} end RUBY
  110. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  legacy_argument = "legacy_#{kwarg}" class_name = find_class_name(node) method_name =

    node.parent.parent.method_name condition += <<-RUBY if #{legacy_argument} != NOT_GIVEN warn_with_uplevel 'Passing `#{kwarg}` with the #{index} argument of `#{class_name}.#{method_name}` is deprecated. Use keyword argument like `#{class_name}.#{method_name} (#{kwarg}: ...)` instead.', uplevel: 1 #{kwarg} = #{legacy_argument} end RUBY ޓ׵ม਺ͷ࡞੒
  111. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  legacy_argument = "legacy_#{kwarg}" class_name = find_class_name(node) method_name =

    node.parent.parent.method_name condition += <<-RUBY if #{legacy_argument} != NOT_GIVEN warn_with_uplevel 'Passing `#{kwarg}` with the #{index} argument of `#{class_name}.#{method_name}` is deprecated. Use keyword argument like `#{class_name}.#{method_name} (#{kwarg}: ...)` instead.', uplevel: 1 #{kwarg} = #{legacy_argument} end RUBY private def find_class_name(node) if node.class_type? return node.identifier.source end find_class_name(node.parent) end
  112. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  legacy_argument = "legacy_#{kwarg}" class_name = find_class_name(node) method_name =

    node.parent.parent.method_name condition += <<-RUBY if #{legacy_argument} != NOT_GIVEN warn_with_uplevel 'Passing `#{kwarg}` with the #{index} argument of `#{class_name}.#{method_name}` is deprecated. Use keyword argument like `#{class_name}.#{method_name} (#{kwarg}: ...)` instead.', uplevel: 1 #{kwarg} = #{legacy_argument} end RUBY ࣗಈमਖ਼ίʔυͷ ஔ׵จࣈྻ
  113. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  lambda do |corrector| corrector.insert_before( arguments_range(node), "#{legacy_argument} = NOT_GIVEN,

    " ) corrector.insert_before( node.parent.parent.children.last.source_range, condition ) end
  114. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  lambda do |corrector| corrector.insert_before( arguments_range(node), "#{legacy_argument} = NOT_GIVEN,

    " ) corrector.insert_before( node.parent.parent.children.last.source_range, condition ) end मਖ਼ίʔυ΁ ͷஔ׵
  115. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  lambda do |corrector| corrector.insert_before( arguments_range(node), "#{legacy_argument} = NOT_GIVEN,

    " ) corrector.insert_before( node.parent.parent.children.last.source_range, condition ) end ޓ׵Ҿ਺ͷૠೖ
  116. CBEέʔεΛࣗಈमਖ਼͢Δ࣮૷ྫ  lambda do |corrector| corrector.insert_before( arguments_range(node), "#{legacy_argument} = NOT_GIVEN,

    " ) corrector.insert_before( node.parent.parent.children.last.source_range, condition ) end ܯࠂ৚݅ͷૠೖ
  117. None
  118. ͓Ϛʔδ

  119. ŠŠŠŠŠŠŠŠŠŠϢʔβʔͷ൓Ԡ Feedback

  120. GBLFSSVCZGBLFS USJHHFSTEFQSFDBUJPOXBSOJOHTGSPNJOTJEFUIF HFN

  121. ⾮推奨警告の量が半端なくて⼤変だったよ

  122. w ,ಥવͷΤϥʔΛճආ͢Δඇਪ঑ ܯࠂ͕׆༻͞ΕͨΑ͏Ͱ͋Δ w 1 ͷഁյతมߋΛ௚ܸ͢Δ ͱͭΒͦ͏Ͱ͋Δ w 5ࣗಈमਖ਼ՄೳͳπʔϧΛఏڙ͠ ͯΞοϓάϨʔυ΁ͷ௧ΈΛݮΒ͢

    ϑΟʔυόοΫʹରͯ͠ߟ͑ͨ͜ͱ
  123. LPJDSVCPDPQGBLFS "3VCP$PQFYUFOTJPOGPS'BLFS

  124. w ͔ͭͯ34QFD͔Β34QFD΁ ͷҠߦͰ࢖ͬͨ5SBOTQFDʹӨڹ Λड͚ͯ࡞ͬͨ(FN w 'BLFSʹඇਪ঑ܯࠂΛೖΕΔ13Λ ࡞ΔաఔͰ͍ͭͰʹฒߦͯ͠࡞Ζ͏ ͱ͍ͯͨ͠Α͏ͳ ͏Ζ֮͑ Ұܳ͸։ൃΛՃ଎͢Δ

  125. None
  126. None
  127. ઌͷ࣮૷ͱࣅͨ Α͏ͳ΋ͷͳͷ Ͱ࣮૷ղઆׂѪ

  128. l (FN͸࡞͚ͬͨͩͰউख ʹ޿·ΔΘ͚Ͱ͸ͳ͘࢖Θ ΕΔͨΊͷͻͱ޻෉ॏཁ !BNBUTVEB

  129. 

  130. IUUQTXXXNPVOUBJOHPBUTPGUXBSFDPNCMPHBSFPGGFBUVSFTSFBMMZSBSFMZPSOFWFSVTFE

  131. ࢲ͕ࢥ͍͍ͭͨ ͜ͷ՝୊ʹର͠ ࠷ڧͷએ఻ํ๏

  132. VQTUSFBN ʹऔΓࠐΜ Ͱ΋Β͏

  133. GBLFSSVCZGBLFS *ODMVEFSVCPDPQGBLFSBVUPDPSSFDUJOEFQSFDBUJPO

  134. None
  135. $POUFYU લྫΛग़͢

  136. )PX ղܾࡦ

  137. &YBNQMF ࣮ྫ

  138. .FSJU ͲΜͳಘ͕

  139. ৺഑ͩͬͨ఺

  140. None
  141. ͓Ϛʔδ

  142. ŠŠŠŠŠŠŠŠŠŠŠŠŠŠͦͷޙ Afterwards

  143. GBLFSSVCZGBLFS 6TJOHLXBSHTGPSNFUIPETUIBUBDDFQUPOMZPOF BSHVNFOUJTJOF⒏DJFOU

  144. 引数ひとつにkwargsはやりすぎじゃね?

  145. 8*1GPS'BLFS

  146. 8*1GPS'BLFS To be continued…

  147. w ࠷ॳ͔Βऑ఺ͷͳ͍ઃܭΛ͢Δͷ͸೉͍͠ w ιϑτ΢ΣΞΛΑΓྑ͍ܗʹ͢ΔͨΊʹɺࢭΉΛ ಘͣޙํޓ׵Λؾʹ͔͚ͭͭ΋ఘΊΔ৔߹͕͋Δ w CVOEMFVQEBUFͰখ͞ͳϦϓϨʔεΛ܁Γฦ ͢͜ͱͰେ͖ͳϦϓϨʔεΛ๷͙ w มߋൣғ͕ڱ͍ํ͕ݪҼͷಛఆ͕༰қ

    w ͋ͳͨͱ·ΘΓ͸ݹ͍όʔδϣϯ͔৽͍͠όʔδϣ ϯͲͪΒΛ࢖͏ͷ͕޷ΈͰ͔͢ʁ ഁյతมߋΛӽ͑Δ
  148. όʔδϣϯӽ͑ lޙੈʹ࢒͢΋ͷz ະདྷ΁

  149. w ͋ͳͨʹΑͬͯෆඞཁ͔ͩͬͨ΋͠Εͳ͍ ഁյతͳมߋΛࢭΊΔ͜ͱ͕Ͱ͖Δ͔΋͠ Εͳ͍ w ͋ͳͨʹΑͬͯഁյతͳมߋ΁ͷμϝʔδ Λ؇࿨Ͱ͖Δ͔΋͠Εͳ͍ w ·ͣ͸खݩͷඇਪ঑ܯࠂΛݟͯΈΑ͏ w

    ຤͸ΈΜͳͰ3VCZ΁ͷΞοϓ άϨʔυࣗຫΛ͍͖ͯ͠·͠ΐ͏ ͋ͳ͕ͨίϛϡχςΟ
  150. l ίϛϡχςΟͱ͸୭͔ɻ΋ͪΖ Μɺ͋ͳͨͷ͜ͱͩɻ͋ͳ͕ͨ ίϛϡχςΟͰ͋ΓɺͦΕҎ֎ ʹίϛϡχςΟ͸͍ͳ͍ɻ͋ͳ ͨͷΑ͏ͳਓʑͷू·ΓΛɺί ϛϡχςΟͱݺͿͷͩɻ IUUQTNBHB[JOFSVCZJTUOFUBSUJDMFT'PSF8PSEIUNM Community is

    yourself
  151. None