class HamlLint::RubyExtraction::Coordinator

Coordinates the entire RubyExtraction system.

The generated Ruby code uses markers to wrap around the Ruby code from the chunks. Those markers look like function calls, like: ‘haml_lint_marker_1`, so are valid ruby. After RuboCop does it’s auto-correction, the markers are used to find the pieces of the corrected Ruby code that correspond to each Chunk.

Attributes

assembled_ruby_lines[R]

@return [Array<String>] The ruby lines after extraction from HAML (before RuboCop)

corrected_ruby_lines[R]

@return [Array<String>] The ruby lines after correction by RuboCop

marker_prefix[R]

@return [String] The prefix used for markers in the Ruby code

script_output_prefix[R]

@return [String] The prefix used for to handle ‘= foo` script’s in the extracted Ruby code.

Public Class Methods

new(document) click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 31
def initialize(document)
  @document = document
  @ruby_chunks = nil
  @assembled_ruby_lines = nil
  @corrected_ruby_lines = nil
  @source_map = {}
  @script_output_prefix = nil

  @haml_lines = nil
end

Public Instance Methods

add_lines(lines, haml_line_index:, skip_indexes_in_source_map: []) click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 101
def add_lines(lines, haml_line_index:, skip_indexes_in_source_map: [])
  nb_skipped_source_map_lines = 0
  lines.size.times do |i|
    if skip_indexes_in_source_map.include?(i)
      nb_skipped_source_map_lines += 1
    end

    line_number = haml_line_index + 1
    # If we skip the first line, we want to them to have the number of the following line
    line_number = [line_number, line_number + i - nb_skipped_source_map_lines].max
    @source_map[@assembled_ruby_lines.size + i + 1] = line_number
  end
  @assembled_ruby_lines.concat(lines)
end
add_marker(indent, haml_line_index:, name: 'marker') click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 120
def add_marker(indent, haml_line_index:, name: 'marker')
  add_lines(["#{' ' * indent}#{marker_prefix}_#{name}_#{@assembled_ruby_lines.size + 1}"],
            haml_line_index: haml_line_index)
  line_count
end
extract_from_corrected_lines(start_marker_line_number, nb_lines) click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 144
def extract_from_corrected_lines(start_marker_line_number, nb_lines)
  cur_start_marker_index = find_line_index_of_marker_in_corrections(start_marker_line_number)
  return if cur_start_marker_index.nil?

  end_marker_line_number = start_marker_line_number + nb_lines + 1
  cur_end_marker_index = find_line_index_of_marker_in_corrections(end_marker_line_number)
  return if cur_end_marker_index.nil?

  @corrected_ruby_lines[(cur_start_marker_index + 1)..(cur_end_marker_index - 1)]
end
extract_ruby_source() click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 42
def extract_ruby_source
  return @ruby_source if @ruby_source

  pick_a_marker_prefix
  pick_a_script_output_prefix

  @ruby_chunks = HamlLint::RubyExtraction::ChunkExtractor.new(@document,
                                                              script_output_prefix: @script_output_prefix).extract
  preprocess_chunks

  @assembled_ruby_lines = []
  @ruby_chunks.each do |ruby_chunk|
    ruby_chunk.full_assemble(self)
  end

  # Making sure the generated source has a final newline
  @assembled_ruby_lines << '' if @assembled_ruby_lines.last && !@assembled_ruby_lines.last.empty?

  @ruby_source = RubySource.new(@assembled_ruby_lines.join("\n"), @source_map, @ruby_chunks)
end
find_line_index_of_marker_in_corrections(line, name: 'marker') click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 134
def find_line_index_of_marker_in_corrections(line, name: 'marker')
  marker = "#{marker_prefix}_#{name}_#{line}"

  # In the best cases, the line didn't move
  # Using end_with? because indentation may have been added
  return line - 1 if @corrected_ruby_lines[line - 1]&.end_with?(marker)

  @corrected_ruby_lines.index { |l| l.end_with?(marker) }
end
haml_lines_with_corrections_applied(corrected_ruby_source) click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 78
def haml_lines_with_corrections_applied(corrected_ruby_source)
  @corrected_ruby_lines = corrected_ruby_source.split("\n")

  @haml_lines = @document.source_lines.dup

  if markers_conflict?(@assembled_ruby_lines, @corrected_ruby_lines)
    raise UnableToTransferCorrections, 'The changes in the corrected ruby are not supported'
  end

  finished_with_empty_line = @haml_lines.last.empty?

  # Going in reverse order, so that if we change the number of lines then the
  # rest of the file will not be offset, which would make things harder
  @ruby_chunks.reverse_each do |ruby_chunk|
    ruby_chunk.transfer_correction(self, @corrected_ruby_lines, @haml_lines)
  end

  if finished_with_empty_line && !@haml_lines.last.empty?
    @haml_lines << ''
  end
  @haml_lines
end
line_count() click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 116
def line_count
  @assembled_ruby_lines.size
end
markers_conflict?(from_ruby_lines, to_ruby_lines) click to toggle source

If the ruby_lines have different markers in them, or are in a different order, then RuboCop did not alter them in a way that is compatible with this system.

# File lib/haml_lint/ruby_extraction/coordinator.rb, line 128
def markers_conflict?(from_ruby_lines, to_ruby_lines)
  from_markers = from_ruby_lines.grep(/#{marker_prefix}/, &:strip)
  to_markers = to_ruby_lines.grep(/#{marker_prefix}/, &:strip)
  from_markers != to_markers
end
pick_a_marker_prefix() click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 155
def pick_a_marker_prefix
  if @document.source.match?(/\bhaml_lint_/)
    100.times do
      suffix = SecureRandom.hex(10)
      next if @document.source.include?(suffix)
      @marker_prefix = "haml_lint#{suffix}"
      return
    end
  else
    @marker_prefix = 'haml_lint'
  end
end
pick_a_script_output_prefix() click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 168
def pick_a_script_output_prefix
  if @document.source.match?(/\bHL\.out\b/)
    100.times do
      suffix = SecureRandom.hex(10)
      next if @document.source.include?(suffix)
      @script_output_prefix = "HL.out#{suffix} = "
      return
    end
  else
    @script_output_prefix = 'HL.out = '
  end
end
preprocess_chunks() click to toggle source
# File lib/haml_lint/ruby_extraction/coordinator.rb, line 63
def preprocess_chunks
  return if @ruby_chunks.size < 2

  new_chunks = [@ruby_chunks.first]
  @ruby_chunks[1..].each do |ruby_chunk|
    fused_chunk = new_chunks.last.fuse(ruby_chunk)
    if fused_chunk
      new_chunks[-1] = fused_chunk
    else
      new_chunks << ruby_chunk
    end
  end
  @ruby_chunks = new_chunks
end