class RuboCop::Cop::Style::InfiniteLoop

Use `Kernel#loop` for infinite loops.

@example

# bad
while true
  work
end

# good
loop do
  work
end

Constants

LEADING_SPACE
MSG

Public Instance Methods

after_leaving_scope(scope, _variable_table) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 27
def after_leaving_scope(scope, _variable_table)
  @variables ||= []
  @variables.concat(scope.variables.values)
end
autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 43
def autocorrect(node)
  if node.while_post_type? || node.until_post_type?
    replace_begin_end_with_modifier(node)
  elsif node.modifier_form?
    replace_source(node.source_range, modifier_replacement(node))
  else
    replace_source(non_modifier_range(node), 'loop do')
  end
end
join_force?(force_class) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 23
def join_force?(force_class)
  force_class == VariableForce
end
on_until(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 36
def on_until(node)
  while_or_until(node) if node.condition.falsey_literal?
end
Also aliased as: on_until_post
on_until_post(node)
Alias for: on_until
on_while(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 32
def on_while(node)
  while_or_until(node) if node.condition.truthy_literal?
end
Also aliased as: on_while_post
on_while_post(node)
Alias for: on_while

Private Instance Methods

assigned_before_loop?(var, range) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 76
def assigned_before_loop?(var, range)
  b = range.begin_pos
  var.assignments.any? { |a| a.node.source_range.end_pos < b }
end
assigned_inside_loop?(var, range) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 72
def assigned_inside_loop?(var, range)
  var.assignments.any? { |a| range.contains?(a.node.source_range) }
end
configured_indent() click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 121
def configured_indent
  ' ' * config.for_cop('IndentationWidth')['Width']
end
modifier_replacement(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 99
def modifier_replacement(node)
  if node.single_line?
    'loop { ' + node.body.source + ' }'
  else
    indentation = node.body.loc.expression.source_line[LEADING_SPACE]

    ['loop do', node.body.source.gsub(/^/, configured_indent),
     'end'].join("\n#{indentation}")
  end
end
non_modifier_range(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 110
def non_modifier_range(node)
  start_range = node.loc.keyword.begin
  end_range = if node.do?
                node.loc.begin.end
              else
                node.condition.source_range.end
              end

  start_range.join(end_range)
end
referenced_after_loop?(var, range) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 81
def referenced_after_loop?(var, range)
  e = range.end_pos
  var.references.any? { |r| r.node.source_range.begin_pos > e }
end
replace_begin_end_with_modifier(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 86
def replace_begin_end_with_modifier(node)
  lambda do |corrector|
    corrector.replace(node.body.loc.begin, 'loop do')
    corrector.remove(node.body.loc.end.end.join(node.source_range.end))
  end
end
replace_source(range, replacement) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 93
def replace_source(range, replacement)
  lambda do |corrector|
    corrector.replace(range, replacement)
  end
end
while_or_until(node) click to toggle source
# File lib/rubocop/cop/style/infinite_loop.rb, line 55
def while_or_until(node)
  range = node.source_range
  # Not every `while true` and `until false` can be turned into a
  # `loop do` without further modification. The reason is that a
  # variable that's introduced inside a while/until loop is in scope
  # outside of that loop too, but a variable that's assigned for the
  # first time inside a block can not be accessed after the block. In
  # those more complicated cases we don't report an offense.
  return if @variables.any? do |var|
    assigned_inside_loop?(var, range) &&
    !assigned_before_loop?(var, range) &&
    referenced_after_loop?(var, range)
  end

  add_offense(node, location: :keyword)
end