Class: HamlLint::RubyExtraction::Coordinator

Inherits:
Object
  • Object
show all
Defined in:
lib/haml_lint/ruby_extraction/coordinator.rb

Overview

Coordinates the entire RubyExtraction system.

  • Uses the extractor to generate chunks.

  • Preprocess the chunks to cleanup/fuse some of them.

  • Generates the extracted ruby code from the Chunks.

  • Handles the markers (see below)

  • Use the chunks to transfer corrections from corrected Ruby code back to HAML

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.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(document) ⇒ Coordinator

Returns a new instance of Coordinator.



31
32
33
34
35
36
37
38
39
40
# 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

Instance Attribute Details

#assembled_ruby_linesArray<String> (readonly)

Returns The ruby lines after extraction from HAML (before RuboCop).

Returns:

  • (Array<String>)

    The ruby lines after extraction from HAML (before RuboCop)



26
27
28
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 26

def assembled_ruby_lines
  @assembled_ruby_lines
end

#corrected_ruby_linesArray<String> (readonly)

Returns The ruby lines after correction by RuboCop.

Returns:

  • (Array<String>)

    The ruby lines after correction by RuboCop



29
30
31
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 29

def corrected_ruby_lines
  @corrected_ruby_lines
end

#marker_prefixString (readonly)

Returns The prefix used for markers in the Ruby code.

Returns:

  • (String)

    The prefix used for markers in the Ruby code



23
24
25
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 23

def marker_prefix
  @marker_prefix
end

#script_output_prefixString (readonly)

Returns The prefix used for to handle ‘= foo` script’s in the extracted Ruby code.

Returns:

  • (String)

    The prefix used for to handle ‘= foo` script’s in the extracted Ruby code.



20
21
22
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 20

def script_output_prefix
  @script_output_prefix
end

Instance Method Details

#add_lines(lines, haml_line_index:, skip_indexes_in_source_map: []) ⇒ Object



101
102
103
104
105
106
107
108
109
110
111
112
113
114
# 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') ⇒ Object



120
121
122
123
124
# 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) ⇒ Object



144
145
146
147
148
149
150
151
152
153
# 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_sourceObject



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# 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') ⇒ Object



134
135
136
137
138
139
140
141
142
# 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) ⇒ Object



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# 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_countObject



116
117
118
# 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) ⇒ Boolean

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.

Returns:

  • (Boolean)


128
129
130
131
132
# 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_prefixObject



155
156
157
158
159
160
161
162
163
164
165
166
# 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_prefixObject



168
169
170
171
172
173
174
175
176
177
178
179
# 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_chunksObject



63
64
65
66
67
68
69
70
71
72
73
74
75
76
# 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