Class: VDF::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/vdf/parse.rb

Overview

The Parser class is responsible for parsing a VDF document into a Ruby Hash

See Also:

Class Method Summary collapse

Class Method Details

.parse(input) ⇒ Hash

Parses a VDF document into a Ruby Hash and returns it

For large files, it’s recommended to pass the File object to VDF.parse instead of reading the whole File contents into memory

Examples:

Parse the contents of a VDF String

contents = VDF.parse(string)

Parse the contents of a VDF File

File.open("filename.vdf", "r") do |file|
  contents = VDF.parse(file)
  puts contents.inspect
end

Parameters:

  • input (String, File, #to_str, #each_line)

    the input object

Returns:

  • (Hash)

    the contents of the VDF document, parsed into a Ruby Hash

Raises:



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
70
71
72
73
74
75
76
77
78
79
80
81
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
# File 'lib/vdf/parse.rb', line 35

def parse(input)
  raise ArgumentError, 'Input has to respond to :each_line or :to_str' unless input.respond_to?(:each_line) || input.respond_to?(:to_str)
  input = StringIO.new(input) unless input.respond_to? :pos

  result = {}
  stack = [result]
  expect = false
  i = 0

  enum = input.each_line
  enum.with_index do |line, _|
    i += 1
    line.encode!('UTF-8').strip!
    next if line.empty? || line[0] == '/'

    if line.start_with?('{')
      expect = false
      next
    elsif expect
      raise ParserError, "Invalid syntax on line #{i+1} (Expected bracket)"
    end

    if line.start_with?('}')
      if stack.length == 1
        raise ParserError, "Invalid syntax on line #{i} (Unexpected closing bracket)"
      end
      stack.pop
      next
    end

    loop do
      if (m = REGEX.match(line)).nil?
        raise ParserError, "Invalid syntax on line #{i+1} (Line didn't match regex)"
      end

      key = m[2] || m[3]
      val = m[6] || m[8]

      if val.nil?
        if stack[-1][key].nil?
          stack[-1][key] = {}
        end
        stack << stack[-1][key]
        expect = true
      else
        if m[7].nil? && m[8].nil?
          if (next_line = enum.next).nil?
            raise ParserError, "Invalid syntax on line #{i+1} (Unexpected EOF)"
          end

          i += 1
          line << "\n" << next_line.to_s.encode("UTF-8").strip
          next
        end

        stack[-1][key] = begin
          begin
            Integer(val)
          rescue ArgumentError
            Float(val)
            end
          rescue ArgumentError
            case val.downcase
          when 'true'
            true
          when 'false'
            false
          when 'null'
            nil
          else
            val
          end
        end
      end

      break
    end
  end

  raise ParserError, 'Open parentheses somewhere' unless stack.length == 1

  return result
end