inifile 1.1.0 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +10 -0
- data/README.md +33 -8
- data/a.rb +125 -0
- data/lib/inifile.rb +295 -204
- data/test/data/comment.ini +5 -0
- data/test/data/escape.ini +2 -1
- data/test/data/good.ini +1 -1
- data/test/data/multiline.ini +7 -4
- data/test/test_inifile.rb +62 -33
- metadata +20 -9
data/History.txt
CHANGED
@@ -1,3 +1,13 @@
|
|
1
|
+
== 2.0.0 / 2012-08-29
|
2
|
+
|
3
|
+
Major Enhancements
|
4
|
+
- Can now initialize from Strings [issue #9]
|
5
|
+
- Quoted multi-line values are supported
|
6
|
+
- Comments can appear at the end of a line
|
7
|
+
Enhancements
|
8
|
+
- TomDoc documentation
|
9
|
+
- Parity between read/write methods
|
10
|
+
|
1
11
|
== 1.1.0 / 2012-02-28
|
2
12
|
|
3
13
|
Enhancements
|
data/README.md
CHANGED
@@ -87,17 +87,42 @@ the earlier section.
|
|
87
87
|
### Comments
|
88
88
|
|
89
89
|
The comment character can be either a semicolon *;* or a number sign *#*. The
|
90
|
-
comment character
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
90
|
+
comment character can appear anywhere on a line including at the end of a
|
91
|
+
name/value pair declaration. If you wish to use a comment character in your
|
92
|
+
value then you will need to either escape the character or put the value in
|
93
|
+
double quotations.
|
94
|
+
|
95
|
+
[section1]
|
96
|
+
var1 = foo # a comment
|
97
|
+
var2 = "foo # this is not a comment"
|
98
|
+
var3 = foo \# this is not a comment either
|
99
|
+
|
100
|
+
### Multi-Line Values
|
101
|
+
|
102
|
+
Values can be continued onto multiple lines in two separate ways. Putting a
|
103
|
+
slash at the end of a line will continue the value declaration to the next
|
104
|
+
line. When parsing, the trailing slash will be consumed and **will not**
|
105
|
+
appear in the resulting value. Comments can appear to the right of the
|
106
|
+
trailing slash.
|
107
|
+
|
108
|
+
var1 = this is a \ # these comments will
|
109
|
+
multiline value # be ignored by the parser
|
110
|
+
|
111
|
+
In the above example the resulting value for `var1` will be `this is a
|
112
|
+
multiline value`. If you want to preserve newline characters in the value then
|
113
|
+
quotations should be used.
|
114
|
+
|
115
|
+
var2 = "this is a
|
116
|
+
multiline value"
|
117
|
+
|
118
|
+
The resulting value for `var2` will be `this is a\nmultiline value`.
|
95
119
|
|
96
120
|
### Escape Characters
|
97
121
|
|
98
122
|
Several escape characters are supported within the **value** for a property.
|
99
|
-
|
100
|
-
|
123
|
+
These escape sequences will be applied to quoted and unquoted values alike.
|
124
|
+
You can enable or disable escaping by setting the **escape** flag to true or
|
125
|
+
false when creating an IniFile instance.
|
101
126
|
|
102
127
|
* \0 -- null character
|
103
128
|
* \n -- newline character
|
@@ -108,7 +133,7 @@ onto the next line. When parsed, a literal newline will appear in the value.
|
|
108
133
|
The backslash escape sequence is only needed if you want one of the escape
|
109
134
|
sequences to appear literally in your value. For example:
|
110
135
|
|
111
|
-
property=this is not a tab \\t character
|
136
|
+
property = this is not a tab \\t character
|
112
137
|
|
113
138
|
|
114
139
|
Install
|
data/a.rb
ADDED
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'pp'
|
3
|
+
|
4
|
+
@content = <<CONTENT
|
5
|
+
[section_one]
|
6
|
+
one = 1
|
7
|
+
two = 2
|
8
|
+
|
9
|
+
[section_two] # inline section comment
|
10
|
+
three = 3
|
11
|
+
multi = multiline \\ # inline multiline comment
|
12
|
+
support
|
13
|
+
quote = "quoted # strings are the best!"
|
14
|
+
|
15
|
+
; comments should be ignored
|
16
|
+
[section three]
|
17
|
+
four =4
|
18
|
+
five=5
|
19
|
+
six =6
|
20
|
+
"[foobar]" = 7
|
21
|
+
|
22
|
+
[section_four]
|
23
|
+
[section_five]
|
24
|
+
seven and eight= 7 & 8
|
25
|
+
CONTENT
|
26
|
+
|
27
|
+
@comment = ';#'
|
28
|
+
@param = '='
|
29
|
+
@default = 'global'
|
30
|
+
|
31
|
+
@ini = Hash.new {|h,k| h[k] = Hash.new}
|
32
|
+
|
33
|
+
def parse
|
34
|
+
|
35
|
+
string = ''
|
36
|
+
property = ''
|
37
|
+
|
38
|
+
@ini.clear
|
39
|
+
@_line = nil
|
40
|
+
@_section = nil
|
41
|
+
|
42
|
+
scanner = StringScanner.new(@content)
|
43
|
+
until scanner.eos?
|
44
|
+
|
45
|
+
# keep track of the current line for error messages
|
46
|
+
if scanner.bol?
|
47
|
+
@_line = scanner.check(%r/\A.*$/) if scanner.bol?
|
48
|
+
puts "[line] #@_line"
|
49
|
+
end
|
50
|
+
|
51
|
+
# look for escaped special characters \# \" etc
|
52
|
+
if scanner.scan(%r/\\([\[\]#{@param}#{@comment}"])/)
|
53
|
+
string << scanner[1]
|
54
|
+
|
55
|
+
# look for quoted strings
|
56
|
+
elsif scanner.scan(%r/"/)
|
57
|
+
quote = scanner.scan_until(/(?:\A|[^\\])"/)
|
58
|
+
parse_error('Unmatched quote') if quote.nil?
|
59
|
+
|
60
|
+
quote.chomp!('"')
|
61
|
+
string << quote
|
62
|
+
|
63
|
+
# look for comments, empty strings, end of lines
|
64
|
+
elsif scanner.skip(%r/\A\s*(?:[#{@comment}].*)?$/)
|
65
|
+
string << scanner.getch unless scanner.eos?
|
66
|
+
|
67
|
+
process_property(property, string)
|
68
|
+
|
69
|
+
# look for the separator between property name and value
|
70
|
+
elsif scanner.scan(%r/#{@param}/)
|
71
|
+
if property.empty?
|
72
|
+
property = string.strip
|
73
|
+
string.clear
|
74
|
+
else
|
75
|
+
parse_error
|
76
|
+
end
|
77
|
+
|
78
|
+
# look for the start of a new section
|
79
|
+
elsif scanner.scan(%r/\A\s*\[([^\]]+)\]/)
|
80
|
+
@_section = @ini[scanner[1]]
|
81
|
+
|
82
|
+
# store the next character and loop again
|
83
|
+
else
|
84
|
+
tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}]|\\[\[\]#{@param}#{@comment}"])/m)
|
85
|
+
len = scanner[1].length
|
86
|
+
tmp.slice!(tmp.length - len, len)
|
87
|
+
|
88
|
+
scanner.pos = scanner.pos - len
|
89
|
+
string << tmp
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
process_property(property, string)
|
94
|
+
end
|
95
|
+
|
96
|
+
def process_property(property, value)
|
97
|
+
value.chomp!
|
98
|
+
return if property.empty? and value.empty?
|
99
|
+
return if value.sub!(%r/\\\s*\z/, '')
|
100
|
+
|
101
|
+
property.strip!
|
102
|
+
value.strip!
|
103
|
+
|
104
|
+
parse_error if property.empty?
|
105
|
+
|
106
|
+
current_section[property.dup] = value.dup
|
107
|
+
|
108
|
+
property.clear
|
109
|
+
value.clear
|
110
|
+
|
111
|
+
nil
|
112
|
+
end
|
113
|
+
|
114
|
+
def current_section
|
115
|
+
@_section ||= @ini[@default]
|
116
|
+
end
|
117
|
+
|
118
|
+
def parse_error( msg = 'Could not parse line' )
|
119
|
+
raise "#{msg}: #{@_line.inspect}"
|
120
|
+
end
|
121
|
+
|
122
|
+
parse
|
123
|
+
|
124
|
+
puts '='*72
|
125
|
+
pp @ini
|
data/lib/inifile.rb
CHANGED
@@ -1,143 +1,193 @@
|
|
1
|
-
#
|
1
|
+
#encoding: UTF-8
|
2
|
+
require 'strscan'
|
3
|
+
|
2
4
|
# This class represents the INI file and can be used to parse, modify,
|
3
5
|
# and write INI files.
|
4
6
|
#
|
5
|
-
|
6
|
-
#encoding: UTF-8
|
7
|
-
|
8
7
|
class IniFile
|
9
|
-
|
10
|
-
# Inifile is enumerable.
|
11
8
|
include Enumerable
|
12
9
|
|
13
|
-
# :stopdoc:
|
14
10
|
class Error < StandardError; end
|
15
|
-
VERSION = '
|
16
|
-
# :startdoc:
|
11
|
+
VERSION = '2.0.0'
|
17
12
|
|
13
|
+
# Public: Open an INI file and load the contents.
|
14
|
+
#
|
15
|
+
# filename - The name of the fiel as a String
|
16
|
+
# opts - The Hash of options (default: {})
|
17
|
+
# :comment - String containing the comment character(s)
|
18
|
+
# :parameter - String used to separate parameter and value
|
19
|
+
# :encoding - Encoding String for reading / writing (Ruby 1.9)
|
20
|
+
# :escape - Boolean used to control character escaping
|
21
|
+
# :default - The String name of the default global section
|
18
22
|
#
|
19
|
-
#
|
20
|
-
# IniFile.load( filename )
|
21
|
-
# IniFile.load( filename, options )
|
23
|
+
# Examples
|
22
24
|
#
|
23
|
-
#
|
24
|
-
#
|
25
|
+
# IniFile.load('file.ini')
|
26
|
+
# #=> IniFile instance
|
25
27
|
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
# :default => 'global' Default global section name
|
28
|
+
# IniFile.load('does/not/exist.ini')
|
29
|
+
# #=> nil
|
30
|
+
#
|
31
|
+
# Returns an IniFile intsnace or nil if the file could not be opened.
|
31
32
|
#
|
32
33
|
def self.load( filename, opts = {} )
|
33
|
-
|
34
|
+
return unless File.file? filename
|
35
|
+
new(opts.merge(:filename => filename))
|
34
36
|
end
|
35
37
|
|
38
|
+
# Get and set the filename
|
39
|
+
attr_accessor :filename
|
40
|
+
|
41
|
+
# Get and set the encoding (Ruby 1.9)
|
42
|
+
attr_accessor :encoding
|
43
|
+
|
44
|
+
# Enable or disable character escaping
|
45
|
+
attr_accessor :escape
|
46
|
+
|
47
|
+
# Public: Create a new INI file from the given content String which
|
48
|
+
# contains the INI file lines. If the content are omitted, then the
|
49
|
+
# :filename option is used to read in the content of the INI file. If
|
50
|
+
# neither the content for a filename is provided then an empty INI file is
|
51
|
+
# created.
|
52
|
+
#
|
53
|
+
# content - The String containing the INI file contents
|
54
|
+
# opts - The Hash of options (default: {})
|
55
|
+
# :comment - String containing the comment character(s)
|
56
|
+
# :parameter - String used to separate parameter and value
|
57
|
+
# :encoding - Encoding String for reading / writing (Ruby 1.9)
|
58
|
+
# :escape - Boolean used to control character escaping
|
59
|
+
# :default - The String name of the default global section
|
60
|
+
# :filename - The filename as a String
|
61
|
+
#
|
62
|
+
# Examples
|
63
|
+
#
|
64
|
+
# IniFile.new
|
65
|
+
# #=> an empty IniFile instance
|
36
66
|
#
|
37
|
-
#
|
38
|
-
#
|
39
|
-
# IniFile.new( filename, options )
|
67
|
+
# IniFile.new( "[global]\nfoo=bar" )
|
68
|
+
# #=> an IniFile instance
|
40
69
|
#
|
41
|
-
#
|
42
|
-
#
|
43
|
-
# The following _options_ can be passed to this method:
|
70
|
+
# IniFile.new( :filename => 'file.ini', :encoding => 'UTF-8' )
|
71
|
+
# #=> an IniFile instance
|
44
72
|
#
|
45
|
-
#
|
46
|
-
#
|
47
|
-
# :encoding => nil The encoding used for read/write (RUBY 1.9)
|
48
|
-
# :escape => true Whether or not to escape values when reading/writing
|
49
|
-
# :default => 'global' Default global section name
|
73
|
+
# IniFile.new( "[global]\nfoo=bar", :comment => '#' )
|
74
|
+
# #=> an IniFile instance
|
50
75
|
#
|
51
|
-
def initialize(
|
52
|
-
|
53
|
-
|
54
|
-
@
|
76
|
+
def initialize( content = nil, opts = {} )
|
77
|
+
opts, content = content, nil if Hash === content
|
78
|
+
|
79
|
+
@content = content
|
80
|
+
|
81
|
+
@comment = opts.fetch(:comment, ';#')
|
82
|
+
@param = opts.fetch(:parameter, '=')
|
55
83
|
@encoding = opts.fetch(:encoding, nil)
|
56
|
-
@escape
|
57
|
-
@default
|
58
|
-
@
|
84
|
+
@escape = opts.fetch(:escape, true)
|
85
|
+
@default = opts.fetch(:default, 'global')
|
86
|
+
@filename = opts.fetch(:filename, nil)
|
59
87
|
|
60
|
-
@
|
61
|
-
@rgxp_section = %r/\A\s*\[([^\]]+)\]/
|
62
|
-
@rgxp_param = %r/[^\\]#{@param}/
|
88
|
+
@ini = Hash.new {|h,k| h[k] = Hash.new}
|
63
89
|
|
64
|
-
parse
|
90
|
+
if @content then parse!
|
91
|
+
elsif @filename then read
|
92
|
+
end
|
65
93
|
end
|
66
94
|
|
95
|
+
# Public: Write the contents of this IniFile to the file system. If left
|
96
|
+
# unspecified, the currently configured filename and encoding will be used.
|
97
|
+
# Otherwise the filename and encoding can be specified in the options hash.
|
67
98
|
#
|
68
|
-
#
|
69
|
-
#
|
70
|
-
#
|
99
|
+
# opts - The default options Hash
|
100
|
+
# :filename - The filename as a String
|
101
|
+
# :encoding - The encoding as a String (Ruby 1.9)
|
71
102
|
#
|
72
|
-
#
|
73
|
-
# will be used to write the file. If _filename_ is not given, then the
|
74
|
-
# named used when constructing this object will be used.
|
75
|
-
# The following _options_ can be passed to this method:
|
103
|
+
# Returns this IniFile instance.
|
76
104
|
#
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
encoding = opts[:encoding] || @encoding
|
83
|
-
mode = (RUBY_VERSION >= '1.9' && @encoding) ?
|
105
|
+
def write( opts = {} )
|
106
|
+
filename = opts.fetch(:filename, @filename)
|
107
|
+
encoding = opts.fetch(:encoding, @encoding)
|
108
|
+
mode = (RUBY_VERSION >= '1.9' && encoding) ?
|
84
109
|
"w:#{encoding.to_s}" :
|
85
110
|
'w'
|
86
111
|
|
87
|
-
File.open(
|
112
|
+
File.open(filename, mode) do |f|
|
88
113
|
@ini.each do |section,hash|
|
89
114
|
f.puts "[#{section}]"
|
90
|
-
hash.each {|param,val| f.puts "#{param} #{@param} #{
|
115
|
+
hash.each {|param,val| f.puts "#{param} #{@param} #{escape_value val}"}
|
91
116
|
f.puts
|
92
117
|
end
|
93
118
|
end
|
119
|
+
|
94
120
|
self
|
95
121
|
end
|
96
122
|
alias :save :write
|
97
123
|
|
124
|
+
# Public: Read the contents of the INI file from the file system and replace
|
125
|
+
# and set the state of this IniFile instance. If left unspecified the
|
126
|
+
# currently configured filename and encoding will be used when reading from
|
127
|
+
# the file system. Otherwise the filename and encoding can be specified in
|
128
|
+
# the options hash.
|
98
129
|
#
|
99
|
-
#
|
100
|
-
#
|
130
|
+
# opts - The default options Hash
|
131
|
+
# :filename - The filename as a String
|
132
|
+
# :encoding - The encoding as a String (Ruby 1.9)
|
101
133
|
#
|
102
|
-
#
|
134
|
+
# Returns this IniFile instance if the read was successful; nil is returned
|
135
|
+
# if the file could not be read.
|
136
|
+
#
|
137
|
+
def read( opts = {} )
|
138
|
+
filename = opts.fetch(:filename, @filename)
|
139
|
+
encoding = opts.fetch(:encoding, @encoding)
|
140
|
+
return unless File.file? filename
|
141
|
+
|
142
|
+
mode = (RUBY_VERSION >= '1.9' && encoding) ?
|
143
|
+
"r:#{encoding.to_s}" :
|
144
|
+
'r'
|
145
|
+
fd = File.open(filename, mode)
|
146
|
+
@content = fd.read
|
147
|
+
|
148
|
+
parse!
|
149
|
+
self
|
150
|
+
ensure
|
151
|
+
fd.close if fd && !fd.closed?
|
152
|
+
end
|
153
|
+
alias :restore :read
|
154
|
+
|
155
|
+
# Returns this IniFile converted to a String.
|
103
156
|
#
|
104
157
|
def to_s
|
105
158
|
s = []
|
106
159
|
@ini.each do |section,hash|
|
107
160
|
s << "[#{section}]"
|
108
|
-
hash.each {|param,val| s << "#{param} #{@param} #{
|
161
|
+
hash.each {|param,val| s << "#{param} #{@param} #{escape_value val}"}
|
109
162
|
s << ""
|
110
163
|
end
|
111
164
|
s.join("\n")
|
112
165
|
end
|
113
166
|
|
114
|
-
#
|
115
|
-
# call-seq:
|
116
|
-
# to_h
|
117
|
-
#
|
118
|
-
# Convert IniFile to hash format.
|
167
|
+
# Returns this IniFile converted to a Hash.
|
119
168
|
#
|
120
169
|
def to_h
|
121
170
|
@ini.dup
|
122
171
|
end
|
123
172
|
|
173
|
+
# Public: Creates a copy of this inifile with the entries from the
|
174
|
+
# other_inifile merged into the copy.
|
124
175
|
#
|
125
|
-
#
|
126
|
-
# merge( other_inifile )
|
176
|
+
# other - The other IniFile.
|
127
177
|
#
|
128
|
-
# Returns a
|
129
|
-
# merged into the copy.
|
178
|
+
# Returns a new IniFile.
|
130
179
|
#
|
131
180
|
def merge( other )
|
132
181
|
self.dup.merge!(other)
|
133
182
|
end
|
134
183
|
|
184
|
+
# Public: Merges other_inifile into this inifile, overwriting existing
|
185
|
+
# entries. Useful for having a system inifile with user over-ridable settings
|
186
|
+
# elsewhere.
|
135
187
|
#
|
136
|
-
#
|
137
|
-
# merge!( other_inifile )
|
188
|
+
# other - The other IniFile.
|
138
189
|
#
|
139
|
-
#
|
140
|
-
# Useful for having a system inifile with user overridable settings elsewhere.
|
190
|
+
# Returns this IniFile.
|
141
191
|
#
|
142
192
|
def merge!( other )
|
143
193
|
my_keys = @ini.keys
|
@@ -158,12 +208,19 @@ class IniFile
|
|
158
208
|
self
|
159
209
|
end
|
160
210
|
|
211
|
+
# Public: Yield each INI file section, parameter, and value in turn to the
|
212
|
+
# given block.
|
213
|
+
#
|
214
|
+
# block - The block that will be iterated by the each method. The block will
|
215
|
+
# be passed the current section and the parameter / value pair.
|
161
216
|
#
|
162
|
-
#
|
163
|
-
# each {|section, parameter, value| block}
|
217
|
+
# Examples
|
164
218
|
#
|
165
|
-
#
|
166
|
-
#
|
219
|
+
# inifile.each do |section, parameter, value|
|
220
|
+
# puts "#{parameter} = #{value} [in section - #{section}]"
|
221
|
+
# end
|
222
|
+
#
|
223
|
+
# Returns this IniFile.
|
167
224
|
#
|
168
225
|
def each
|
169
226
|
return unless block_given?
|
@@ -175,12 +232,18 @@ class IniFile
|
|
175
232
|
self
|
176
233
|
end
|
177
234
|
|
235
|
+
# Public: Yield each section in turn to the given block.
|
236
|
+
#
|
237
|
+
# block - The block that will be iterated by the each method. The block will
|
238
|
+
# be passed the current section as a Hash.
|
178
239
|
#
|
179
|
-
#
|
180
|
-
# each_section {|section| block}
|
240
|
+
# Examples
|
181
241
|
#
|
182
|
-
#
|
183
|
-
#
|
242
|
+
# inifile.each_section do |section|
|
243
|
+
# puts section.inspect
|
244
|
+
# end
|
245
|
+
#
|
246
|
+
# Returns this IniFile.
|
184
247
|
#
|
185
248
|
def each_section
|
186
249
|
return unless block_given?
|
@@ -188,77 +251,86 @@ class IniFile
|
|
188
251
|
self
|
189
252
|
end
|
190
253
|
|
254
|
+
# Public: Remove a section identified by name from the IniFile.
|
191
255
|
#
|
192
|
-
#
|
193
|
-
# delete_section( section )
|
256
|
+
# section - The section name as a String.
|
194
257
|
#
|
195
|
-
#
|
196
|
-
# parameter / value pairs if the section exists in the INI file. Otherwise,
|
197
|
-
# returns +nil+.
|
258
|
+
# Returns the deleted section Hash.
|
198
259
|
#
|
199
260
|
def delete_section( section )
|
200
261
|
@ini.delete section.to_s
|
201
262
|
end
|
202
263
|
|
264
|
+
# Public: Get the section Hash by name. If the section does not exist, then
|
265
|
+
# it will be created.
|
266
|
+
#
|
267
|
+
# section - The section name as a String.
|
268
|
+
#
|
269
|
+
# Examples
|
203
270
|
#
|
204
|
-
#
|
205
|
-
#
|
271
|
+
# inifile['global']
|
272
|
+
# #=> global section Hash
|
206
273
|
#
|
207
|
-
#
|
208
|
-
# _section_ hash does not exist it will be created.
|
274
|
+
# Returns the Hash of parameter/value pairs for this section.
|
209
275
|
#
|
210
276
|
def []( section )
|
211
277
|
return nil if section.nil?
|
212
278
|
@ini[section.to_s]
|
213
279
|
end
|
214
280
|
|
281
|
+
# Public: Set the section to a hash of parameter/value pairs.
|
282
|
+
#
|
283
|
+
# section - The section name as a String.
|
284
|
+
# value - The Hash of parameter/value pairs.
|
285
|
+
#
|
286
|
+
# Examples
|
215
287
|
#
|
216
|
-
#
|
217
|
-
#
|
288
|
+
# inifile['tenderloin'] = { 'gritty' => 'yes' }
|
289
|
+
# #=> { 'gritty' => 'yes' }
|
218
290
|
#
|
219
|
-
#
|
291
|
+
# Returns the value Hash.
|
220
292
|
#
|
221
293
|
def []=( section, value )
|
222
294
|
@ini[section.to_s] = value
|
223
295
|
end
|
224
296
|
|
297
|
+
# Public: Create a Hash containing only those INI file sections whose names
|
298
|
+
# match the given regular expression.
|
225
299
|
#
|
226
|
-
#
|
227
|
-
# ini_file.match( /section/ ) #=> hash
|
300
|
+
# regex - The Regexp used to match section names.
|
228
301
|
#
|
229
|
-
#
|
302
|
+
# Examples
|
303
|
+
#
|
304
|
+
# inifile.match(/^tree_/)
|
305
|
+
# #=> Hash of matching sections
|
306
|
+
#
|
307
|
+
# Return a Hash containing only those sections that match the given regular
|
230
308
|
# expression.
|
231
309
|
#
|
232
310
|
def match( regex )
|
233
311
|
@ini.dup.delete_if { |section, _| section !~ regex }
|
234
312
|
end
|
235
313
|
|
314
|
+
# Public: Check to see if the IniFile contains the section.
|
236
315
|
#
|
237
|
-
#
|
238
|
-
# has_section?( section )
|
316
|
+
# section - The section name as a String.
|
239
317
|
#
|
240
|
-
# Returns
|
318
|
+
# Returns true if the section exists in the IniFile.
|
241
319
|
#
|
242
320
|
def has_section?( section )
|
243
321
|
@ini.has_key? section.to_s
|
244
322
|
end
|
245
323
|
|
246
|
-
#
|
247
|
-
# call-seq:
|
248
|
-
# sections
|
249
|
-
#
|
250
|
-
# Returns an array of the section names.
|
324
|
+
# Returns an Array of section names contained in this IniFile.
|
251
325
|
#
|
252
326
|
def sections
|
253
327
|
@ini.keys
|
254
328
|
end
|
255
329
|
|
330
|
+
# Public: Freeze the state of this IniFile object. Any attempts to change
|
331
|
+
# the object will raise an error.
|
256
332
|
#
|
257
|
-
#
|
258
|
-
# freeze
|
259
|
-
#
|
260
|
-
# Freeze the state of the +IniFile+ object. Any attempts to change the
|
261
|
-
# object will raise an error.
|
333
|
+
# Returns this IniFile.
|
262
334
|
#
|
263
335
|
def freeze
|
264
336
|
super
|
@@ -267,12 +339,10 @@ class IniFile
|
|
267
339
|
self
|
268
340
|
end
|
269
341
|
|
342
|
+
# Public: Mark this IniFile as tainted -- this will traverse each section
|
343
|
+
# marking each as tainted.
|
270
344
|
#
|
271
|
-
#
|
272
|
-
# taint
|
273
|
-
#
|
274
|
-
# Marks the INI file as tainted -- this will traverse each section marking
|
275
|
-
# each section as tainted as well.
|
345
|
+
# Returns this IniFile.
|
276
346
|
#
|
277
347
|
def taint
|
278
348
|
super
|
@@ -281,14 +351,12 @@ class IniFile
|
|
281
351
|
self
|
282
352
|
end
|
283
353
|
|
284
|
-
#
|
285
|
-
#
|
286
|
-
# dup
|
287
|
-
#
|
288
|
-
# Produces a duplicate of this INI file. The duplicate is independent of the
|
289
|
-
# original -- i.e. the duplicate can be modified without changing the
|
354
|
+
# Public: Produces a duplicate of this IniFile. The duplicate is independent
|
355
|
+
# of the original -- i.e. the duplicate can be modified without changing the
|
290
356
|
# original. The tainted state of the original is copied to the duplicate.
|
291
357
|
#
|
358
|
+
# Returns a new IniFile.
|
359
|
+
#
|
292
360
|
def dup
|
293
361
|
other = super
|
294
362
|
other.instance_variable_set(:@ini, Hash.new {|h,k| h[k] = Hash.new})
|
@@ -297,28 +365,26 @@ class IniFile
|
|
297
365
|
other
|
298
366
|
end
|
299
367
|
|
300
|
-
#
|
301
|
-
#
|
302
|
-
# clone
|
303
|
-
#
|
304
|
-
# Produces a duplicate of this INI file. The duplicate is independent of the
|
305
|
-
# original -- i.e. the duplicate can be modified without changing the
|
368
|
+
# Public: Produces a duplicate of this IniFile. The duplicate is independent
|
369
|
+
# of the original -- i.e. the duplicate can be modified without changing the
|
306
370
|
# original. The tainted state and the frozen state of the original is copied
|
307
371
|
# to the duplicate.
|
308
372
|
#
|
373
|
+
# Returns a new IniFile.
|
374
|
+
#
|
309
375
|
def clone
|
310
376
|
other = dup
|
311
377
|
other.freeze if self.frozen?
|
312
378
|
other
|
313
379
|
end
|
314
380
|
|
381
|
+
# Public: Compare this IniFile to some other IniFile. For two INI files to
|
382
|
+
# be equivalent, they must have the same sections with the same parameter /
|
383
|
+
# value pairs in each section.
|
315
384
|
#
|
316
|
-
#
|
317
|
-
# eql?( other )
|
385
|
+
# other - The other IniFile.
|
318
386
|
#
|
319
|
-
# Returns
|
320
|
-
# two INI files to be equivalent, they must have the same sections with the
|
321
|
-
# same parameter / value pairs in each section.
|
387
|
+
# Returns true if the INI files are equivalent and false if they differ.
|
322
388
|
#
|
323
389
|
def eql?( other )
|
324
390
|
return true if equal? other
|
@@ -327,105 +393,126 @@ class IniFile
|
|
327
393
|
end
|
328
394
|
alias :== :eql?
|
329
395
|
|
330
|
-
#
|
331
|
-
# call-seq:
|
332
|
-
# restore
|
333
|
-
#
|
334
|
-
# Restore data from the ini file. If the state of this object has been
|
335
|
-
# changed but not yet saved, this will effectively undo the changes.
|
336
|
-
#
|
337
|
-
def restore
|
338
|
-
parse
|
339
|
-
end
|
340
396
|
|
341
397
|
private
|
342
398
|
|
343
|
-
# Parse the ini file contents.
|
399
|
+
# Parse the ini file contents. This will clear any values currently stored
|
400
|
+
# in the ini hash.
|
344
401
|
#
|
345
|
-
def parse
|
346
|
-
return unless
|
402
|
+
def parse!
|
403
|
+
return unless @content
|
347
404
|
|
348
|
-
|
349
|
-
|
350
|
-
@_current_value = nil
|
405
|
+
string = ''
|
406
|
+
property = ''
|
351
407
|
|
352
|
-
|
353
|
-
|
354
|
-
|
408
|
+
@ini.clear
|
409
|
+
@_line = nil
|
410
|
+
@_section = nil
|
355
411
|
|
356
|
-
|
357
|
-
|
412
|
+
scanner = StringScanner.new(@content)
|
413
|
+
until scanner.eos?
|
358
414
|
|
359
|
-
#
|
360
|
-
|
361
|
-
finish_property
|
362
|
-
next
|
363
|
-
end
|
415
|
+
# keep track of the current line for error messages
|
416
|
+
@_line = scanner.check(%r/\A.*$/) if scanner.bol?
|
364
417
|
|
365
|
-
#
|
366
|
-
if
|
367
|
-
|
368
|
-
@_current_section = @ini[$1.strip]
|
369
|
-
next
|
370
|
-
end
|
418
|
+
# look for escaped special characters \# \" etc
|
419
|
+
if scanner.scan(%r/\\([\[\]#{@param}#{@comment}"])/)
|
420
|
+
string << scanner[1]
|
371
421
|
|
372
|
-
|
422
|
+
# look for quoted strings
|
423
|
+
elsif scanner.scan(%r/"/)
|
424
|
+
quote = scanner.scan_until(/(?:\A|[^\\])"/)
|
425
|
+
parse_error('Unmatched quote') if quote.nil?
|
373
426
|
|
374
|
-
|
427
|
+
quote.chomp!('"')
|
428
|
+
string << quote
|
375
429
|
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
430
|
+
# look for comments, empty strings, end of lines
|
431
|
+
elsif scanner.skip(%r/\A\s*(?:[#{@comment}].*)?$/)
|
432
|
+
string << scanner.getch unless scanner.eos?
|
433
|
+
|
434
|
+
process_property(property, string)
|
435
|
+
|
436
|
+
# look for the separator between property name and value
|
437
|
+
elsif scanner.scan(%r/#{@param}/)
|
438
|
+
if property.empty?
|
439
|
+
property = string.strip
|
440
|
+
string.slice!(0, string.length)
|
441
|
+
else
|
442
|
+
parse_error
|
443
|
+
end
|
444
|
+
|
445
|
+
# look for the start of a new section
|
446
|
+
elsif scanner.scan(%r/\A\s*\[([^\]]+)\]/)
|
447
|
+
@_section = @ini[scanner[1]]
|
448
|
+
|
449
|
+
# otherwise scan and store characters till we hit the start of some
|
450
|
+
# special section like a quote, newline, comment, etc.
|
451
|
+
else
|
452
|
+
tmp = scanner.scan_until(%r/([\n"#{@param}#{@comment}]|\\[\[\]#{@param}#{@comment}"])/m)
|
453
|
+
len = scanner[1].length
|
454
|
+
tmp.slice!(tmp.length - len, len)
|
455
|
+
|
456
|
+
scanner.pos = scanner.pos - len
|
457
|
+
string << tmp
|
458
|
+
end
|
459
|
+
end
|
460
|
+
|
461
|
+
process_property(property, string)
|
382
462
|
end
|
383
463
|
|
384
|
-
#
|
385
|
-
# method
|
464
|
+
# Store the property / value pair in the currently active section. This
|
465
|
+
# method checks for continuation of the value to the next line.
|
466
|
+
#
|
467
|
+
# property - The property name as a String.
|
468
|
+
# value - The property value as a String.
|
386
469
|
#
|
387
|
-
|
388
|
-
|
389
|
-
|
470
|
+
# Returns nil.
|
471
|
+
#
|
472
|
+
def process_property( property, value )
|
473
|
+
value.chomp!
|
474
|
+
return if property.empty? and value.empty?
|
475
|
+
return if value.sub!(%r/\\\s*\z/, '')
|
390
476
|
|
391
|
-
|
392
|
-
|
393
|
-
v = line.slice(split+2, line.length).strip
|
394
|
-
else
|
395
|
-
v = line
|
396
|
-
end
|
477
|
+
property.strip!
|
478
|
+
value.strip!
|
397
479
|
|
398
|
-
if
|
399
|
-
raise Error, "could not parse line '#{line}'"
|
400
|
-
end
|
480
|
+
parse_error if property.empty?
|
401
481
|
|
402
|
-
|
482
|
+
current_section[property.dup] = unescape_value(value.dup)
|
403
483
|
|
404
|
-
|
405
|
-
|
484
|
+
property.slice!(0, property.length)
|
485
|
+
value.slice!(0, value.length)
|
406
486
|
|
407
|
-
|
487
|
+
nil
|
408
488
|
end
|
409
489
|
|
410
|
-
#
|
411
|
-
# storing the name and value in the current section and resetting for the
|
412
|
-
# next parse step.
|
490
|
+
# Returns the current section Hash.
|
413
491
|
#
|
414
|
-
def
|
415
|
-
|
416
|
-
|
417
|
-
@_current_section = @ini[@default] if @_current_section.nil?
|
418
|
-
@_current_section[@_current_param] = unescape @_current_value
|
492
|
+
def current_section
|
493
|
+
@_section ||= @ini[@default]
|
494
|
+
end
|
419
495
|
|
420
|
-
|
421
|
-
|
496
|
+
# Raise a parse error using the given message and appending the current line
|
497
|
+
# being parsed.
|
498
|
+
#
|
499
|
+
# msg - The message String to use.
|
500
|
+
#
|
501
|
+
# Raises IniFile::Error
|
502
|
+
#
|
503
|
+
def parse_error( msg = 'Could not parse line' )
|
504
|
+
raise Error, "#{msg}: #{@_line.inspect}"
|
422
505
|
end
|
423
506
|
|
424
507
|
# Unescape special characters found in the value string. This will convert
|
425
508
|
# escaped null, tab, carriage return, newline, and backslash into their
|
426
509
|
# literal equivalents.
|
427
510
|
#
|
428
|
-
|
511
|
+
# value - The String value to unescape.
|
512
|
+
#
|
513
|
+
# Returns the unescaped value.
|
514
|
+
#
|
515
|
+
def unescape_value( value )
|
429
516
|
return value unless @escape
|
430
517
|
|
431
518
|
value = value.to_s
|
@@ -441,9 +528,13 @@ private
|
|
441
528
|
value
|
442
529
|
end
|
443
530
|
|
444
|
-
# Escape special characters
|
531
|
+
# Escape special characters.
|
532
|
+
#
|
533
|
+
# value - The String value to escape.
|
534
|
+
#
|
535
|
+
# Returns the escaped value.
|
445
536
|
#
|
446
|
-
def
|
537
|
+
def escape_value( value )
|
447
538
|
return value unless @escape
|
448
539
|
|
449
540
|
value = value.to_s.dup
|
data/test/data/comment.ini
CHANGED
data/test/data/escape.ini
CHANGED
@@ -6,7 +6,8 @@ foo = http://en.wikipedia.org/wiki/Foobar
|
|
6
6
|
tabs = There is a tab\tcharacter in here somewhere
|
7
7
|
carriage return = Who uses these anyways?\r
|
8
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
|
9
|
+
null = Who'd be silly enough to put\0 a null character in the middle of a string? \
|
10
10
|
Stroustrup would not approve!
|
11
11
|
backslash = This string \\t contains \\n no \\r special \\0 characters!
|
12
|
+
quoted = "Escaping works\tinside quoted strings!"
|
12
13
|
|
data/test/data/good.ini
CHANGED
data/test/data/multiline.ini
CHANGED
@@ -7,14 +7,17 @@ three = 3
|
|
7
7
|
|
8
8
|
; comments should be ignored
|
9
9
|
[section_three]
|
10
|
-
three = hello\
|
10
|
+
three = hello \
|
11
11
|
multiline
|
12
12
|
other = "stuff"
|
13
13
|
|
14
14
|
[section_four]
|
15
|
-
four = hello\
|
16
|
-
multiple\
|
17
|
-
multilines
|
15
|
+
four = hello \ # comments work here, too
|
16
|
+
multiple \ # and here !!!
|
17
|
+
multilines # and even here (OMG)
|
18
|
+
five = "multiple lines
|
19
|
+
inside of quotations
|
20
|
+
preserve everything"
|
18
21
|
|
19
22
|
[empty_lines]
|
20
23
|
empty =
|
data/test/test_inifile.rb
CHANGED
@@ -1,7 +1,3 @@
|
|
1
|
-
# Code Generated by ZenTest v. 3.3.0
|
2
|
-
# classname: asrt / meth = ratio%
|
3
|
-
# Rini::IniFile: 0 / 9 = 0.00%
|
4
|
-
|
5
1
|
# encoding: UTF-8
|
6
2
|
|
7
3
|
libpath = File.expand_path '../../lib', __FILE__
|
@@ -13,12 +9,12 @@ require 'test/unit'
|
|
13
9
|
class TestIniFile < Test::Unit::TestCase
|
14
10
|
|
15
11
|
def setup
|
16
|
-
@ini_file = IniFile.new 'test/data/good.ini'
|
12
|
+
@ini_file = IniFile.new(:filename => 'test/data/good.ini')
|
17
13
|
@contents = [
|
18
14
|
['section_one', 'one', '1'],
|
19
15
|
['section_one', 'two', '2'],
|
20
16
|
['section_two', 'three', '3'],
|
21
|
-
['section_two', 'multi', "multiline
|
17
|
+
['section_two', 'multi', "multiline support"],
|
22
18
|
['section three', 'four', '4'],
|
23
19
|
['section three', 'five', '5'],
|
24
20
|
['section three', 'six', '6'],
|
@@ -128,7 +124,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
128
124
|
assert_equal @contents, ary.sort
|
129
125
|
|
130
126
|
ary = []
|
131
|
-
IniFile.new('temp.ini').each {|*args| ary << args}
|
127
|
+
IniFile.new(:filename => 'temp.ini').each {|*args| ary << args}
|
132
128
|
assert_equal [], ary
|
133
129
|
end
|
134
130
|
|
@@ -144,7 +140,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
144
140
|
assert_equal expected, ary.sort
|
145
141
|
|
146
142
|
ary = []
|
147
|
-
IniFile.new('temp.ini').each_section {|section| ary << section}
|
143
|
+
IniFile.new(:filename => 'temp.ini').each_section {|section| ary << section}
|
148
144
|
assert_equal [], ary
|
149
145
|
end
|
150
146
|
|
@@ -175,7 +171,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
175
171
|
assert_equal true, @ini_file.has_section?(:section_two)
|
176
172
|
assert_equal false, @ini_file.has_section?(nil)
|
177
173
|
|
178
|
-
ini_file = IniFile.new 'temp.ini'
|
174
|
+
ini_file = IniFile.new(:filename => 'temp.ini')
|
179
175
|
assert_equal false, ini_file.has_section?('section_one')
|
180
176
|
assert_equal false, ini_file.has_section?('one')
|
181
177
|
assert_equal false, ini_file.has_section?('two')
|
@@ -188,7 +184,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
188
184
|
}
|
189
185
|
assert_equal expected, @ini_file[:section_one]
|
190
186
|
|
191
|
-
expected = {'three' => '3', 'multi' => "multiline
|
187
|
+
expected = {'three' => '3', 'multi' => "multiline support"}
|
192
188
|
assert_equal expected, @ini_file['section_two']
|
193
189
|
|
194
190
|
expected = {
|
@@ -210,7 +206,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
210
206
|
assert_nil @ini_file[nil]
|
211
207
|
|
212
208
|
expected = {}
|
213
|
-
ini_file = IniFile.new 'temp.ini'
|
209
|
+
ini_file = IniFile.new(:filename => 'temp.ini')
|
214
210
|
assert_equal expected, ini_file['section_one']
|
215
211
|
assert_equal expected, ini_file['one']
|
216
212
|
assert_nil ini_file[nil]
|
@@ -220,7 +216,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
220
216
|
expected = {
|
221
217
|
"section_two" =>
|
222
218
|
{
|
223
|
-
"three"=>"3", "multi"=>"multiline
|
219
|
+
"three"=>"3", "multi"=>"multiline support"
|
224
220
|
},
|
225
221
|
"section three" =>
|
226
222
|
{
|
@@ -240,19 +236,33 @@ class TestIniFile < Test::Unit::TestCase
|
|
240
236
|
# see if we can parse different style comments
|
241
237
|
#assert_raise(IniFile::Error) {IniFile.new 'test/data/comment.ini'}
|
242
238
|
|
243
|
-
ini_file = IniFile.new 'test/data/comment.ini', :comment => '#'
|
244
|
-
|
239
|
+
ini_file = IniFile.new(:filename => 'test/data/comment.ini', :comment => '#')
|
240
|
+
assert ini_file.has_section?('section_one')
|
241
|
+
assert_equal '20 + 22 = 42', ini_file['section_two']['multi']
|
245
242
|
|
246
243
|
# see if we can parse different style param separators
|
247
|
-
assert_raise(IniFile::Error) {IniFile.new 'test/data/param.ini'}
|
244
|
+
assert_raise(IniFile::Error) {IniFile.new(:filename => 'test/data/param.ini')}
|
248
245
|
|
249
|
-
ini_file = IniFile.new 'test/data/param.ini', :parameter => ':'
|
250
|
-
|
246
|
+
ini_file = IniFile.new(:filename => 'test/data/param.ini', :parameter => ':')
|
247
|
+
assert ini_file.has_section?('section_one')
|
251
248
|
assert_equal '1', ini_file['section_one']['one']
|
252
249
|
assert_equal '2', ini_file['section_one']['two']
|
253
250
|
|
254
251
|
# make sure we error out on files with bad lines
|
255
|
-
assert_raise(IniFile::Error) {IniFile.new 'test/data/bad_1.ini'}
|
252
|
+
assert_raise(IniFile::Error) {IniFile.new :filename => 'test/data/bad_1.ini'}
|
253
|
+
end
|
254
|
+
|
255
|
+
def test_initialize_from_string
|
256
|
+
content = File.read('test/data/good.ini')
|
257
|
+
|
258
|
+
ini_file = IniFile.new(content, :comment => ';')
|
259
|
+
assert ini_file.has_section?('section_one')
|
260
|
+
assert ini_file.has_section?('section_two')
|
261
|
+
assert ini_file.has_section?('section three')
|
262
|
+
assert ini_file.has_section?('section_four')
|
263
|
+
assert ini_file.has_section?('section_five')
|
264
|
+
|
265
|
+
assert_equal '7 & 8', ini_file['section_five']['seven and eight']
|
256
266
|
end
|
257
267
|
|
258
268
|
def test_sections
|
@@ -263,7 +273,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
263
273
|
|
264
274
|
assert_equal expected, @ini_file.sections.sort
|
265
275
|
|
266
|
-
ini_file = IniFile.new 'temp.ini'
|
276
|
+
ini_file = IniFile.new(:filename => 'temp.ini')
|
267
277
|
assert_equal [], ini_file.sections
|
268
278
|
end
|
269
279
|
|
@@ -285,18 +295,34 @@ class TestIniFile < Test::Unit::TestCase
|
|
285
295
|
tmp = 'test/data/temp.ini'
|
286
296
|
File.delete tmp if Kernel.test(?f, tmp)
|
287
297
|
|
288
|
-
@ini_file.save tmp
|
298
|
+
@ini_file.save(:filename => tmp)
|
289
299
|
assert_equal true, Kernel.test(?f, tmp)
|
290
300
|
|
291
301
|
File.delete tmp if Kernel.test(?f, tmp)
|
292
302
|
|
293
|
-
ini_file = IniFile.new tmp
|
303
|
+
ini_file = IniFile.new(:filename => tmp)
|
294
304
|
ini_file.save
|
295
305
|
assert_nil Kernel.test(?s, tmp)
|
296
306
|
|
297
307
|
File.delete tmp if Kernel.test(?f, tmp)
|
298
308
|
end
|
299
309
|
|
310
|
+
def test_read
|
311
|
+
assert @ini_file.has_section?('section_one')
|
312
|
+
|
313
|
+
@ini_file['section_one']['one'] = 42
|
314
|
+
@ini_file['section_one']['two'] = 42
|
315
|
+
assert_equal 42, @ini_file['section_one']['one']
|
316
|
+
assert_equal 42, @ini_file['section_one']['two']
|
317
|
+
|
318
|
+
@ini_file.read
|
319
|
+
assert_equal '1', @ini_file['section_one']['one']
|
320
|
+
assert_equal '2', @ini_file['section_one']['two']
|
321
|
+
|
322
|
+
@ini_file.read(:filename => 'test/data/mixed_comment.ini')
|
323
|
+
assert_equal false, @ini_file.has_section?('section_two')
|
324
|
+
end
|
325
|
+
|
300
326
|
def test_modifies_current_keys
|
301
327
|
ini = IniFile.load("test/data/tmp.ini")
|
302
328
|
ini["section one"]["one"] = 17
|
@@ -306,7 +332,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
306
332
|
end
|
307
333
|
|
308
334
|
def test_can_add_key_to_inifile
|
309
|
-
ini_file = IniFile.new("test/data/tmp.ini")
|
335
|
+
ini_file = IniFile.new(:filename => "test/data/tmp.ini")
|
310
336
|
ini_file["new_section"] = {}
|
311
337
|
ini_file.save
|
312
338
|
|
@@ -314,7 +340,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
314
340
|
end
|
315
341
|
|
316
342
|
def test_adds_correct_key_to_inifile
|
317
|
-
ini_file = IniFile.new("test/data/tmp.ini")
|
343
|
+
ini_file = IniFile.new(:filename => "test/data/tmp.ini")
|
318
344
|
ini_file["foo"] = {}
|
319
345
|
ini_file.save
|
320
346
|
|
@@ -322,7 +348,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
322
348
|
end
|
323
349
|
|
324
350
|
def test_assigns_values_to_inifile
|
325
|
-
ini_file = IniFile.new("test/data/tmp.ini")
|
351
|
+
ini_file = IniFile.new(:filename => "test/data/tmp.ini")
|
326
352
|
ini_file["foo"] = {
|
327
353
|
:bar => "baz"
|
328
354
|
}
|
@@ -331,7 +357,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
331
357
|
end
|
332
358
|
|
333
359
|
def test_assigns_correct_values_to_inifile
|
334
|
-
ini_file = IniFile.new("test/data/tmp.ini")
|
360
|
+
ini_file = IniFile.new(:filename => "test/data/tmp.ini")
|
335
361
|
ini_file["foo"] = {
|
336
362
|
:one => "two"
|
337
363
|
}
|
@@ -340,7 +366,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
340
366
|
end
|
341
367
|
|
342
368
|
def test_assignment_stringifies_key
|
343
|
-
ini_file = IniFile.new("test/data/tmp.ini")
|
369
|
+
ini_file = IniFile.new(:filename => "test/data/tmp.ini")
|
344
370
|
ini_file["foo"] = {:one => :two}
|
345
371
|
ini_file[:foo] = {}
|
346
372
|
assert_equal ini_file["foo"], {}
|
@@ -350,11 +376,12 @@ class TestIniFile < Test::Unit::TestCase
|
|
350
376
|
ini_file = IniFile.load('test/data/multiline.ini')
|
351
377
|
|
352
378
|
multiline = ini_file['section_three']
|
353
|
-
expected = {"three" => "hello
|
379
|
+
expected = {"three" => "hello multiline", "other" => "stuff"}
|
354
380
|
assert_equal expected, multiline
|
355
381
|
|
356
382
|
multiple = ini_file['section_four']
|
357
|
-
expected = {"four" => "hello
|
383
|
+
expected = {"four" => "hello multiple multilines",
|
384
|
+
"five" => "multiple lines\ninside of quotations\npreserve everything" }
|
358
385
|
assert_equal expected, multiple
|
359
386
|
|
360
387
|
multiple = ini_file['empty_lines']
|
@@ -397,7 +424,7 @@ class TestIniFile < Test::Unit::TestCase
|
|
397
424
|
|
398
425
|
if RUBY_VERSION >= '1.9'
|
399
426
|
def test_parse_encoding
|
400
|
-
ini_file = IniFile.new("test/data/browscap.ini", :encoding => 'ISO-8859-1')
|
427
|
+
ini_file = IniFile.new(:filename => "test/data/browscap.ini", :encoding => 'ISO-8859-1')
|
401
428
|
assert_equal ini_file['www.substancia.com AutoHTTPAgent (ver *)']['Browser'], "Subst\xE2ncia".force_encoding('ISO-8859-1')
|
402
429
|
end
|
403
430
|
|
@@ -405,10 +432,10 @@ class TestIniFile < Test::Unit::TestCase
|
|
405
432
|
tmp = 'test/data/tmp.ini'
|
406
433
|
File.delete tmp if Kernel.test(?f, tmp)
|
407
434
|
|
408
|
-
@ini_file = IniFile.new(tmp, :encoding => 'UTF-8')
|
435
|
+
@ini_file = IniFile.new(:filename => tmp, :encoding => 'UTF-8')
|
409
436
|
@ini_file['testutf-8'] = {"utf-8" => "appr\u20accier"}
|
410
437
|
|
411
|
-
@ini_file.save tmp
|
438
|
+
@ini_file.save(:filename => tmp)
|
412
439
|
|
413
440
|
test = File.open(tmp)
|
414
441
|
assert_equal test.external_encoding.to_s, 'UTF-8'
|
@@ -422,8 +449,9 @@ class TestIniFile < Test::Unit::TestCase
|
|
422
449
|
assert_equal %Q{There is a tab\tcharacter in here somewhere}, escaped['tabs']
|
423
450
|
assert_equal %Q{Who uses these anyways?\r}, escaped['carriage return']
|
424
451
|
assert_equal %Q{Trust newline!\nAlways there when you need him.\nSplittin' those lines.}, escaped['newline']
|
425
|
-
assert_equal %Q{Who'd be silly enough to put\0 a null character in the middle of a string
|
452
|
+
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']
|
426
453
|
assert_equal %q{This string \t contains \n no \r special \0 characters!}, escaped['backslash']
|
454
|
+
assert_equal %Q{Escaping works\tinside quoted strings!}, escaped['quoted']
|
427
455
|
end
|
428
456
|
|
429
457
|
def test_value_escaping_disabled
|
@@ -433,8 +461,9 @@ class TestIniFile < Test::Unit::TestCase
|
|
433
461
|
assert_equal %q{There is a tab\tcharacter in here somewhere}, escaped['tabs']
|
434
462
|
assert_equal %q{Who uses these anyways?\r}, escaped['carriage return']
|
435
463
|
assert_equal %q{Trust newline!\nAlways there when you need him.\nSplittin' those lines.}, escaped['newline']
|
436
|
-
assert_equal %Q{Who'd be silly enough to put\\0 a null character in the middle of a string
|
464
|
+
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']
|
437
465
|
assert_equal %q{This string \\\\t contains \\\\n no \\\\r special \\\\0 characters!}, escaped['backslash']
|
466
|
+
assert_equal %q{Escaping works\tinside quoted strings!}, escaped['quoted']
|
438
467
|
end
|
439
468
|
|
440
469
|
def test_global_section
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inifile
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,30 +9,40 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bones-git
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version:
|
21
|
+
version: '0'
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: bones
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
35
|
- - ! '>='
|
31
36
|
- !ruby/object:Gem::Version
|
32
|
-
version: 3.
|
37
|
+
version: 3.8.0
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 3.8.0
|
36
46
|
description: ! "Although made popular by Windows, INI files can be used on any system
|
37
47
|
thanks\nto their flexibility. They allow a program to store configuration data,
|
38
48
|
which\ncan then be easily parsed and changed. Two notable systems that use the INI\nformat
|
@@ -61,6 +71,7 @@ files:
|
|
61
71
|
- History.txt
|
62
72
|
- README.md
|
63
73
|
- Rakefile
|
74
|
+
- a.rb
|
64
75
|
- lib/inifile.rb
|
65
76
|
- test/data/bad_1.ini
|
66
77
|
- test/data/browscap.ini
|
@@ -95,7 +106,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
106
|
version: '0'
|
96
107
|
requirements: []
|
97
108
|
rubyforge_project: inifile
|
98
|
-
rubygems_version: 1.8.
|
109
|
+
rubygems_version: 1.8.24
|
99
110
|
signing_key:
|
100
111
|
specification_version: 3
|
101
112
|
summary: INI file reader and writer
|