class IniFile::Parser
The IniFile::Parser
has the responsibility of reading the contents of an .ini file and storing that information into a ruby Hash. The object being parsed must respond to `each_line` - this includes Strings and any IO object.
Attributes
Public Class Methods
Create a new IniFile::Parser
that can be used to parse the contents of an .ini file.
hash - The Hash where parsed information will be stored param - String used to separate parameter and value comment - String containing the comment character(s) default - The String name of the default global section continuation - Use backslash as a line continuation character
# File lib/inifile.rb, line 455 def initialize( hash, param, comment, default, continuation, force_array ) @hash = hash @default = default @continuation = continuation @force_array = force_array comment = comment.to_s.empty? ? "\\z" : "\\s*(?:[#{comment}].*)?\\z" @section_regexp = %r/\A\s*\[([^\]]+)\]#{comment}/ @ignore_regexp = %r/\A#{comment}/ @property_regexp = %r/\A(.*?)(?<!\\)#{param}(.*)\z/ @switch_regexp = %r/\A\s*([\w\.]+)\s*#{comment}/ @open_quote = %r/\A\s*(".*)\z/ @close_quote = %r/\A(.*(?<!\\)")#{comment}/ @full_quote = %r/\A\s*(".*(?<!\\)")#{comment}/ if @continuation @trailing_slash = %r/\A(.*)(?<!\\)\\#{comment}/ else @trailing_slash = %r/\A(.*\\)#{comment}/ end @normal_value = %r/\A(.*?)#{comment}/ end
Public Instance Methods
Raise a parse error using the given message and appending the current line being parsed.
msg - The message String to use.
Raises IniFile::Error
# File lib/inifile.rb, line 625 def error( msg = 'Could not parse line' ) raise Error, "#{msg}: #{@line.inspect}" end
Returns `true` if the current value starts with a leading double quote. Otherwise returns false.
# File lib/inifile.rb, line 481 def leading_quote? value && value =~ %r/\A"/ end
Parse the ini file contents. This will clear any values currently stored in the ini hash.
content - Any object that responds to `each_line`
Returns nil.
# File lib/inifile.rb, line 546 def parse( content ) return unless content continuation = false @hash.clear @line = nil self.section = nil content.each_line do |line| @line = line.chomp if continuation continuation = parse_value @line else case @line when @ignore_regexp nil when @section_regexp self.section = @hash[$1] when @property_regexp self.property = $1.strip error if property.empty? continuation = parse_value $2 when @switch_regexp #self.property = $1.strip self.section[$1.strip] = {} else error end end end # check here if we have a dangling value ... usually means we have an # unmatched open quote if leading_quote? error "Unmatched open quote" elsif property && value process_property elsif value error end nil end
Given a string, attempt to parse out a value from that string. This value might be continued on the following line. So this method returns `true` if it is expecting more data.
string - String to parse
Returns `true` if the next line is also part of the current value. Returns `fase` if the string contained a complete value.
# File lib/inifile.rb, line 493 def parse_value( string ) continuation = false # if our value starts with a double quote, then we are in a # line continuation situation if leading_quote? # check for a closing quote at the end of the string if string =~ @close_quote value << $1 # otherwise just append the string to the value else value << string continuation = true end # not currently processing a continuation line else case string when @full_quote self.value = $1 when @open_quote self.value = $1 continuation = true when @trailing_slash self.value ? self.value << $1 : self.value = $1 continuation = @continuation when @normal_value self.value ? self.value << $1 : self.value = $1 else error end end if continuation self.value << $/ if leading_quote? else process_property end continuation end
Store the property/value pair in the currently active section. This method checks for continuation of the value to the next line.
Returns nil.
# File lib/inifile.rb, line 596 def process_property property.strip! value.strip! self.value = $1 if value =~ %r/\A"(.*)(?<!\\)"\z/m if section[property].nil? || !@force_array section[property] = typecast(value) elsif section[property].is_a?(Array) section[property] << typecast(value) else section[property] = [section[property], typecast(value)] end self.property = nil self.value = nil end
Returns the current section Hash.
# File lib/inifile.rb, line 615 def section @section ||= @hash[@default] end
Attempt to typecast the value string. We are looking for boolean values, integers, floats, and empty strings. Below is how each gets cast, but it is pretty logical and straightforward.
"true" --> true "false" --> false "" --> nil "42" --> 42 "3.14" --> 3.14 "foo" --> "foo"
Returns the typecast value.
# File lib/inifile.rb, line 641 def typecast( value ) case value when %r/\Atrue\z/i; true when %r/\Afalse\z/i; false when %r/\A\s*\z/i; nil else stripped_value = value.strip if stripped_value =~ /^\d*\.\d+$/ Float(stripped_value) elsif stripped_value =~ /^[^0]\d*$/ Integer(stripped_value) else unescape_value(value) end end rescue unescape_value(value) end
Unescape special characters found in the value string. This will convert escaped null, tab, carriage return, newline, and backslash into their literal equivalents.
value - The String value to unescape.
Returns the unescaped value.
# File lib/inifile.rb, line 667 def unescape_value( value ) value = value.to_s value.gsub!(%r/\\[0nrt\\]/) { |char| case char when '\0'; "\0" when '\n'; "\n" when '\r'; "\r" when '\t'; "\t" when '\\\\'; "\\" end } value end