Class: HamlLint::ScriptExtractor

Inherits:
Object
  • Object
show all
Includes:
HamlVisitor
Defined in:
lib/haml_lint/script_extractor.rb

Overview

Utility class for extracting Ruby script from a HAML file that can then be linted with a Ruby linter (i.e. is “legal” Ruby). The goal is to turn this:

- if signed_in?(viewer)
  %span Stuff
  = link_to 'Sign Out', sign_out_path
- else
  .some-class{ class: my_method }= my_method
  = link_to 'Sign In', sign_in_path

into this:

if signed_in?(viewer)
  link_to 'Sign Out', sign_out_path
else
  { class: my_method }
  my_method
  link_to 'Sign In', 
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from HamlVisitor

#visit, #visit_children

Constructor Details

#initialize(parser) ⇒ ScriptExtractor

Returns a new instance of ScriptExtractor


27
28
29
# File 'lib/haml_lint/script_extractor.rb', line 27

def initialize(parser)
  @parser = parser
end

Instance Attribute Details

#sourceObject (readonly)

Returns the value of attribute source


25
26
27
# File 'lib/haml_lint/script_extractor.rb', line 25

def source
  @source
end

#source_mapObject (readonly)

Returns the value of attribute source_map


25
26
27
# File 'lib/haml_lint/script_extractor.rb', line 25

def source_map
  @source_map
end

Instance Method Details

#extractObject


31
32
33
34
# File 'lib/haml_lint/script_extractor.rb', line 31

def extract
  visit(@parser.tree)
  @source = @code.join("\n")
end

#visit_filter(node) ⇒ Object


100
101
102
103
104
105
106
107
108
109
110
111
# File 'lib/haml_lint/script_extractor.rb', line 100

def visit_filter(node)
  if node.filter_type == 'ruby'
    node.text.split("\n").each_with_index do |line, index|
      add_line(line, node.line + index + 1)
    end
  else
    add_line('puts', node)
    HamlLint::Utils.extract_interpolated_values(node.text) do |interpolated_code|
      add_line(interpolated_code, node)
    end
  end
end

#visit_plain(node) ⇒ Object


45
46
47
48
49
50
# File 'lib/haml_lint/script_extractor.rb', line 45

def visit_plain(node)
  # Don't output the text, as we don't want to have to deal with any RuboCop
  # cops regarding StringQuotes or AsciiComments, and it's not important to
  # overall document anyway.
  add_line('puts', node)
end

#visit_root(_node) ⇒ Object


36
37
38
39
40
41
42
43
# File 'lib/haml_lint/script_extractor.rb', line 36

def visit_root(_node)
  @code = []
  @total_lines = 0
  @source_map = {}
  @indent_level = 0

  yield # Collect lines of code from children
end

#visit_script(node) ⇒ Object


78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/haml_lint/script_extractor.rb', line 78

def visit_script(node)
  code = node.text
  add_line(code.strip, node)

  start_block = anonymous_block?(code) || start_block_keyword?(code)

  if start_block
    @indent_level += 1
  end

  yield # Continue extracting code from children

  if start_block
    @indent_level -= 1
    add_line('end', node)
  end
end

#visit_silent_script(node, &block) ⇒ Object


96
97
98
# File 'lib/haml_lint/script_extractor.rb', line 96

def visit_silent_script(node, &block)
  visit_script(node, &block)
end

#visit_tag(node) ⇒ Object


52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
# File 'lib/haml_lint/script_extractor.rb', line 52

def visit_tag(node)
  additional_attributes = node.dynamic_attributes_sources

  # Include dummy references to code executed in attributes list
  # (this forces a "use" of a variable to prevent "assigned but unused
  # variable" lints)
  additional_attributes.each do |attributes_code|
    # Normalize by removing excess whitespace to avoid format lints
    attributes_code = attributes_code.gsub(/\s*\n\s*/, ' ').strip

    # Attributes can either be a method call or a literal hash, so wrap it
    # in a method call itself in order to avoid having to differentiate the
    # two.
    add_line("{}.merge(#{attributes_code.strip})", node)
  end

  check_tag_static_hash_source(node)

  # We add a dummy puts statement to represent the tag name being output.
  # This prevents some erroneous RuboCop warnings.
  add_line("puts # #{node.tag_name}", node)

  code = node.script.strip
  add_line(code, node) unless code.empty?
end