Class: RuboCop::Cop::AlignmentCorrector
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Class Chain:
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/cop/correctors/alignment_corrector.rb |
Overview
This class does autocorrection of nodes that should just be moved to the left or to the right, amount being determined by the instance variable column_delta.
Class Attribute Summary
- .processed_source readonly
- .using_tabs? ⇒ Boolean readonly private
Alignment - Extended
Class Method Summary
- .align_end(corrector, processed_source, node, align_to)
-
.correct(corrector, processed_source, node, column_delta, tab_indentation: false)
tab_indentationmay only be set by callers whosecolumn_deltarepresents whole indentation levels (e.g.Layout/IndentationWidth). - .alignment_column(align_to) private
- .autocorrect_line(corrector, line_begin_pos, expr, column_delta, taboo_ranges) private
- .block_comment_within?(expr) ⇒ Boolean private
- .calculate_range(expr, line_begin_pos, column_delta) private
-
.configured_indentation_width
private
The number of columns a single tab spans.
-
.correct_tab_indentation(corrector, expr, column_delta, taboo_ranges)
private
Tab indentation is corrected by rewriting each line’s leading whitespace to the target number of tabs.
- .correct_tab_line(corrector, line_range, column_delta, taboo_ranges) private
-
.delimited_string_literal?(node) ⇒ Boolean
private
Some special kinds of string literals are not composed of literal characters between two delimiters: - The source map of
?aresponds to :begin and :end but its end is. - .each_line(expr) private
- .indentation_string(column) private
- .inside_string_range(node) private
- .inside_string_ranges(node) private
- .target_tab_indentation(leading, column_delta) private
- .whitespace_range(node) private
Alignment - Extended
| check_alignment, configured_indentation_width, display_column, each_bad_alignment, end_of_line_comment, indentation, offset, register_offense, within? |
RangeHelp - Extended
| add_range, | |
| arguments_range | A range containing the first to the last argument of a method call or method definition. |
| column_offset_between, | |
| contents_range | A range containing only the contents of a literal with delimiters (e.g. |
| directions, | |
| effective_column | Returns the column attribute of the range, except if the range is on the first line and there’s a byte order mark at the beginning of that line, in which case 1 is subtracted from the column value. |
| final_pos, move_pos, move_pos_str, range_between, range_by_whole_lines, range_with_comments, range_with_comments_and_lines, range_with_surrounding_comma, range_with_surrounding_space, source_range | |
Class Attribute Details
.processed_source (readonly)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 13
attr_reader :processed_source
.using_tabs? ⇒ Boolean (readonly, private)
[ GitHub ]
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 186
def using_tabs? config = processed_source.config indentation_style = config.for_cop('Layout/IndentationStyle')['EnforcedStyle'] indentation_style == 'tabs' end
Class Method Details
.align_end(corrector, processed_source, node, align_to)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 40
def align_end(corrector, processed_source, node, align_to) @processed_source = processed_source whitespace = whitespace_range(node) column = alignment_column(align_to) indentation = indentation_string(column) if whitespace.source.strip.empty? corrector.replace(whitespace, indentation) else corrector.insert_after(whitespace, "\n#{indentation}") end end
.alignment_column(align_to) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 168
def alignment_column(align_to) if !align_to 0 elsif align_to.respond_to?(:loc) align_to.source_range.column else align_to.column end end
.autocorrect_line(corrector, line_begin_pos, expr, column_delta, taboo_ranges) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 55
def autocorrect_line(corrector, line_begin_pos, expr, column_delta, taboo_ranges) range = calculate_range(expr, line_begin_pos, column_delta) # We must not change indentation of heredoc strings or inside other # string literals return if taboo_ranges.any? { |t| within?(range, t) } if column_delta.positive? && range.resize(1).source != "\n" corrector.insert_before(range, ' ' * column_delta) elsif /\A[ \t]+\z/.match?(range.source) corrector.remove(range) end end
.block_comment_within?(expr) ⇒ Boolean (private)
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 136
def block_comment_within?(expr) processed_source.comments.select(&:document?).any? do |c| within?(c.source_range, expr) end end
.calculate_range(expr, line_begin_pos, column_delta) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 142
def calculate_range(expr, line_begin_pos, column_delta) return range_between(line_begin_pos, line_begin_pos) if column_delta.positive? starts_with_space = expr.source_buffer.source[line_begin_pos].start_with?(' ') if starts_with_space range_between(line_begin_pos, line_begin_pos + column_delta.abs) else range_between(line_begin_pos - column_delta.abs, line_begin_pos) end end
.configured_indentation_width (private)
The number of columns a single tab spans. This must match the width
Layout/IndentationWidth uses to compute column_delta, otherwise
the division below would not land on a tab boundary. Layout/IndentationStyle
has its own IndentationWidth, but that only governs how that cop replaces tabs
with spaces, so it must not be consulted here.
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 107
def configured_indentation_width processed_source.config.for_cop('Layout/IndentationWidth')['Width'] || 2 end
.correct(corrector, processed_source, node, column_delta, tab_indentation: false)
tab_indentation may only be set by callers whose column_delta represents
whole indentation levels (e.g. Layout/IndentationWidth).
Alignment to an arbitrary column cannot be expressed with tabs, so those callers
leave tab correction disabled to avoid producing a never-converging correction.
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 19
def correct(corrector, processed_source, node, column_delta, tab_indentation: false) return unless node @processed_source = processed_source expr = node.respond_to?(:loc) ? node.source_range : node return if block_comment_within?(expr) taboo_ranges = inside_string_ranges(node) if using_tabs? return unless tab_indentation correct_tab_indentation(corrector, expr, column_delta, taboo_ranges) else each_line(expr) do |line_begin_pos| autocorrect_line(corrector, line_begin_pos, expr, column_delta, taboo_ranges) end end end
.correct_tab_indentation(corrector, expr, column_delta, taboo_ranges) (private)
Tab indentation is corrected by rewriting each line’s leading whitespace to the target number of tabs. Working in whole tabs rather than applying a column delta keeps the result idempotent, which avoids the infinite loops that delta-based correction caused for tabs.
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 73
def correct_tab_indentation(corrector, expr, column_delta, taboo_ranges) buffer = expr.source_buffer each_line(expr) do |line_begin_pos| line_range = buffer.line_range(buffer.line_for_position(line_begin_pos)) correct_tab_line(corrector, line_range, column_delta, taboo_ranges) end end
.correct_tab_line(corrector, line_range, column_delta, taboo_ranges) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 82
def correct_tab_line(corrector, line_range, column_delta, taboo_ranges) leading = line_range.source[/\A[ \t]*/] return if leading.length == line_range.source.length # blank line leading_range = range_between(line_range.begin_pos, line_range.begin_pos + leading.length) return if taboo_ranges.any? { |t| within?(leading_range, t) } target = target_tab_indentation(leading, column_delta) corrector.replace(leading_range, target) unless leading == target end
.delimited_string_literal?(node) ⇒ Boolean (private)
Some special kinds of string literals are not composed of literal
characters between two delimiters:
- The source map of ?a responds to :begin and :end but its end is
nil.
- The source map of FILE responds to neither :begin nor :end.
# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 132
def delimited_string_literal?(node) node.loc?(:begin) && node.loc?(:end) end
.each_line(expr) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 154
def each_line(expr) line_begin_pos = expr.begin_pos expr.source.each_line do |line| yield line_begin_pos line_begin_pos += line.length end end
.indentation_string(column) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 178
def indentation_string(column) if using_tabs? "\t" * column else ' ' * column end end
.inside_string_range(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 117
def inside_string_range(node) loc = node.location if node.heredoc? loc.heredoc_body.join(loc.heredoc_end) elsif delimited_string_literal?(node) loc.begin.end.join(loc.end.begin) end end
.inside_string_ranges(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 111
def inside_string_ranges(node) return [] unless node.is_a?(Parser::AST::Node) node.each_node(:any_str).filter_map { |n| inside_string_range(n) } end
.target_tab_indentation(leading, column_delta) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 93
def target_tab_indentation(leading, column_delta) width = configured_indentation_width return leading unless width.positive? visual_width = leading.chars.sum { |char| char == "\t" ? width : 1 } "\t" * ([visual_width + column_delta, 0].max / width) end
.whitespace_range(node) (private)
[ GitHub ]# File 'lib/rubocop/cop/correctors/alignment_corrector.rb', line 162
def whitespace_range(node) begin_pos = node.loc.end.begin_pos range_between(begin_pos - node.loc.end.column, begin_pos) end