iniparse 0.2.1
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/LICENSE +19 -0
- data/README.rdoc +75 -0
- data/Rakefile +102 -0
- data/lib/iniparse.rb +68 -0
- data/lib/iniparse/document.rb +62 -0
- data/lib/iniparse/generator.rb +200 -0
- data/lib/iniparse/line_collection.rb +164 -0
- data/lib/iniparse/lines.rb +290 -0
- data/lib/iniparse/parser.rb +92 -0
- data/lib/iniparse/version.rb +3 -0
- data/spec/document_spec.rb +72 -0
- data/spec/fixture_spec.rb +166 -0
- data/spec/fixtures/openttd.ini +397 -0
- data/spec/fixtures/race07.ini +133 -0
- data/spec/fixtures/smb.ini +102 -0
- data/spec/generator/method_missing_spec.rb +104 -0
- data/spec/generator/with_section_blocks_spec.rb +322 -0
- data/spec/generator/without_section_blocks_spec.rb +136 -0
- data/spec/iniparse_spec.rb +21 -0
- data/spec/line_collection_spec.rb +212 -0
- data/spec/lines_spec.rb +409 -0
- data/spec/parser/document_parsing_spec.rb +50 -0
- data/spec/parser/line_parsing_spec.rb +367 -0
- data/spec/spec_fixtures.rb +46 -0
- data/spec/spec_helper.rb +164 -0
- data/spec/spec_helper_spec.rb +201 -0
- metadata +92 -0
@@ -0,0 +1,136 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/../spec_helper'
|
2
|
+
|
3
|
+
# Tests use of the Generator when used like so:
|
4
|
+
#
|
5
|
+
# @gen = IniParse::Generator.new
|
6
|
+
# @gen.comment('My very own comment')
|
7
|
+
# @gen.section('my_section')
|
8
|
+
# @gen.option('my_option', 'my value')
|
9
|
+
# ...
|
10
|
+
#
|
11
|
+
# Or
|
12
|
+
#
|
13
|
+
# IniParse::Generator.gen do |doc|
|
14
|
+
# doc.comment('My very own comment')
|
15
|
+
# doc.section('my_section')
|
16
|
+
# doc.option('my_option', 'my value')
|
17
|
+
# end
|
18
|
+
#
|
19
|
+
|
20
|
+
describe 'When generating a document using Generator without section blocks,' do
|
21
|
+
before(:each) { @gen = IniParse::Generator.new }
|
22
|
+
|
23
|
+
# --
|
24
|
+
# ==========================================================================
|
25
|
+
# SECTION LINES
|
26
|
+
# ==========================================================================
|
27
|
+
# ++
|
28
|
+
|
29
|
+
describe 'adding a section' do
|
30
|
+
it 'should add a Section to the document' do
|
31
|
+
@gen.section("a section")
|
32
|
+
@gen.document.should have_section("a section")
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should change the Generator context to the section' do
|
36
|
+
@gen.section("a section")
|
37
|
+
@gen.context.should == @gen.document['a section']
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should pass extra options to the Section instance' do
|
41
|
+
@gen.section("a section", :indent => ' ')
|
42
|
+
@gen.document["a section"].to_ini.should match(/\A /)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# --
|
47
|
+
# ==========================================================================
|
48
|
+
# OPTION LINES
|
49
|
+
# ==========================================================================
|
50
|
+
# ++
|
51
|
+
|
52
|
+
describe 'adding a option' do
|
53
|
+
it 'should pass extra options to the Option instance' do
|
54
|
+
@gen.section("a section")
|
55
|
+
@gen.option("my option", "a value", :indent => ' ')
|
56
|
+
@gen.document["a section"].option("my option").to_ini.should match(/^ /)
|
57
|
+
end
|
58
|
+
|
59
|
+
describe 'when the context is a Document' do
|
60
|
+
it "should raise a NoSectionError" do
|
61
|
+
lambda { @gen.option("key", "value") }.should \
|
62
|
+
raise_error(IniParse::NoSectionError)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'when the context is a Section' do
|
67
|
+
it 'should add the option to the section' do
|
68
|
+
@gen.section("a section")
|
69
|
+
@gen.option("my option", "a value")
|
70
|
+
@gen.document["a section"].should have_option("my option")
|
71
|
+
@gen.document["a section"]["my option"].should == "a value"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# --
|
77
|
+
# ==========================================================================
|
78
|
+
# COMMENT LINES
|
79
|
+
# ==========================================================================
|
80
|
+
# ++
|
81
|
+
|
82
|
+
describe 'adding a comment' do
|
83
|
+
it 'should pass extra options to the Option instance' do
|
84
|
+
@gen.comment("My comment", :indent => ' ')
|
85
|
+
@gen.document.lines.to_a.first.to_ini.should match(/^ /)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should ignore any extra :comment option' do
|
89
|
+
@gen.comment("My comment", :comment => 'Ignored')
|
90
|
+
comment_ini = @gen.document.lines.to_a.first.to_ini
|
91
|
+
comment_ini.should match(/My comment/)
|
92
|
+
comment_ini.should_not match(/Ignored/)
|
93
|
+
end
|
94
|
+
|
95
|
+
describe 'when the context is a Document' do
|
96
|
+
it 'should add a comment to the document' do
|
97
|
+
@gen.comment('My comment')
|
98
|
+
comment = @gen.document.lines.to_a.first
|
99
|
+
comment.should be_kind_of(IniParse::Lines::Comment)
|
100
|
+
comment.to_ini.should match(/; My comment/)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
describe 'when the context is a Section' do
|
105
|
+
it 'should add a comment to the section' do
|
106
|
+
@gen.section('a section')
|
107
|
+
@gen.comment('My comment')
|
108
|
+
comment = @gen.document['a section'].lines.to_a.first
|
109
|
+
comment.should be_kind_of(IniParse::Lines::Comment)
|
110
|
+
comment.to_ini.should match(/My comment/)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
# --
|
116
|
+
# ==========================================================================
|
117
|
+
# BLANK LINES
|
118
|
+
# ==========================================================================
|
119
|
+
# ++
|
120
|
+
|
121
|
+
describe 'adding a blank line' do
|
122
|
+
it 'should add a blank line to the document when it is the context' do
|
123
|
+
@gen.blank
|
124
|
+
comment = @gen.document.lines.to_a.first
|
125
|
+
comment.should be_kind_of(IniParse::Lines::Blank)
|
126
|
+
end
|
127
|
+
|
128
|
+
it 'should add a blank line to the section when it is the context' do
|
129
|
+
@gen.section('a section')
|
130
|
+
@gen.blank
|
131
|
+
comment = @gen.document['a section'].lines.to_a.first
|
132
|
+
comment.should be_kind_of(IniParse::Lines::Blank)
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
|
4
|
+
describe "IniParse" do
|
5
|
+
describe '.open' do
|
6
|
+
before(:each) { File.stub!(:read).and_return('[section]') }
|
7
|
+
|
8
|
+
it 'should return an IniParse::Document' do
|
9
|
+
IniParse.open('/my/path.ini').should be_kind_of(IniParse::Document)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'should set the path on the returned Document' do
|
13
|
+
IniParse.open('/my/path.ini').path.should == '/my/path.ini'
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'should read the file at the given path' do
|
17
|
+
File.should_receive(:read).with('/my/path.ini').and_return('[section]')
|
18
|
+
IniParse.open('/my/path.ini')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
# ----------------------------------------------------------------------------
|
4
|
+
# Shared specs for all Collection types...
|
5
|
+
# ----------------------------------------------------------------------------
|
6
|
+
|
7
|
+
describe "LineCollection", :shared => true do
|
8
|
+
before(:each) do
|
9
|
+
@collection << (@c1 = IniParse::Lines::Comment.new)
|
10
|
+
@collection << @i1
|
11
|
+
@collection << @i2
|
12
|
+
@collection << (@b1 = IniParse::Lines::Blank.new)
|
13
|
+
@collection << @i3
|
14
|
+
@collection << (@b2 = IniParse::Lines::Blank.new)
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#each' do
|
18
|
+
it 'should remove blanks and comments by default' do
|
19
|
+
@collection.each { |l| l.should be_kind_of(@i1.class) }
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should not remove blanks and comments if true is given' do
|
23
|
+
arr = []
|
24
|
+
|
25
|
+
# map(true)->each(true) not possible with Enumerable
|
26
|
+
@collection.each(true) do |line|
|
27
|
+
arr << line
|
28
|
+
end
|
29
|
+
|
30
|
+
arr.should == [@c1, @i1, @i2, @b1, @i3, @b2]
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#[]' do
|
35
|
+
it 'should fetch the correct value' do
|
36
|
+
@collection['first'].should == @i1
|
37
|
+
@collection['second'].should == @i2
|
38
|
+
@collection['third'].should == @i3
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should return nil if the given key does not exist' do
|
42
|
+
@collection['does not exist'].should be_nil
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe '#[]=' do
|
47
|
+
it 'should successfully add a new key' do
|
48
|
+
@collection['fourth'] = @new
|
49
|
+
@collection['fourth'].should == @new
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should successfully update an existing key' do
|
53
|
+
@collection['second'] = @new
|
54
|
+
@collection['second'].should == @new
|
55
|
+
|
56
|
+
# Make sure the old data is gone.
|
57
|
+
@collection.detect { |s| s.key == 'second' }.should be_nil
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should typecast given keys to a string' do
|
61
|
+
@collection[:a_symbol] = @new
|
62
|
+
@collection['a_symbol'].should == @new
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe '#<<' do
|
67
|
+
it 'should set the key correctly if given a new item' do
|
68
|
+
@collection.should_not have_key(@new.key)
|
69
|
+
@collection << @new
|
70
|
+
@collection.should have_key(@new.key)
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'should append Blank lines' do
|
74
|
+
@collection << IniParse::Lines::Blank.new
|
75
|
+
@collection.instance_variable_get(:@lines).last.should \
|
76
|
+
be_kind_of(IniParse::Lines::Blank)
|
77
|
+
end
|
78
|
+
|
79
|
+
it 'should append Comment lines' do
|
80
|
+
@collection << IniParse::Lines::Comment.new
|
81
|
+
@collection.instance_variable_get(:@lines).last.should \
|
82
|
+
be_kind_of(IniParse::Lines::Comment)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'should return self' do
|
86
|
+
(@collection << @new).should == @collection
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
describe '#delete' do
|
91
|
+
it 'should remove the given value and adjust the indicies' do
|
92
|
+
@collection['second'].should_not be_nil
|
93
|
+
@collection.delete('second')
|
94
|
+
@collection['second'].should be_nil
|
95
|
+
@collection['first'].should == @i1
|
96
|
+
@collection['third'].should == @i3
|
97
|
+
end
|
98
|
+
|
99
|
+
it "should do nothing if the supplied key does not exist" do
|
100
|
+
@collection.delete('does not exist')
|
101
|
+
@collection['first'].should == @i1
|
102
|
+
@collection['third'].should == @i3
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#to_a' do
|
107
|
+
it 'should return an array' do
|
108
|
+
@collection.to_a.should be_kind_of(Array)
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'should include all lines' do
|
112
|
+
@collection.to_a.should == [@c1, @i1, @i2, @b1, @i3, @b2]
|
113
|
+
end
|
114
|
+
|
115
|
+
it 'should include references to the same line objects as the collection' do
|
116
|
+
@collection << @new
|
117
|
+
@collection.to_a.last.object_id.should == @new.object_id
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
describe '#to_hash' do
|
122
|
+
it 'should return a hash' do
|
123
|
+
@collection.to_hash.should be_kind_of(Hash)
|
124
|
+
end
|
125
|
+
|
126
|
+
it 'should have the correct keys' do
|
127
|
+
hash = @collection.to_hash
|
128
|
+
hash.keys.length.should == 3
|
129
|
+
hash.should have_key('first')
|
130
|
+
hash.should have_key('second')
|
131
|
+
hash.should have_key('third')
|
132
|
+
end
|
133
|
+
|
134
|
+
it 'should have the correct values' do
|
135
|
+
hash = @collection.to_hash
|
136
|
+
hash['first'].should == @i1
|
137
|
+
hash['second'].should == @i2
|
138
|
+
hash['third'].should == @i3
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
describe '#keys' do
|
143
|
+
it 'should return an array of strings' do
|
144
|
+
@collection.keys.should == ['first', 'second', 'third']
|
145
|
+
end
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# ----------------------------------------------------------------------------
|
150
|
+
# On with the collection specs...
|
151
|
+
# ----------------------------------------------------------------------------
|
152
|
+
|
153
|
+
describe 'IniParse::OptionCollection' do
|
154
|
+
before(:each) do
|
155
|
+
@collection = IniParse::OptionCollection.new
|
156
|
+
@i1 = IniParse::Lines::Option.new('first', 'v1')
|
157
|
+
@i2 = IniParse::Lines::Option.new('second', 'v2')
|
158
|
+
@i3 = IniParse::Lines::Option.new('third', 'v3')
|
159
|
+
@new = IniParse::Lines::Option.new('fourth', 'v4')
|
160
|
+
end
|
161
|
+
|
162
|
+
it_should_behave_like 'LineCollection'
|
163
|
+
|
164
|
+
describe '#<<' do
|
165
|
+
it 'should raise a LineNotAllowed exception if a Section is pushed' do
|
166
|
+
lambda { @collection << IniParse::Lines::Section.new('s') }.should \
|
167
|
+
raise_error(IniParse::LineNotAllowed)
|
168
|
+
end
|
169
|
+
|
170
|
+
it 'should add the Option as a duplicate if an option with the same key exists' do
|
171
|
+
option_one = IniParse::Lines::Option.new('k', 'value one')
|
172
|
+
option_two = IniParse::Lines::Option.new('k', 'value two')
|
173
|
+
|
174
|
+
@collection << option_one
|
175
|
+
@collection << option_two
|
176
|
+
|
177
|
+
@collection['k'].should == [option_one, option_two]
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
describe '#keys' do
|
182
|
+
it 'should handle duplicates' do
|
183
|
+
@collection << IniParse::Lines::Option.new('first', 'v5')
|
184
|
+
@collection.keys.should == ['first', 'second', 'third']
|
185
|
+
end
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe 'IniParse::SectionCollection' do
|
190
|
+
before(:each) do
|
191
|
+
@collection = IniParse::SectionCollection.new
|
192
|
+
@i1 = IniParse::Lines::Section.new('first')
|
193
|
+
@i2 = IniParse::Lines::Section.new('second')
|
194
|
+
@i3 = IniParse::Lines::Section.new('third')
|
195
|
+
@new = IniParse::Lines::Section.new('fourth')
|
196
|
+
end
|
197
|
+
|
198
|
+
it_should_behave_like 'LineCollection'
|
199
|
+
|
200
|
+
describe '#<<' do
|
201
|
+
it 'should raise a LineNotAllowed exception if an Option is pushed' do
|
202
|
+
lambda { @collection << IniParse::Lines::Option.new('k', 'v') }.should \
|
203
|
+
raise_error(IniParse::LineNotAllowed)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'should add merge Section with the other, if it is a duplicate' do
|
207
|
+
new_section = IniParse::Lines::Section.new('first')
|
208
|
+
@i1.should_receive(:merge!).with(new_section).once
|
209
|
+
@collection << new_section
|
210
|
+
end
|
211
|
+
end
|
212
|
+
end
|
data/spec/lines_spec.rb
ADDED
@@ -0,0 +1,409 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper'
|
2
|
+
|
3
|
+
module IniParse::Test
|
4
|
+
class FakeLine
|
5
|
+
include IniParse::Lines::Line
|
6
|
+
|
7
|
+
def line_contents
|
8
|
+
'fake line'
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "IniParse::Lines::Line module" do
|
14
|
+
describe '#to_ini' do
|
15
|
+
it 'should return +line_contents+' do
|
16
|
+
IniParse::Test::FakeLine.new.to_ini.should == 'fake line'
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should preserve line indents' do
|
20
|
+
IniParse::Test::FakeLine.new(
|
21
|
+
:indent => ' '
|
22
|
+
).to_ini.should == ' fake line'
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'when a comment is set' do
|
26
|
+
it 'should correctly include the comment' do
|
27
|
+
IniParse::Test::FakeLine.new(
|
28
|
+
:comment => 'comment', :comment_sep => ';', :comment_offset => 10
|
29
|
+
).to_ini.should == 'fake line ; comment'
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should correctly indent the comment' do
|
33
|
+
IniParse::Test::FakeLine.new(
|
34
|
+
:comment => 'comment', :comment_sep => ';', :comment_offset => 15
|
35
|
+
).to_ini.should == 'fake line ; comment'
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'should use ";" as a default comment seperator' do
|
39
|
+
IniParse::Test::FakeLine.new(
|
40
|
+
:comment => 'comment'
|
41
|
+
).to_ini.should == 'fake line ; comment'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should use the correct seperator' do
|
45
|
+
IniParse::Test::FakeLine.new(
|
46
|
+
:comment => 'comment', :comment_sep => '#'
|
47
|
+
).to_ini.should == 'fake line # comment'
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should use the ensure a space is added before the comment seperator' do
|
51
|
+
IniParse::Test::FakeLine.new(
|
52
|
+
:comment => 'comment', :comment_sep => ';', :comment_offset => 0
|
53
|
+
).to_ini.should == 'fake line ; comment'
|
54
|
+
end
|
55
|
+
|
56
|
+
it 'should not add an extra space if the line is blank' do
|
57
|
+
line = IniParse::Test::FakeLine.new(
|
58
|
+
:comment => 'comment', :comment_sep => ';', :comment_offset => 0
|
59
|
+
)
|
60
|
+
|
61
|
+
line.stub!(:line_contents).and_return('')
|
62
|
+
line.to_ini.should == '; comment'
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe 'when no comment is set' do
|
67
|
+
it 'should not add trailing space if :comment_offset has a value' do
|
68
|
+
IniParse::Test::FakeLine.new(:comment_offset => 10).to_ini.should == 'fake line'
|
69
|
+
end
|
70
|
+
|
71
|
+
it 'should not add a comment seperator :comment_sep has a value' do
|
72
|
+
IniParse::Test::FakeLine.new(:comment_sep => ';').to_ini.should == 'fake line'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
describe '#has_comment?' do
|
78
|
+
it 'should return true if :comment has a non-blank value' do
|
79
|
+
IniParse::Test::FakeLine.new(:comment => 'comment').should have_comment
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should return true if :comment has a blank value' do
|
83
|
+
IniParse::Test::FakeLine.new(:comment => '').should have_comment
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'should return false if :comment has a nil value' do
|
87
|
+
IniParse::Test::FakeLine.new.should_not have_comment
|
88
|
+
IniParse::Test::FakeLine.new(:comment => nil).should_not have_comment
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
#
|
94
|
+
# Section
|
95
|
+
#
|
96
|
+
|
97
|
+
describe 'IniParse::Lines::Section' do
|
98
|
+
before(:each) { @section = IniParse::Lines::Section.new('a section') }
|
99
|
+
|
100
|
+
it 'should respond_to +lines+' do
|
101
|
+
@section.should respond_to(:lines)
|
102
|
+
end
|
103
|
+
|
104
|
+
it 'should not respond_to +lines=+' do
|
105
|
+
@section.should_not respond_to(:lines=)
|
106
|
+
end
|
107
|
+
|
108
|
+
it 'should include Enumerable' do
|
109
|
+
IniParse::Lines::Section.included_modules.should include(Enumerable)
|
110
|
+
end
|
111
|
+
|
112
|
+
describe '#initialize' do
|
113
|
+
it 'should typecast the given key to a string' do
|
114
|
+
IniParse::Lines::Section.new(:symbol).key.should == 'symbol'
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe '#option' do
|
119
|
+
it 'should retrieve the line identified by the given key' do
|
120
|
+
option = IniParse::Lines::Option.new('k', 'value one')
|
121
|
+
@section.lines << option
|
122
|
+
@section.option('k').should == option
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'should return nil if the given key does not exist' do
|
126
|
+
@section.option('does_not_exist').should be_nil
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
describe '#each' do
|
131
|
+
it 'should call #each on +lines+' do
|
132
|
+
@section.lines.should_receive(:each)
|
133
|
+
@section.each { |l| }
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#[]' do
|
138
|
+
it 'should return nil if the given key does not exist' do
|
139
|
+
@section['k'].should be_nil
|
140
|
+
end
|
141
|
+
|
142
|
+
it 'should return a value if the given key exists' do
|
143
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v')
|
144
|
+
@section['k'].should == 'v'
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'should return an array of values if the key is a duplicate' do
|
148
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v1')
|
149
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v2')
|
150
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v3')
|
151
|
+
@section['k'].should == ['v1', 'v2', 'v3']
|
152
|
+
end
|
153
|
+
|
154
|
+
it 'should typecast the key to a string' do
|
155
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v')
|
156
|
+
@section[:k].should == 'v'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
describe '#[]=' do
|
161
|
+
it 'should add a new Option with the given key and value' do
|
162
|
+
@section['k'] = 'a value'
|
163
|
+
@section.option('k').should be_kind_of(IniParse::Lines::Option)
|
164
|
+
@section['k'].should == 'a value'
|
165
|
+
end
|
166
|
+
|
167
|
+
it 'should update the Option if one already exists' do
|
168
|
+
@section.lines << IniParse::Lines::Option.new('k', 'orig value')
|
169
|
+
@section['k'] = 'new value'
|
170
|
+
@section['k'].should == 'new value'
|
171
|
+
end
|
172
|
+
|
173
|
+
it 'should replace the existing Option if it is an array' do
|
174
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v1')
|
175
|
+
@section.lines << IniParse::Lines::Option.new('k', 'v2')
|
176
|
+
@section['k'] = 'new value'
|
177
|
+
@section.option('k').should be_kind_of(IniParse::Lines::Option)
|
178
|
+
@section['k'].should == 'new value'
|
179
|
+
end
|
180
|
+
|
181
|
+
it 'should typecast the key to a string' do
|
182
|
+
@section[:k] = 'a value'
|
183
|
+
@section['k'].should == 'a value'
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
describe '#merge!' do
|
188
|
+
before(:each) do
|
189
|
+
@section.lines << IniParse::Lines::Option.new('a', 'val1')
|
190
|
+
@section.lines << IniParse::Lines::Blank.new
|
191
|
+
@section.lines << IniParse::Lines::Comment.new
|
192
|
+
@section.lines << IniParse::Lines::Option.new('b', 'val2')
|
193
|
+
|
194
|
+
@new_section = IniParse::Lines::Section.new('new section')
|
195
|
+
end
|
196
|
+
|
197
|
+
it 'should merge options from the given Section into the receiver' do
|
198
|
+
@new_section.lines << IniParse::Lines::Option.new('c', 'val3')
|
199
|
+
@new_section.lines << IniParse::Lines::Option.new('d', 'val4')
|
200
|
+
|
201
|
+
@section.merge!(@new_section)
|
202
|
+
@section['a'].should == 'val1'
|
203
|
+
@section['b'].should == 'val2'
|
204
|
+
@section['c'].should == 'val3'
|
205
|
+
@section['d'].should == 'val4'
|
206
|
+
end
|
207
|
+
|
208
|
+
it 'should handle duplicates' do
|
209
|
+
@new_section.lines << IniParse::Lines::Option.new('a', 'val2')
|
210
|
+
@section.merge!(@new_section)
|
211
|
+
@section['a'].should == ['val1', 'val2']
|
212
|
+
end
|
213
|
+
|
214
|
+
it 'should handle duplicates on both sides' do
|
215
|
+
@section.lines << IniParse::Lines::Option.new('a', 'val2')
|
216
|
+
@new_section.lines << IniParse::Lines::Option.new('a', 'val3')
|
217
|
+
@new_section.lines << IniParse::Lines::Option.new('a', 'val4')
|
218
|
+
|
219
|
+
@section.merge!(@new_section)
|
220
|
+
@section['a'].should == ['val1', 'val2', 'val3', 'val4']
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'should copy blank lines' do
|
224
|
+
@new_section.lines << IniParse::Lines::Blank.new
|
225
|
+
@section.merge!(@new_section)
|
226
|
+
line = nil
|
227
|
+
@section.each(true) { |l| line = l }
|
228
|
+
line.should be_kind_of(IniParse::Lines::Blank)
|
229
|
+
end
|
230
|
+
|
231
|
+
it 'should copy comments' do
|
232
|
+
@new_section.lines << IniParse::Lines::Comment.new
|
233
|
+
@section.merge!(@new_section)
|
234
|
+
line = nil
|
235
|
+
@section.each(true) { |l| line = l }
|
236
|
+
line.should be_kind_of(IniParse::Lines::Comment)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
describe '#to_ini' do
|
241
|
+
it 'should include the section key' do
|
242
|
+
IniParse::Lines::Section.new('a section').to_ini.should == '[a section]'
|
243
|
+
end
|
244
|
+
|
245
|
+
it 'should include lines belonging to the section' do
|
246
|
+
@section.lines << IniParse::Lines::Option.new('a', 'val1')
|
247
|
+
@section.lines << IniParse::Lines::Blank.new
|
248
|
+
@section.lines << IniParse::Lines::Comment.new(
|
249
|
+
:comment => 'my comment', :comment_sep => ';', :comment_offset => 0
|
250
|
+
)
|
251
|
+
@section.lines << IniParse::Lines::Option.new('b', 'val2')
|
252
|
+
|
253
|
+
@section.to_ini.should == <<-INI.margin
|
254
|
+
[a section]
|
255
|
+
a = val1
|
256
|
+
|
257
|
+
; my comment
|
258
|
+
b = val2
|
259
|
+
INI
|
260
|
+
end
|
261
|
+
|
262
|
+
it 'should include duplicate lines' do
|
263
|
+
@section.lines << IniParse::Lines::Option.new('a', 'val1')
|
264
|
+
@section.lines << IniParse::Lines::Option.new('a', 'val2')
|
265
|
+
|
266
|
+
@section.to_ini.should == <<-INI.margin
|
267
|
+
[a section]
|
268
|
+
a = val1
|
269
|
+
a = val2
|
270
|
+
INI
|
271
|
+
end
|
272
|
+
end
|
273
|
+
|
274
|
+
describe '#has_option?' do
|
275
|
+
before do
|
276
|
+
@section['first'] = 'value'
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'should return true if an option with the given key exists' do
|
280
|
+
@section.should have_option('first')
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'should return true if no option with the given key exists' do
|
284
|
+
@section.should_not have_option('second')
|
285
|
+
end
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
#
|
290
|
+
# Option
|
291
|
+
#
|
292
|
+
|
293
|
+
describe 'Iniparse::Lines::Option' do
|
294
|
+
describe '#initialize' do
|
295
|
+
it 'should typecast the given key to a string' do
|
296
|
+
IniParse::Lines::Option.new(:symbol, '').key.should == 'symbol'
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
describe '#to_ini' do
|
301
|
+
it 'should include the key and value' do
|
302
|
+
IniParse::Lines::Option.new('key', 'value').to_ini.should == 'key = value'
|
303
|
+
end
|
304
|
+
end
|
305
|
+
|
306
|
+
describe '.parse' do
|
307
|
+
def parse(line, opts = {})
|
308
|
+
IniParse::Lines::Option.parse(line, opts)
|
309
|
+
end
|
310
|
+
|
311
|
+
it 'should typecast empty values to nil' do
|
312
|
+
parse('key =').should be_option_tuple('key', nil)
|
313
|
+
parse('key = ').should be_option_tuple('key', nil)
|
314
|
+
parse('key = ').should be_option_tuple('key', nil)
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'should typecast "true" to TrueClass' do
|
318
|
+
parse('key = true').should be_option_tuple('key', true)
|
319
|
+
parse('key = TRUE').should be_option_tuple('key', true)
|
320
|
+
end
|
321
|
+
|
322
|
+
it 'should typecast "false" to FalseClass' do
|
323
|
+
parse('key = false').should be_option_tuple('key', false)
|
324
|
+
parse('key = FALSE').should be_option_tuple('key', false)
|
325
|
+
end
|
326
|
+
|
327
|
+
it 'should typecast integer values to Integer' do
|
328
|
+
parse('key = 1').should be_option_tuple('key', 1)
|
329
|
+
parse('key = 10').should be_option_tuple('key', 10)
|
330
|
+
end
|
331
|
+
|
332
|
+
it 'should not typecast integers with a leading 0 to Integer' do
|
333
|
+
parse('key = 0700').should be_option_tuple('key', '0700')
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'should typecast negative integer values to Integer' do
|
337
|
+
parse('key = -1').should be_option_tuple('key', -1)
|
338
|
+
end
|
339
|
+
|
340
|
+
it 'should typecast float values to Float' do
|
341
|
+
parse('key = 3.14159265').should be_option_tuple('key', 3.14159265)
|
342
|
+
end
|
343
|
+
|
344
|
+
it 'should typecast negative float values to Float' do
|
345
|
+
parse('key = -3.14159265').should be_option_tuple('key', -3.14159265)
|
346
|
+
end
|
347
|
+
|
348
|
+
it 'should typecast scientific notation numbers to Float' do
|
349
|
+
parse('key = 10e5').should be_option_tuple('key', 10e5)
|
350
|
+
parse('key = 10e+5').should be_option_tuple('key', 10e5)
|
351
|
+
parse('key = 10e-5').should be_option_tuple('key', 10e-5)
|
352
|
+
|
353
|
+
parse('key = -10e5').should be_option_tuple('key', -10e5)
|
354
|
+
parse('key = -10e+5').should be_option_tuple('key', -10e5)
|
355
|
+
parse('key = -10e-5').should be_option_tuple('key', -10e-5)
|
356
|
+
|
357
|
+
parse('key = 3.14159265e5').should be_option_tuple('key', 3.14159265e5)
|
358
|
+
parse('key = 3.14159265e+5').should be_option_tuple('key', 3.14159265e5)
|
359
|
+
parse('key = 3.14159265e-5').should be_option_tuple('key', 3.14159265e-5)
|
360
|
+
|
361
|
+
parse('key = -3.14159265e5').should be_option_tuple('key', -3.14159265e5)
|
362
|
+
parse('key = -3.14159265e+5').should be_option_tuple('key', -3.14159265e5)
|
363
|
+
parse('key = -3.14159265e-5').should be_option_tuple('key', -3.14159265e-5)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
#
|
369
|
+
# Blank
|
370
|
+
#
|
371
|
+
|
372
|
+
#
|
373
|
+
# Comment
|
374
|
+
#
|
375
|
+
|
376
|
+
describe 'IniParse::Lines::Comment' do
|
377
|
+
describe '#has_comment?' do
|
378
|
+
it 'should return true if :comment has a non-blank value' do
|
379
|
+
IniParse::Lines::Comment.new(:comment => 'comment').should have_comment
|
380
|
+
end
|
381
|
+
|
382
|
+
it 'should return true if :comment has a blank value' do
|
383
|
+
IniParse::Lines::Comment.new(:comment => '').should have_comment
|
384
|
+
end
|
385
|
+
|
386
|
+
it 'should return true if :comment has a nil value' do
|
387
|
+
IniParse::Lines::Comment.new.should have_comment
|
388
|
+
IniParse::Lines::Comment.new(:comment => nil).should have_comment
|
389
|
+
end
|
390
|
+
end
|
391
|
+
|
392
|
+
describe '#to_ini' do
|
393
|
+
it 'should return the comment' do
|
394
|
+
IniParse::Lines::Comment.new(
|
395
|
+
:comment => 'a comment'
|
396
|
+
).to_ini.should == '; a comment'
|
397
|
+
end
|
398
|
+
|
399
|
+
it 'should preserve comment offset' do
|
400
|
+
IniParse::Lines::Comment.new(
|
401
|
+
:comment => 'a comment', :comment_offset => 10
|
402
|
+
).to_ini.should == ' ; a comment'
|
403
|
+
end
|
404
|
+
|
405
|
+
it 'should return just the comment_sep if the comment is blank' do
|
406
|
+
IniParse::Lines::Comment.new.to_ini.should == ';'
|
407
|
+
end
|
408
|
+
end
|
409
|
+
end
|