class RuboCop::Cop::Layout::LineLength
}
baz: “0000000000”,
bar: “0000000000”,
foo: “0000000000”,
{
# good (with recommended cops enabled)
bar: “0000000000”, baz: “0000000000”}
{foo: “0000000000”,
# good
{foo: “0000000000”, bar: “0000000000”, baz: “0000000000”}
# bad
@example
is 25:
method calls, etc. For example, let’s say the max columns
Together, these cops will pretty print hashes, arrays,
* ParameterAlignment
* MultilineMethodArgumentLineBreaks
* MultilineHashKeyLineBreaks
* MultilineHashBraceLayout
* MultilineBlockLayout
* MultilineArrayLineBreaks
* IndentationWidth
* HashAlignment
* FirstParameterIndentation
* FirstHashElementIndentation
* FirstArrayElementIndentation
* FirstArgumentIndentation
* ClosingParenthesisIndentation
* BlockEndNewline
* BlockDelimiters
* BlockAlignment
* ArgumentAlignment
(Many of these are enabled by default.)
are recommended to further format the broken lines.
If autocorrection is enabled, the following Layout cops
method calls with argument lists.
split across lines. These include arrays, hashes, and
inserting line breaks into expressions that can be safely
It can programmatically shorten certain long lines by
This cop has some autocorrection capabilities.
It also ignores a shebang line by default.
of the ‘Layout/IndentationStyle` cop.
The tab size is configured in the `IndentationWidth`
The maximum length is configurable.
This cop checks the length of lines in the source code.
def allow_heredoc?
def allow_heredoc? allowed_heredoc end
def allowed_heredoc
def allowed_heredoc cop_config['AllowHeredoc'] end
def breakable_block_range(block_node)
def breakable_block_range(block_node) if block_node.arguments? && !block_node.lambda? block_node.arguments.loc.end else block_node.loc.begin end end
def breakable_range_after_semicolon(semicolon_token)
def breakable_range_after_semicolon(semicolon_token) range = semicolon_token.pos end_pos = range.end_pos next_range = range_between(end_pos, end_pos + 1) return nil unless next_range.line == range.line next_char = next_range.source return nil if /[\r\n]/.match?(next_char) return nil if next_char == ';' next_range end
def breakable_range_by_line_index
def breakable_range_by_line_index @breakable_range_by_line_index ||= {} end
def check_directive_line(line, line_index)
def check_directive_line(line, line_index) return if line_length_without_directive(line) <= max range = max..(line_length_without_directive(line) - 1) register_offense( source_range( processed_source.buffer, line_index + 1, range ), line, line_index ) end
def check_for_breakable_block(block_node)
def check_for_breakable_block(block_node) return unless block_node.single_line? line_index = block_node.loc.line - 1 range = breakable_block_range(block_node) pos = range.begin_pos + 1 breakable_range_by_line_index[line_index] = range_between(pos, pos + 1) end
def check_for_breakable_node(node)
def check_for_breakable_node(node) breakable_node = extract_breakable_node(node, max) return if breakable_node.nil? line_index = breakable_node.first_line - 1 range = breakable_node.source_range existing = breakable_range_by_line_index[line_index] return if existing breakable_range_by_line_index[line_index] = range end
def check_for_breakable_semicolons(processed_source)
def check_for_breakable_semicolons(processed_source) tokens = processed_source.tokens.select { |t| t.type == :tSEMI } tokens.reverse_each do |token| range = breakable_range_after_semicolon(token) breakable_range_by_line_index[range.line - 1] = range if range end end
def check_line(line, line_index)
def check_line(line, line_index) return if line_length(line) <= max return if ignored_line?(line, line_index) if ignore_cop_directives? && directive_on_source_line?(line_index) return check_directive_line(line, line_index) end return check_uri_line(line, line_index) if allow_uri? register_offense( excess_range(nil, line, line_index), line, line_index ) end
def check_uri_line(line, line_index)
def check_uri_line(line, line_index) uri_range = find_excessive_uri_range(line) return if uri_range && allowed_uri_position?(line, uri_range) register_offense( excess_range(uri_range, line, line_index), line, line_index ) end
def excess_range(uri_range, line, line_index)
def excess_range(uri_range, line, line_index) excessive_position = if uri_range && uri_range.begin < max uri_range.end else highlight_start(line) end source_range(processed_source.buffer, line_index + 1, excessive_position...(line_length(line))) end
def extract_heredocs(ast)
def extract_heredocs(ast) return [] unless ast ast.each_node(:str, :dstr, :xstr).select(&:heredoc?).map do |node| body = node.location.heredoc_body delimiter = node.location.heredoc_end.source.strip [body.first_line...body.last_line, delimiter] end end
def heredocs
def heredocs @heredocs ||= extract_heredocs(processed_source.ast) end
def highlight_start(line)
def highlight_start(line) # TODO: The max with 0 is a quick fix to avoid crashes when a line # begins with many tabs, but getting a correct highlighting range # when tabs are used for indentation doesn't work currently. [max - indentation_difference(line), 0].max end
def ignored_line?(line, line_index)
def ignored_line?(line, line_index) matches_ignored_pattern?(line) || shebang?(line, line_index) || heredocs && line_in_permitted_heredoc?(line_index.succ) end
def line_in_heredoc?(line_number)
def line_in_heredoc?(line_number) heredocs.any? do |range, _delimiter| range.cover?(line_number) end end
def line_in_permitted_heredoc?(line_number)
def line_in_permitted_heredoc?(line_number) return false unless allowed_heredoc heredocs.any? do |range, delimiter| range.cover?(line_number) && (allowed_heredoc == true || allowed_heredoc.include?(delimiter)) end end
def max
def max cop_config['Max'] end
def on_block(node)
def on_block(node) check_for_breakable_block(node) end
def on_investigation_end
def on_investigation_end processed_source.lines.each_with_index do |line, line_index| check_line(line, line_index) end end
def on_new_investigation
def on_new_investigation check_for_breakable_semicolons(processed_source) end
def on_potential_breakable_node(node)
def on_potential_breakable_node(node) check_for_breakable_node(node) end
def register_offense(loc, line, line_index)
def register_offense(loc, line, line_index) message = format(MSG, length: line_length(line), max: max) self.breakable_range = breakable_range_by_line_index[line_index] add_offense(loc, message: message) do |corrector| self.max = line_length(line) corrector.insert_before(breakable_range, "\n") unless breakable_range.nil? end end
def shebang?(line, line_index)
def shebang?(line, line_index) line_index.zero? && line.start_with?('#!') end