class RuboCop::Cop::Layout::MultilineBlockLayout

Checks whether the multiline do end blocks have a newline after the start of the block. Additionally, it checks whether the block arguments, if any, are on the same line as the start of the block. Putting block arguments on separate lines, because the whole line would otherwise be too long, is accepted.

@example

# bad
blah do |i| foo(i)
  bar(i)
end

# bad
blah do
  |i| foo(i)
  bar(i)
end

# good
blah do |i|
  foo(i)
  bar(i)
end

# bad
blah { |i| foo(i)
  bar(i)
}

# good
blah { |i|
  foo(i)
  bar(i)
}

# good
blah { |
  long_list,
  of_parameters,
  that_would_not,
  fit_on_one_line
|
  foo(i)
  bar(i)
}

Constants

ARG_MSG
MSG
PIPE_SIZE

Public Instance Methods

on_block(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 59
def on_block(node)
  return if node.single_line?

  unless args_on_beginning_line?(node) || line_break_necessary_in_args?(node)
    add_offense_for_expression(node, node.arguments, ARG_MSG)
  end

  return unless node.body && same_line?(node.loc.begin, node.body)

  add_offense_for_expression(node, node.body, MSG)
end
Also aliased as: on_numblock
on_numblock(node)
Alias for: on_block

Private Instance Methods

add_offense_for_expression(node, expr, msg) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 98
def add_offense_for_expression(node, expr, msg)
  expression = expr.source_range
  range = range_between(expression.begin_pos, expression.end_pos)

  add_offense(range, message: msg) { |corrector| autocorrect(corrector, node) }
end
args_on_beginning_line?(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 75
def args_on_beginning_line?(node)
  !node.arguments? || node.loc.begin.line == node.arguments.loc.last_line
end
autocorrect(corrector, node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 105
def autocorrect(corrector, node)
  unless args_on_beginning_line?(node)
    autocorrect_arguments(corrector, node)
    expr_before_body = node.arguments.source_range.end
  end

  return unless node.body

  expr_before_body ||= node.loc.begin

  return unless same_line?(expr_before_body, node.body)

  autocorrect_body(corrector, node, node.body)
end
autocorrect_arguments(corrector, node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 120
def autocorrect_arguments(corrector, node)
  end_pos = range_with_surrounding_space(
    node.arguments.source_range,
    side: :right,
    newlines: false
  ).end_pos
  range = range_between(node.loc.begin.end.begin_pos, end_pos)
  corrector.replace(range, " |#{block_arg_string(node, node.arguments)}|")
end
autocorrect_body(corrector, node, block_body) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 130
def autocorrect_body(corrector, node, block_body)
  first_node = if block_body.begin_type? && !block_body.source.start_with?('(')
                 block_body.children.first
               else
                 block_body
               end

  block_start_col = node.source_range.column

  corrector.insert_before(first_node, "\n  #{' ' * block_start_col}")
end
block_arg_string(node, args) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 142
def block_arg_string(node, args)
  arg_string = args.children.map do |arg|
    if arg.mlhs_type?
      "(#{block_arg_string(node, arg)})"
    else
      arg.source
    end
  end.join(', ')
  arg_string += ',' if include_trailing_comma?(node.arguments)
  arg_string
end
characters_needed_for_space_and_pipes(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 90
def characters_needed_for_space_and_pipes(node)
  if node.source.lines.first.end_with?("|\n")
    PIPE_SIZE
  else
    (PIPE_SIZE * 2) + 1
  end
end
include_trailing_comma?(args) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 154
def include_trailing_comma?(args)
  arg_count = args.each_descendant(:arg).to_a.size
  arg_count == 1 && args.source.include?(',')
end
line_break_necessary_in_args?(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 79
def line_break_necessary_in_args?(node)
  needed_length_for_args(node) > max_line_length
end
needed_length_for_args(node) click to toggle source
# File lib/rubocop/cop/layout/multiline_block_layout.rb, line 83
def needed_length_for_args(node)
  node.source_range.column +
    characters_needed_for_space_and_pipes(node) +
    node.source.lines.first.chomp.length +
    block_arg_string(node, node.arguments).length
end