class RuboCop::Cop::Layout::IndentHeredoc
This cop checks the indentation of the here document bodies. The bodies are indented one step. In Ruby 2.3 or newer, squiggly heredocs (`<<~`) should be used. If you use the older rubies, you should introduce some library to your project (e.g. ActiveSupport, Powerpack or Unindent). Note: When `Metrics/LineLength`'s `AllowHeredoc` is false (not default),
this cop does not add any offenses for long here documents to avoid `Metrics/LineLength`'s offenses.
@example EnforcedStyle: squiggly (default)
# bad <<-RUBY something RUBY # good # When EnforcedStyle is squiggly, bad code is auto-corrected to the # following code. <<~RUBY something RUBY
@example EnforcedStyle: active_support
# good # When EnforcedStyle is active_support, bad code is auto-corrected to # the following code. <<-RUBY.strip_heredoc something RUBY
@example EnforcedStyle: powerpack
# good # When EnforcedStyle is powerpack, bad code is auto-corrected to # the following code. <<~RUBY something RUBY
@example EnforcedStyle: unindent
# good # When EnforcedStyle is unindent, bad code is auto-corrected to # the following code. <<-RUBY.unindent something RUBY
Constants
- LIBRARY_MSG
- RUBY23_TYPE_MSG
- RUBY23_WIDTH_MSG
- STRIP_METHODS
Public Instance Methods
autocorrect(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 87 def autocorrect(node) check_style! case style when :squiggly correct_by_squiggly(node) else correct_by_library(node) end end
on_heredoc(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 69 def on_heredoc(node) body = heredoc_body(node) return if body.strip.empty? body_indent_level = indent_level(body) if heredoc_indent_type(node) == '~' expected_indent_level = base_indent_level(node) + indentation_width return if expected_indent_level == body_indent_level else return unless body_indent_level.zero? end return if line_too_long?(node) add_offense(node, location: :heredoc_body) end
Private Instance Methods
adjust_minus(corrector, node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 184 def adjust_minus(corrector, node) heredoc_beginning = node.loc.expression.source corrected = heredoc_beginning.sub(/<<-?/, '<<~') corrector.replace(node.loc.expression, corrected) end
adjust_squiggly(corrector, node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 179 def adjust_squiggly(corrector, node) corrector.replace(node.loc.heredoc_body, indented_body(node)) corrector.replace(node.loc.heredoc_end, indented_end(node)) end
base_indent_level(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 223 def base_indent_level(node) base_line_num = node.loc.expression.line base_line = processed_source.lines[base_line_num - 1] indent_level(base_line) end
check_style!()
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 198 def check_style! return if style raise Warning, "Auto-correction does not work for #{cop_name}. " \ 'Please configure EnforcedStyle.' end
correct_by_library(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 190 def correct_by_library(node) lambda do |corrector| corrector.replace(node.loc.heredoc_body, indented_body(node)) corrected = ".#{STRIP_METHODS[style]}" corrector.insert_after(node.loc.expression, corrected) end end
correct_by_squiggly(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 169 def correct_by_squiggly(node) lambda do |corrector| if heredoc_indent_type(node) == '~' adjust_squiggly(corrector, node) else adjust_minus(corrector, node) end end end
heredoc_body(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 245 def heredoc_body(node) node.loc.heredoc_body.source.scrub end
heredoc_end(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 249 def heredoc_end(node) node.loc.heredoc_end.source.scrub end
heredoc_indent_type(node)
click to toggle source
Returns '~', '-' or nil
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 237 def heredoc_indent_type(node) node.source[/^<<([~-])/, 1] end
indent_level(str)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 229 def indent_level(str) indentations = str.lines .map { |line| line[/^\s*/] } .reject { |line| line == "\n" } indentations.empty? ? 0 : indentations.min_by(&:size).size end
indentation_width()
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 241 def indentation_width @config.for_cop('IndentationWidth')['Width'] || 2 end
indented_body(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 205 def indented_body(node) body = heredoc_body(node) body_indent_level = indent_level(body) correct_indent_level = base_indent_level(node) + indentation_width body.gsub(/^\s{#{body_indent_level}}/, ' ' * correct_indent_level) end
indented_end(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 212 def indented_end(node) end_ = heredoc_end(node) end_indent_level = indent_level(end_) correct_indent_level = base_indent_level(node) if end_indent_level < correct_indent_level end_.gsub(/^\s{#{end_indent_level}}/, ' ' * correct_indent_level) else end_ end end
library_message(indentation_width, method)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 114 def library_message(indentation_width, method) format( LIBRARY_MSG, indentation_width: indentation_width, method: method ) end
line_too_long?(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 145 def line_too_long?(node) return false if unlimited_heredoc_length? body = heredoc_body(node) expected_indent = base_indent_level(node) + indentation_width actual_indent = indent_level(body) increase_indent_level = expected_indent - actual_indent longest_line(body).size + increase_indent_level >= max_line_length end
longest_line(lines)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 157 def longest_line(lines) lines.each_line.max_by { |line| line.chomp.size }.chomp end
max_line_length()
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 165 def max_line_length config.for_cop('Metrics/LineLength')['Max'] end
message(node)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 100 def message(node) case style when :squiggly current_indent_type = "<<#{heredoc_indent_type(node)}" ruby23_message(indentation_width, current_indent_type) when nil method = "some library(e.g. ActiveSupport's `String#strip_heredoc`)" library_message(indentation_width, method) else method = "`String##{STRIP_METHODS[style]}`" library_message(indentation_width, method) end end
ruby23_message(indentation_width, current_indent_type)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 122 def ruby23_message(indentation_width, current_indent_type) if current_indent_type == '<<~' ruby23_width_message(indentation_width) else ruby23_type_message(indentation_width, current_indent_type) end end
ruby23_type_message(indentation_width, current_indent_type)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 130 def ruby23_type_message(indentation_width, current_indent_type) format( RUBY23_TYPE_MSG, indentation_width: indentation_width, current_indent_type: current_indent_type ) end
ruby23_width_message(indentation_width)
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 138 def ruby23_width_message(indentation_width) format( RUBY23_WIDTH_MSG, indentation_width: indentation_width ) end
unlimited_heredoc_length?()
click to toggle source
# File lib/rubocop/cop/layout/indent_heredoc.rb, line 161 def unlimited_heredoc_length? config.for_cop('Metrics/LineLength')['AllowHeredoc'] end