Вот модуль для чтения и записи .ini-файлов с как можно меньшим изменением исходного файла (для файлов, которые читают люди и машины):
class IniFileExc < RuntimeError
end</p>
<p>class IniNode
def initialize(name, value=nil)
@line_start = -1;
@line_end = -1;
@level = 0;
@name = name;
@value = value;
@keys = {};
@keylist = [];
@modified = false;
@deleted = false;
end
attr_reader :level,:line_start,:line_end,:name,:value,:keylist,:keys,:modified,:deleted
attr_writer :level,:line_start,:line_end,:name,:value,:keylist,:keys,:modified,:deleted</p>
<p>def to_str
return @name.to_s + ' = ' + @value.to_s;
end</p>
<p>def to_s
return @value.to_s;
end
def to_i
return @value.to_i
end
def to_f
return @value.to_f;
end</p>
<p>def
insert(key, nil);
return @keys[key];
end</p>
<p>def insert(key, value)
return false if (@keys.has_key?(key));
node = nil;
if (value && ((value.class == IniNode) || (value.class == IniSection)))
node = value;
else
if (@level <= 0)
node = IniSection.new(key);
else
node = IniNode.new(key, value)
end
end
node.line_start = @line_end + 1 if (node.line_start < 0);
node.level = @level + 1;
@keys[key] = node;
@keylist.push(key);
return true;
end</p>
<p>def []=(key, value)
rc = insert(key, value);
@keys[key].value = value;
@keys[key].modified = true;
@modified = true;
end</p>
<p>def delete(key)
return false if (! @keys.has_key?(key));
@keys[key].deleted = true;
@modified = true;
end
end</p>
<p>class IniSection < IniNode
def initialize(name)
super(name);
end</p>
<p>def to_str
return ('[' + @name + ']');
end
end
<pre>
class IniFile < IniNode
def initialize(path, load=true)
super(path);
@lines = [];
reload() if (load);
end</p>
<p>def reload
begin
input = File.new(@name, "r");
rescue
raise;
else
prevnode = node = self;
lineno = 0;
input.each do |line|
@lines.push(line);
parsed_node = parse_line(lineno, line);
if (parsed_node);
if (parsed_node.class == IniSection)
if (parsed_node != node)
prev_node = node;
node = parsed_node;
insert(node.name, node);
prev_node.line_end = lineno - 1;
end
else
node.insert(parsed_node.name, parsed_node);
end
end
lineno += 1;
end
input.close;</p>
<pre><code> node.line_end = @line_end = lineno - 1;
end
конец
def parse_line (бельё, строка)
вернуть nil if (line = ~ / ^ \ s * $ /);
вернуть nil if (line = ~ / ^ \ s * # /);
вернуть nil if (line = ~ / ^ \ s *; /);
if (line = ~ /^\s*[\s*(.+)\s*].$/)
rv = IniSection.new ($ 1);
rv.line_start = белья;
rv.level = @level + 1;
возврат рв;
элсиф #; \ s \ п]) $ /).
rv = IniNode.new ($ 1, $ 2);
rv.line_start = rv.line_end = lineno;
rv.level = @level + 2;
возврат рв;
конец
вернуть ноль;
конец
def write
вставлено = {};
@ keylist.each do | sect |
sectnode = @keys [sect];
далее if (! sectnode.modified || sectnode.deleted);
if (sectnode.line_end <0)
@ Lines.push ( "\ п");
@ lines.push (sectnode.to_str + "\ n");
конец
sectnode.keylist.each do | key |
keynode = sectnode.keys [ключ];
далее if (! keynode.modified || keynode.deleted);
if (keynode.line_end <0)
if (sectnode.line_end <0)
@ lines.push (keynode.to_str + "\ n");
еще
idx = sectnode.line_end.to_i;
вставлено [idx] = [] if (! insert.has_key? (idx));
вставляется [IDX] .С (keynode.to_str);
конец
еще
line = @lines [keynode.line_start];
if (строка = ~ / ^ (\ s *) (\ S?. <em>[^ = \ s] \ s = \ s * \ S?. + [^ #; \ s]) (\ с * [#;]. ) $ /)
строка = $ 1 + keynode.to_str + $ 3 + "\ n";
еще
line = line.gsub (/ ^ (\ s ) (\ S?. [^ = \ s] \ s = \ s * \ S? [^ #;] + [^ # ; \ п \ s]) (*) $ /) {.
$ 1 + keynode.to_str + $ 3};
конец
@lines [keynode.line_start] = line;
конец
конец
конец
<pre>
deleted = {};
@keylist.each do |sect|
sectnode = @keys[sect];
next if (!sectnode.deleted && !sectnode.modified);
if (sectnode.deleted && (sectnode.line_start >= 0) && (sectnode.line_end >= 0) \
&& (sectnode.line_end >= sectnode.line_start))
for i in sectnode.line_start..sectnode.line_end
deleted[i] = true;
end
end
sectnode.keylist.each do |key|
keynode = sectnode.keys[key];
next if (!keynode.deleted);
deleted[keynode.line_start.to_i] = true \
if ((keynode.line_start >= 0) && (keynode.line_end >= 0) && (keynode.line_start == keynode.line_end));
end
end</p>
<pre><code>begin
file = File.new(@name, 'w');
rescue
raise(IniFileExc, "Failed to open " + @name + " for writing: #{$!}", caller);
else
cnt = -1;
@lines.each do |line|
cnt += 1;
if (inserted.has_key?(cnt))
inserted[cnt].each do |ins|
file.puts(ins + "\n");
end
end
next if (deleted[cnt]);
file.puts(line);
end
file.close;
end
конец
конец
Пример использования:
begin
ini = IniFile.new('file.ini');
ini['common']['param'] = 'value';
ini['common'].delete('unused_param');
ini.delete('unused_section');
print "Valuable value: ", ini['common']['param'], "\n";
ini.write;
rescue IniFileExc
print "Oh, that's not good: ", $!, "\n";
end
Надеюсь, это поможет.