Hello community,

here is the log from the commit of package rubygem-inifile for openSUSE:Factory 
checked in at 2015-02-11 16:45:01
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/rubygem-inifile (Old)
 and      /work/SRC/openSUSE:Factory/.rubygem-inifile.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "rubygem-inifile"

Changes:
--------
--- /work/SRC/openSUSE:Factory/rubygem-inifile/rubygem-inifile.changes  
2012-09-23 21:13:34.000000000 +0200
+++ /work/SRC/openSUSE:Factory/.rubygem-inifile.new/rubygem-inifile.changes     
2015-02-11 16:45:06.000000000 +0100
@@ -1,0 +2,5 @@
+Tue Feb 10 17:56:17 UTC 2015 - co...@suse.com
+
+- updated to version 3.0.0
+
+-------------------------------------------------------------------

Old:
----
  inifile-2.0.2.gem

New:
----
  gem2rpm.yml
  inifile-3.0.0.gem

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ rubygem-inifile.spec ++++++
--- /var/tmp/diff_new_pack.k2WwzR/_old  2015-02-11 16:45:07.000000000 +0100
+++ /var/tmp/diff_new_pack.k2WwzR/_new  2015-02-11 16:45:07.000000000 +0100
@@ -1,7 +1,7 @@
 #
 # spec file for package rubygem-inifile
 #
-# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany.
+# Copyright (c) 2015 SUSE LINUX GmbH, Nuernberg, Germany.
 #
 # All modifications and additions to the file contributed by third parties
 # remain the property of their copyright owners, unless otherwise agreed
@@ -16,17 +16,26 @@
 #
 
 
+#
+# This file was generated with a gem2rpm.yml and not just plain gem2rpm.
+# All sections marked as MANUAL, license headers, summaries and descriptions
+# can be maintained in that file. Please consult this file before editing any
+# of those fields
+#
+
 Name:           rubygem-inifile
-Version:        2.0.2
+Version:        3.0.0
 Release:        0
 %define mod_name inifile
 %define mod_full_name %{mod_name}-%{version}
-
 BuildRoot:      %{_tmppath}/%{name}-%{version}-build
-BuildRequires:  ruby-macros >= 1
-BuildRequires:  rubygem(rdoc) > 3.10
+BuildRequires:  %{rubygem gem2rpm}
+BuildRequires:  %{rubygem rdoc > 3.10}
+BuildRequires:  %{ruby}
+BuildRequires:  ruby-macros >= 5
 Url:            http://rubygems.org/gems/inifile
-Source:         %{mod_full_name}.gem
+Source:         http://rubygems.org/gems/%{mod_full_name}.gem
+Source1:        gem2rpm.yml
 Summary:        INI file reader and writer
 License:        MIT
 Group:          Development/Languages/Ruby
@@ -62,48 +71,17 @@
 [section2]
 # another comment
 var1 = baz
-var2 = shoodle
-
-%package doc
-Summary:        RDoc documentation for %{mod_name}
-Group:          Development/Languages/Ruby
-Requires:       %{name} = %{version}
-
-%description doc
-Documentation generated at gem installation time.
-Usually in RDoc and RI formats.
-
-%package testsuite
-Summary:        Test suite for %{mod_name}
-Group:          Development/Languages/Ruby
-Requires:       %{name} = %{version}
-
-%description testsuite
-Test::Unit or RSpec files, useful for developers.
+var2 = shoodle.
 
 %prep
-#gem_unpack
-#if you need patches, apply them here and replace the # with a % sign in the 
surrounding lines
-#gem_build
 
 %build
 
 %install
-%gem_install -f
+%gem_install \
+  --doc-files="History.txt README.md" \
+  -f
 
-%files
-%defattr(-,root,root,-)
-%{_libdir}/ruby/gems/%{rb_ver}/cache/%{mod_full_name}.gem
-%{_libdir}/ruby/gems/%{rb_ver}/gems/%{mod_full_name}/
-%exclude %{_libdir}/ruby/gems/%{rb_ver}/gems/%{mod_full_name}/test
-%{_libdir}/ruby/gems/%{rb_ver}/specifications/%{mod_full_name}.gemspec
-
-%files doc
-%defattr(-,root,root,-)
-%doc %{_libdir}/ruby/gems/%{rb_ver}/doc/%{mod_full_name}/
-
-%files testsuite
-%defattr(-,root,root,-)
-%{_libdir}/ruby/gems/%{rb_ver}/gems/%{mod_full_name}/test
+%gem_packages
 
 %changelog

++++++ gem2rpm.yml ++++++
# ---
# ## used by gem2rpm
# :summary: this is a custom summary
# ## used by gem2rpm
# :description: |-
#   this is a custom description
#
#   it can be multiline
# ## used by gem2rpm
# :license: MIT or Ruby
# ## used by gem2rpm and gem_packages
# :version_suffix: -x_y
# ## used by gem2rpm and gem_packages
# :disable_docs: true
# ## used by gem2rpm
# :disable_automatic_rdoc_dep: true
# ## used by gem2rpm
# :preamble: |-
#   BuildRequires: foobar
#   Requires: foobar
# ## used by gem2rpm
# :patches:
#   foo.patch: -p1
#   bar.patch: 
# ## used by gem2rpm
:sources:
# - foo.desktop
# - bar.desktop
# :gem_install_args: '....'
# ## used by gem2rpm
# :pre_install: |-
#   %if 0%{?use_system_libev}
#   export USE_VENDORED_LIBEV="no"
#   %endif
# ## used by gem2rpm
# :post_install: |-
#   # delete custom files here or do other fancy stuff
#   install -D -m 0644 %{S:1} %{buildroot}%{_bindir}/gem2rpm-opensuse
# ## used by gem2rpm
# :testsuite_command: |-
#   (pushd %{buildroot}%{gem_base}/gems/%{mod_full_name} && rake test)
# ## used by gem2rpm
# :filelist: |-
#   /usr/bin/gem2rpm-opensuse
# ## used by gem2rpm
# :scripts:
#   :post: |-
#     /bin/echo foo
# ## used by gem_packages
# :main:
#   :preamble: |-
#     Requires: util-linux
#     Recommends: pwgen
#   :filelist: |-
#     /usr/bin/gem2rpm-opensuse
# ## used by gem_packages
# :custom:
#   apache:
#     :preamble: |-
#       Requires: .....
#     :filelist: |-
#       /etc/apache2/conf.d/passenger.conf
#     :summary: Custom summary is optional
#     :description: |-
#       Custom description is optional
#
#       bar
#     :post: |-
#       /bin/echo foo
#
++++++ inifile-2.0.2.gem -> inifile-3.0.0.gem ++++++
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/.gitignore new/.gitignore
--- old/.gitignore      1970-01-01 01:00:00.000000000 +0100
+++ new/.gitignore      2014-08-01 18:30:01.000000000 +0200
@@ -15,3 +15,4 @@
 coverage
 doc
 pkg
+vendor
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/README.md new/README.md
--- old/README.md       1970-01-01 01:00:00.000000000 +0100
+++ new/README.md       2014-08-01 18:30:01.000000000 +0200
@@ -135,6 +135,19 @@
 
     property = this is not a tab \\t character
 
+### Value Type Casting
+
+Some values will be type cast when parsed by the code. Those values are
+booleans, integers, floats, and empty strings are cast to `nil`.
+
+* ""  -->  nil
+* "42"  -->  42
+* "3.14159"  -->  3.14159
+* "true"  -->  true
+* "false"  -->  false
+* "normal string"  -->  "normal string"
+
+Pretty basic stuff.
 
 Install
 -------
@@ -150,6 +163,15 @@
     $ rake
 
 
+Examples
+--------
+
+    require 'inifile'
+    myini = IniFile.load('mytest.ini')
+    myini.each_section do |section|
+      puts "I want #{myini[section]['somevar']} printed here!"
+    end
+
 Contributing
 ------------
 
@@ -171,7 +193,7 @@
 -------
 
 MIT License
-Copyright (c) 2006 - 2012
+Copyright (c) 2006 - 2014
 
 Permission is hereby granted, free of charge, to any person obtaining
 a copy of this software and associated documentation files (the
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/Rakefile new/Rakefile
--- old/Rakefile        1970-01-01 01:00:00.000000000 +0100
+++ new/Rakefile        2014-08-01 18:30:01.000000000 +0200
@@ -20,5 +20,5 @@
   version      IniFile::VERSION
 
   use_gmail
-  depend_on    'bones-git', :development => true
+  depend_on    'bones-git', "~> 1.3", :development => true
 }
Files old/checksums.yaml.gz and new/checksums.yaml.gz differ
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/inifile.gemspec new/inifile.gemspec
--- old/inifile.gemspec 1970-01-01 01:00:00.000000000 +0100
+++ new/inifile.gemspec 2014-08-01 18:30:01.000000000 +0200
@@ -0,0 +1,24 @@
+# coding: utf-8
+lib = File.expand_path('../lib', __FILE__)
+$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
+require 'inifile'
+
+Gem::Specification.new do |spec|
+  spec.name          = "inifile"
+  spec.version       = IniFile::VERSION
+  spec.authors       = ["Tim Pease"]
+  spec.email         = ["tim.pe...@gmail.com"]
+  spec.summary       = %q{INI file reader and writer}
+  spec.description   = %q{INI file reader and writer}
+  spec.description   = %q{IniFile is a pure ruby gem that can read and write 
most INI file formats}
+  spec.homepage      = "https://rubygems.org/gems/inifile";
+  spec.license       = "MIT"
+
+  spec.files         = `git ls-files -z`.split("\x0")
+  spec.executables   = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
+  spec.test_files    = spec.files.grep(%r{^(test|spec|features)/})
+  spec.require_paths = ["lib"]
+
+  spec.add_development_dependency "bones",      "~> 3.8"
+  spec.add_development_dependency "bones-git",  "~> 1.3"
+end
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/lib/inifile.rb new/lib/inifile.rb
--- old/lib/inifile.rb  1970-01-01 01:00:00.000000000 +0100
+++ new/lib/inifile.rb  2014-08-01 18:30:01.000000000 +0200
@@ -1,23 +1,20 @@
 #encoding: UTF-8
-require 'strscan'
 
 # This class represents the INI file and can be used to parse, modify,
 # and write INI files.
-#
 class IniFile
   include Enumerable
 
   class Error < StandardError; end
-  VERSION = '2.0.2'
+  VERSION = '3.0.0'
 
   # Public: Open an INI file and load the contents.
   #
-  # filename - The name of the fiel as a String
+  # filename - The name of the file as a String
   # opts     - The Hash of options (default: {})
   #            :comment   - String containing the comment character(s)
   #            :parameter - String used to separate parameter and value
-  #            :encoding  - Encoding String for reading / writing (Ruby 1.9)
-  #            :escape    - Boolean used to control character escaping
+  #            :encoding  - Encoding String for reading / writing
   #            :default   - The String name of the default global section
   #
   # Examples
@@ -28,8 +25,7 @@
   #   IniFile.load('does/not/exist.ini')
   #   #=> nil
   #
-  # Returns an IniFile intsnace or nil if the file could not be opened.
-  #
+  # Returns an IniFile instance or nil if the file could not be opened.
   def self.load( filename, opts = {} )
     return unless File.file? filename
     new(opts.merge(:filename => filename))
@@ -38,57 +34,50 @@
   # Get and set the filename
   attr_accessor :filename
 
-  # Get and set the encoding (Ruby 1.9)
+  # Get and set the encoding
   attr_accessor :encoding
 
-  # Enable or disable character escaping
-  attr_accessor :escape
-
-  # Public: Create a new INI file from the given content String which
-  # contains the INI file lines. If the content are omitted, then the
-  # :filename option is used to read in the content of the INI file. If
-  # neither the content for a filename is provided then an empty INI file is
-  # created.
-  #
-  # content - The String containing the INI file contents
-  # opts    - The Hash of options (default: {})
-  #           :comment   - String containing the comment character(s)
-  #           :parameter - String used to separate parameter and value
-  #           :encoding  - Encoding String for reading / writing (Ruby 1.9)
-  #           :escape    - Boolean used to control character escaping
-  #           :default   - The String name of the default global section
-  #           :filename  - The filename as a String
+  # Public: Create a new INI file from the given set of options. If :content
+  # is provided then it will be used to populate the INI file. If a :filename
+  # is provided then the contents of the file will be parsed and stored in the
+  # INI file. If neither the :content or :filename is provided then an empty
+  # INI file is created.
+  #
+  # opts - The Hash of options (default: {})
+  #   :content   - The String/Hash containing the INI contents
+  #   :comment   - String containing the comment character(s)
+  #   :parameter - String used to separate parameter and value
+  #   :encoding  - Encoding String for reading / writing
+  #   :default   - The String name of the default global section
+  #   :filename  - The filename as a String
   #
   # Examples
   #
   #   IniFile.new
   #   #=> an empty IniFile instance
   #
-  #   IniFile.new( "[global]\nfoo=bar" )
+  #   IniFile.new( :content => "[global]\nfoo=bar" )
   #   #=> an IniFile instance
   #
   #   IniFile.new( :filename => 'file.ini', :encoding => 'UTF-8' )
   #   #=> an IniFile instance
   #
-  #   IniFile.new( "[global]\nfoo=bar", :comment => '#' )
+  #   IniFile.new( :content => "[global]\nfoo=bar", :comment => '#' )
   #   #=> an IniFile instance
   #
-  def initialize( content = nil, opts = {} )
-    opts, content = content, nil if Hash === content
-
-    @content = content
-
+  def initialize( opts = {} )
     @comment  = opts.fetch(:comment, ';#')
     @param    = opts.fetch(:parameter, '=')
     @encoding = opts.fetch(:encoding, nil)
-    @escape   = opts.fetch(:escape, true)
     @default  = opts.fetch(:default, 'global')
     @filename = opts.fetch(:filename, nil)
+    content   = opts.fetch(:content, nil)
 
     @ini = Hash.new {|h,k| h[k] = Hash.new}
 
-    if    @content  then parse!
-    elsif @filename then read
+    if    content.is_a?(Hash) then merge!(content)
+    elsif content             then parse(content)
+    elsif @filename           then read
     end
   end
 
@@ -98,16 +87,13 @@
   #
   # opts - The default options Hash
   #        :filename - The filename as a String
-  #        :encoding - The encoding as a String (Ruby 1.9)
+  #        :encoding - The encoding as a String
   #
   # Returns this IniFile instance.
-  #
   def write( opts = {} )
     filename = opts.fetch(:filename, @filename)
     encoding = opts.fetch(:encoding, @encoding)
-    mode = (RUBY_VERSION >= '1.9' && encoding) ?
-         "w:#{encoding.to_s}" :
-         'w'
+    mode = encoding ? "w:#{encoding}" : "w"
 
     File.open(filename, mode) do |f|
       @ini.each do |section,hash|
@@ -129,31 +115,22 @@
   #
   # opts - The default options Hash
   #        :filename - The filename as a String
-  #        :encoding - The encoding as a String (Ruby 1.9)
+  #        :encoding - The encoding as a String
   #
   # Returns this IniFile instance if the read was successful; nil is returned
   # if the file could not be read.
-  #
   def read( opts = {} )
     filename = opts.fetch(:filename, @filename)
     encoding = opts.fetch(:encoding, @encoding)
     return unless File.file? filename
 
-    mode = (RUBY_VERSION >= '1.9' && encoding) ?
-           "r:#{encoding.to_s}" :
-           'r'
-    fd = File.open(filename, mode)
-    @content = fd.read
-
-    parse!
+    mode = encoding ? "r:#{encoding}" : "r"
+    File.open(filename, mode) { |fd| parse fd }
     self
-  ensure
-    fd.close if fd && !fd.closed?
   end
   alias :restore :read
 
   # Returns this IniFile converted to a String.
-  #
   def to_s
     s = []
     @ini.each do |section,hash|
@@ -165,7 +142,6 @@
   end
 
   # Returns this IniFile converted to a Hash.
-  #
   def to_h
     @ini.dup
   end
@@ -176,33 +152,50 @@
   # other - The other IniFile.
   #
   # Returns a new IniFile.
-  #
   def merge( other )
     self.dup.merge!(other)
   end
 
   # Public: Merges other_inifile into this inifile, overwriting existing
-  # entries. Useful for having a system inifile with user over-ridable settings
+  # entries. Useful for having a system inifile with user overridable settings
   # elsewhere.
   #
   # other - The other IniFile.
   #
   # Returns this IniFile.
-  #
   def merge!( other )
+    return self if other.nil?
+
     my_keys = @ini.keys
-    other_keys =
-        case other
-        when IniFile; other.instance_variable_get(:@ini).keys
-        when Hash; other.keys
-        else raise "cannot merge contents from '#{other.class.name}'" end
+    other_keys = case other
+      when IniFile
+        other.instance_variable_get(:@ini).keys
+      when Hash
+        other.keys
+      else
+        raise Error, "cannot merge contents from '#{other.class.name}'"
+      end
 
     (my_keys & other_keys).each do |key|
-      @ini[key].merge!(other[key])
+      case other[key]
+      when Hash
+        @ini[key].merge!(other[key])
+      when nil
+        nil
+      else
+        raise Error, "cannot merge section #{key.inspect} - unsupported type: 
#{other[key].class.name}"
+      end
     end
 
     (other_keys - my_keys).each do |key|
-      @ini[key] = other[key]
+      @ini[key] = case other[key]
+        when Hash
+          other[key].dup
+        when nil
+          {}
+        else
+          raise Error, "cannot merge section #{key.inspect} - unsupported 
type: #{other[key].class.name}"
+        end
     end
 
     self
@@ -212,7 +205,7 @@
   # given block.
   #
   # block - The block that will be iterated by the each method. The block will
-  #         be passed the current section and the parameter / value pair.
+  #         be passed the current section and the parameter/value pair.
   #
   # Examples
   #
@@ -221,7 +214,6 @@
   #   end
   #
   # Returns this IniFile.
-  #
   def each
     return unless block_given?
     @ini.each do |section,hash|
@@ -244,7 +236,6 @@
   #   end
   #
   # Returns this IniFile.
-  #
   def each_section
     return unless block_given?
     @ini.each_key {|section| yield section}
@@ -256,7 +247,6 @@
   # section - The section name as a String.
   #
   # Returns the deleted section Hash.
-  #
   def delete_section( section )
     @ini.delete section.to_s
   end
@@ -272,7 +262,6 @@
   #   #=> global section Hash
   #
   # Returns the Hash of parameter/value pairs for this section.
-  #
   def []( section )
     return nil if section.nil?
     @ini[section.to_s]
@@ -289,7 +278,6 @@
   #   #=> { 'gritty' => 'yes' }
   #
   # Returns the value Hash.
-  #
   def []=( section, value )
     @ini[section.to_s] = value
   end
@@ -306,7 +294,6 @@
   #
   # Return a Hash containing only those sections that match the given regular
   # expression.
-  #
   def match( regex )
     @ini.dup.delete_if { |section, _| section !~ regex }
   end
@@ -316,13 +303,11 @@
   # section - The section name as a String.
   #
   # Returns true if the section exists in the IniFile.
-  #
   def has_section?( section )
     @ini.has_key? section.to_s
   end
 
   # Returns an Array of section names contained in this IniFile.
-  #
   def sections
     @ini.keys
   end
@@ -331,7 +316,6 @@
   # the object will raise an error.
   #
   # Returns this IniFile.
-  #
   def freeze
     super
     @ini.each_value {|h| h.freeze}
@@ -343,7 +327,6 @@
   # marking each as tainted.
   #
   # Returns this IniFile.
-  #
   def taint
     super
     @ini.each_value {|h| h.taint}
@@ -356,7 +339,6 @@
   # original. The tainted state of the original is copied to the duplicate.
   #
   # Returns a new IniFile.
-  #
   def dup
     other = super
     other.instance_variable_set(:@ini, Hash.new {|h,k| h[k] = Hash.new})
@@ -371,7 +353,6 @@
   # to the duplicate.
   #
   # Returns a new IniFile.
-  #
   def clone
     other = dup
     other.freeze if self.frozen?
@@ -385,7 +366,6 @@
   # other - The other IniFile.
   #
   # Returns true if the INI files are equivalent and false if they differ.
-  #
   def eql?( other )
     return true if equal? other
     return false unless other.instance_of? self.class
@@ -393,159 +373,255 @@
   end
   alias :== :eql?
 
-
-private
-
-  # Parse the ini file contents. This will clear any values currently stored
-  # in the ini hash.
+  # Escape special characters.
   #
-  def parse!
-    return unless @content
-
-    string = ''
-    property = ''
-
-    @ini.clear
-    @_line = nil
-    @_section = nil
+  # value - The String value to escape.
+  #
+  # Returns the escaped value.
+  def escape_value( value )
+    value = value.to_s.dup
+    value.gsub!(%r/\\([0nrt])/, '\\\\\1')
+    value.gsub!(%r/\n/, '\n')
+    value.gsub!(%r/\r/, '\r')
+    value.gsub!(%r/\t/, '\t')
+    value.gsub!(%r/\0/, '\0')
+    value
+  end
 
-    scanner = StringScanner.new(@content)
-    until scanner.eos?
+  # Parse the given content and store the information in this IniFile
+  # instance. All data will be cleared out and replaced with the information
+  # read from the content.
+  #
+  # content - A String or a file descriptor (must respond to `each_line`)
+  #
+  # Returns this IniFile.
+  def parse( content )
+    parser = Parser.new(@ini, @param, @comment, @default)
+    parser.parse(content)
+    self
+  end
 
-      # keep track of the current line for error messages
-      @_line = scanner.check(%r/\A.*$/) if scanner.bol?
+  # 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.
+  class Parser
+
+    attr_writer :section
+    attr_accessor :property
+    attr_accessor :value
+
+    # 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
+    #
+    def initialize( hash, param, comment, default )
+      @hash = hash
+      @default = default
+
+      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/
+
+      @open_quote      = %r/\A\s*(".*)\z/
+      @close_quote     = %r/\A(.*(?<!\\)")#{comment}/
+      @full_quote      = %r/\A\s*(".*(?<!\\)")#{comment}/
+      @trailing_slash  = %r/\A(.*)(?<!\\)\\#{comment}/
+      @normal_value    = %r/\A(.*?)#{comment}/
+    end
 
-      # look for escaped special characters \# \" etc
-      if scanner.scan(%r/\\([\[\]#{@param}#{@comment}"])/)
-        string << scanner[1]
+    # Returns `true` if the current value starts with a leading double quote.
+    # Otherwise returns false.
+    def leading_quote?
+      value && value =~ %r/\A"/
+    end
 
-      # look for quoted strings
-      elsif scanner.scan(%r/"/)
-        quote = scanner.scan_until(/(?:\A|[^\\])"/)
-        parse_error('Unmatched quote') if quote.nil?
+    # 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.
+    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
 
-        quote.chomp!('"')
-        string << quote
+        # otherwise just append the string to the value
+        else
+          value << string
+          continuation = true
+        end
 
-      # look for comments, empty strings, end of lines
-      elsif scanner.skip(%r/\A\s*(?:[#{@comment}].*)?$/)
-        string << scanner.getch unless scanner.eos?
+      # 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 = true
 
-        process_property(property, string)
+        when @normal_value
+          self.value ?  self.value << $1 : self.value = $1
 
-      # look for the separator between property name and value
-      elsif scanner.scan(%r/#{@param}/)
-        if property.empty?
-          property = string.strip
-          string.slice!(0, string.length)
         else
-          parse_error
+          error
         end
+      end
 
-      # look for the start of a new section
-      elsif scanner.scan(%r/\A\s*\[([^\]]+)\]/)
-        @_section = @ini[scanner[1]]
-
-      # otherwise scan and store characters till we hit the start of some
-      # special section like a quote, newline, comment, etc.
+      if continuation
+        self.value << $/ if leading_quote?
       else
-        tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}] | \z | 
\\[\[\]#{@param}#{@comment}"])/mx)
-        parse_error if tmp.nil?
-
-        len = scanner[1].length
-        tmp.slice!(tmp.length - len, len)
-
-        scanner.pos = scanner.pos - len
-        string << tmp
+        process_property
       end
+
+      continuation
     end
 
-    process_property(property, string)
-  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.
+    def parse( content )
+      return unless content
+
+      continuation = false
+
+      @hash.clear
+      @line = nil
+      self.section = nil
 
-  # Store the property / value pair in the currently active section. This
-  # method checks for continuation of the value to the next line.
-  #
-  # property - The property name as a String.
-  # value    - The property value as a String.
-  #
-  # Returns nil.
-  #
-  def process_property( property, value )
-    value.chomp!
-    return if property.empty? and value.empty?
-    return if value.sub!(%r/\\\s*\z/, '')
+      content.each_line do |line|
+        @line = line.chomp
 
-    property.strip!
-    value.strip!
+        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
+          else
+            error
+          end
+        end
+      end
 
-    parse_error if property.empty?
+      # 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
 
-    current_section[property.dup] = unescape_value(value.dup)
+      nil
+    end
 
-    property.slice!(0, property.length)
-    value.slice!(0, value.length)
+    # Store the property/value pair in the currently active section. This
+    # method checks for continuation of the value to the next line.
+    #
+    # Returns nil.
+    def process_property
+      property.strip!
+      value.strip!
 
-    nil
-  end
+      self.value = $1 if value =~ %r/\A"(.*)(?<!\\)"\z/m
 
-  # Returns the current section Hash.
-  #
-  def current_section
-    @_section ||= @ini[@default]
-  end
+      section[property] = typecast(value)
 
-  # Raise a parse error using the given message and appending the current line
-  # being parsed.
-  #
-  # msg - The message String to use.
-  #
-  # Raises IniFile::Error
-  #
-  def parse_error( msg = 'Could not parse line' )
-    raise Error, "#{msg}: #{@_line.inspect}"
-  end
+      self.property = nil
+      self.value = nil
+    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.
-  #
-  def unescape_value( value )
-    return value unless @escape
+    # Returns the current section Hash.
+    def section
+      @section ||= @hash[@default]
+    end
 
-    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
+    # Raise a parse error using the given message and appending the current 
line
+    # being parsed.
+    #
+    # msg - The message String to use.
+    #
+    # Raises IniFile::Error
+    def error( msg = 'Could not parse line' )
+      raise Error, "#{msg}: #{@line.inspect}"
+    end
 
-  # Escape special characters.
-  #
-  # value - The String value to escape.
-  #
-  # Returns the escaped value.
-  #
-  def escape_value( value )
-    return value unless @escape
+    # 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.
+    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
+        Integer(value) rescue \
+        Float(value)   rescue \
+        unescape_value(value)
+      end
+    end
 
-    value = value.to_s.dup
-    value.gsub!(%r/\\([0nrt])/, '\\\\\1')
-    value.gsub!(%r/\n/, '\n')
-    value.gsub!(%r/\r/, '\r')
-    value.gsub!(%r/\t/, '\t')
-    value.gsub!(%r/\0/, '\0')
-    value
+    # 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.
+    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
   end
 
 end  # IniFile
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/metadata new/metadata
--- old/metadata        1970-01-01 01:00:00.000000000 +0100
+++ new/metadata        2014-08-01 18:30:01.000000000 +0200
@@ -1,80 +1,104 @@
 --- !ruby/object:Gem::Specification
 name: inifile
 version: !ruby/object:Gem::Version
-  version: 2.0.2
-  prerelease: 
+  version: 3.0.0
 platform: ruby
 authors:
 - Tim Pease
 autorequire: 
 bindir: bin
 cert_chain: []
-date: 2012-09-15 00:00:00.000000000 Z
+date: 2014-08-01 00:00:00.000000000 Z
 dependencies:
 - !ruby/object:Gem::Dependency
   name: bones-git
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '1.3'
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - "~>"
       - !ruby/object:Gem::Version
-        version: '0'
+        version: '1.3'
 - !ruby/object:Gem::Dependency
   name: bones
   requirement: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - ">="
       - !ruby/object:Gem::Version
-        version: 3.8.0
+        version: 3.8.1
   type: :development
   prerelease: false
   version_requirements: !ruby/object:Gem::Requirement
-    none: false
     requirements:
-    - - ! '>='
+    - - ">="
       - !ruby/object:Gem::Version
-        version: 3.8.0
-description: ! "Although made popular by Windows, INI files can be used on any 
system
-  thanks\nto their flexibility. They allow a program to store configuration 
data,
-  which\ncan then be easily parsed and changed. Two notable systems that use 
the INI\nformat
-  are Samba and Trac.\n\nMore information about INI files can be found on the 
[Wikipedia
-  Page](http://en.wikipedia.org/wiki/INI_file).\n\n### Properties\n\nThe basic 
element
-  contained in an INI file is the property. Every property has\na name and a 
value,
-  delimited by an equals sign *=*. The name appears to the\nleft of the equals 
sign
-  and the value to the right.\n\n    name=value\n\n### Sections\n\nSection 
declarations
-  start with *[* and end with *]* as in `[section1]` and\n`[section2]` shown 
in the
-  example below. The section declaration marks the\nbeginning of a section. 
All properties
-  after the section declaration will be\nassociated with that section.\n\n### 
Comments\n\nAll
-  lines beginning with a semicolon *;* or a number sign *#* are considered\nto 
be
-  comments. Comment lines are ignored when parsing INI files.\n\n### Example 
File
-  Format\n\nA typical INI file might look like this:\n\n    [section1]\n    ; 
some
-  comment on section1\n    var1 = foo\n    var2 = doodle\n    var3 = multiline 
values
-  \\\n    are also possible\n\n    [section2]\n    # another comment\n    var1 
= baz\n
-  \   var2 = shoodle"
+        version: 3.8.1
+description: |-
+  Although made popular by Windows, INI files can be used on any system thanks
+  to their flexibility. They allow a program to store configuration data, which
+  can then be easily parsed and changed. Two notable systems that use the INI
+  format are Samba and Trac.
+
+  More information about INI files can be found on the [Wikipedia 
Page](http://en.wikipedia.org/wiki/INI_file).
+
+  ### Properties
+
+  The basic element contained in an INI file is the property. Every property 
has
+  a name and a value, delimited by an equals sign *=*. The name appears to the
+  left of the equals sign and the value to the right.
+
+      name=value
+
+  ### Sections
+
+  Section declarations start with *[* and end with *]* as in `[section1]` and
+  `[section2]` shown in the example below. The section declaration marks the
+  beginning of a section. All properties after the section declaration will be
+  associated with that section.
+
+  ### Comments
+
+  All lines beginning with a semicolon *;* or a number sign *#* are considered
+  to be comments. Comment lines are ignored when parsing INI files.
+
+  ### Example File Format
+
+  A typical INI file might look like this:
+
+      [section1]
+      ; some comment on section1
+      var1 = foo
+      var2 = doodle
+      var3 = multiline values \
+      are also possible
+
+      [section2]
+      # another comment
+      var1 = baz
+      var2 = shoodle
 email: tim.pe...@gmail.com
 executables: []
 extensions: []
 extra_rdoc_files:
 - History.txt
 files:
-- .gitignore
-- .travis.yml
+- ".gitignore"
+- ".travis.yml"
 - History.txt
 - README.md
 - Rakefile
+- inifile.gemspec
 - lib/inifile.rb
 - test/data/bad_1.ini
+- test/data/bad_2.ini
 - test/data/browscap.ini
 - test/data/comment.ini
+- test/data/continuation.ini
 - test/data/escape.ini
 - test/data/global.ini
 - test/data/good.ini
@@ -82,32 +106,32 @@
 - test/data/mixed_comment.ini
 - test/data/multiline.ini
 - test/data/param.ini
+- test/data/section.ini
 - test/test_inifile.rb
 homepage: http://rubygems.org/gems/inifile
 licenses: []
+metadata: {}
 post_install_message: 
 rdoc_options:
-- --main
+- "--main"
 - README.md
 require_paths:
 - lib
 required_ruby_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
 required_rubygems_version: !ruby/object:Gem::Requirement
-  none: false
   requirements:
-  - - ! '>='
+  - - ">="
     - !ruby/object:Gem::Version
       version: '0'
 requirements: []
 rubyforge_project: inifile
-rubygems_version: 1.8.24
+rubygems_version: 2.2.2
 signing_key: 
-specification_version: 3
+specification_version: 4
 summary: INI file reader and writer
 test_files:
 - test/test_inifile.rb
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/data/bad_2.ini new/test/data/bad_2.ini
--- old/test/data/bad_2.ini     1970-01-01 01:00:00.000000000 +0100
+++ new/test/data/bad_2.ini     2014-08-01 18:30:01.000000000 +0200
@@ -0,0 +1,11 @@
+[section_one]
+one = 1
+two = 2
+
+[section_two]
+close-quote = "some text without
+a closing quote - should
+be interesting
+
+[section_three]
+wat = where is that closing quote?
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/data/comment.ini new/test/data/comment.ini
--- old/test/data/comment.ini   1970-01-01 01:00:00.000000000 +0100
+++ new/test/data/comment.ini   2014-08-01 18:30:01.000000000 +0200
@@ -6,5 +6,5 @@
 [section_two]  # you can comment here
 one = 42       # and even here!
 multi = 20 \   # and here, too
-+ 22 \= 42
++ 22 = 42
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/data/continuation.ini 
new/test/data/continuation.ini
--- old/test/data/continuation.ini      1970-01-01 01:00:00.000000000 +0100
+++ new/test/data/continuation.ini      2014-08-01 18:30:01.000000000 +0200
@@ -0,0 +1,6 @@
+[section_one]
+one = 1
+two = 2
+
+[section_two]
+end-of-file = here is the last value \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/data/good.ini new/test/data/good.ini
--- old/test/data/good.ini      1970-01-01 01:00:00.000000000 +0100
+++ new/test/data/good.ini      2014-08-01 18:30:01.000000000 +0200
@@ -3,15 +3,15 @@
 two = 2
 
 [section_two]
-three =         3
+three =         -3
 multi = multiline \
 support
 
 ; comments should be ignored
 [section three]
-four   =4
-five=5
-six =6
+four   =true
+five=false   # comments can go here
+six =6.0     ; and here, too
 
 [section_four]
    [section_five]
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/data/section.ini new/test/data/section.ini
--- old/test/data/section.ini   1970-01-01 01:00:00.000000000 +0100
+++ new/test/data/section.ini   2014-08-01 18:30:01.000000000 +0200
@@ -0,0 +1,4 @@
+; section headers can be values
+[section_one]
+one=[value]
+two=2
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' old/test/test_inifile.rb new/test/test_inifile.rb
--- old/test/test_inifile.rb    1970-01-01 01:00:00.000000000 +0100
+++ new/test/test_inifile.rb    2014-08-01 18:30:01.000000000 +0200
@@ -11,13 +11,13 @@
   def setup
     @ini_file = IniFile.new(:filename => 'test/data/good.ini')
     @contents = [
-      ['section_one', 'one', '1'],
-      ['section_one', 'two', '2'],
-      ['section_two', 'three', '3'],
+      ['section_one', 'one', 1],
+      ['section_one', 'two', 2],
+      ['section_two', 'three', -3],
       ['section_two', 'multi', "multiline support"],
-      ['section three', 'four', '4'],
-      ['section three', 'five', '5'],
-      ['section three', 'six', '6'],
+      ['section three', 'four', true],
+      ['section three', 'five', false],
+      ['section three', 'six', 6.0],
       ['section_five', 'seven and eight', '7 & 8']
     ].sort
 
@@ -84,7 +84,7 @@
   def test_delete_section
     assert_nil @ini_file.delete_section('section_nil')
 
-    h = {'one' => '1', 'two' => '2'}
+    h = {'one' => 1, 'two' => 2}
     assert_equal true, @ini_file.has_section?('section_one')
     assert_equal h, @ini_file.delete_section('section_one')
     assert_equal false, @ini_file.has_section?('section_one')
@@ -148,7 +148,7 @@
     assert @ini_file.eql?(@ini_file)
     assert @ini_file.eql?(@ini_file.clone)
     assert !@ini_file.eql?('string')
-    assert !@ini_file.eql?(IniFile.new(''))
+    assert !@ini_file.eql?(IniFile.new(:content => ''))
   end
 
   def test_freeze
@@ -179,18 +179,18 @@
 
   def test_index
     expected = {
-      'one' => '1',
-      'two' => '2'
+      'one' => 1,
+      'two' => 2
     }
     assert_equal expected, @ini_file[:section_one]
 
-    expected = {'three' => '3', 'multi' => "multiline support"}
+    expected = {'three' => -3, 'multi' => "multiline support"}
     assert_equal expected, @ini_file['section_two']
 
     expected = {
-      'four' => '4',
-      'five' => '5',
-      'six'  => '6',
+      'four' => true,
+      'five' => false,
+      'six'  => 6.0,
     }
     assert_equal expected, @ini_file['section three']
 
@@ -214,13 +214,11 @@
 
   def test_match
     expected = {
-     "section_two" =>
-      {
-        "three"=>"3", "multi"=>"multiline support"
+     "section_two" => {
+        "three" => -3, "multi" => "multiline support"
       },
-     "section three" =>
-      {
-        "four"=>"4", "five"=>"5", "six"=>"6"
+      "section three" => {
+        "four" => true, "five"=> false, "six" => 6.0
       }
     }
     assert_equal expected, @ini_file.match(/(two|three)/)
@@ -245,8 +243,8 @@
 
     ini_file = IniFile.new(:filename => 'test/data/param.ini', :parameter => 
':')
     assert ini_file.has_section?('section_one')
-    assert_equal '1', ini_file['section_one']['one']
-    assert_equal '2', ini_file['section_one']['two']
+    assert_equal 1, ini_file['section_one']['one']
+    assert_equal 2, ini_file['section_one']['two']
 
     # make sure we error out on files with bad lines
     assert_raise(IniFile::Error) {IniFile.new :filename => 
'test/data/bad_1.ini'}
@@ -254,7 +252,7 @@
 
   def test_initialize_from_string_without_ending_newline
     content = "[section_one]\n  foo=bar"
-    ini_file = IniFile.new(content)
+    ini_file = IniFile.new(:content => content)
     assert ini_file.has_section?('section_one')
     assert_equal 'bar', ini_file['section_one']['foo']
   end
@@ -262,7 +260,7 @@
   def test_initialize_from_string
     content = File.read('test/data/good.ini')
 
-    ini_file = IniFile.new(content, :comment => ';')
+    ini_file = IniFile.new(:content => content, :comment => ';')
     assert ini_file.has_section?('section_one')
     assert ini_file.has_section?('section_two')
     assert ini_file.has_section?('section three')
@@ -272,6 +270,35 @@
     assert_equal '7 & 8', ini_file['section_five']['seven and eight']
   end
 
+  def test_initialize_from_hash
+    hash = {
+      'section one' => {
+        'foo' => 'bar',
+        'baz' => 'buz'
+      },
+      'colors' => {
+        'perrywinkle' => '7e6ff3',
+        'steelblue' => '4682b4'
+      },
+      'empty' => nil
+    }
+
+    ini_file = IniFile.new(:content => hash)
+    assert ini_file.has_section?('section one')
+    assert ini_file.has_section?('colors')
+    assert ini_file.has_section?('empty')
+
+    assert_equal %w[baz foo], ini_file['section one'].keys.sort
+    assert_equal 'bar', ini_file['section one']['foo']
+    assert_equal 'buz', ini_file['section one']['baz']
+
+    assert_equal %w[perrywinkle steelblue], ini_file['colors'].keys.sort
+    assert_equal '7e6ff3', ini_file['colors']['perrywinkle']
+    assert_equal '4682b4', ini_file['colors']['steelblue']
+
+    assert_empty ini_file['empty']
+  end
+
   def test_sections
     expected = [
       'section_one', 'section_two', 'section three',
@@ -323,8 +350,8 @@
     assert_equal 42, @ini_file['section_one']['two']
 
     @ini_file.read
-    assert_equal '1', @ini_file['section_one']['one']
-    assert_equal '2', @ini_file['section_one']['two']
+    assert_equal 1, @ini_file['section_one']['one']
+    assert_equal 2, @ini_file['section_one']['two']
 
     @ini_file.read(:filename => 'test/data/mixed_comment.ini')
     assert_equal false, @ini_file.has_section?('section_two')
@@ -392,61 +419,73 @@
     assert_equal expected, multiple
 
     multiple = ini_file['empty_lines']
-    expected = {'empty' => '', 'not_empty' => 'full'}
+    expected = {'empty' => nil, 'not_empty' => 'full'}
     assert_equal expected, multiple
   end
 
   def test_merge
     ini_file = @ini_file.merge(IniFile.load("test/data/merge.ini"))
-    assert_equal '3', ini_file['section_one']['one']
-    assert_equal '2', ini_file['section_one']['two']
+    assert_equal 3, ini_file['section_one']['one']
+    assert_equal 2, ini_file['section_one']['two']
 
     # make sure that the rest haven't changed
-    assert_equal '3', ini_file['section_two']['three']
+    assert_equal(-3, ini_file['section_two']['three'])
 
     # and that we got any additional sections too
-    assert_equal '5', ini_file['section_five']['five']
+    assert_equal 5, ini_file['section_five']['five']
 
     # original object is unchanged
-    assert_equal '1', @ini_file['section_one']['one']
+    assert_equal 1, @ini_file['section_one']['one']
   end
 
   def test_merge_hash
     ini_file = @ini_file.merge({
-      'section_one'  => { 'one'  => '3' },
-      'section_five' => { 'five' => '5' }
+      'section_one'  => { 'one'  => 3 },
+      'section_five' => { 'five' => 5 }
     })
-    assert_equal '3', ini_file['section_one']['one']
-    assert_equal '2', ini_file['section_one']['two']
+    assert_equal 3, ini_file['section_one']['one']
+    assert_equal 2, ini_file['section_one']['two']
 
     # make sure that the rest haven't changed
-    assert_equal '3', ini_file['section_two']['three']
+    assert_equal(-3, ini_file['section_two']['three'])
 
     # and that we got any additional sections too
-    assert_equal '5', ini_file['section_five']['five']
+    assert_equal 5, ini_file['section_five']['five']
 
     # original object is unchanged
-    assert_equal '1', @ini_file['section_one']['one']
+    assert_equal 1, @ini_file['section_one']['one']
   end
 
-  if RUBY_VERSION >= '1.9'
-    def test_parse_encoding
-      ini_file = IniFile.new(:filename => "test/data/browscap.ini", :encoding 
=> 'ISO-8859-1')
-      assert_equal ini_file['www.substancia.com AutoHTTPAgent (ver 
*)']['Browser'], "Subst\xE2ncia".force_encoding('ISO-8859-1')
-    end
+  def test_merge_invalid_hash
+    bad_hash = { 'section_one' => [1, 2, 3, 4] }
+    assert_raise(IniFile::Error) { @ini_file.merge(bad_hash) }
+
+    bad_hash = { 'foo' => 'bar' }
+    assert_raise(IniFile::Error) { @ini_file.merge(bad_hash) }
 
-    def test_write_encoding
-      tmp = 'test/data/tmp.ini'
-      File.delete tmp if Kernel.test(?f, tmp)
+    not_a_hash = [['section_one', ['foo','bar'], ['baz', 'buz']]]
+    assert_raise(IniFile::Error) { @ini_file.merge(not_a_hash) }
 
-      @ini_file = IniFile.new(:filename => tmp, :encoding => 'UTF-8')
-      @ini_file['testutf-8'] = {"utf-8" => "appr\u20accier"}
+    ini_file = @ini_file.merge nil
+    assert ini_file.eql?(@ini_file)
+  end
 
-      @ini_file.save(:filename => tmp)
+  def test_parse_encoding
+    ini_file = IniFile.new(:filename => "test/data/browscap.ini", :encoding => 
'ISO-8859-1')
+    assert_equal ini_file['www.substancia.com AutoHTTPAgent (ver 
*)']['Browser'], "Subst\xE2ncia".force_encoding('ISO-8859-1')
+  end
 
-      test = File.open(tmp)
-      assert_equal test.external_encoding.to_s, 'UTF-8'
-    end
+  def test_write_encoding
+    tmp = 'test/data/tmp.ini'
+    File.delete tmp if Kernel.test(?f, tmp)
+
+    @ini_file = IniFile.new(:filename => tmp, :encoding => 'UTF-8')
+    @ini_file['testutf-8'] = {"utf-8" => "appr\u20accier"}
+
+    @ini_file.save(:filename => tmp)
+
+    test = File.open(tmp)
+    assert_equal test.external_encoding.to_s, 'UTF-8'
   end
 
   def test_value_escaping
@@ -461,32 +500,62 @@
     assert_equal %Q{Escaping works\tinside quoted strings!}, escaped['quoted']
   end
 
+  # disabling escaping is no longer supported
   def test_value_escaping_disabled
     ini_file = IniFile.load('test/data/escape.ini', :escape => false)
     escaped = ini_file['escaped']
 
-    assert_equal %q{There is a tab\tcharacter in here somewhere}, 
escaped['tabs']
-    assert_equal %q{Who uses these anyways?\r}, escaped['carriage return']
-    assert_equal %q{Trust newline!\nAlways there when you need him.\nSplittin' 
those lines.}, escaped['newline']
-    assert_equal %Q{Who'd be silly enough to put\\0 a null character in the 
middle of a string? Stroustrup would not approve!}, escaped['null']
-    assert_equal %q{This string \\\\t contains \\\\n no \\\\r special \\\\0 
characters!}, escaped['backslash']
-    assert_equal %q{Escaping works\tinside quoted strings!}, escaped['quoted']
+    assert_equal %Q{There is a tab\tcharacter in here somewhere}, 
escaped['tabs']
+    assert_equal %Q{Who uses these anyways?\r}, escaped['carriage return']
+    assert_equal %Q{Trust newline!\nAlways there when you need him.\nSplittin' 
those lines.}, escaped['newline']
+    assert_equal %Q{Who'd be silly enough to put\0 a null character in the 
middle of a string? Stroustrup would not approve!}, escaped['null']
+    assert_equal %q{This string \t contains \n no \r special \0 characters!}, 
escaped['backslash']
+    assert_equal %Q{Escaping works\tinside quoted strings!}, escaped['quoted']
   end
 
   def test_global_section
     ini_file = IniFile.load('test/data/global.ini')
 
     assert_equal %w[global], ini_file.sections
-    assert_equal '1', ini_file['global']['one']
-    assert_equal '2', ini_file['global']['two']
+    assert_equal 1, ini_file['global']['one']
+    assert_equal 2, ini_file['global']['two']
   end
 
   def test_default_global_section
     ini_file = IniFile.load('test/data/global.ini', :default => 'nonce')
 
     assert_equal %w[nonce], ini_file.sections
-    assert_equal '1', ini_file['nonce']['one']
-    assert_equal '2', ini_file['nonce']['two']
+    assert_equal 1, ini_file['nonce']['one']
+    assert_equal 2, ini_file['nonce']['two']
+  end
+
+  def test_unescaped_section_header_as_value
+    ini_file = IniFile.load('test/data/section.ini')
+
+    assert_equal %w[section_one], ini_file.sections
+    assert_equal '[value]', ini_file['section_one']['one']
+    assert_equal 2, ini_file['section_one']['two']
+  end
+
+  def test_unmatched_quotes
+    # missing a closing quote should raise an error
+    assert_raise(IniFile::Error) { IniFile.load 'test/data/bad_2.ini' }
+  end
+
+  def test_continuation_at_end_of_file
+    ini_file = IniFile.load('test/data/continuation.ini')
+
+    assert_equal 1, ini_file['section_one']['one']
+    assert_equal 2, ini_file['section_one']['two']
+
+    assert_equal 'here is the last value', 
ini_file['section_two']['end-of-file']
+  end
+
+  def test_empty_comment_string
+    ini_file = IniFile.load('test/data/merge.ini', :comment => nil)
+
+    assert_equal 3, ini_file['section_one']['one']
+    assert_equal 5, ini_file['section_five']['five']
   end
 end
 

-- 
To unsubscribe, e-mail: opensuse-commit+unsubscr...@opensuse.org
For additional commands, e-mail: opensuse-commit+h...@opensuse.org

Reply via email to