class RuboCop::Cop::Lint::MixedCaseRange
Checks for mixed-case character ranges since they include likely unintended characters.
Offenses are registered for regexp character classes like ‘/[A-z]/` as well as range objects like `(’A’..‘z’)‘.
NOTE: Range objects cannot be autocorrected.
@safety
The cop autocorrects regexp character classes by replacing one character range with two: `A-z` becomes `A-Za-z`. In most cases this is probably what was originally intended but it changes the regexp to no longer match symbols it used to include. For this reason, this cop's autocorrect is unsafe (it will change the behavior of the code).
@example
# bad r = /[A-z]/ # good r = /[A-Za-z]/
Constants
- MSG
- RANGES
Public Instance Methods
each_unsafe_regexp_range(node) { |build_source_range(range_start, range_end)| ... }
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 56 def each_unsafe_regexp_range(node) node.parsed_tree&.each_expression do |expr| next if skip_expression?(expr) range_pairs(expr).reject do |range_start, range_end| next if skip_range?(range_start, range_end) next unless unsafe_range?(range_start.text, range_end.text) yield(build_source_range(range_start, range_end)) end end end
on_irange(node)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 37 def on_irange(node) return unless node.children.compact.all?(&:str_type?) range_start, range_end = node.children return if range_start.nil? || range_end.nil? add_offense(node) if unsafe_range?(range_start.value, range_end.value) end
Also aliased as: on_erange
on_regexp(node)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 48 def on_regexp(node) each_unsafe_regexp_range(node) do |loc| add_offense(loc) do |corrector| corrector.replace(loc, rewrite_regexp_range(loc.source)) end end end
Private Instance Methods
build_source_range(range_start, range_end)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 72 def build_source_range(range_start, range_end) range_between(range_start.expression.begin_pos, range_end.expression.end_pos) end
range_for(char)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 76 def range_for(char) RANGES.detect do |range| range.include?(char) end end
range_pairs(expr)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 82 def range_pairs(expr) RuboCop::Cop::Utils::RegexpRanges.new(expr).pairs end
rewrite_regexp_range(source)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 102 def rewrite_regexp_range(source) open, close = source.split('-') first = [open, range_for(open).end] second = [range_for(close).begin, close] "#{first.uniq.join('-')}#{second.uniq.join('-')}" end
skip_expression?(expr)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 92 def skip_expression?(expr) !(expr.type == :set && expr.token == :character) end
skip_range?(range_start, range_end)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 96 def skip_range?(range_start, range_end) [range_start, range_end].any? do |bound| bound.type == :escape end end
unsafe_range?(range_start, range_end)
click to toggle source
# File lib/rubocop/cop/lint/mixed_case_range.rb, line 86 def unsafe_range?(range_start, range_end) return false if range_start.length != 1 || range_end.length != 1 range_for(range_start) != range_for(range_end) end