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