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

Breaking Change

Avatar for Koichi ITO Koichi ITO
December 14, 2019

Breaking Change

Avatar for Koichi ITO

Koichi ITO

December 14, 2019
Tweet

More Decks by Koichi ITO

Other Decks in Programming

Transcript

  1. ։ൃ൛ͷ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
  2. ։ൃ൛ͷ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
  3. w ͦ΋ͦ΋ιϑτ΢ΣΞ։ൃ͸೉͍͠ w ΋ͬͱ࢖͍΍͍ͩ͢Ζ͏ઃܭ͕͋Ε ͹ɺͰ͖Ε͹ͦ͏͍ͨ͠ ᷤ౻  w ιϑτ΢ΣΞ͸ਓ͕࡞͍ͬͯΔ w

    ͭ·Γެ։"1*Ͱ΋ᷤ౻ͷ຤ɺഁյ ͞ΕΔ ͢Δ ͜ͱ͕͋Δ ެ։"1*Λ࢖͑͹໰୊͸ى͖ͳ͍ʁ
  4. '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)
  5. 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*෼ͷରԠͱ͸
  6. 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*෼ͷରԠͱ͸
  7. 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*෼ͷରԠͱ͸
  8. 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*෼ͷରԠͱ͸
  9. 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*෼ͷରԠͱ͸
  10. 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*෼ͷରԠͱ͸
  11. ԶDPQ͕ظ଴͢Δ࢓༷ # bad # def email( # name: nil, #

    separators: nil # ) # # good # def email( # legacy_name = NOT_GIVEN, # legacy_separators = NOT_GIVEN, # name: nil, # separators: nil # ) ΩʔϫʔυҾ਺ͷΈ Ͱߏ੒͞Ε͍ͯΔ
  12. 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
  13. 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ϊʔυͷॲཧ
  14. 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*
  15. 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 ܯࠂ͠ͳ͍৚݅
  16. 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)
  17. 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έʔεΛଊ͑Δ࣮૷ྫ ϊʔυͷλΠϓ
  18. 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
  19. 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 ࣗಈमਖ਼ ΁ͷίʔϧόοΫ ఆٛ
  20. 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ͷ ϊʔυ
  21. 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ͷ Ҿ਺Ґஔ
  22. 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
  23. 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 ޓ׵ม਺ͷ࡞੒
  24. 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
  25. 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 ࣗಈमਖ਼ίʔυͷ ஔ׵จࣈྻ
  26. 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 मਖ਼ίʔυ΁ ͷஔ׵
  27. 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 ޓ׵Ҿ਺ͷૠೖ
  28. 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 ܯࠂ৚݅ͷૠೖ
  29.