Class: HamlLint::RubyExtraction::ScriptChunk

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

Overview

Chunk for handling outputting and silent scripts, so ‘ = foo` and ` - bar` Does NOT handle a script beside a tag (ex: `%div= spam`)

Constant Summary collapse

MID_BLOCK_KEYWORDS =
%w[else elsif when rescue ensure].freeze

Constants inherited from BaseChunk

BaseChunk::COMMA_CHANGES_LINES

Instance Attribute Summary collapse

Attributes inherited from BaseChunk

#end_marker_indent, #haml_line_index, #node, #ruby_lines, #start_marker_line_number

Instance Method Summary collapse

Methods inherited from BaseChunk

#assemble_in, #full_assemble, #haml_end_line_index, #nb_haml_lines, #transfer_correction, #wrap_in_markers

Constructor Details

#initialize(*args, previous_chunk:, must_start_chunk: false, skip_line_indexes_in_source_map: [], **kwargs) ⇒ ScriptChunk

Returns a new instance of ScriptChunk.



22
23
24
25
26
27
28
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 22

def initialize(*args, previous_chunk:, must_start_chunk: false,
               skip_line_indexes_in_source_map: [], **kwargs)
  super(*args, **kwargs)
  @must_start_chunk = must_start_chunk
  @skip_line_indexes_in_source_map = skip_line_indexes_in_source_map
  @previous_chunk = previous_chunk
end

Instance Attribute Details

#must_start_chunkBoolean (readonly)

Returns true if this ScriptChunk must be at the beginning of a chunk. This blocks this ScriptChunk from being fused to a ScriptChunk that is before it. Needed to handle some patterns of outputting script.

Returns:

  • (Boolean)

    true if this ScriptChunk must be at the beginning of a chunk. This blocks this ScriptChunk from being fused to a ScriptChunk that is before it. Needed to handle some patterns of outputting script.



12
13
14
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 12

def must_start_chunk
  @must_start_chunk
end

#previous_chunkHamlLint::RubyExtraction::BaseChunk (readonly)

Returns The previous chunk can affect how our starting marker must be indented.

Returns:



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

def previous_chunk
  @previous_chunk
end

#skip_line_indexes_in_source_mapArray<Integer> (readonly)

Returns Line indexes to ignore when building the source_map. For examples, implicit ‘end` are on their own line in the Ruby file, but in the HAML, they are absent.

Returns:

  • (Array<Integer>)

    Line indexes to ignore when building the source_map. For examples, implicit ‘end` are on their own line in the Ruby file, but in the HAML, they are absent.



16
17
18
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 16

def skip_line_indexes_in_source_map
  @skip_line_indexes_in_source_map
end

Instance Method Details

#fuse(following_chunk) ⇒ Object



30
31
32
33
34
35
36
37
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 30

def fuse(following_chunk)
  case following_chunk
  when ScriptChunk
    fuse_script_chunk(following_chunk)
  when ImplicitEndChunk
    fuse_implicit_end(following_chunk)
  end
end

#fuse_implicit_end(following_chunk) ⇒ Object



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 59

def fuse_implicit_end(following_chunk)
  new_lines = @ruby_lines.dup
  last_non_empty_line_index = new_lines.rindex { |line| line =~ /\S/ }

  # There is only one line in ImplicitEndChunk
  new_end_index = last_non_empty_line_index + 1
  new_lines.insert(new_end_index, following_chunk.ruby_lines.first)
  source_map_skips = @skip_line_indexes_in_source_map + [new_end_index]

  ScriptChunk.new(node,
                  new_lines,
                  haml_line_index: haml_line_index,
                  skip_line_indexes_in_source_map: source_map_skips,
                  end_marker_indent: following_chunk.end_marker_indent,
                  previous_chunk: previous_chunk)
end

#fuse_script_chunk(following_chunk) ⇒ Object



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 39

def fuse_script_chunk(following_chunk)
  return if following_chunk.end_marker_indent.nil?
  return if following_chunk.must_start_chunk

  nb_blank_lines_between = following_chunk.haml_line_index - haml_line_index - nb_haml_lines
  blank_lines = nb_blank_lines_between > 0 ? [''] * nb_blank_lines_between : []
  new_lines = @ruby_lines + blank_lines + following_chunk.ruby_lines

  source_map_skips = @skip_line_indexes_in_source_map
  source_map_skips.concat(following_chunk.skip_line_indexes_in_source_map
                            .map { |i| i + @ruby_lines.size })

  ScriptChunk.new(node,
                  new_lines,
                  haml_line_index: haml_line_index,
                  skip_line_indexes_in_source_map: source_map_skips,
                  end_marker_indent: following_chunk.end_marker_indent,
                  previous_chunk: previous_chunk)
end

#line_starts_script?(lines, line_index) ⇒ Boolean

Returns:

  • (Boolean)


127
128
129
130
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 127

def line_starts_script?(lines, line_index)
  return true if line_index == 0
  !unfinished_script_line?(lines, line_index - 1)
end

#start_marker_indentObject



76
77
78
79
80
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 76

def start_marker_indent
  default_indent = super
  default_indent += 2 if MID_BLOCK_KEYWORDS.include?(ChunkExtractor.block_keyword(ruby_lines.first))
  [default_indent, previous_chunk&.end_marker_indent || previous_chunk&.start_marker_indent].compact.max
end

#transfer_correction_logic(coordinator, to_ruby_lines, haml_lines) ⇒ Object

rubocop:disable Metrics



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 82

def transfer_correction_logic(coordinator, to_ruby_lines, haml_lines) # rubocop:disable Metrics
  to_ruby_lines.reject! { |l| l.strip == 'end' }

  output_comment_prefix = ' ' + coordinator.script_output_prefix.rstrip
  to_ruby_lines.map! do |line|
    if line.lstrip.start_with?('#' + output_comment_prefix)
      line = line.dup
      comment_index = line.index('#')
      removal_start_index = comment_index + 1
      removal_end_index = removal_start_index + output_comment_prefix.size
      line[removal_start_index...removal_end_index] = ''
      # It will be removed again below, but will know its suposed to be a =
      line.insert(comment_index, coordinator.script_output_prefix)
    end
    line
  end

  continued_line_indent_delta = 2

  to_haml_lines = to_ruby_lines.map.with_index do |line, i|
    if line !~ /\S/
      # whitespace or empty lines, we don't want any indentation
      ''
    elsif line_starts_script?(to_ruby_lines, i)
      code_start = line.index(/\S/)
      if line[code_start..].start_with?(coordinator.script_output_prefix)
        line = line.sub(coordinator.script_output_prefix, '')
        continued_line_indent_delta = 2 - coordinator.script_output_prefix.size
        "#{line[0...code_start]}= #{line[code_start..]}"
      else
        continued_line_indent_delta = 2
        "#{line[0...code_start]}- #{line[code_start..]}"
      end
    else
      HamlLint::Utils.indent(line, continued_line_indent_delta)
    end
  end

  haml_lines[@haml_line_index..haml_end_line_index] = to_haml_lines
end

#unfinished_script_line?(lines, line_index) ⇒ Boolean

Returns:

  • (Boolean)


123
124
125
# File 'lib/haml_lint/ruby_extraction/script_chunk.rb', line 123

def unfinished_script_line?(lines, line_index)
  !!lines[line_index][/,[ \t]*\z/]
end