class VDF::Parser

The Parser class is responsible for parsing a VDF document into a Ruby Hash @see VDF.parse

Constants

REGEX

Regex for splitting up a line in a VDF document into meaningful parts. Taken from {github.com/node-steam/vdf/blob/master/src/index.ts#L18-L24}

Public Class Methods

parse(input) click to toggle source

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

@param input [String, File, to_str, each_line] the input object @return [Hash] the contents of the VDF document, parsed into a Ruby Hash @raise [ParserError] if the VDF document is invalid @example Parse the contents of a VDF String

contents = VDF.parse(string)

@example Parse the contents of a VDF File

File.open("filename.vdf", "r") do |file|
 contents = VDF.parse(file)
 puts contents.inspect
end
# File lib/vdf/parse.rb, line 31
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?(-'}')
                        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