Class: HclParser::Loader

Inherits:
Object
  • Object
show all
Defined in:
lib/hcl_parser/loader.rb

Constant Summary collapse

COMMENT_REGEX =
/^(^|\s)#/i

Instance Method Summary collapse

Constructor Details

#initialize(raw) ⇒ Loader

Returns a new instance of Loader.



5
6
7
# File 'lib/hcl_parser/loader.rb', line 5

def initialize(raw)
  @raw = raw
end

Instance Method Details

#codeObject

The parser being used cannot handle unquoted literal type values and comments. Hacking it and updating the raw code as a workaround. May have to fix the parser or write a new parser.



17
18
19
20
21
# File 'lib/hcl_parser/loader.rb', line 17

def code
  return @code if @code
  @code = fix_quotes(@raw)
  @code = rewrite_complex_types(@code)
end

#complex_type_line?(l) ⇒ Boolean

Returns:

  • (Boolean)


81
82
83
# File 'lib/hcl_parser/loader.rb', line 81

def complex_type_line?(l)
  l.match(/object\(/) || l.match(/=\s*"any/)
end

#complex_type_lines?(lines) ⇒ Boolean

Returns:

  • (Boolean)


75
76
77
78
79
# File 'lib/hcl_parser/loader.rb', line 75

def complex_type_lines?(lines)
  !!lines.find do |l|
    complex_type_line?(l)
  end
end

#empty?Boolean

Returns:

  • (Boolean)


92
93
94
95
96
97
# File 'lib/hcl_parser/loader.rb', line 92

def empty?
  text = remove_comments(code)
  lines = text.split("\n")
  lines.reject! { |l| l.strip.empty? }
  lines.empty?
end

#fix_quotes(raw) ⇒ Object



109
110
111
112
113
114
115
# File 'lib/hcl_parser/loader.rb', line 109

def fix_quotes(raw)
  lines = raw.split("\n")
  lines.map! do |l|
    quote_line(l)
  end
  lines.join("\n")
end

#loadObject



9
10
11
12
# File 'lib/hcl_parser/loader.rb', line 9

def load
  return {} if empty? # Rhcl parser cannot handle empty file
  Rhcl.parse(code)
end

#quote_line(l) ⇒ Object



117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/hcl_parser/loader.rb', line 117

def quote_line(l)
  return "# " if l =~ COMMENT_REGEX # return empty comment so parser wont try to parse it
  return l unless l =~ /(type|default)\s*=/ # just check for type and default
  return l if l =~ /(type|default)\s*=\s*['"]([a-zA-Z0-9()]+)["']/ # check quotes in the type value

  # Reaching here means there is probably a type value without quotes
  # Try to capture unquoted value so we can add quotes
  md = l.match(/(type|default)\s*=\s*([a-zA-Z0-9()]+)/)

  if md
    prop, value = md[1], md[2]
    %Q|#{prop} = "#{value}"|
  else
    # Example: type = "list(object({
    l # unable to capture quotes, passthrough as fallback
  end
end

#remove_comments(raw) ⇒ Object



100
101
102
103
104
105
106
107
# File 'lib/hcl_parser/loader.rb', line 100

def remove_comments(raw)
  lines = raw.split("\n")
  # filter out commented lines
  lines.reject! { |l| l =~ COMMENT_REGEX }
  # filter out empty lines
  lines.reject! { |l| l.strip.empty? }
  lines.join("\n")
end

#rewrite_complex_types(raw) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/hcl_parser/loader.rb', line 23

def rewrite_complex_types(raw)
  lines = raw.split("\n")
  results = []

  variable_start_found = false
  variable_start_index = nil
  variable_end_index = nil
  rewrite_lines = false

  lines.each_with_index do |l,i|
    # We dont rewrite lines until the next line/iteration
    # This is actually the next iteration since we set rewrite_lines = true previously
    # in rewrite_lines = complex_type_lines?(lookahead_lines)
    if rewrite_lines
      if complex_type_line?(l)
        # Doesnt matter what the default value is as long as there is one
        # Doing this in case the default value spans multiple lines
        results << '  default = "any"'
      elsif simple_default_assignment?(l)
        results << l
      else
        results << "# #{l}"
      end
    else
      results << l
    end
    # End of logic in the next iteration

    # Start of logic in the current iteration
    variable_start_found = l.match(/^variable /)
    if variable_start_found
      variable_start_index = i
      variable_end_index = variable_end_index(lines, variable_start_index)
      lookahead_lines = lines[variable_start_index..variable_end_index]
      rewrite_lines = complex_type_lines?(lookahead_lines)
    end

    # Disable rewriting before reaching the end of the variable definition so: i + 1
    if variable_end_index == i + 1
      variable_start_index = nil
      variable_end_index = nil
      rewrite_lines = false
    end
  end

  results.join("\n")
end

#simple_default_assignment?(line) ⇒ Boolean

Returns:

  • (Boolean)


71
72
73
# File 'lib/hcl_parser/loader.rb', line 71

def simple_default_assignment?(line)
  line.match(/default\s*=\s*("|'|null)/)
end

#variable_end_index(lines, variable_start_index) ⇒ Object



85
86
87
88
89
90
# File 'lib/hcl_parser/loader.rb', line 85

def variable_end_index(lines, variable_start_index)
  lines.each_with_index do |l,i|
    next unless i >= variable_start_index
    return i if l.match(/^}/) || l.match(/{\s*}/)
  end
end