class RuboCop::Cop::Lint::AmbiguousRange
(a.foo)..(b.bar)
# good
a.foo..b.bar
# bad
@example RequireParenthesesForMethodChains: true
(a.foo)..(b.bar)
a.foo..b.bar
# good
@example RequireParenthesesForMethodChains: false (default)
(1..2).to_a
(x || 1)..(y || 2)
(x || 1)..2
x || (1..2)
# good, ambiguity removed
-a..b
a..b
@min..@max
MyClass::MIN..MyClass::MAX
:bar..:baz
’a’..‘z’
1..2
# good, unambiguous
1..2.to_a
(x || 1..2)
x || 1..2
# bad
@example
intent of the program).
change the behavior of the code, but will not necessarily match the
programmer. For this reason, this cop’s autocorrect is unsafe (it will not
makes the outcome more explicit but is possible to not be the intention of the
The cop autocorrects by wrapping the entire boundary in parentheses, which
@safety
value, it will be wrapped in order to prevent the ambiguity of ‘1..2.to_a`.
NOTE: Regardless of this configuration, if a method receiver is a basic literal
by this cop.
specify whether method chains (including `self.foo`) should be wrapped in parens
This cop can be configured with `RequireParenthesesForMethodChains` in order to
that is not a literal: numerics, strings, symbols, etc.).
explicit by requiring parenthesis around complex range boundaries (anything
using a range with other operators. This cop avoids that by making ranges
Ranges have quite low precedence, which leads to unexpected behavior when
Checks for ambiguous ranges.
def acceptable?(node)
def acceptable?(node) node.begin_type? || node.literal? || node.variable? || node.const_type? || node.self_type? || (node.call_type? && acceptable_call?(node)) end
def acceptable_call?(node)
def acceptable_call?(node) return true if node.unary_operation? # Require parentheses when making a method call on a literal # to avoid the ambiguity of `1..2.to_a`. return false if node.receiver&.basic_literal? require_parentheses_for_method_chain? || node.receiver.nil? end
def each_boundary(range)
def each_boundary(range) yield range.begin if range.begin yield range.end if range.end end
def on_irange(node)
def on_irange(node) each_boundary(node) do |boundary| next if acceptable?(boundary) add_offense(boundary) do |corrector| corrector.wrap(boundary, '(', ')') end end end
def require_parentheses_for_method_chain?
def require_parentheses_for_method_chain? !cop_config['RequireParenthesesForMethodChains'] end