class RuboCop::Cop::Layout::EmptyLineBetweenDefs
end
def b
end
def a
# good
@example
end
def b
end
def a
# bad
@example
one line methods definitions are an offense
`AllowAdjacentOneLineDefs` can be used to configure is adjacent
empty lines.
an array (e.g. [1, 2]) to specificy a minimum and a maximum of
`NumberOfEmptyLines` can be and integer (e.g. 1 by default) or
separated by one empty line.
This cop checks whether method definitions are
def self.autocorrect_incompatible_with
def self.autocorrect_incompatible_with [Layout::EmptyLines] end
def autocorrect(node)
def autocorrect(node) prev_def = prev_node(node) # finds position of first newline end_pos = prev_def.loc.end.end_pos source_buffer = prev_def.loc.end.source_buffer newline_pos = source_buffer.source.index("\n", end_pos) count = blank_lines_count_between(prev_def, node) if count > maximum_empty_lines autocorrect_remove_lines(newline_pos, count) else autocorrect_insert_lines(newline_pos, count) end end
def autocorrect_insert_lines(newline_pos, count)
def autocorrect_insert_lines(newline_pos, count) difference = minimum_empty_lines - count where_to_insert = range_between(newline_pos, newline_pos + 1) lambda do |corrector| corrector.insert_after(where_to_insert, "\n" * difference) end end
def autocorrect_remove_lines(newline_pos, count)
def autocorrect_remove_lines(newline_pos, count) difference = count - maximum_empty_lines range_to_remove = range_between(newline_pos, newline_pos + difference) lambda do |corrector| corrector.remove(range_to_remove) end end
def blank_lines_between?(first_def_node, second_def_node)
def blank_lines_between?(first_def_node, second_def_node) count = blank_lines_count_between(first_def_node, second_def_node) (minimum_empty_lines..maximum_empty_lines).cover?(count) end
def blank_lines_count_between(first_def_node, second_def_node)
def blank_lines_count_between(first_def_node, second_def_node) lines_between_defs(first_def_node, second_def_node).count(&:blank?) end
def check_defs(nodes)
def check_defs(nodes) return if blank_lines_between?(*nodes) return if multiple_blank_lines_groups?(*nodes) return if nodes.all?(&:single_line?) && cop_config['AllowAdjacentOneLineDefs'] add_offense(nodes.last, :keyword) end
def def_end(node)
def def_end(node) node.loc.end.line end
def def_node?(node)
def def_node?(node) return unless node node.def_type? || node.defs_type? end
def def_start(node)
def def_start(node) node.loc.keyword.line end
def lines_between_defs(first_def_node, second_def_node)
def lines_between_defs(first_def_node, second_def_node) line_range = def_end(first_def_node)..(def_start(second_def_node) - 2) processed_source.lines[line_range] end
def maximum_empty_lines
def maximum_empty_lines Array(cop_config['NumberOfEmptyLines']).last end
def minimum_empty_lines
def minimum_empty_lines Array(cop_config['NumberOfEmptyLines']).first end
def multiple_blank_lines_groups?(first_def_node, second_def_node)
def multiple_blank_lines_groups?(first_def_node, second_def_node) lines = lines_between_defs(first_def_node, second_def_node) blank_start = lines.each_index.select { |i| lines[i].blank? }.max non_blank_end = lines.each_index.reject { |i| lines[i].blank? }.min return false if blank_start.nil? || non_blank_end.nil? blank_start > non_blank_end end
def on_begin(node)
doing a linear scan over siblings, so we don't want to call
efficiently access a node's predecessor; #prev_node ends up
so that we can walk over pairs of consecutive nodes and
We operate on `begin` nodes, instead of using `OnMethodDef`,
def on_begin(node) node.children.each_cons(2) do |prev, n| nodes = [prev, n] check_defs(nodes) if nodes.all?(&method(:def_node?)) end end
def prev_node(node)
def prev_node(node) return nil unless node.sibling_index > 0 node.parent.children[node.sibling_index - 1] end