# frozen_string_literal: true module RuboCop module Cop # This module contains a collection of useful utility methods. module Util include PathUtil # Match literal regex characters, not including anchors, character # classes, alternatives, groups, repetitions, references, etc LITERAL_REGEX = %r{[\w\s\-,"'!#%&<>=;:`~/]|\\[^AbBdDgGhHkpPRwWXsSzZ0-9]}.freeze module_function # This is a bad API def comment_line?(line_source) /^\s*#/.match?(line_source) end # @deprecated Use `ProcessedSource#line_with_comment?`, `contains_comment?` or similar def comment_lines?(node) processed_source[line_range(node)].any? { |line| comment_line?(line) } end def line_range(node) node.first_line..node.last_line end def parentheses?(node) node.loc.respond_to?(:end) && node.loc.end && node.loc.end.is?(')') end # rubocop:disable Metrics/AbcSize, Metrics/MethodLength def add_parentheses(node, corrector) if node.args_type? arguments_range = node.source_range args_with_space = range_with_surrounding_space(arguments_range, side: :left) leading_space = range_between(args_with_space.begin_pos, arguments_range.begin_pos) corrector.replace(leading_space, '(') corrector.insert_after(arguments_range, ')') elsif !node.respond_to?(:arguments) corrector.wrap(node, '(', ')') elsif node.arguments.empty? corrector.insert_after(node, '()') else args_begin = args_begin(node) corrector.remove(args_begin) corrector.insert_before(args_begin, '(') corrector.insert_after(args_end(node), ')') end end # rubocop:enable Metrics/AbcSize, Metrics/MethodLength def args_begin(node) loc = node.loc selector = if node.super_type? || node.yield_type? loc.keyword elsif node.def_type? || node.defs_type? loc.name else loc.selector end selector.end.resize(1) end def args_end(node) node.loc.expression.end end def on_node(syms, sexp, excludes = [], &block) return to_enum(:on_node, syms, sexp, excludes) unless block yield sexp if Array(syms).include?(sexp.type) return if Array(excludes).include?(sexp.type) sexp.each_child_node { |elem| on_node(syms, elem, excludes, &block) } end def begins_its_line?(range) range.source_line.index(/\S/) == range.column end # Returns, for example, a bare `if` node if the given node is an `if` # with calls chained to the end of it. def first_part_of_call_chain(node) while node case node.type when :send node = node.receiver when :block node = node.send_node else break end end node end # If converting a string to Ruby string literal source code, must # double quotes be used? def double_quotes_required?(string) # Double quotes are required for strings which either: # - Contain single quotes # - Contain non-printable characters, which must use an escape # Regex matches IF there is a ' or there is a \\ in the string that is # not preceded/followed by another \\ (e.g. "\\x34") but not "\\\\". /'|(?