inifile 0.4.1 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ # The list of files that should be ignored by Mr Bones.
2
+ # Lines that start with '#' are comments.
3
+ #
4
+ # A .gitignore file can be used instead by setting it as the ignore
5
+ # file in your Rakefile:
6
+ #
7
+ # PROJ.ignore_file = '.gitignore'
8
+ #
9
+ # For a project with a C extension, the following would be a good set of
10
+ # exclude patterns (uncomment them if you want to use them):
11
+ # *.[oa]
12
+ *~
13
+ *.sw[op]
14
+ announcement.txt
15
+ coverage
16
+ doc
17
+ pkg
@@ -1,3 +1,12 @@
1
+ == 1.0.0 / 2012-02-27
2
+
3
+ Major Enhancements
4
+ - Changed how multi-line values are handled [issue #7]
5
+ - Added backslash escaping support for values
6
+ Enhancements
7
+ - Inifile merge functionality [Jens Hilligsøe]
8
+ - Use regular expressions to find sections [issue 8]
9
+
1
10
  == 0.4.1 / 2011-02-22
2
11
 
3
12
  Bug Fixes
@@ -0,0 +1,164 @@
1
+ inifile
2
+ =======
3
+
4
+ This is a native Ruby package for reading and writing INI files.
5
+
6
+
7
+ Description
8
+ -----------
9
+
10
+ Although made popular by Windows, INI files can be used on any system thanks
11
+ to their flexibility. They allow a program to store configuration data, which
12
+ can then be easily parsed and changed. Two notable systems that use the INI
13
+ format are Samba and Trac.
14
+
15
+ More information about INI files can be found on the [Wikipedia Page](http://en.wikipedia.org/wiki/INI_file).
16
+
17
+ ### Properties
18
+
19
+ The basic element contained in an INI file is the property. Every property has
20
+ a name and a value, delimited by an equals sign *=*. The name appears to the
21
+ left of the equals sign and the value to the right.
22
+
23
+ name=value
24
+
25
+ All properties must exist within a section. If the file contains a property
26
+ before the first section is declared, an error will be raised.
27
+
28
+ ### Sections
29
+
30
+ Section declarations start with *[* and end with *]* as in `[section1]` and
31
+ `[section2]` shown in the example below. The section declaration marks the
32
+ beginning of a section. All properties after the section declaration will be
33
+ associated with that section.
34
+
35
+ ### Comments
36
+
37
+ All lines beginning with a semicolon *;* or a number sign *#* are considered
38
+ to be comments. Comment lines are ignored when parsing INI files.
39
+
40
+ ### Example File Format
41
+
42
+ A typical INI file might look like this:
43
+
44
+ [section1]
45
+ ; some comment on section1
46
+ var1 = foo
47
+ var2 = doodle
48
+ var3 = multiline values \
49
+ are also possible
50
+
51
+ [section2]
52
+ # another comment
53
+ var1 = baz
54
+ var2 = shoodle
55
+
56
+
57
+ Implementation
58
+ --------------
59
+
60
+ The format of INI files is not well defined. Several assumptions are made by
61
+ the **inifile** gem when parsing INI files. Most of these assumptions can be
62
+ modified at, but the defaults are listed below.
63
+
64
+ ### Duplicate Properties
65
+
66
+ Duplicate properties are allowed in a single section. The last property value
67
+ set is the one that will be stored in the `IniFile` instance.
68
+
69
+ [section1]
70
+ var1 = foo
71
+ var2 = bar
72
+ var1 = poodle
73
+
74
+ The resulting value of `var1` will be `poodle`.
75
+
76
+ ### Duplicate Sections
77
+
78
+ If you have more than one section with the same name then the sections will be
79
+ merged. Duplicate properties between the two sections will follow the rules
80
+ discussed above. Properties in the latter section will override properties in
81
+ the earlier section.
82
+
83
+ ### Comments
84
+
85
+ The comment character can be either a semicolon *;* or a number sign *#*. The
86
+ comment character must be the first non-whitespace character on the line. This
87
+ means it is perfectly valid to include a comment character inside a **value**
88
+ or event a property **name** (although this is not recommended). For this
89
+ reason, comments cannot be placed on the end of a line after a name/value
90
+ pair.
91
+
92
+ ### Escape Characters
93
+
94
+ Several escape characters are supported within the **value** for a property.
95
+ Most notably, a backslash *\* at the end of a line will continue the value
96
+ onto the next line. When parsed, a literal newline will appear in the value.
97
+
98
+ * \0 -- null character
99
+ * \n -- newline character
100
+ * \r -- carriage return character
101
+ * \t -- tab character
102
+ * \\\\ -- backslash character
103
+
104
+ The backslash escape sequence is only needed if you want one of the escape
105
+ sequences to appear literally in your value. For example:
106
+
107
+ property=this is not a tab \\t character
108
+
109
+
110
+ Install
111
+ -------
112
+
113
+ gem install inifile
114
+
115
+
116
+ Testing
117
+ -------
118
+
119
+ To run the tests:
120
+
121
+ $ rake
122
+
123
+
124
+ Contributing
125
+ ------------
126
+
127
+ Contributions are gladly welcome! For small modifications (fixing typos,
128
+ improving documentation) you can use GitHub's in-browser editing capabilities
129
+ to create a pull request. For larger modifications I would recommend forking
130
+ the project, creating your patch, and then submitting a pull request.
131
+
132
+ Mr Bones is used to manage rake tasks and to install dependent files. To setup
133
+ your environment ...
134
+
135
+ $ gem install bones
136
+ $ rake gem:install_dependencies
137
+
138
+ And always remember that `rake -T` will show you the list of available tasks.
139
+
140
+
141
+ License
142
+ -------
143
+
144
+ MIT License
145
+ Copyright (c) 2006 - 2012
146
+
147
+ Permission is hereby granted, free of charge, to any person obtaining
148
+ a copy of this software and associated documentation files (the
149
+ 'Software'), to deal in the Software without restriction, including
150
+ without limitation the rights to use, copy, modify, merge, publish,
151
+ distribute, sublicense, and/or sell copies of the Software, and to
152
+ permit persons to whom the Software is furnished to do so, subject to
153
+ the following conditions:
154
+
155
+ The above copyright notice and this permission notice shall be
156
+ included in all copies or substantial portions of the Software.
157
+
158
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
159
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
160
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
161
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
162
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
163
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
164
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile CHANGED
@@ -16,9 +16,8 @@ Bones {
16
16
  summary 'INI file reader and writer'
17
17
  authors 'Tim Pease'
18
18
  email 'tim.pease@gmail.com'
19
- url 'http://gemcutter.org/gems/inifile'
19
+ url 'http://rubygems.org/gems/inifile'
20
20
  version IniFile::VERSION
21
- ignore_file '.gitignore'
22
21
 
23
22
  use_gmail
24
23
  depend_on 'bones-git', :development => true
@@ -12,7 +12,7 @@ class IniFile
12
12
 
13
13
  # :stopdoc:
14
14
  class Error < StandardError; end
15
- VERSION = '0.4.1'
15
+ VERSION = '1.0.0'
16
16
  # :startdoc:
17
17
 
18
18
  #
@@ -20,11 +20,13 @@ class IniFile
20
20
  # IniFile.load( filename )
21
21
  # IniFile.load( filename, options )
22
22
  #
23
- # Open the given _filename_ and load the contetns of the INI file.
23
+ # Open the given _filename_ and load the contents of the INI file.
24
24
  # The following _options_ can be passed to this method:
25
25
  #
26
26
  # :comment => ';' The line comment character(s)
27
27
  # :parameter => '=' The parameter / value separator
28
+ # :encoding => nil The encoding used for read/write (RUBY 1.9)
29
+ # :escape => true Whether or not to escape values when reading/writing
28
30
  #
29
31
  def self.load( filename, opts = {} )
30
32
  new(filename, opts)
@@ -42,21 +44,19 @@ class IniFile
42
44
  # :comment => ';' The line comment character(s)
43
45
  # :parameter => '=' The parameter / value separator
44
46
  # :encoding => nil The encoding used for read/write (RUBY 1.9)
47
+ # :escape => true Whether or not to escape values when reading/writing
45
48
  #
46
49
  def initialize( filename, opts = {} )
47
50
  @fn = filename
48
- @comment = opts[:comment] || ';#'
49
- @param = opts[:parameter] || '='
50
- @encoding = opts[:encoding]
51
+ @comment = opts.fetch(:comment, ';#')
52
+ @param = opts.fetch(:parameter, '=')
53
+ @encoding = opts.fetch(:encoding, nil)
54
+ @escape = opts.fetch(:escape, true)
51
55
  @ini = Hash.new {|h,k| h[k] = Hash.new}
52
56
 
53
57
  @rgxp_comment = %r/\A\s*\z|\A\s*[#{@comment}]/
54
- @rgxp_section = %r/\A\s*\[([^\]]+)\]/o
55
- @rgxp_param = %r/\A([^#{@param}]+)#{@param}\s*"?([^"]*)"?\z/
56
-
57
- @rgxp_multiline_start = %r/\A([^#{@param}]+)#{@param}\s*"([^"]*)?\z/
58
- @rgxp_multiline_value = %r/\A([^"]*)\z/
59
- @rgxp_multiline_end = %r/\A([^"]*)"\z/
58
+ @rgxp_section = %r/\A\s*\[([^\]]+)\]/
59
+ @rgxp_param = %r/[^\\]#{@param}/
60
60
 
61
61
  parse
62
62
  end
@@ -66,7 +66,7 @@ class IniFile
66
66
  # write
67
67
  # write( filename )
68
68
  #
69
- # Write the INI file contents to the filesystem. The given _filename_
69
+ # Write the INI file contents to the file system. The given _filename_
70
70
  # will be used to write the file. If _filename_ is not given, then the
71
71
  # named used when constructing this object will be used.
72
72
  # The following _options_ can be passed to this method:
@@ -84,7 +84,7 @@ class IniFile
84
84
  File.open(@fn, mode) do |f|
85
85
  @ini.each do |section,hash|
86
86
  f.puts "[#{section}]"
87
- hash.each {|param,val| f.puts "#{param} #{@param} #{val}"}
87
+ hash.each {|param,val| f.puts "#{param} #{@param} #{escape val}"}
88
88
  f.puts
89
89
  end
90
90
  end
@@ -102,7 +102,7 @@ class IniFile
102
102
  s = []
103
103
  @ini.each do |section,hash|
104
104
  s << "[#{section}]"
105
- hash.each {|param,val| s << "#{param} #{@param} #{val}"}
105
+ hash.each {|param,val| s << "#{param} #{@param} #{escape val}"}
106
106
  s << ""
107
107
  end
108
108
  s.join("\n")
@@ -118,6 +118,43 @@ class IniFile
118
118
  @ini.dup
119
119
  end
120
120
 
121
+ #
122
+ # call-seq:
123
+ # merge( other_inifile )
124
+ #
125
+ # Returns a copy of this inifile with the entries from the other_inifile
126
+ # merged into the copy.
127
+ #
128
+ def merge( other )
129
+ self.dup.merge!(other)
130
+ end
131
+
132
+ #
133
+ # call-seq:
134
+ # merge!( other_inifile )
135
+ #
136
+ # Merges other_inifile into this inifile, overwriting existing entries.
137
+ # Useful for having a system inifile with user overridable settings elsewhere.
138
+ #
139
+ def merge!( other )
140
+ my_keys = @ini.keys
141
+ other_keys =
142
+ case other
143
+ when IniFile; other.instance_variable_get(:@ini).keys
144
+ when Hash; other.keys
145
+ else raise "cannot merge contents from '#{other.class.name}'" end
146
+
147
+ (my_keys & other_keys).each do |key|
148
+ @ini[key].merge!(other[key])
149
+ end
150
+
151
+ (other_keys - my_keys).each do |key|
152
+ @ini[key] = other[key]
153
+ end
154
+
155
+ self
156
+ end
157
+
121
158
  #
122
159
  # call-seq:
123
160
  # each {|section, parameter, value| block}
@@ -182,6 +219,17 @@ class IniFile
182
219
  @ini[section.to_s] = value
183
220
  end
184
221
 
222
+ #
223
+ # call-seq:
224
+ # ini_file.match( /section/ ) #=> hash
225
+ #
226
+ # Return a hash containing only those sections that match the given regular
227
+ # expression.
228
+ #
229
+ def match( regex )
230
+ @ini.dup.delete_if { |section, _| section !~ regex }
231
+ end
232
+
185
233
  #
186
234
  # call-seq:
187
235
  # has_section?( section )
@@ -236,7 +284,7 @@ class IniFile
236
284
  #
237
285
  # Produces a duplicate of this INI file. The duplicate is independent of the
238
286
  # original -- i.e. the duplicate can be modified without changing the
239
- # orgiinal. The tainted state of the original is copied to the duplicate.
287
+ # original. The tainted state of the original is copied to the duplicate.
240
288
  #
241
289
  def dup
242
290
  other = super
@@ -252,7 +300,7 @@ class IniFile
252
300
  #
253
301
  # Produces a duplicate of this INI file. The duplicate is independent of the
254
302
  # original -- i.e. the duplicate can be modified without changing the
255
- # orgiinal. The tainted state and the frozen state of the original is copied
303
+ # original. The tainted state and the frozen state of the original is copied
256
304
  # to the duplicate.
257
305
  #
258
306
  def clone
@@ -287,19 +335,16 @@ class IniFile
287
335
  parse
288
336
  end
289
337
 
290
- private
291
- #
292
- # call-seq
293
- # parse
294
- #
338
+ private
339
+
295
340
  # Parse the ini file contents.
296
341
  #
297
342
  def parse
298
343
  return unless File.file?(@fn)
299
344
 
300
- section = nil
301
- tmp_value = ""
302
- tmp_param = ""
345
+ @_current_section = nil
346
+ @_current_param = nil
347
+ @_current_value = nil
303
348
 
304
349
  fd = (RUBY_VERSION >= '1.9' && @encoding) ?
305
350
  File.open(@fn, 'r', :encoding => @encoding) :
@@ -308,53 +353,103 @@ class IniFile
308
353
  while line = fd.gets
309
354
  line = line.chomp
310
355
 
311
- # mutline start
312
- # create tmp variables to indicate that a multine has started
313
- # and the next lines of the ini file will be checked
314
- # against the other mutline rgxps.
315
- if line =~ @rgxp_multiline_start then
356
+ # we ignore comment lines and blank lines
357
+ if line =~ @rgxp_comment
358
+ finish_property
359
+ next
360
+ end
316
361
 
317
- tmp_param = $1.strip
318
- tmp_value = $2 + "\n"
362
+ # place values in the current section
363
+ if line =~ @rgxp_section
364
+ finish_property
365
+ @_current_section = @ini[$1.strip]
366
+ next
367
+ end
319
368
 
320
- # the mutline end-delimiter is found
321
- # clear the tmp vars and add the param / value pair to the section
322
- elsif line =~ @rgxp_multiline_end && tmp_param != "" then
369
+ parse_property line
370
+
371
+ end # while
372
+
373
+ finish_property
374
+ ensure
375
+ fd.close if defined? fd and fd
376
+ @_current_section = nil
377
+ @_current_param = nil
378
+ @_current_value = nil
379
+ end
323
380
 
324
- section[tmp_param] = tmp_value + $1
325
- tmp_value, tmp_param = "", ""
381
+ # Attempt to parse a property name and value from the given _line_. This
382
+ # method takes into account multi-line values.
383
+ #
384
+ def parse_property( line )
385
+ p = v = nil
386
+ split = line =~ @rgxp_param
326
387
 
327
- # anything else between multiline start and end
328
- elsif line =~ @rgxp_multiline_value && tmp_param != "" then
388
+ if split
389
+ p = line.slice(0, split+1).strip
390
+ v = line.slice(split+2, line.length).strip
391
+ else
392
+ v = line
393
+ end
329
394
 
330
- tmp_value += $1 + "\n"
395
+ if p.nil? and @_current_param.nil?
396
+ raise Error, "could not parse line '#{line}'"
397
+ end
331
398
 
332
- # ignore blank lines and comment lines
333
- elsif line =~ @rgxp_comment then
399
+ @_current_param = p unless p.nil?
334
400
 
335
- next
401
+ if @_current_value then @_current_value << v
402
+ else @_current_value = v end
336
403
 
337
- # this is a section declaration
338
- elsif line =~ @rgxp_section then
404
+ finish_property unless @_current_value.sub!(%r/\\\z/, "\n")
405
+ end
339
406
 
340
- section = @ini[$1.strip]
407
+ # If there is a current property being parsed, finish this parse step by
408
+ # storing the name and value in the current section and resetting for the
409
+ # next parse step.
410
+ #
411
+ def finish_property
412
+ return unless @_current_param
341
413
 
342
- # otherwise we have a parameter
343
- elsif line =~ @rgxp_param then
414
+ raise Error, "parameter encountered before first section" if @_current_section.nil?
415
+ @_current_section[@_current_param] = unescape @_current_value
344
416
 
345
- begin
346
- section[$1.strip] = $2.strip
347
- rescue NoMethodError
348
- raise Error, "parameter encountered before first section"
349
- end
417
+ @_current_param = nil
418
+ @_current_value = nil
419
+ end
350
420
 
351
- else
352
- raise Error, "could not parse line '#{line}"
421
+ # Unescape special characters found in the value string. This will convert
422
+ # escaped null, tab, carriage return, newline, and backslash into their
423
+ # literal equivalents.
424
+ #
425
+ def unescape( value )
426
+ return value unless @escape
427
+
428
+ value = value.to_s
429
+ value.gsub!(%r/\\[0nrt\\]/) { |char|
430
+ case char
431
+ when '\0'; "\0"
432
+ when '\n'; "\n"
433
+ when '\r'; "\r"
434
+ when '\t'; "\t"
435
+ when '\\\\'; "\\"
353
436
  end
354
- end # while
437
+ }
438
+ value
439
+ end
355
440
 
356
- ensure
357
- fd.close if defined? fd and fd
441
+ # Escape special characters
442
+ #
443
+ def escape( value )
444
+ return value unless @escape
445
+
446
+ value = value.to_s.dup
447
+ value.gsub!(%r/\\([0nrt])/, '\\\\\1')
448
+ value.gsub!(%r/\n/, '\n')
449
+ value.gsub!(%r/\r/, '\r')
450
+ value.gsub!(%r/\t/, '\t')
451
+ value.gsub!(%r/\0/, '\0')
452
+ value
358
453
  end
359
454
 
360
455
  end # IniFile
@@ -0,0 +1,12 @@
1
+ ; this test file demonstrates escape sequences supported by IniFile
2
+ [normal]
3
+ foo = http://en.wikipedia.org/wiki/Foobar
4
+
5
+ [escaped]
6
+ tabs = There is a tab\tcharacter in here somewhere
7
+ carriage return = Who uses these anyways?\r
8
+ newline = Trust newline!\nAlways there when you need him.\nSplittin' those lines.
9
+ null = Who'd be silly enough to put\0 a null character in the middle of a string?\
10
+ Stroustrup would not approve!
11
+ backslash = This string \\t contains \\n no \\r special \\0 characters!
12
+
@@ -4,8 +4,8 @@ two = 2
4
4
 
5
5
  [section_two]
6
6
  three = 3
7
- multi = "multiline
8
- support"
7
+ multi = multiline\
8
+ support
9
9
 
10
10
  ; comments should be ignored
11
11
  [section three]
@@ -0,0 +1,5 @@
1
+ [section_one]
2
+ one = 3
3
+
4
+ [section_five]
5
+ five=5
@@ -1,5 +1,5 @@
1
1
  # comments should be ignored
2
- ; multiple comments characeters are supported
2
+ ; multiple comments characters are supported
3
3
  ; (I'm lookin' at you, samba)
4
4
  [section_one]
5
5
  one = 1
@@ -7,15 +7,15 @@ three = 3
7
7
 
8
8
  ; comments should be ignored
9
9
  [section_three]
10
- three = "hello
11
- multiline"
10
+ three = hello\
11
+ multiline
12
12
  other = "stuff"
13
13
 
14
14
  [section_four]
15
- four = "hello
16
- multiple
17
- multilines"
15
+ four = hello\
16
+ multiple\
17
+ multilines
18
18
 
19
19
  [empty_lines]
20
- empty = ""
20
+ empty =
21
21
  not_empty=full
@@ -4,17 +4,11 @@
4
4
 
5
5
  # encoding: UTF-8
6
6
 
7
- begin
8
- require 'inifile'
9
- rescue LoadError
10
- require 'rubygems'
11
- require 'inifile'
12
- end
13
-
7
+ libpath = File.expand_path '../../lib', __FILE__
8
+ require File.join(libpath, 'inifile')
14
9
  require 'fileutils'
10
+ require 'test/unit'
15
11
 
16
- begin; require 'turn'; rescue LoadError; end
17
- require 'test/unit' unless defined? $ZENTEST and $ZENTEST
18
12
 
19
13
  class TestIniFile < Test::Unit::TestCase
20
14
 
@@ -223,6 +217,26 @@ class TestIniFile < Test::Unit::TestCase
223
217
  assert_nil ini_file[nil]
224
218
  end
225
219
 
220
+ def test_match
221
+ expected = {
222
+ "section_two" =>
223
+ {
224
+ "three"=>"3", "multi"=>"multiline\nsupport"
225
+ },
226
+ "section three" =>
227
+ {
228
+ "four"=>"4", "five"=>"5", "six"=>"6"
229
+ }
230
+ }
231
+ assert_equal expected, @ini_file.match(/(two|three)/)
232
+
233
+ # the match function should not delete entries from the inifile hash
234
+ assert_equal({'seven and eight' => '7 & 8'}, @ini_file['section_five'])
235
+
236
+ expected = {}
237
+ assert_equal expected, @ini_file.match(/houndreds/)
238
+ end
239
+
226
240
  def test_initialize
227
241
  # see if we can parse different style comments
228
242
  #assert_raise(IniFile::Error) {IniFile.new 'test/data/comment.ini'}
@@ -338,7 +352,7 @@ class TestIniFile < Test::Unit::TestCase
338
352
  ini_file = IniFile.load('test/data/multiline.ini')
339
353
 
340
354
  multiline = ini_file['section_three']
341
- expected = {"three" => "hello\nmultiline", "other" => "stuff"}
355
+ expected = {"three" => "hello\nmultiline", "other" => '"stuff"'}
342
356
  assert_equal expected, multiline
343
357
 
344
358
  multiple = ini_file['section_four']
@@ -347,7 +361,40 @@ class TestIniFile < Test::Unit::TestCase
347
361
 
348
362
  multiple = ini_file['empty_lines']
349
363
  expected = {'empty' => '', 'not_empty' => 'full'}
364
+ assert_equal expected, multiple
365
+ end
366
+
367
+ def test_merge
368
+ ini_file = @ini_file.merge(IniFile.load("test/data/merge.ini"))
369
+ assert_equal '3', ini_file['section_one']['one']
370
+ assert_equal '2', ini_file['section_one']['two']
371
+
372
+ # make sure that the rest haven't changed
373
+ assert_equal '3', ini_file['section_two']['three']
350
374
 
375
+ # and that we got any additional sections too
376
+ assert_equal '5', ini_file['section_five']['five']
377
+
378
+ # original object is unchanged
379
+ assert_equal '1', @ini_file['section_one']['one']
380
+ end
381
+
382
+ def test_merge_hash
383
+ ini_file = @ini_file.merge({
384
+ 'section_one' => { 'one' => '3' },
385
+ 'section_five' => { 'five' => '5' }
386
+ })
387
+ assert_equal '3', ini_file['section_one']['one']
388
+ assert_equal '2', ini_file['section_one']['two']
389
+
390
+ # make sure that the rest haven't changed
391
+ assert_equal '3', ini_file['section_two']['three']
392
+
393
+ # and that we got any additional sections too
394
+ assert_equal '5', ini_file['section_five']['five']
395
+
396
+ # original object is unchanged
397
+ assert_equal '1', @ini_file['section_one']['one']
351
398
  end
352
399
 
353
400
  if RUBY_VERSION >= '1.9'
@@ -370,5 +417,27 @@ class TestIniFile < Test::Unit::TestCase
370
417
  end
371
418
  end
372
419
 
420
+ def test_value_escaping
421
+ ini_file = IniFile.load('test/data/escape.ini')
422
+ escaped = ini_file['escaped']
423
+
424
+ assert_equal %Q{There is a tab\tcharacter in here somewhere}, escaped['tabs']
425
+ assert_equal %Q{Who uses these anyways?\r}, escaped['carriage return']
426
+ assert_equal %Q{Trust newline!\nAlways there when you need him.\nSplittin' those lines.}, escaped['newline']
427
+ assert_equal %Q{Who'd be silly enough to put\0 a null character in the middle of a string?\nStroustrup would not approve!}, escaped['null']
428
+ assert_equal %q{This string \t contains \n no \r special \0 characters!}, escaped['backslash']
429
+ end
430
+
431
+ def test_value_escaping_disabled
432
+ ini_file = IniFile.load('test/data/escape.ini', :escape => false)
433
+ escaped = ini_file['escaped']
434
+
435
+ assert_equal %q{There is a tab\tcharacter in here somewhere}, escaped['tabs']
436
+ assert_equal %q{Who uses these anyways?\r}, escaped['carriage return']
437
+ assert_equal %q{Trust newline!\nAlways there when you need him.\nSplittin' those lines.}, escaped['newline']
438
+ assert_equal %Q{Who'd be silly enough to put\\0 a null character in the middle of a string?\nStroustrup would not approve!}, escaped['null']
439
+ assert_equal %q{This string \\\\t contains \\\\n no \\\\r special \\\\0 characters!}, escaped['backslash']
440
+ end
441
+
373
442
  end
374
443
 
metadata CHANGED
@@ -1,129 +1,104 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: inifile
3
- version: !ruby/object:Gem::Version
4
- hash: 13
5
- prerelease: false
6
- segments:
7
- - 0
8
- - 4
9
- - 1
10
- version: 0.4.1
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ prerelease:
11
6
  platform: ruby
12
- authors:
7
+ authors:
13
8
  - Tim Pease
14
9
  autorequire:
15
10
  bindir: bin
16
11
  cert_chain: []
17
-
18
- date: 2011-02-22 00:00:00 -07:00
19
- default_executable:
20
- dependencies:
21
- - !ruby/object:Gem::Dependency
12
+ date: 2012-02-28 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
22
15
  name: bones-git
23
- prerelease: false
24
- requirement: &id001 !ruby/object:Gem::Requirement
16
+ requirement: &2157141580 !ruby/object:Gem::Requirement
25
17
  none: false
26
- requirements:
27
- - - ">="
28
- - !ruby/object:Gem::Version
29
- hash: 23
30
- segments:
31
- - 1
32
- - 2
33
- - 4
34
- version: 1.2.4
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.2.5
35
22
  type: :development
36
- version_requirements: *id001
37
- - !ruby/object:Gem::Dependency
38
- name: bones
39
23
  prerelease: false
40
- requirement: &id002 !ruby/object:Gem::Requirement
24
+ version_requirements: *2157141580
25
+ - !ruby/object:Gem::Dependency
26
+ name: bones
27
+ requirement: &2157140760 !ruby/object:Gem::Requirement
41
28
  none: false
42
- requirements:
43
- - - ">="
44
- - !ruby/object:Gem::Version
45
- hash: 21
46
- segments:
47
- - 3
48
- - 6
49
- - 5
50
- version: 3.6.5
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: 3.7.2
51
33
  type: :development
52
- version_requirements: *id002
53
- description: |-
54
- This is a native Ruby package for reading and writing INI files.
55
-
56
- Although made popular by Windows, INI files can be used on any system thanks
57
- to their flexibility. They allow a program to store configuration data, which
58
- can then be easily parsed and changed. Two notable systems that use the INI
59
- format are Samba and Trac.
60
-
61
- == SYNOPSIS:
62
-
63
- An initialization file, or INI file, is a configuration file that contains
64
- configuration data for Microsoft Windows based applications. Starting with
65
- Windows 95, the INI file format was superseded but not entirely replaced by
66
- a registry database in Microsoft operating systems.
67
-
68
- Although made popular by Windows, INI files can be used on any system thanks
69
- to their flexibility. They allow a program to store configuration data, which
70
- can then be easily parsed and changed.
34
+ prerelease: false
35
+ version_requirements: *2157140760
36
+ description: ! "Although made popular by Windows, INI files can be used on any system
37
+ thanks\nto their flexibility. They allow a program to store configuration data,
38
+ which\ncan then be easily parsed and changed. Two notable systems that use the INI\nformat
39
+ are Samba and Trac.\n\nMore information about INI files can be found on the [Wikipedia
40
+ Page](http://en.wikipedia.org/wiki/INI_file).\n\n### Properties\n\nThe basic element
41
+ contained in an INI file is the property. Every property has\na name and a value,
42
+ delimited by an equals sign *=*. The name appears to the\nleft of the equals sign
43
+ and the value to the right.\n\n name=value\n\nAll properties must exist within
44
+ a section. If the file contains a property\nbefore the first section is declared,
45
+ an error will be raised.\n\n### Sections\n\nSection declarations start with *[*
46
+ and end with *]* as in `[section1]` and\n`[section2]` shown in the example below.
47
+ The section declaration marks the\nbeginning of a section. All properties after
48
+ the section declaration will be\nassociated with that section.\n\n### Comments\n\nAll
49
+ lines beginning with a semicolon *;* or a number sign *#* are considered\nto be
50
+ comments. Comment lines are ignored when parsing INI files.\n\n### Example File
51
+ Format\n\nA typical INI file might look like this:\n\n [section1]\n ; some
52
+ comment on section1\n var1 = foo\n var2 = doodle\n var3 = multiline values
53
+ \\\n are also possible\n\n [section2]\n # another comment\n var1 = baz\n
54
+ \ var2 = shoodle"
71
55
  email: tim.pease@gmail.com
72
56
  executables: []
73
-
74
57
  extensions: []
75
-
76
- extra_rdoc_files:
58
+ extra_rdoc_files:
77
59
  - History.txt
78
- - README.txt
79
- files:
60
+ files:
61
+ - .gitignore
80
62
  - History.txt
81
- - README.txt
63
+ - README.md
82
64
  - Rakefile
83
65
  - lib/inifile.rb
84
66
  - test/data/bad_1.ini
85
67
  - test/data/bad_2.ini
86
68
  - test/data/browscap.ini
87
69
  - test/data/comment.ini
70
+ - test/data/escape.ini
88
71
  - test/data/good.ini
72
+ - test/data/merge.ini
89
73
  - test/data/mixed_comment.ini
90
74
  - test/data/multiline.ini
91
75
  - test/data/param.ini
92
76
  - test/test_inifile.rb
93
- has_rdoc: true
94
- homepage: http://gemcutter.org/gems/inifile
77
+ homepage: http://rubygems.org/gems/inifile
95
78
  licenses: []
96
-
97
79
  post_install_message:
98
- rdoc_options:
80
+ rdoc_options:
99
81
  - --main
100
- - README.txt
101
- require_paths:
82
+ - README.md
83
+ require_paths:
102
84
  - lib
103
- required_ruby_version: !ruby/object:Gem::Requirement
85
+ required_ruby_version: !ruby/object:Gem::Requirement
104
86
  none: false
105
- requirements:
106
- - - ">="
107
- - !ruby/object:Gem::Version
108
- hash: 3
109
- segments:
110
- - 0
111
- version: "0"
112
- required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
91
+ required_rubygems_version: !ruby/object:Gem::Requirement
113
92
  none: false
114
- requirements:
115
- - - ">="
116
- - !ruby/object:Gem::Version
117
- hash: 3
118
- segments:
119
- - 0
120
- version: "0"
93
+ requirements:
94
+ - - ! '>='
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
121
97
  requirements: []
122
-
123
98
  rubyforge_project: inifile
124
- rubygems_version: 1.3.7
99
+ rubygems_version: 1.8.11
125
100
  signing_key:
126
101
  specification_version: 3
127
102
  summary: INI file reader and writer
128
- test_files:
103
+ test_files:
129
104
  - test/test_inifile.rb
data/README.txt DELETED
@@ -1,101 +0,0 @@
1
- = inifile
2
- by Tim Pease
3
- http://codeforpeople.rubyforge.org/inifile
4
-
5
- == DESCRIPTION:
6
-
7
- This is a native Ruby package for reading and writing INI files.
8
-
9
- Although made popular by Windows, INI files can be used on any system thanks
10
- to their flexibility. They allow a program to store configuration data, which
11
- can then be easily parsed and changed. Two notable systems that use the INI
12
- format are Samba and Trac.
13
-
14
- == SYNOPSIS:
15
-
16
- An initialization file, or INI file, is a configuration file that contains
17
- configuration data for Microsoft Windows based applications. Starting with
18
- Windows 95, the INI file format was superseded but not entirely replaced by
19
- a registry database in Microsoft operating systems.
20
-
21
- Although made popular by Windows, INI files can be used on any system thanks
22
- to their flexibility. They allow a program to store configuration data, which
23
- can then be easily parsed and changed.
24
-
25
- === File Format
26
-
27
- A typical INI file might look like this:
28
-
29
- [section1]
30
-
31
- ; some comment on section1
32
- var1 = foo
33
- var2 = doodle
34
- var3 = "multiline
35
- also possible"
36
-
37
- [section2]
38
-
39
- ; another comment
40
- var1 = baz
41
- var2 = shoodle
42
-
43
-
44
- ==== Format
45
-
46
- This describes the elements of the INI file format:
47
-
48
- * *Sections*: Section declarations start with '[' and end with ']' as in [section1] and [section2] above. And sections start with section declarations.
49
- * *Parameters*: The "var1 = foo" above is an example of a parameter (also known as an item). Parameters are made up of a key ('var1'), equals sign ('='), and a value ('foo'). Multiline is support if value of parameter is enclosed by ".
50
- * *Comments*: All the lines starting with a ';' are assumed to be comments, and are ignored.
51
-
52
- ==== Differences
53
-
54
- The format of INI files is not well defined. Many programs interpret their
55
- structure differently than the basic structure that was defined in the above
56
- example. The following is a basic list of some of the differences:
57
-
58
- * *Comments*: Programs like Samba accept either ';' or '#' as comments. Comments can be added after parameters with several formats.
59
- * *Backslashes*: Adding a backslash '\' allows you to continue the value from one line to another. Some formats also allow various escapes with a '\', such as '\n' for newline.
60
- * <b>Duplicate parameters</b>: Most of the time, you can't have two parameters with the same name in one section. Therefore one can say that parameters are local to the section. Although this behavior can vary between implementations, it is advisable to stick with this rule.
61
- * <b>Duplicate sections</b>: If you have more than one section with the same name then the last section overrides the previous one. (Some implementations will merge them if they have different keys.)
62
- * Some implementations allow ':' in place of '='.
63
-
64
- === This Package
65
-
66
- This package supports the standard INI file format described in the *Format*
67
- section above. The following differences are also supported:
68
-
69
- * *Comments*: The comment character can be specified when an +IniFile+ is created. The comment character must be the first non-whitespace character on a line.
70
- * *Backslashes*: Backslashes are not supported by this package. But multilines are. Enclose the param's value by ".
71
- * <b>Duplicate parameters</b>: Duplicate parameters are allowed in a single section. The last parameter value is the one that will be stored in the +IniFile+.
72
- * <b>Duplicate sections</b>: Duplicate sections will be merged. Parameters duplicated between to the two sections follow the duplicate parameters rule above.
73
- * *Parameters*: The parameter separator character can be specified when an +IniFile+ is created.
74
-
75
- == INSTALL:
76
-
77
- sudo gem install inifile
78
-
79
- == LICENSE:
80
-
81
- MIT License
82
- Copyright (c) 2006 - 2008
83
-
84
- Permission is hereby granted, free of charge, to any person obtaining
85
- a copy of this software and associated documentation files (the
86
- 'Software'), to deal in the Software without restriction, including
87
- without limitation the rights to use, copy, modify, merge, publish,
88
- distribute, sublicense, and/or sell copies of the Software, and to
89
- permit persons to whom the Software is furnished to do so, subject to
90
- the following conditions:
91
-
92
- The above copyright notice and this permission notice shall be
93
- included in all copies or substantial portions of the Software.
94
-
95
- THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
96
- EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
97
- MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
98
- IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
99
- CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
100
- TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
101
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.