lib/rubocop/cop/style/unneeded_percent_q.rb



# encoding: utf-8

module RuboCop
  module Cop
    module Style
      # This cop checks for usage of the %q/%Q syntax when '' or "" would do.
      class UnneededPercentQ < Cop
        MSG = 'Use `%s` only for strings that contain both single quotes and ' \
              'double quotes%s.'
        DYNAMIC_MSG = ', or for dynamic strings that contain double quotes'
        SINGLE_QUOTE = "'".freeze
        QUOTE = '"'.freeze
        EMPTY = ''.freeze
        PERCENT_Q = '%q'.freeze
        PERCENT_CAPITAL_Q = '%Q'.freeze
        STRING_INTERPOLATION_REGEXP = /#\{.+}/

        def on_dstr(node)
          check(node)
        end

        def on_str(node)
          # Interpolated strings that contain more than just interpolation
          # will call `on_dstr` for the entire string and `on_str` for the
          # non interpolated portion of the string
          return unless string_literal?(node)
          check(node)
        end

        private

        def check(node)
          src = node.loc.expression.source
          return unless start_with_percent_q_variant?(src)
          return if src.include?(SINGLE_QUOTE) && src.include?(QUOTE)
          return if src =~ StringHelp::ESCAPED_CHAR_REGEXP
          if src.start_with?(PERCENT_Q) && src =~ STRING_INTERPOLATION_REGEXP
            return
          end

          extra = if src.start_with?(PERCENT_CAPITAL_Q)
                    DYNAMIC_MSG
                  else
                    EMPTY
                  end
          add_offense(node, :expression, format(MSG, src[0, 2], extra))
        end

        def autocorrect(node)
          delimiter =
            node.loc.expression.source =~ /^%Q[^"]+$|'/ ? QUOTE : SINGLE_QUOTE
          lambda do |corrector|
            corrector.replace(node.loc.begin, delimiter)
            corrector.replace(node.loc.end, delimiter)
          end
        end

        def string_literal?(node)
          node.loc.respond_to?(:begin) && node.loc.respond_to?(:end) &&
            node.loc.begin && node.loc.end
        end

        def start_with_percent_q_variant?(string)
          string.start_with?(PERCENT_Q) || string.start_with?(PERCENT_CAPITAL_Q)
        end
      end
    end
  end
end