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, autocorrect:) ⇒ Coordinator

Returns a new instance of Coordinator.



34
35
36
37
38
39
40
41
42
43
44
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 34

def initialize(document, autocorrect:)
  @document = document
  @autocorrect = autocorrect
  @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

#autocorrectSymbol? (readonly)

Returns The autocorrect mode (:safe, :all, or nil).

Returns:

  • (Symbol, nil)

    The autocorrect mode (:safe, :all, or nil)



32
33
34
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 32

def autocorrect
  @autocorrect
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



106
107
108
109
110
111
112
113
114
115
116
117
118
119
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 106

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



125
126
127
128
129
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 125

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



149
150
151
152
153
154
155
156
157
158
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 149

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



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 46

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,
                                                              autocorrect: autocorrect).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



139
140
141
142
143
144
145
146
147
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 139

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



83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 83

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



121
122
123
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 121

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)


133
134
135
136
137
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 133

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



160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 160

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



173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 173

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



68
69
70
71
72
73
74
75
76
77
78
79
80
81
# File 'lib/haml_lint/ruby_extraction/coordinator.rb', line 68

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