class RuboCop::Cop::Lint::BlockAlignment

end
i
variable = lambda do |i|
@example
end blocks.
This cop checks whether the end keywords are aligned properly for do

def already_processed_node?(node)

def already_processed_node?(node)
  @inspected_blocks.include?(node)
end

def alt_start_msg(match, start_loc, do_loc, indentation_of_do_line)

def alt_start_msg(match, start_loc, do_loc, indentation_of_do_line)
  if start_loc.line == do_loc.line &&
      start_loc.column == indentation_of_do_line
    ''
  else
    " or `#{match[0]}` at #{do_loc.line}, #{indentation_of_do_line}"
  end
end

def autocorrect(node)

def autocorrect(node)
  key = node.children.first
  source = node.loc.expression.source_buffer
  @corrections << lambda do |corrector|
    start_col = key.loc.expression.column
    starting_position_of_block_end = node.loc.end.begin_pos
    end_col = node.loc.end.column
    if end_col < start_col
      delta = start_col - end_col
      corrector.insert_before(node.loc.end, ' ' * delta)
    elsif end_col > start_col
      delta = start_col - end_col
      range_start = starting_position_of_block_end + delta
      range_end = range_start - delta
      range = Parser::Source::Range.new(source, range_start, range_end)
      corrector.remove(range)
    end
  end
end

def block_is_on_next_line?(begin_node, block_node)

def block_is_on_next_line?(begin_node, block_node)
  begin_node.loc.line != block_node.loc.line
end

def check_assignment(begin_node, other_node)

def check_assignment(begin_node, other_node)
  return unless other_node
  block_node = find_block_node(other_node)
  return unless block_node.type == :block
  # If the block is an argument in a function call, align end with
  # the block itself, and not with the function.
  if begin_node.type == :send
    _receiver, method, *_args = *begin_node
    begin_node = block_node if method.to_s =~ /^\w+$/
  end
  # Align with the expression that is on the same line
  # where the block is defined
  if begin_node.type != :mlhs && block_is_on_next_line?(begin_node,
                                                        block_node)
    return
  end
  return if already_processed_node?(block_node)
  @inspected_blocks << block_node
  check_block_alignment(begin_node, block_node)
end

def check_block_alignment(start_node, block_node)

def check_block_alignment(start_node, block_node)
  end_loc = block_node.loc.end
  return unless begins_its_line?(end_loc)
  start_loc = start_node.loc.expression
  return unless start_loc.column != end_loc.column
  do_loc = block_node.loc.begin # Actually it's either do or {.
  # We've found that "end" is not aligned with the start node (which
  # can be a block, a variable assignment, etc). But we also allow
  # the "end" to be aligned with the start of the line where the "do"
  # is, which is a style some people use in multi-line chains of
  # blocks.
  match = /\S.*/.match(do_loc.source_line)
  indentation_of_do_line = match.begin(0)
  return unless end_loc.column != indentation_of_do_line
  add_offense(block_node,
              end_loc,
              format(MSG, end_loc.line, end_loc.column,
                     start_loc.source.lines.to_a.first.chomp,
                     start_loc.line, start_loc.column,
                     alt_start_msg(match, start_loc, do_loc,
                                   indentation_of_do_line)))
end

def find_block_node(node)

def find_block_node(node)
  while [:send, :lvasgn].include?(node.type)
    n = case node.type
        when :send
          find_block_or_send_node(node) || break
        when :lvasgn
          _variable, value = *node
          value
        end
    node = n if n
  end
  node
end

def find_block_or_send_node(send_node)

def find_block_or_send_node(send_node)
  receiver, _method, args = *send_node
  [receiver, args].find do |subnode|
    subnode && [:block, :send].include?(subnode.type)
  end
end

def initialize(config = nil, options = nil)

def initialize(config = nil, options = nil)
  super
  @inspected_blocks = []
end

def message

def message
end

def on_and(node)

def on_and(node)
  return if already_processed_node?(node)
  _left, right = *node
  return unless right.type == :block
  check_block_alignment(node, right)
  @inspected_blocks << right
end

def on_block(node)

def on_block(node)
  return if already_processed_node?(node)
  check_block_alignment(node, node)
end

def on_masgn(node)

def on_masgn(node)
  variables, args = *node
  check_assignment(variables, args)
end

def on_op_asgn(node)

def on_op_asgn(node)
  variable, _op, args = *node
  check_assignment(variable, args)
end

def on_send(node)

def on_send(node)
  _receiver, _method, *args = *node
  check_assignment(node, args.last)
end