inifile 0.4.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/History.txt +9 -0
- data/README.md +164 -0
- data/Rakefile +1 -2
- data/lib/inifile.rb +152 -57
- data/test/data/escape.ini +12 -0
- data/test/data/good.ini +2 -2
- data/test/data/merge.ini +5 -0
- data/test/data/mixed_comment.ini +1 -1
- data/test/data/multiline.ini +6 -6
- data/test/test_inifile.rb +79 -10
- metadata +64 -89
- data/README.txt +0 -101
data/.gitignore
ADDED
@@ -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
|
data/History.txt
CHANGED
@@ -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
|
data/README.md
ADDED
@@ -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://
|
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
|
data/lib/inifile.rb
CHANGED
@@ -12,7 +12,7 @@ class IniFile
|
|
12
12
|
|
13
13
|
# :stopdoc:
|
14
14
|
class Error < StandardError; end
|
15
|
-
VERSION = '0.
|
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
|
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
|
49
|
-
@param = opts
|
50
|
-
@encoding = opts
|
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*\[([^\]]+)\]/
|
55
|
-
@rgxp_param = %r
|
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
|
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
|
-
#
|
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
|
-
#
|
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
|
-
|
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
|
-
|
301
|
-
|
302
|
-
|
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
|
-
#
|
312
|
-
|
313
|
-
|
314
|
-
|
315
|
-
|
356
|
+
# we ignore comment lines and blank lines
|
357
|
+
if line =~ @rgxp_comment
|
358
|
+
finish_property
|
359
|
+
next
|
360
|
+
end
|
316
361
|
|
317
|
-
|
318
|
-
|
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
|
-
|
321
|
-
|
322
|
-
|
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
|
-
|
325
|
-
|
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
|
-
|
328
|
-
|
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
|
-
|
395
|
+
if p.nil? and @_current_param.nil?
|
396
|
+
raise Error, "could not parse line '#{line}'"
|
397
|
+
end
|
331
398
|
|
332
|
-
|
333
|
-
elsif line =~ @rgxp_comment then
|
399
|
+
@_current_param = p unless p.nil?
|
334
400
|
|
335
|
-
|
401
|
+
if @_current_value then @_current_value << v
|
402
|
+
else @_current_value = v end
|
336
403
|
|
337
|
-
|
338
|
-
|
404
|
+
finish_property unless @_current_value.sub!(%r/\\\z/, "\n")
|
405
|
+
end
|
339
406
|
|
340
|
-
|
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
|
-
|
343
|
-
|
414
|
+
raise Error, "parameter encountered before first section" if @_current_section.nil?
|
415
|
+
@_current_section[@_current_param] = unescape @_current_value
|
344
416
|
|
345
|
-
|
346
|
-
|
347
|
-
|
348
|
-
raise Error, "parameter encountered before first section"
|
349
|
-
end
|
417
|
+
@_current_param = nil
|
418
|
+
@_current_value = nil
|
419
|
+
end
|
350
420
|
|
351
|
-
|
352
|
-
|
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
|
-
|
437
|
+
}
|
438
|
+
value
|
439
|
+
end
|
355
440
|
|
356
|
-
|
357
|
-
|
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
|
+
|
data/test/data/good.ini
CHANGED
data/test/data/merge.ini
ADDED
data/test/data/mixed_comment.ini
CHANGED
data/test/data/multiline.ini
CHANGED
@@ -7,15 +7,15 @@ three = 3
|
|
7
7
|
|
8
8
|
; comments should be ignored
|
9
9
|
[section_three]
|
10
|
-
three =
|
11
|
-
multiline
|
10
|
+
three = hello\
|
11
|
+
multiline
|
12
12
|
other = "stuff"
|
13
13
|
|
14
14
|
[section_four]
|
15
|
-
four =
|
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
|
data/test/test_inifile.rb
CHANGED
@@ -4,17 +4,11 @@
|
|
4
4
|
|
5
5
|
# encoding: UTF-8
|
6
6
|
|
7
|
-
|
8
|
-
|
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
|
-
|
5
|
-
prerelease:
|
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
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
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
|
-
|
79
|
-
|
60
|
+
files:
|
61
|
+
- .gitignore
|
80
62
|
- History.txt
|
81
|
-
- README.
|
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
|
-
|
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.
|
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
|
-
|
109
|
-
|
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
|
-
|
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.
|
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.
|