iniparser 0.1.0 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 361522b3234615dbc73ae63ecd9abbb9ed1df79a
4
- data.tar.gz: 9c7d1909eb8a8c7d5616d9be5d8d2f9021ee2d1b
3
+ metadata.gz: 6681fa0238b38ea834fdc8452d8da9bc1233996f
4
+ data.tar.gz: 70f3ef1fd66d4692bd2087fed4004f8788839047
5
5
  SHA512:
6
- metadata.gz: bd91875fcc709176b7a1da91264497c82aa954660debcc5b3a51083f5c521618cf728e382c66b1b09ddbc32b2bea11c304f1e815ea0995fc6ea4fc79577811c5
7
- data.tar.gz: 34a3188526a16e62006c34d4a9406c2f5c256ea020ceea8def88c68d105fb14670782cf54a6d7bd8a47ac5c1db48342464b8f7de3e269e04f8d42b2e0e755983
6
+ metadata.gz: b4e304e2f6d4fac81144565b4c3d265767ec5a672a040f8fa7eac0262cf89b6242fe66e69e86522c2854bff531974d4319333fe10346093c95cfdc9653453c3c
7
+ data.tar.gz: 4559486a9a9dc64f0f4312ee9664ca54b70bb7358cc1c09b3b8f250825e132e329e3ec5b3ae17afa4b21dfecc657038e8a0daf3af0cd9c02f02933c3f05c2a91
File without changes
@@ -0,0 +1,116 @@
1
+ CC0 1.0 Universal
2
+
3
+ Statement of Purpose
4
+
5
+ The laws of most jurisdictions throughout the world automatically confer
6
+ exclusive Copyright and Related Rights (defined below) upon the creator and
7
+ subsequent owner(s) (each and all, an "owner") of an original work of
8
+ authorship and/or a database (each, a "Work").
9
+
10
+ Certain owners wish to permanently relinquish those rights to a Work for the
11
+ purpose of contributing to a commons of creative, cultural and scientific
12
+ works ("Commons") that the public can reliably and without fear of later
13
+ claims of infringement build upon, modify, incorporate in other works, reuse
14
+ and redistribute as freely as possible in any form whatsoever and for any
15
+ purposes, including without limitation commercial purposes. These owners may
16
+ contribute to the Commons to promote the ideal of a free culture and the
17
+ further production of creative, cultural and scientific works, or to gain
18
+ reputation or greater distribution for their Work in part through the use and
19
+ efforts of others.
20
+
21
+ For these and/or other purposes and motivations, and without any expectation
22
+ of additional consideration or compensation, the person associating CC0 with a
23
+ Work (the "Affirmer"), to the extent that he or she is an owner of Copyright
24
+ and Related Rights in the Work, voluntarily elects to apply CC0 to the Work
25
+ and publicly distribute the Work under its terms, with knowledge of his or her
26
+ Copyright and Related Rights in the Work and the meaning and intended legal
27
+ effect of CC0 on those rights.
28
+
29
+ 1. Copyright and Related Rights. A Work made available under CC0 may be
30
+ protected by copyright and related or neighboring rights ("Copyright and
31
+ Related Rights"). Copyright and Related Rights include, but are not limited
32
+ to, the following:
33
+
34
+ i. the right to reproduce, adapt, distribute, perform, display, communicate,
35
+ and translate a Work;
36
+
37
+ ii. moral rights retained by the original author(s) and/or performer(s);
38
+
39
+ iii. publicity and privacy rights pertaining to a person's image or likeness
40
+ depicted in a Work;
41
+
42
+ iv. rights protecting against unfair competition in regards to a Work,
43
+ subject to the limitations in paragraph 4(a), below;
44
+
45
+ v. rights protecting the extraction, dissemination, use and reuse of data in
46
+ a Work;
47
+
48
+ vi. database rights (such as those arising under Directive 96/9/EC of the
49
+ European Parliament and of the Council of 11 March 1996 on the legal
50
+ protection of databases, and under any national implementation thereof,
51
+ including any amended or successor version of such directive); and
52
+
53
+ vii. other similar, equivalent or corresponding rights throughout the world
54
+ based on applicable law or treaty, and any national implementations thereof.
55
+
56
+ 2. Waiver. To the greatest extent permitted by, but not in contravention of,
57
+ applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and
58
+ unconditionally waives, abandons, and surrenders all of Affirmer's Copyright
59
+ and Related Rights and associated claims and causes of action, whether now
60
+ known or unknown (including existing as well as future claims and causes of
61
+ action), in the Work (i) in all territories worldwide, (ii) for the maximum
62
+ duration provided by applicable law or treaty (including future time
63
+ extensions), (iii) in any current or future medium and for any number of
64
+ copies, and (iv) for any purpose whatsoever, including without limitation
65
+ commercial, advertising or promotional purposes (the "Waiver"). Affirmer makes
66
+ the Waiver for the benefit of each member of the public at large and to the
67
+ detriment of Affirmer's heirs and successors, fully intending that such Waiver
68
+ shall not be subject to revocation, rescission, cancellation, termination, or
69
+ any other legal or equitable action to disrupt the quiet enjoyment of the Work
70
+ by the public as contemplated by Affirmer's express Statement of Purpose.
71
+
72
+ 3. Public License Fallback. Should any part of the Waiver for any reason be
73
+ judged legally invalid or ineffective under applicable law, then the Waiver
74
+ shall be preserved to the maximum extent permitted taking into account
75
+ Affirmer's express Statement of Purpose. In addition, to the extent the Waiver
76
+ is so judged Affirmer hereby grants to each affected person a royalty-free,
77
+ non transferable, non sublicensable, non exclusive, irrevocable and
78
+ unconditional license to exercise Affirmer's Copyright and Related Rights in
79
+ the Work (i) in all territories worldwide, (ii) for the maximum duration
80
+ provided by applicable law or treaty (including future time extensions), (iii)
81
+ in any current or future medium and for any number of copies, and (iv) for any
82
+ purpose whatsoever, including without limitation commercial, advertising or
83
+ promotional purposes (the "License"). The License shall be deemed effective as
84
+ of the date CC0 was applied by Affirmer to the Work. Should any part of the
85
+ License for any reason be judged legally invalid or ineffective under
86
+ applicable law, such partial invalidity or ineffectiveness shall not
87
+ invalidate the remainder of the License, and in such case Affirmer hereby
88
+ affirms that he or she will not (i) exercise any of his or her remaining
89
+ Copyright and Related Rights in the Work or (ii) assert any associated claims
90
+ and causes of action with respect to the Work, in either case contrary to
91
+ Affirmer's express Statement of Purpose.
92
+
93
+ 4. Limitations and Disclaimers.
94
+
95
+ a. No trademark or patent rights held by Affirmer are waived, abandoned,
96
+ surrendered, licensed or otherwise affected by this document.
97
+
98
+ b. Affirmer offers the Work as-is and makes no representations or warranties
99
+ of any kind concerning the Work, express, implied, statutory or otherwise,
100
+ including without limitation warranties of title, merchantability, fitness
101
+ for a particular purpose, non infringement, or the absence of latent or
102
+ other defects, accuracy, or the present or absence of errors, whether or not
103
+ discoverable, all to the greatest extent permissible under applicable law.
104
+
105
+ c. Affirmer disclaims responsibility for clearing rights of other persons
106
+ that may apply to the Work or any use thereof, including without limitation
107
+ any person's Copyright and Related Rights in the Work. Further, Affirmer
108
+ disclaims responsibility for obtaining any necessary consents, permissions
109
+ or other rights required for any use of the Work.
110
+
111
+ d. Affirmer understands and acknowledges that Creative Commons is not a
112
+ party to this document and has no duty or obligation with respect to this
113
+ CC0 or use of the Work.
114
+
115
+ For more information, please see
116
+ <http://creativecommons.org/publicdomain/zero/1.0/>
@@ -1,4 +1,5 @@
1
- HISTORY.md
1
+ CHANGELOG.md
2
+ LICENSE.md
2
3
  Manifest.txt
3
4
  README.md
4
5
  Rakefile
@@ -7,4 +8,3 @@ lib/iniparser/parser.rb
7
8
  lib/iniparser/version.rb
8
9
  test/helper.rb
9
10
  test/test_parser.rb
10
- test/test_version.rb
data/README.md CHANGED
@@ -1,19 +1,39 @@
1
- # iniparser
2
-
3
- iniparser gem - read / parse INI configuration, setttings and data files into a hash
1
+ # iniparser - read / parse INI configuration, settings and data files into a hash
4
2
 
5
3
 
6
4
  * home :: [github.com/datatxt/iniparser](https://github.com/datatxt/iniparser)
7
5
  * bugs :: [github.com/datatxt/iniparser/issues](https://github.com/datatxt/iniparser/issues)
8
6
  * gem :: [rubygems.org/gems/iniparser](https://rubygems.org/gems/iniparser)
9
7
  * rdoc :: [rubydoc.info/gems/iniparser](http://rubydoc.info/gems/iniparser)
8
+ * forum :: [groups.google.com/group/wwwmake](http://groups.google.com/group/wwwmake)
9
+
10
+
11
+
12
+ ## Usage
10
13
 
14
+ `INI.load` • `INI.load_file`
11
15
 
12
16
 
13
- ## Usage - `INI.load`, `INI.load_file`
17
+ Option 1) `INI.load` - load from string. Example:
18
+
19
+ ``` ruby
20
+ hash = INI.load( <<TXT )
21
+ title = Planet Open Data News
22
+
23
+ [Open Street Map (OSM) News]
24
+ feed = https://blog.openstreetmap.org/feed
25
+ TXT
26
+ ```
27
+
28
+
29
+ Option 2) `INI.load_file` - load from file (shortcut). Example:
30
+
31
+ ``` ruby
32
+ hash = INI.load_file( './planet.ini' )
33
+ ```
14
34
 
15
- Use `INI.load` or `INI.load_file`. Example:
16
35
 
36
+ All together now. Example:
17
37
 
18
38
  ``` ruby
19
39
  require 'iniparser'
@@ -23,21 +43,21 @@ text = <<TXT
23
43
  ; another comment
24
44
 
25
45
  key1 = hello
26
- key2 : hi!
46
+ key2 = hi!
27
47
 
28
48
  [section1]
29
- key3 = salut # end of line comment here
49
+ key3 = salut # end of line comment here
30
50
 
31
51
  [section2]
32
- key4: hola
52
+ key4 = hola ; another end of line comment here
33
53
  blank =
34
- blank2:
54
+ blank2
35
55
 
36
- [ http://example.com ]
37
- title = A rose is a rose is a rose, eh?
38
- title2: A rose is a rose is a rose, eh? # comment here
39
- ; another one here
40
- title3 = A rose is a rose is a rose, eh?
56
+ [section3 "http://example.com"]
57
+ # comment here
58
+ title = A rose is a rose is a rose, eh?
59
+ ; another comment here
60
+ title2 = A rose is a rose is a rose, eh?
41
61
  TXT
42
62
 
43
63
  hash = INI.load( text )
@@ -51,35 +71,239 @@ resulting in:
51
71
  "key2"=>"hi!",
52
72
  "section1"=>{"key3"=>"salut"},
53
73
  "section2"=>{"key4"=>"hola", "blank"=>"", "blank2"=>""},
54
- "http://example.com"=>
55
- {"title"=>"A rose is a rose is a rose, eh?",
56
- "title2"=>"A rose is a rose is a rose, eh?",
57
- "title3"=>"A rose is a rose is a rose, eh?"}}
74
+ "section3"=>{"http://example.com"=>{"title"=>"A rose is a rose is a rose, eh?",
75
+ "title2"=>"A rose is a rose is a rose, eh?"}}}
58
76
  ```
59
77
 
60
78
  to access use:
61
79
 
62
80
  ``` ruby
63
81
  puts hash['key1']
64
- # => 'hello'
82
+ #=> 'hello'
65
83
  puts hash['key2']
66
- # => 'hi!'
84
+ #=> 'hi!'
67
85
  puts hash['section1']['key3']
68
- # => 'salut'
86
+ #=> 'salut'
69
87
  puts hash['section2']['key4']
70
- # => 'hola'
88
+ #=> 'hola'
71
89
  puts hash['section2']['blank']
72
- # => ''
90
+ #=> ''
73
91
  puts hash['section2']['blank2']
74
- # => ''
75
- puts hash['http://example.com']['title']
76
- # => 'A rose is a rose is a rose, eh?'
77
- puts hash['http://example.com']['title2']
78
- # => 'A rose is a rose is a rose, eh?'
79
- puts hash['http://example.com']['title3']
80
- # => 'A rose is a rose is a rose, eh?'
92
+ #=> ''
93
+ puts hash['section3']['http://example.com']['title']
94
+ #=> 'A rose is a rose is a rose, eh?'
95
+ puts hash['section3']['http://example.com']['title2']
96
+ #=> 'A rose is a rose is a rose, eh?'
97
+ ```
98
+
99
+
100
+
101
+ ## Real World Example
102
+
103
+
104
+ **Git Config**
105
+
106
+ ```
107
+ #
108
+ # This is the config file, and
109
+ # a '#' or ';' character indicates
110
+ # a comment
111
+ #
112
+
113
+ ; core variables
114
+ [core]
115
+ ; Don't trust file modes
116
+ filemode = false
117
+
118
+ ; Our diff algorithm
119
+ [diff]
120
+ external = /usr/local/bin/diff-wrapper
121
+ renames = true
122
+
123
+ ; Proxy settings
124
+ [core]
125
+ gitproxy=proxy-command for kernel.org
126
+ gitproxy=default-proxy ; for all the rest
127
+
128
+ ; HTTP
129
+ [http]
130
+ sslVerify
131
+ [http "https://weak.example.com"]
132
+ sslVerify = false
133
+ cookieFile = /tmp/cookie.txt
81
134
  ```
82
135
 
136
+ resulting in
137
+ a format warning:
138
+
139
+ ```
140
+ WARN: line 20 - duplicate key >gitproxy< in section; will overwrite existing value
141
+ ```
142
+
143
+ and:
144
+
145
+ ``` ruby
146
+ {"core"=>{"filemode"=>"false", "gitproxy"=>"default-proxy"},
147
+ "diff"=>{"external"=>"/usr/local/bin/diff-wrapper", "renames"=>"true"},
148
+ "http"=>
149
+ {"sslVerify"=>"",
150
+ "https://weak.example.com"=>
151
+ {"sslVerify"=>"false", "cookieFile"=>"/tmp/cookie.txt"}}}
152
+ ```
153
+
154
+ **"Classic" Windows INI Config**
155
+
156
+ ```
157
+ ; last modified 1 April 2001 by John Doe
158
+ [owner]
159
+ name=John Doe
160
+ organization=Acme Widgets Inc.
161
+
162
+ [database]
163
+ ; use IP address in case network name resolution is not working
164
+ server=192.0.2.62
165
+ port=143
166
+ file=payroll.dat
167
+ ```
168
+
169
+ resulting in:
170
+
171
+ ```
172
+ {"owner"=>{"name"=>"John Doe", "organization"=>"Acme Widgets Inc."},
173
+ "database"=>{"server"=>"192.0.2.62", "port"=>"143", "file"=>"payroll.dat"}}
174
+ ```
175
+
176
+ **Planet Pluto Config**
177
+
178
+ ```
179
+ title = Planet Ruby
180
+
181
+ [Ruby Lang News]
182
+ feed = http://www.ruby-lang.org/en/feeds/news.rss
183
+
184
+ [Rails Girls Summer of Code News]
185
+ feed = https://railsgirlssummerofcode.org/blog.xml
186
+
187
+
188
+ [Benoit Daloze]
189
+ feed = https://eregon.me/blog/feed.xml
190
+ location = Zürich › Switzerland
191
+
192
+ [Thomas Leitner]
193
+ feed = https://gettalong.org/posts.atom
194
+ location = Vienna • Wien › Austria
195
+
196
+ [Paweł Świątkowski]
197
+ feed = https://rubytuesday.katafrakt.me/feed.xml
198
+ location = Kraków › Poland
199
+ ```
200
+
201
+ resulting in:
202
+
203
+ ``` ruby
204
+ {"title"=>"Planet Ruby",
205
+ "Ruby Lang News"=>
206
+ {"feed"=>"http://www.ruby-lang.org/en/feeds/news.rss"},
207
+ "Rails Girls Summer of Code News"=>
208
+ {"feed"=>"https://railsgirlssummerofcode.org/blog.xml"},
209
+ "Benoit Daloze"=>
210
+ {"feed"=>"https://eregon.me/blog/feed.xml",
211
+ "location"=>"Z\u00FCrich \u203A Switzerland"},
212
+ "Thomas Leitner"=>
213
+ {"feed"=>"https://gettalong.org/posts.atom",
214
+ "location"=>"Vienna \u2022 Wien \u203A Austria"},
215
+ "Pawe\u0142 \u015Awi\u0105tkowski"=>
216
+ {"feed"=>"https://rubytuesday.katafrakt.me/feed.xml",
217
+ "location"=>"Krak\u00F3w \u203A Poland"}}
218
+ ```
219
+
220
+
221
+ ## Frequently Asked Questions (FAQ) and Answers
222
+
223
+ ### Q: Why not use TOML (Tom's Obvious, Minimal Language)?
224
+
225
+ The IniParser returns a simple (nested) hash table and
226
+ all values are always strings, period
227
+ (no auto-magic type inference or casting) and you MUST always
228
+ use strings "unquoted" e.g.
229
+
230
+ title = Planet Open Data News
231
+
232
+ instead of requiring "typed" quoted string values:
233
+
234
+ title = "Planet Open Data News"
235
+
236
+ Yes, TOML is great for more "advanced" INI configurations / settings
237
+ that require (strong) data types,
238
+ nested lists, inline arrays, and much more.
239
+
240
+
241
+ ### Q: Why not use `IniFile` - the most popular library (10+ million downloads and counting)?
242
+
243
+ Again the IniParser returns a simple (nested) "standard" hash table and
244
+ all values are always strings, period
245
+ (no auto-magic type inference or casting
246
+ e.g. no conversion to bool (for true/false)
247
+ or numbers (for 1,2, etc.).
248
+ No wrapper around Hash or anything. Here be dragons ;-).
249
+
250
+ The popular IniFile CANNOT handle properties without values. Example:
251
+
252
+ ```
253
+ [http]
254
+ sslVerify
255
+ ```
256
+
257
+ resulting in:
258
+
259
+ ```
260
+ ERROR: Could not parse line: " sslVerify" (IniFile::Error)
261
+ ```
262
+
263
+ And parses "modern" named subsections into "flat" sections. Example:
264
+
265
+ ```
266
+ [http]
267
+ ; sslVerify
268
+ [http "https://weak.example.com"]
269
+ sslVerify = false
270
+ cookieFile = /tmp/cookie.txt
271
+
272
+ ```
273
+
274
+ resulting in:
275
+
276
+ ``` ruby
277
+ {"http"=>{},
278
+ "http \"https://weak.example.com\""=>
279
+ {"sslVerify"=>false, "cookieFile"=>"/tmp/cookie.txt"}}}
280
+ ```
281
+
282
+ and NOT resulting in:
283
+
284
+ ``` ruby
285
+ {"http"=>
286
+ {"https://weak.example.com"=>
287
+ {"sslVerify"=>"false", "cookieFile"=>"/tmp/cookie.txt"}}}
288
+ ```
289
+
290
+
291
+
292
+ ### Q: What are some known IniParser format quirks?
293
+
294
+ No quoted values (e.g. `"Hello"`)
295
+ or escapes (e.g. `\#` `\n`) or quoted values with escapes (e.g. `"\n"`).
296
+
297
+ No multi-line support for values.
298
+
299
+ Inline end-of-line comments MUST start with at least one leading
300
+ space (e.g. `test.html#test` is NOT an inline end-of-line comment but `test.html #test` is).
301
+
302
+ Property key names must match the text pattern / regular expression `[a-zA-Z0-9_]([a-zA-Z0-9_-]*[a-zA-Z0-9_])?`,
303
+ that is, use `a-z` / `A-Z`, `0-9` or underscore (`_`) and dash (`-`) only inside
304
+ BUT no dot (`.`) for now.
305
+
306
+
83
307
 
84
308
  ## License
85
309
 
data/Rakefile CHANGED
@@ -5,7 +5,7 @@ Hoe.spec 'iniparser' do
5
5
 
6
6
  self.version = IniParser::VERSION
7
7
 
8
- self.summary = 'iniparser - read / parse INI configuration, setttings and data files into a hash'
8
+ self.summary = 'iniparser - read / parse INI configuration, settings and data files into a hash'
9
9
  self.description = summary
10
10
 
11
11
  self.urls = ['https://github.com/datatxt/iniparser']
@@ -15,12 +15,12 @@ Hoe.spec 'iniparser' do
15
15
 
16
16
  # switch extension to .markdown for gihub formatting
17
17
  self.readme_file = 'README.md'
18
- self.history_file = 'HISTORY.md'
18
+ self.history_file = 'CHANGELOG.md'
19
19
 
20
20
  self.licenses = ['Public Domain']
21
21
 
22
22
  self.spec_extras = {
23
- required_ruby_version: '>= 1.9.2'
23
+ required_ruby_version: '>= 2.2.2'
24
24
  }
25
25
 
26
26
  end
@@ -9,17 +9,5 @@ require 'iniparser/parser'
9
9
 
10
10
 
11
11
 
12
- module INI
13
-
14
- # returns a nested hash
15
- # (compatible structure - works like YAML.load_file)
16
-
17
- def self.load_file( path ) IniParser::IniParser.load_file( path ); end
18
- def self.load( text ) IniParser::IniParser.load( text ); end
19
-
20
- end # module INI
21
-
22
-
23
-
24
12
  # say hello
25
13
  puts IniParser.banner if defined?( $RUBYLIBS_DEBUG )
@@ -1,86 +1,164 @@
1
1
  # encoding: utf-8
2
2
 
3
3
 
4
- module IniParser
5
-
6
4
 
7
- class IniParser
5
+ module IniParser
8
6
 
9
7
  # returns a nested hash
10
8
  # (compatible structure - works like YAML.load_file)
9
+ def self.load_file( path ) Parser.load_file( path ); end
10
+ def self.load( text ) Parser.load( text ); end
11
+
11
12
 
12
- def self.load_file( path )
13
- text = File.open( path, 'r:bom|utf-8' ).read
14
- self.load( text )
13
+ class Error < StandardError
15
14
  end
16
15
 
17
- def self.load( text )
18
- self.new( text ).parse
16
+ ## todo/check - what is JSON and YAML returning Parser/ParseError something else?
17
+ ## YAML uses ParseError and JSON uses ParserError
18
+ class ParseError < Error
19
19
  end
20
20
 
21
21
 
22
- def initialize( text )
23
- @text = text
24
- end
22
+ class Parser
23
+
24
+ # returns a nested hash
25
+ # (compatible structure - works like YAML.load_file)
26
+
27
+ def self.load_file( path )
28
+ text = File.open( path, 'r:bom|utf-8' ) {|f| f.read }
29
+ load( text )
30
+ end
31
+
32
+ def self.load( text )
33
+ new( text ).parse
34
+ end
35
+
36
+
37
+ def initialize( text )
38
+ @text = text
39
+ end
40
+
41
+
42
+ COMMENT_CLASS = '[#;]' # note: for now support # and ; - why? why not?
43
+
44
+ SEP_CLASS = '[=]' # note: name/value separator - for now only support = (no longer support :) - why? why not?
45
+
46
+
47
+ # note: for now do NOT support dot (.) - keep reserved for hierarchy latter
48
+ # note: for now allow dash (-) only inside identifier (NOT beginning or end)
49
+ # note: yes, allow just numbers as identifiers
50
+ IDENT = '[a-zA-Z0-9_](?:[a-zA-Z0-9_-]*[a-zA-Z0-9_])?'
51
+ STRICT_SECTION_RE = %r{^
52
+ \s*
53
+ \[
54
+ \s*
55
+ (?<key>#{IDENT})
56
+ \s*
57
+ (?:" ## allow optional subsection
58
+ (?<sub>[^"]+)
59
+ "
60
+ \s*
61
+ )?
62
+ \]
63
+ \s*
64
+ $}x
65
+
66
+ # note: yes, allow spaces inside (but only inside) section name
67
+ # note: for now NO quotes ("") allowed
68
+ SECTION_RE = %r{^
69
+ \s*
70
+ \[
71
+ \s*
72
+ (?<key>[^ "\]]
73
+ (?:[^"\]]*[^ "\]])?
74
+ )
75
+ \s*
76
+ \]
77
+ \s*
78
+ $}x # liberal section; allow everything in key
79
+
80
+
81
+ PROP_RE = %r{^
82
+ \s*
83
+ (?<key>#{IDENT})
84
+ \s*
85
+ (?:#{SEP_CLASS}
86
+ \s*
87
+ (?<value>.*?) ## note: use non-greedy (.*?) match
88
+ \s*
89
+ )?
90
+ $}x
91
+
92
+
93
+ def parse
94
+ hash = top_hash = {}
95
+
96
+ text = @text
97
+ text = text.gsub( "\t", ' ' ) # replace all tabs w/ spaces for now
98
+
99
+ lineno = 0
100
+ text.each_line do |line|
101
+ lineno += 1 ## track line numbers for (parse) error reporting
102
+
103
+ ### skip comments
104
+ # e.g. # this is a comment line
105
+
106
+ if line =~ /^\s*#{COMMENT_CLASS}/
107
+ ## logger.debug 'skipping comment line'
108
+ next
109
+ end
110
+
111
+ ### skip blank lines
112
+ if line =~ /^\s*$/
113
+ ## logger.debug 'skipping blank line'
114
+ next
115
+ end
116
+
117
+ # pass 1) remove possible trailing eol comment
118
+ ## e.g -> New York # Sample EOL Comment Here (with or without commas,,,,)
119
+ ## e.g -> New York ; Sample EOL Comment Here (with or without commas,,,,)
120
+ ## becomes -> New York
121
+ ## NOTE: MUST have leading white space for now - keep - why? why not!!!!!
122
+ ## do any urls use # for fragments?
123
+
124
+ line = line.sub( /\s+#{COMMENT_CLASS}.*$/, '' )
125
+
126
+ # pass 2) remove leading and trailing whitespace
127
+
128
+ line = line.strip
129
+
130
+ if m=STRICT_SECTION_RE.match( line ) # strict section
131
+ key = m[ :key ]
132
+ hash = top_hash[ key ] ||= {}
133
+
134
+ sub_key = m[ :sub ]
135
+ if sub_key ## check for subsection
136
+ hash = hash[ sub_key ] ||= {}
137
+ end
138
+ elsif m=SECTION_RE.match( line ) # liberal section; allow everything in key
139
+ key = m[ :key ]
140
+ hash = top_hash[ key ] ||= {}
141
+ elsif m=PROP_RE.match( line )
142
+ key = m[ :key ]
143
+ value = m[ :value].to_s # note: use to_s - might return nil
144
+ ### todo: strip quotes from value??? why? why not?
145
+ ## todo/check - raise error on duplicate - why? why not?
146
+ ## for now just warn
147
+ puts "WARN: line #{lineno} - duplicate key >#{key}< in section; will overwrite existing value" if hash.key?( key )
148
+ hash[ key ] = value
149
+ else
150
+ raise ParseError.new( "line #{lineno} - unknown line type; cannot parse >#{line}<" )
151
+ end
152
+ end # each lines
153
+
154
+ top_hash
155
+ end
156
+
157
+ end # class Parser
158
+ end # module IniParser
25
159
 
26
- def parse
27
- hash = top_hash = Hash.new
28
-
29
- text = @text
30
- text = text.gsub( "\t", ' ' ) # replace all tabs w/ spaces
31
-
32
- text.each_line do |line|
33
-
34
- ### skip comments
35
- # e.g. # this is a comment line
36
- # or ; this too
37
- # or -- haskell style
38
- # or % text style
39
-
40
- if line =~ /^\s*#/ || line =~ /^\s*;/ || line =~ /^\s*--/ || line =~ /^\s*%/
41
- ## logger.debug 'skipping comment line'
42
- next
43
- end
44
-
45
- ### skip blank lines
46
- if line =~ /^\s*$/
47
- ## logger.debug 'skipping blank line'
48
- next
49
- end
50
-
51
- # pass 1) remove possible trailing eol comment
52
- ## e.g -> New York # Sample EOL Comment Here (with or without commas,,,,)
53
- ## becomes -> New York
54
-
55
- line = line.sub( /\s+#.*$/, '' )
56
-
57
- # pass 2) remove leading and trailing whitespace
58
-
59
- line = line.strip
60
-
61
- ## check for new section e.g. [planet012-xxx_bc]
62
-
63
- ### todo: allow _ or - in strict section key? why? why not??
64
- ### allow _ or - in value key? why why not??
65
- if line =~ /^\s*\[\s*([a-z0-9_\-]+)\s*\]\s*$/ # strict section
66
- key = $1.to_s.dup
67
- hash = top_hash[ key ] = Hash.new
68
- elsif line =~ /^\s*\[\s*([^ \]]+)\s*\]\s*$/ # liberal section; allow everything in key
69
- key = $1.to_s.dup
70
- hash = top_hash[ key ] = Hash.new
71
- elsif line =~ /^\s*([a-z0-9_\-]+)\s*[:=](.*)$/
72
- key = $1.to_s.dup
73
- value = $2.to_s.strip.dup # check if it can be nil? if yes use blank string e.g. ''
74
- ### todo: strip quotes from value??? why? why not?
75
- hash[ key ] = value
76
- else
77
- puts "*** warn: skipping unknown line type in ini >#{line}<"
78
- end
79
- end # each lines
80
-
81
- top_hash
82
- end
83
160
 
84
- end # class IniParser
161
+ ####
162
+ # add a convenience shortcut
163
+ INI = IniParser
85
164
 
86
- end # module IniParser
@@ -1,8 +1,8 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module IniParser
4
- MAJOR = 0 ## todo: namespace inside version or something - why? why not??
5
- MINOR = 1
4
+ MAJOR = 1 ## todo: namespace inside version or something - why? why not??
5
+ MINOR = 0
6
6
  PATCH = 0
7
7
  VERSION = [MAJOR,MINOR,PATCH].join('.')
8
8
 
@@ -17,21 +17,21 @@ class TestParser < MiniTest::Test
17
17
  ; another comment
18
18
 
19
19
  key1 = hello
20
- key2 : hi!
20
+ key2 = hi!
21
21
 
22
22
  [section1]
23
23
  key3 = salut # end of line comment here
24
24
 
25
25
  [section2]
26
- key4: hola
26
+ key4 = hola ; end of line comment here
27
27
  blank =
28
- blank2:
28
+ blank2
29
29
 
30
- [ http://example.com ]
31
- title = A rose is a rose is a rose, eh?
32
- title2: A rose is a rose is a rose, eh? # comment here
33
- ; another one here
34
- title3 = A rose is a rose is a rose, eh?
30
+ [section3 "http://example.com"]
31
+ # comment here
32
+ title = A rose is a rose is a rose, eh?
33
+ ; another comment here
34
+ title2 = A rose is a rose is a rose, eh?
35
35
  TXT
36
36
 
37
37
  hash = INI.load( text )
@@ -43,9 +43,145 @@ TXT
43
43
  assert_equal 'hola', hash['section2']['key4']
44
44
  assert_equal '', hash['section2']['blank']
45
45
  assert_equal '', hash['section2']['blank2']
46
- assert_equal 'A rose is a rose is a rose, eh?', hash['http://example.com']['title']
47
- assert_equal 'A rose is a rose is a rose, eh?', hash['http://example.com']['title2']
48
- assert_equal 'A rose is a rose is a rose, eh?', hash['http://example.com']['title3']
46
+ assert_equal 'A rose is a rose is a rose, eh?', hash['section3']['http://example.com']['title']
47
+ assert_equal 'A rose is a rose is a rose, eh?', hash['section3']['http://example.com']['title2']
49
48
  end
50
49
 
51
- end
50
+ def test_git
51
+ text = <<TXT
52
+ #
53
+ # This is the config file, and
54
+ # a '#' or ';' character indicates
55
+ # a comment
56
+ #
57
+
58
+ ; core variables
59
+ [core]
60
+ ; Don't trust file modes
61
+ filemode = false
62
+
63
+ ; Our diff algorithm
64
+ [diff]
65
+ external = /usr/local/bin/diff-wrapper
66
+ renames = true
67
+
68
+ ; Proxy settings
69
+ [core]
70
+ gitproxy=proxy-command for kernel.org
71
+ gitproxy=default-proxy ; for all the rest
72
+
73
+ ; HTTP
74
+ [http]
75
+ sslVerify
76
+ [http "https://weak.example.com"]
77
+ sslVerify = false
78
+ cookieFile = /tmp/cookie.txt
79
+ TXT
80
+
81
+ hash = INI.load( text )
82
+ pp hash
83
+
84
+
85
+ assert_equal 'default-proxy', hash['core']['gitproxy']
86
+
87
+ assert_equal '', hash['http']['sslVerify']
88
+ assert_equal 'false', hash['http']['https://weak.example.com']['sslVerify']
89
+ end
90
+
91
+ def test_planet
92
+ text =<<TXT
93
+ title = Planet Ruby
94
+
95
+ [Ruby Lang News]
96
+ feed = http://www.ruby-lang.org/en/feeds/news.rss
97
+
98
+ [Rails Girls Summer of Code News]
99
+ feed = https://railsgirlssummerofcode.org/blog.xml
100
+
101
+
102
+ [Benoit Daloze]
103
+ feed = https://eregon.me/blog/feed.xml
104
+ location = Zürich › Switzerland
105
+
106
+ [Thomas Leitner]
107
+ feed = https://gettalong.org/posts.atom
108
+ location = Vienna • Wien › Austria
109
+
110
+ [Paweł Świątkowski]
111
+ feed = https://rubytuesday.katafrakt.me/feed.xml
112
+ location = Kraków › Poland
113
+ TXT
114
+
115
+ hash = INI.load( text )
116
+ pp hash
117
+
118
+ assert_equal 'Kraków › Poland', hash['Paweł Świątkowski']['location']
119
+ end
120
+
121
+ def test_database
122
+ text =<<TXT
123
+ [database "development"]
124
+ adapter = sqlite3
125
+ database = db/development.sqlite3
126
+
127
+ [database "test"]
128
+ adapter = sqlite3
129
+ database = db/test.sqlite3
130
+
131
+ [database "production"]
132
+ adapter = sqlite3
133
+ database = db/production.sqlite3
134
+ TXT
135
+
136
+ hash = INI.load( text )
137
+ pp hash
138
+
139
+ assert_equal 'db/development.sqlite3', hash['database']['development']['database']
140
+ assert_equal 'db/test.sqlite3', hash['database']['test']['database']
141
+ end
142
+
143
+ def test_windows
144
+ text =<<TXT
145
+ ; last modified 1 April 2001 by John Doe
146
+ [owner]
147
+ name=John Doe
148
+ organization=Acme Widgets Inc.
149
+
150
+ [database]
151
+ ; use IP address in case network name resolution is not working
152
+ server=192.0.2.62
153
+ port=143
154
+ file=payroll.dat
155
+ TXT
156
+
157
+ hash = INI.load( text )
158
+ pp hash
159
+
160
+ assert_equal '192.0.2.62', hash['database']['server']
161
+ end
162
+
163
+ def test_quick
164
+ ## from python's configparser
165
+ text =<<TXT
166
+ [DEFAULT]
167
+ ServerAliveInterval = 45
168
+ Compression = yes
169
+ CompressionLevel = 9
170
+ ForwardX11 = yes
171
+
172
+ [bitbucket.org]
173
+ User = hg
174
+
175
+ [topsecret.server.com]
176
+ Port = 50022
177
+ ForwardX11 = no
178
+ TXT
179
+
180
+ hash = INI.load( text )
181
+ pp hash
182
+
183
+ assert_equal 'yes', hash['DEFAULT']['ForwardX11']
184
+ assert_equal 'hg', hash['bitbucket.org']['User']
185
+ assert_equal 'no', hash['topsecret.server.com']['ForwardX11']
186
+ end
187
+ end # class TestParser
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: iniparser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gerald Bauer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-29 00:00:00.000000000 Z
11
+ date: 2020-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rdoc
@@ -30,25 +30,27 @@ dependencies:
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '3.15'
33
+ version: '3.16'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
- version: '3.15'
41
- description: iniparser - read / parse INI configuration, setttings and data files
42
- into a hash
40
+ version: '3.16'
41
+ description: iniparser - read / parse INI configuration, settings and data files into
42
+ a hash
43
43
  email: ruby-talk@ruby-lang.org
44
44
  executables: []
45
45
  extensions: []
46
46
  extra_rdoc_files:
47
- - HISTORY.md
47
+ - CHANGELOG.md
48
+ - LICENSE.md
48
49
  - Manifest.txt
49
50
  - README.md
50
51
  files:
51
- - HISTORY.md
52
+ - CHANGELOG.md
53
+ - LICENSE.md
52
54
  - Manifest.txt
53
55
  - README.md
54
56
  - Rakefile
@@ -57,7 +59,6 @@ files:
57
59
  - lib/iniparser/version.rb
58
60
  - test/helper.rb
59
61
  - test/test_parser.rb
60
- - test/test_version.rb
61
62
  homepage: https://github.com/datatxt/iniparser
62
63
  licenses:
63
64
  - Public Domain
@@ -72,7 +73,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
72
73
  requirements:
73
74
  - - ">="
74
75
  - !ruby/object:Gem::Version
75
- version: 1.9.2
76
+ version: 2.2.2
76
77
  required_rubygems_version: !ruby/object:Gem::Requirement
77
78
  requirements:
78
79
  - - ">="
@@ -80,9 +81,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
81
  version: '0'
81
82
  requirements: []
82
83
  rubyforge_project:
83
- rubygems_version: 2.6.7
84
+ rubygems_version: 2.5.2
84
85
  signing_key:
85
86
  specification_version: 4
86
- summary: iniparser - read / parse INI configuration, setttings and data files into
87
+ summary: iniparser - read / parse INI configuration, settings and data files into
87
88
  a hash
88
89
  test_files: []
@@ -1,21 +0,0 @@
1
- # encoding: utf-8
2
-
3
- ###
4
- # to run use
5
- # ruby -I ./lib -I ./test test/test_version.rb
6
-
7
-
8
- require 'helper'
9
-
10
-
11
- class TestVersion < MiniTest::Test
12
-
13
-
14
- def test_version
15
-
16
- puts IniParser::VERSION
17
- assert true
18
- ## assume everything ok if get here
19
- end
20
-
21
- end # class TestVersion