class RuboCop::Cop::Style::NestedModifier

This cop checks for nested use of if, unless, while and until in their modifier form.

@example

# bad
something if a if b

# good
something if b && a

Constants

MSG

Public Instance Methods

autocorrect(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 56
def autocorrect(node)
  return unless node.if_type?

  ancestor = node.ancestors.first
  return unless ancestor.if_type?

  autocorrect_if_unless(ancestor, node)
end
autocorrect_if_unless(outer_node, inner_node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 65
def autocorrect_if_unless(outer_node, inner_node)
  outer_cond, = *outer_node

  range =
    Parser::Source::Range.new(inner_node.source_range.source_buffer,
                              inner_node.loc.keyword.begin_pos,
                              outer_cond.source_range.end_pos)

  lambda do |corrector|
    corrector.replace(range, new_expression(outer_node, inner_node))
  end
end
check(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 33
def check(node)
  return if part_of_ignored_node?(node)
  return unless modifier?(node)

  ancestor = node.ancestors.first
  return unless ancestor &&
                [:if, :while, :until].include?(ancestor.type) &&
                modifier?(ancestor)

  add_offense(node, :keyword)
  ignore_node(node)
end
modifier?(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 46
def modifier?(node)
  modifier_if?(node) || modifier_while_or_until?(node)
end
modifier_while_or_until?(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 50
def modifier_while_or_until?(node)
  node.loc.respond_to?(:keyword) &&
    %w(while until).include?(node.loc.keyword.source) &&
    node.loc.respond_to?(:end) && node.loc.end.nil?
end
new_expression(outer_node, inner_node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 78
def new_expression(outer_node, inner_node)
  outer_cond, = *outer_node
  inner_cond, = *inner_node

  outer_keyword = outer_node.loc.keyword.source
  inner_keyword = inner_node.loc.keyword.source

  operator = outer_keyword == 'if'.freeze ? '&&'.freeze : '||'.freeze

  outer_expr = outer_cond.source
  outer_expr = "(#{outer_expr})" if outer_cond.or_type? &&
                                    operator == '&&'.freeze
  inner_expr = inner_cond.source

  inner_expr = "(#{inner_expr})" if requires_parens?(inner_cond)
  inner_expr = "!#{inner_expr}" unless outer_keyword == inner_keyword

  "#{outer_node.loc.keyword.source} "            "#{outer_expr} #{operator} #{inner_expr}"
end
on_if(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 29
def on_if(node)
  check(node)
end
on_until(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 25
def on_until(node)
  check(node)
end
on_while(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 21
def on_while(node)
  check(node)
end
requires_parens?(node) click to toggle source
# File lib/rubocop/cop/style/nested_modifier.rb, line 99
def requires_parens?(node)
  node.or_type? ||
    !(RuboCop::Node::COMPARISON_OPERATORS & node.children).empty?
end