inifile 0.3.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,9 @@
1
+ == 0.4.0 / 2011-02-
2
+
3
+ Enhancements
4
+ - Added multiline support [André Gawron]
5
+ - Added file encoding support [Gilles Devaux]
6
+
1
7
  == 0.3.0 / 2009-12-10
2
8
 
3
9
  * 1 minor enhancement
data/README.txt CHANGED
@@ -31,6 +31,8 @@ A typical INI file might look like this:
31
31
  ; some comment on section1
32
32
  var1 = foo
33
33
  var2 = doodle
34
+ var3 = "multiline
35
+ also possible"
34
36
 
35
37
  [section2]
36
38
 
@@ -38,12 +40,13 @@ A typical INI file might look like this:
38
40
  var1 = baz
39
41
  var2 = shoodle
40
42
 
43
+
41
44
  ==== Format
42
45
 
43
46
  This describes the elements of the INI file format:
44
47
 
45
48
  * *Sections*: Section declarations start with '[' and end with ']' as in [section1] and [section2] above. And sections start with section declarations.
46
- * *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').
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 ".
47
50
  * *Comments*: All the lines starting with a ';' are assumed to be comments, and are ignored.
48
51
 
49
52
  ==== Differences
@@ -64,7 +67,7 @@ This package supports the standard INI file format described in the *Format*
64
67
  section above. The following differences are also supported:
65
68
 
66
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.
67
- * *Backslashes*: Backslashes are not supported by this package.
70
+ * *Backslashes*: Backslashes are not supported by this package. But multilines are. Enclose the param's value by ".
68
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+.
69
72
  * <b>Duplicate sections</b>: Duplicate sections will be merged. Parameters duplicated between to the two sections follow the duplicate parameters rule above.
70
73
  * *Parameters*: The parameter separator character can be specified when an +IniFile+ is created.
@@ -2,6 +2,9 @@
2
2
  # This class represents the INI file and can be used to parse, modify,
3
3
  # and write INI files.
4
4
  #
5
+
6
+ #encoding: UTF-8
7
+
5
8
  class IniFile
6
9
 
7
10
  # Inifile is enumerable.
@@ -9,7 +12,7 @@ class IniFile
9
12
 
10
13
  # :stopdoc:
11
14
  class Error < StandardError; end
12
- VERSION = '0.3.0'
15
+ VERSION = '0.4.0'
13
16
  # :startdoc:
14
17
 
15
18
  #
@@ -38,16 +41,22 @@ class IniFile
38
41
  #
39
42
  # :comment => ';' The line comment character(s)
40
43
  # :parameter => '=' The parameter / value separator
44
+ # :encoding => nil The encoding used for read/write (RUBY 1.9)
41
45
  #
42
46
  def initialize( filename, opts = {} )
43
47
  @fn = filename
44
48
  @comment = opts[:comment] || ';#'
45
49
  @param = opts[:parameter] || '='
50
+ @encoding = opts[:encoding]
46
51
  @ini = Hash.new {|h,k| h[k] = Hash.new}
47
52
 
48
53
  @rgxp_comment = %r/\A\s*\z|\A\s*[#{@comment}]/
49
54
  @rgxp_section = %r/\A\s*\[([^\]]+)\]/o
50
- @rgxp_param = %r/\A([^#{@param}]+)#{@param}(.*)\z/
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/
51
60
 
52
61
  parse
53
62
  end
@@ -60,11 +69,19 @@ class IniFile
60
69
  # Write the INI file contents to the filesystem. The given _filename_
61
70
  # will be used to write the file. If _filename_ is not given, then the
62
71
  # named used when constructing this object will be used.
72
+ # The following _options_ can be passed to this method:
73
+ #
74
+ # :encoding => nil The encoding used for writing (RUBY 1.9)
63
75
  #
64
- def write( filename = nil )
76
+ def write( filename = nil, opts={} )
65
77
  @fn = filename unless filename.nil?
66
78
 
67
- File.open(@fn, 'w') do |f|
79
+ encoding = opts[:encoding] || @encoding
80
+ mode = (RUBY_VERSION >= '1.9' && @encoding) ?
81
+ "w:#{encoding.to_s}" :
82
+ 'w'
83
+
84
+ File.open(@fn, mode) do |f|
68
85
  @ini.each do |section,hash|
69
86
  f.puts "[#{section}]"
70
87
  hash.each {|param,val| f.puts "#{param} #{@param} #{val}"}
@@ -279,34 +296,66 @@ class IniFile
279
296
  #
280
297
  def parse
281
298
  return unless File.file?(@fn)
299
+
282
300
  section = nil
301
+ tmp_value = ""
302
+ tmp_param = ""
303
+
304
+ fd = (RUBY_VERSION >= '1.9' && @encoding) ?
305
+ File.open(@fn, 'r', :encoding => @encoding) :
306
+ File.open(@fn, 'r')
307
+
308
+ while line = fd.gets
309
+ line = line.chomp
310
+
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
283
316
 
284
- File.open(@fn, 'r') do |f|
285
- while line = f.gets
286
- line = line.chomp
317
+ tmp_param = $1.strip
318
+ tmp_value = $2 + "\n"
287
319
 
288
- case line
289
- # ignore blank lines and comment lines
290
- when @rgxp_comment; next
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
291
323
 
292
- # this is a section declaration
293
- when @rgxp_section; section = @ini[$1.strip]
324
+ section[tmp_param] = tmp_value + $1
325
+ tmp_value, tmp_param = "", ""
294
326
 
295
- # otherwise we have a parameter
296
- when @rgxp_param
297
- begin
298
- section[$1.strip] = $2.strip
299
- rescue NoMethodError
300
- raise Error, "parameter encountered before first section"
301
- end
327
+ # anything else between multiline start and end
328
+ elsif line =~ @rgxp_multiline_value && tmp_param != "" then
302
329
 
303
- else
304
- raise Error, "could not parse line '#{line}"
330
+ tmp_value += $1 + "\n"
331
+
332
+ # ignore blank lines and comment lines
333
+ elsif line =~ @rgxp_comment then
334
+
335
+ next
336
+
337
+ # this is a section declaration
338
+ elsif line =~ @rgxp_section then
339
+
340
+ section = @ini[$1.strip]
341
+
342
+ # otherwise we have a parameter
343
+ elsif line =~ @rgxp_param then
344
+
345
+ begin
346
+ section[$1.strip] = $2.strip
347
+ rescue NoMethodError
348
+ raise Error, "parameter encountered before first section"
305
349
  end
306
- end # while
307
- end # File.open
350
+
351
+ else
352
+ raise Error, "could not parse line '#{line}"
353
+ end
354
+ end # while
355
+
356
+ ensure
357
+ fd.close if defined? fd and fd
308
358
  end
309
359
 
310
- end # class IniFile
360
+ end # IniFile
311
361
 
312
- # EOF
@@ -0,0 +1,5 @@
1
+
2
+ ;just the offending entry
3
+ [www.substancia.com AutoHTTPAgent (ver *)]
4
+ Parent=Version Checkers
5
+ Browser=Subst�ncia
@@ -3,7 +3,9 @@ one = 1
3
3
  two = 2
4
4
 
5
5
  [section_two]
6
- three = 3
6
+ three = 3
7
+ multi = "multiline
8
+ support"
7
9
 
8
10
  ; comments should be ignored
9
11
  [section three]
@@ -0,0 +1,17 @@
1
+ [section_one]
2
+ one = 1
3
+ two = 2
4
+
5
+ [section_two]
6
+ three = 3
7
+
8
+ ; comments should be ignored
9
+ [section_three]
10
+ three = "hello
11
+ multiline"
12
+ other = "stuff"
13
+
14
+ [section_four]
15
+ four = "hello
16
+ multiple
17
+ multilines"
@@ -2,6 +2,8 @@
2
2
  # classname: asrt / meth = ratio%
3
3
  # Rini::IniFile: 0 / 9 = 0.00%
4
4
 
5
+ # encoding: UTF-8
6
+
5
7
  begin
6
8
  require 'inifile'
7
9
  rescue LoadError
@@ -22,6 +24,7 @@ class TestIniFile < Test::Unit::TestCase
22
24
  ['section_one', 'one', '1'],
23
25
  ['section_one', 'two', '2'],
24
26
  ['section_two', 'three', '3'],
27
+ ['section_two', 'multi', "multiline\nsupport"],
25
28
  ['section three', 'four', '4'],
26
29
  ['section three', 'five', '5'],
27
30
  ['section three', 'six', '6'],
@@ -192,7 +195,7 @@ class TestIniFile < Test::Unit::TestCase
192
195
  }
193
196
  assert_equal expected, @ini_file[:section_one]
194
197
 
195
- expected = {'three' => '3'}
198
+ expected = {'three' => '3', 'multi' => "multiline\nsupport"}
196
199
  assert_equal expected, @ini_file['section_two']
197
200
 
198
201
  expected = {
@@ -330,6 +333,39 @@ class TestIniFile < Test::Unit::TestCase
330
333
  ini_file[:foo] = {}
331
334
  assert_equal ini_file["foo"], {}
332
335
  end
336
+
337
+ def test_multiline_parsing
338
+ ini_file = IniFile.load('test/data/multiline.ini')
339
+
340
+ multiline = ini_file['section_three']
341
+ expected = {"three" => "hello\nmultiline", "other" => "stuff"}
342
+ assert_equal expected, multiline
343
+
344
+ multiple = ini_file['section_four']
345
+ expected = {"four" => "hello\nmultiple\nmultilines"}
346
+ assert_equal expected, multiple
347
+
348
+ end
349
+
350
+ if RUBY_VERSION >= '1.9'
351
+ def test_parse_encoding
352
+ ini_file = IniFile.new("test/data/browscap.ini", :encoding => 'ISO-8859-1')
353
+ assert_equal ini_file['www.substancia.com AutoHTTPAgent (ver *)']['Browser'], "Subst\xE2ncia".force_encoding('ISO-8859-1')
354
+ end
355
+
356
+ def test_write_encoding
357
+ tmp = 'test/data/tmp.ini'
358
+ File.delete tmp if Kernel.test(?f, tmp)
359
+
360
+ @ini_file = IniFile.new(tmp, :encoding => 'UTF-8')
361
+ @ini_file['testutf-8'] = {"utf-8" => "appr\u20accier"}
362
+
363
+ @ini_file.save tmp
364
+
365
+ test = File.open(tmp)
366
+ assert_equal test.external_encoding.to_s, 'UTF-8'
367
+ end
368
+ end
369
+
333
370
  end
334
371
 
335
- # EOF
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: inifile
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 4
9
+ - 0
10
+ version: 0.4.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Tim Pease
@@ -9,30 +15,59 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2009-12-10 00:00:00 -07:00
18
+ date: 2011-02-15 00:00:00 -07:00
13
19
  default_executable:
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: bones-git
17
- type: :development
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - ">="
22
28
  - !ruby/object:Gem::Version
23
- version: 1.1.1
24
- version:
29
+ hash: 23
30
+ segments:
31
+ - 1
32
+ - 2
33
+ - 4
34
+ version: 1.2.4
35
+ type: :development
36
+ version_requirements: *id001
25
37
  - !ruby/object:Gem::Dependency
26
38
  name: bones
27
- type: :development
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
39
+ prerelease: false
40
+ requirement: &id002 !ruby/object:Gem::Requirement
41
+ none: false
30
42
  requirements:
31
43
  - - ">="
32
44
  - !ruby/object:Gem::Version
33
- version: 3.2.0
34
- version:
35
- description: This is a native Ruby package for reading and writing INI files.
45
+ hash: 21
46
+ segments:
47
+ - 3
48
+ - 6
49
+ - 5
50
+ version: 3.6.5
51
+ 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.
36
71
  email: tim.pease@gmail.com
37
72
  executables: []
38
73
 
@@ -42,16 +77,17 @@ extra_rdoc_files:
42
77
  - History.txt
43
78
  - README.txt
44
79
  files:
45
- - .gitignore
46
80
  - History.txt
47
81
  - README.txt
48
82
  - Rakefile
49
83
  - lib/inifile.rb
50
84
  - test/data/bad_1.ini
51
85
  - test/data/bad_2.ini
86
+ - test/data/browscap.ini
52
87
  - test/data/comment.ini
53
88
  - test/data/good.ini
54
89
  - test/data/mixed_comment.ini
90
+ - test/data/multiline.ini
55
91
  - test/data/param.ini
56
92
  - test/test_inifile.rb
57
93
  has_rdoc: true
@@ -65,21 +101,27 @@ rdoc_options:
65
101
  require_paths:
66
102
  - lib
67
103
  required_ruby_version: !ruby/object:Gem::Requirement
104
+ none: false
68
105
  requirements:
69
106
  - - ">="
70
107
  - !ruby/object:Gem::Version
108
+ hash: 3
109
+ segments:
110
+ - 0
71
111
  version: "0"
72
- version:
73
112
  required_rubygems_version: !ruby/object:Gem::Requirement
113
+ none: false
74
114
  requirements:
75
115
  - - ">="
76
116
  - !ruby/object:Gem::Version
117
+ hash: 3
118
+ segments:
119
+ - 0
77
120
  version: "0"
78
- version:
79
121
  requirements: []
80
122
 
81
123
  rubyforge_project: inifile
82
- rubygems_version: 1.3.5
124
+ rubygems_version: 1.3.7
83
125
  signing_key:
84
126
  specification_version: 3
85
127
  summary: INI file reader and writer
data/.gitignore DELETED
@@ -1,17 +0,0 @@
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