lib/rubocop/cop/performance/delete_suffix.rb in rubocop-performance-1.6.0 vs lib/rubocop/cop/performance/delete_suffix.rb in rubocop-performance-1.6.1

- old
+ new

@@ -3,47 +3,69 @@ module RuboCop module Cop module Performance # In Ruby 2.5, `String#delete_suffix` has been added. # - # This cop identifies places where `gsub(/suffix\z/, '')` + # This cop identifies places where `gsub(/suffix\z/, '')` and `sub(/suffix\z/, '')` # can be replaced by `delete_suffix('suffix')`. # - # The `delete_suffix('suffix')` method is faster than - # `gsub(/suffix\z/, '')`. + # This cop has `SafeMultiline` configuration option that `true` by default because + # `suffix$` is unsafe as it will behave incompatible with `delete_suffix?` + # for receiver is multiline string. # + # The `delete_suffix('suffix')` method is faster than `gsub(/suffix\z/, '')`. + # # @example # # # bad # str.gsub(/suffix\z/, '') # str.gsub!(/suffix\z/, '') - # str.gsub(/suffix$/, '') - # str.gsub!(/suffix$/, '') # + # str.sub(/suffix\z/, '') + # str.sub!(/suffix\z/, '') + # # # good # str.delete_suffix('suffix') # str.delete_suffix!('suffix') # + # @example SafeMultiline: true (default) + # + # # good + # str.gsub(/suffix$/, '') + # str.gsub!(/suffix$/, '') + # str.sub(/suffix$/, '') + # str.sub!(/suffix$/, '') + # + # @example SafeMultiline: false + # + # # bad + # str.gsub(/suffix$/, '') + # str.gsub!(/suffix$/, '') + # str.sub(/suffix$/, '') + # str.sub!(/suffix$/, '') + # class DeleteSuffix < Cop extend TargetRubyVersion include RegexpMetacharacter minimum_target_ruby_version 2.5 MSG = 'Use `%<prefer>s` instead of `%<current>s`.' PREFERRED_METHODS = { gsub: :delete_suffix, - gsub!: :delete_suffix! + gsub!: :delete_suffix!, + sub: :delete_suffix, + sub!: :delete_suffix! }.freeze - def_node_matcher :gsub_method?, <<~PATTERN - (send $!nil? ${:gsub :gsub!} (regexp (str $#literal_at_end?) (regopt)) (str $_)) + def_node_matcher :delete_suffix_candidate?, <<~PATTERN + (send $!nil? ${:gsub :gsub! :sub :sub!} (regexp (str $#literal_at_end?) (regopt)) (str $_)) PATTERN def on_send(node) - gsub_method?(node) do |_, bad_method, _, replace_string| + delete_suffix_candidate?(node) do |_, bad_method, _, replace_string| return unless replace_string.blank? good_method = PREFERRED_METHODS[bad_method] message = format(MSG, current: bad_method, prefer: good_method) @@ -51,19 +73,21 @@ add_offense(node, location: :selector, message: message) end end def autocorrect(node) - gsub_method?(node) do |receiver, bad_method, regexp_str, _| + delete_suffix_candidate?(node) do |receiver, bad_method, regexp_str, _| lambda do |corrector| good_method = PREFERRED_METHODS[bad_method] regexp_str = drop_end_metacharacter(regexp_str) regexp_str = interpret_string_escapes(regexp_str) string_literal = to_string_literal(regexp_str) new_code = "#{receiver.source}.#{good_method}(#{string_literal})" - corrector.replace(node, new_code) + # TODO: `source_range` is no longer required when RuboCop 0.81 or lower support will be dropped. + # https://github.com/rubocop-hq/rubocop/commit/82eb350d2cba16 + corrector.replace(node.source_range, new_code) end end end end end