figtree 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -5
- data/bin/console +20 -0
- data/bin/setup +8 -0
- data/lib/figtree/ini_config.rb +6 -2
- data/lib/figtree/parser.rb +113 -43
- data/lib/figtree/transformer.rb +77 -64
- data/lib/figtree/version.rb +1 -1
- data/spec/figtree/parser_spec.rb +102 -23
- data/spec/figtree/transformer_spec.rb +15 -2
- data/spec/figtree_spec.rb +55 -13
- data/spec/spec_helper.rb +4 -0
- data/spec/support/comment.ini +10 -0
- data/spec/support/good.ini +18 -0
- data/spec/support/invalid/bad_1.ini +6 -0
- data/spec/support/invalid/bad_2.ini +11 -0
- data/spec/support/invalid/browscap.ini +5 -0
- data/spec/support/invalid/continuation.ini +6 -0
- data/spec/support/invalid/escape.ini +13 -0
- data/spec/support/invalid/global.ini +3 -0
- data/spec/support/{unparseable_settings.conf → invalid/unparseable_settings.conf} +0 -0
- data/spec/support/{untransformable_settings.conf → invalid/untransformable_settings.conf} +0 -0
- data/spec/support/merge.ini +5 -0
- data/spec/support/mini_ini_example.ini +4 -0
- data/spec/support/mixed_comment.ini +7 -0
- data/spec/support/multiline.ini +23 -0
- data/spec/support/multiline_only.ini +5 -0
- data/spec/support/param.ini +5 -0
- data/spec/support/section.ini +4 -0
- metadata +41 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 027e03ceb0e9b227e731efdacc239459ee0a344b
|
4
|
+
data.tar.gz: cda00334893c5bbc8c7d2c299ad91f35c6df4859
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 76e628f7ef15ff4474d8f2bc09adfa02b2c6a315607b68b2c3879a1b12e1938022e05b0a82aecccc70ab7c47e011109cc4eb46de9c8d5dcbc353a03b310e8979
|
7
|
+
data.tar.gz: a6552300f61d0d71020667b41a01e37ecc9bdc09f4b87888eef1b547d496fa2ced5783a4f5cff170da637a1e7e51dfc939a88ba8b8ae7b66e03fae5fc61a00c4
|
data/README.md
CHANGED
@@ -11,10 +11,17 @@
|
|
11
11
|
|
12
12
|
# Figtree
|
13
13
|
## about
|
14
|
-
A parser and transformer for loading `.ini` files into Ruby dot notation accessible objects. `.ini` is not a standardized format. But the parser and transformer are easy to extend
|
14
|
+
A parser and transformer for loading `.ini` files into Ruby dot notation accessible objects. `.ini` is not a standardized format. But the parser and transformer are easy to extend.
|
15
|
+
|
16
|
+
The goal of figtree is not to accept all `.ini` files generously, but more strictly define `.ini` files so we can make smarter guesses about how to covert your settings into objects.
|
17
|
+
|
18
|
+
What kinds of objects are supported? Currently we can recognize [unix style filepaths into Pathname](http://ruby-doc.org/stdlib-2.0.0/libdoc/pathname/rdoc/Pathname.html), [ip4 and ip6 addresses into IPAddr](http://ruby-doc.org/stdlib-2.0.0/libdoc/ipaddr/rdoc/IPAddr.html), and most common Ruby types (String, Array, Boolean, Integer). If there's other types you'd like to see supported, please [file an issue](https://github.com/mooreniemi/figtree/issues/new).
|
15
19
|
|
16
20
|
If the `.ini` file is invalid, an error will be raised, with the line and char position of the error. If you extend this gem to have more rules, and one of those rules fails to transform, you will have an error raised.
|
17
21
|
|
22
|
+
## alternatives
|
23
|
+
If you want an industrial strength, pure Ruby solution, check out [inifile gem](https://github.com/TwP/inifile). It is much looser about what it accepts as valid `.ini` files, and with no pesky dependencies! If you want to see exactly which cases `figtree` supports vs `inifile`, compare our spec files. Many of the cases in our `invalid/` folder `inifile` will parse for you.
|
24
|
+
|
18
25
|
## disambiguation
|
19
26
|
Looking for the graphical viewer of phyllogenic trees? You want this other [Figtree](http://tree.bio.ed.ac.uk/software/figtree/).
|
20
27
|
|
@@ -43,13 +50,15 @@ A typical `.ini` file takes slightly less than 0.02s to be parsed, transformed,
|
|
43
50
|
=> "/srv/var/tmp/"
|
44
51
|
|
45
52
|
## development
|
46
|
-
###
|
47
|
-
`
|
53
|
+
### helpers
|
54
|
+
`bin/setup`
|
55
|
+
`bin/console`
|
56
|
+
|
57
|
+
While in console, you can use `parse_ini_named name` and as long as it's in `spec/support/name.ini` it'll parse it for you with helpful error output. Sometimes this is a faster feedback mechanism than going through the tests.
|
48
58
|
|
49
59
|
### tests
|
50
60
|
`rspec spec/`
|
51
61
|
|
52
62
|
#### TODO
|
53
|
-
-
|
63
|
+
- more cleanup
|
54
64
|
- give char/line position of transformer failures
|
55
|
-
- refactor marked TODO listings in files (mostly refactoring to generic in Transformer)
|
data/bin/console
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "figtree"
|
5
|
+
|
6
|
+
require "parslet/convenience"
|
7
|
+
|
8
|
+
parser = Figtree::Parser.new
|
9
|
+
|
10
|
+
require "pry"
|
11
|
+
command_set = Pry::CommandSet.new do
|
12
|
+
command "parse_ini_named", "", :keep_retval => true do |name|
|
13
|
+
parser = Figtree::Parser.new
|
14
|
+
ini_as_string = File.read("spec/support/#{name}.ini")
|
15
|
+
parser.parse_with_debug(ini_as_string)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
#Pry.start parser, :commands => command_set
|
20
|
+
Pry.start nil, :commands => command_set
|
data/bin/setup
ADDED
data/lib/figtree/ini_config.rb
CHANGED
@@ -20,9 +20,13 @@ module Figtree
|
|
20
20
|
|
21
21
|
def figgy_parse(str)
|
22
22
|
Parser.new.parse(str)
|
23
|
-
|
23
|
+
# argument error is invalid byte sequence
|
24
|
+
rescue Parslet::ParseFailed, ArgumentError => failure
|
25
|
+
if failure.class == Parslet::ParseFailed
|
26
|
+
failure = failure.cause.ascii_tree
|
27
|
+
end
|
24
28
|
STDERR.puts "\nInvalid ini file.\n" +
|
25
|
-
"Error: #{failure
|
29
|
+
"Error: #{failure}" +
|
26
30
|
"Please correct the file and retry."
|
27
31
|
raise
|
28
32
|
end
|
data/lib/figtree/parser.rb
CHANGED
@@ -8,33 +8,73 @@ module Figtree
|
|
8
8
|
include IPv6
|
9
9
|
|
10
10
|
rule(:eof) { any.absent? }
|
11
|
-
rule(:group_title) { match('[a-zA-
|
12
|
-
rule(:space) { match("\s")
|
13
|
-
rule(:
|
11
|
+
rule(:group_title) { match('[a-zA-Z_]').repeat(1) }
|
12
|
+
rule(:space) { (match("\s") | str(' ')) }
|
13
|
+
rule(:spaces) { (space.repeat(2) | comment) }
|
14
|
+
rule(:newline) { str("\n") >> match("\r").maybe }
|
15
|
+
rule(:terminator) do
|
16
|
+
space.repeat(0) >> (comment | newline | eof)
|
17
|
+
end
|
18
|
+
rule(:backslash) do
|
19
|
+
space.repeat(0) >> str("\\")
|
20
|
+
end
|
14
21
|
|
15
22
|
rule(:grouper) do
|
16
|
-
newline.maybe >>
|
17
23
|
str('[') >>
|
18
24
|
group_title.as(:group_title) >>
|
19
25
|
str(']')
|
20
26
|
end
|
21
27
|
|
28
|
+
rule(:comment_start) { (str(';') | str('#')) }
|
29
|
+
rule(:comment_end) { (newline | eof) }
|
22
30
|
rule(:comment) do
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
31
|
+
(
|
32
|
+
comment_start >>
|
33
|
+
space.repeat(0) >>
|
34
|
+
(
|
35
|
+
comment_end.absent? >> any
|
36
|
+
).repeat
|
37
|
+
) >>
|
38
|
+
space.repeat(0) >>
|
39
|
+
comment_end
|
40
|
+
end
|
41
|
+
|
42
|
+
rule(:quoted_string) do
|
43
|
+
str('"') >>
|
44
|
+
(
|
45
|
+
(str('\\') >> any) | (str('"').absent? >> any)
|
46
|
+
).repeat(1) >>
|
47
|
+
str('"')
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
rule(:unquoted_string) do
|
52
|
+
(
|
53
|
+
(
|
54
|
+
(
|
55
|
+
(backslash | terminator).absent?
|
56
|
+
) >> any
|
57
|
+
).repeat(1).as(:left) >>
|
58
|
+
backslash >>
|
59
|
+
terminator
|
60
|
+
).repeat(0) >>
|
61
|
+
(
|
62
|
+
terminator.absent? >> any
|
63
|
+
).repeat(1).as(:right) >>
|
64
|
+
terminator
|
27
65
|
end
|
28
66
|
|
29
67
|
rule(:string) do
|
30
|
-
|
31
|
-
((str('\\') >> any) | (str('"').absent? >> any)).repeat.as(:string) >>
|
32
|
-
str('"')
|
68
|
+
(quoted_string | unquoted_string).as(:string)
|
33
69
|
end
|
34
70
|
|
35
71
|
rule(:boolean) do
|
36
|
-
|
37
|
-
|
72
|
+
(
|
73
|
+
str('no') |
|
74
|
+
str('yes') |
|
75
|
+
str('false') |
|
76
|
+
str('true')
|
77
|
+
).as(:boolean)
|
38
78
|
end
|
39
79
|
|
40
80
|
rule(:number) do
|
@@ -45,19 +85,36 @@ module Figtree
|
|
45
85
|
(ipv4 | ipv6).as(:ip_address)
|
46
86
|
end
|
47
87
|
|
88
|
+
rule(:at_least_one_char) do
|
89
|
+
match('[a-zA-Z]').repeat(1)
|
90
|
+
end
|
91
|
+
|
48
92
|
rule(:array) do
|
49
|
-
(
|
50
|
-
|
51
|
-
|
52
|
-
|
93
|
+
(
|
94
|
+
# minimum array
|
95
|
+
at_least_one_char >>
|
96
|
+
(
|
97
|
+
# extending elementwise
|
98
|
+
str(',') >> space.repeat.maybe >>
|
99
|
+
at_least_one_char
|
100
|
+
).repeat(1)
|
101
|
+
).as(:array) >>
|
102
|
+
(newline | eof)
|
53
103
|
end
|
54
104
|
|
55
105
|
rule(:file_path) do
|
56
|
-
|
106
|
+
(
|
107
|
+
(
|
108
|
+
str('/') >>
|
109
|
+
at_least_one_char
|
110
|
+
).repeat(1) >>
|
111
|
+
str('/').maybe
|
112
|
+
).as(:file_path)
|
57
113
|
end
|
58
114
|
|
59
115
|
rule(:snake_case_key) do
|
60
|
-
match('[a-zA-Z0-9_]').repeat(1).
|
116
|
+
match('[a-zA-Z0-9_]').repeat(1).
|
117
|
+
as(:snake_case_key)
|
61
118
|
end
|
62
119
|
|
63
120
|
rule(:snakey_option_key) do
|
@@ -67,29 +124,36 @@ module Figtree
|
|
67
124
|
str('>')
|
68
125
|
end
|
69
126
|
|
70
|
-
rule(:
|
71
|
-
snake_case_key >>
|
72
|
-
space >>
|
73
|
-
str("=") >>
|
74
|
-
space >>
|
127
|
+
rule(:value) do
|
75
128
|
# this ordering matters
|
76
129
|
# we are roughly moving from more
|
77
130
|
# to less specific
|
78
|
-
(
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
131
|
+
(
|
132
|
+
ip_address |
|
133
|
+
number |
|
134
|
+
boolean |
|
135
|
+
array |
|
136
|
+
file_path |
|
137
|
+
string
|
138
|
+
)
|
139
|
+
end
|
140
|
+
|
141
|
+
rule(:equals_value) do
|
142
|
+
space.repeat(0) >>
|
143
|
+
str("=") >>
|
144
|
+
space.repeat(0) >>
|
145
|
+
value >>
|
146
|
+
newline.repeat(0)
|
147
|
+
end
|
148
|
+
|
149
|
+
rule(:assignment) do
|
150
|
+
snake_case_key >>
|
151
|
+
equals_value
|
85
152
|
end
|
86
153
|
|
87
154
|
rule(:override_assignment) do
|
88
155
|
snakey_option_key >>
|
89
|
-
|
90
|
-
str("=") >>
|
91
|
-
space >>
|
92
|
-
file_path
|
156
|
+
equals_value
|
93
157
|
end
|
94
158
|
|
95
159
|
rule(:assignment_or_comment) do
|
@@ -97,21 +161,27 @@ module Figtree
|
|
97
161
|
end
|
98
162
|
|
99
163
|
rule(:group_member) do
|
100
|
-
newline.maybe >>
|
101
164
|
assignment_or_comment >>
|
102
|
-
|
165
|
+
space.repeat(0) >>
|
166
|
+
newline.repeat(0)
|
103
167
|
end
|
104
168
|
|
105
169
|
rule(:group) do
|
106
|
-
(
|
107
|
-
|
108
|
-
|
170
|
+
(
|
171
|
+
grouper >>
|
172
|
+
space.repeat(0) >>
|
173
|
+
comment.maybe >>
|
174
|
+
newline.repeat(0) >>
|
175
|
+
group_member.repeat(0)
|
176
|
+
).as(:group).
|
177
|
+
repeat(0)
|
109
178
|
end
|
110
179
|
|
111
180
|
rule(:comment_or_group) do
|
112
|
-
|
113
|
-
|
114
|
-
|
181
|
+
# may start file with attribution
|
182
|
+
# comment or timestamp etc
|
183
|
+
comment.repeat.maybe >>
|
184
|
+
group
|
115
185
|
end
|
116
186
|
|
117
187
|
root(:comment_or_group)
|
data/lib/figtree/transformer.rb
CHANGED
@@ -4,71 +4,84 @@ require 'ipaddr'
|
|
4
4
|
require 'wannabe_bool'
|
5
5
|
|
6
6
|
module Figtree
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
7
|
+
# a transformer takes a parsed, valid AST and applies rules, usually
|
8
|
+
# in a context free manner
|
9
|
+
class Transformer < Parslet::Transform
|
10
|
+
rule(:snake_case_key => simple(:key), :number => simple(:value)) do
|
11
|
+
{
|
12
|
+
key.to_sym => Integer(value)
|
13
|
+
}
|
14
|
+
end
|
15
|
+
rule(:snake_case_key => simple(:key), :string => subtree(:value)) do
|
16
|
+
merged_string =
|
17
|
+
case value
|
18
|
+
when Hash
|
19
|
+
value[:right]
|
20
|
+
when Array
|
21
|
+
value.inject("") do |string, element|
|
22
|
+
if !element[:left].nil?
|
23
|
+
string + element[:left]
|
24
|
+
else
|
25
|
+
string + element[:right]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
else
|
29
|
+
value
|
30
|
+
end
|
31
|
+
{
|
32
|
+
# remove whitespace after cast
|
33
|
+
key.to_sym => String(merged_string).strip
|
34
|
+
}
|
35
|
+
end
|
36
|
+
rule(:snake_case_key => simple(:key), :file_path => simple(:value)) do
|
37
|
+
{
|
38
|
+
key.to_sym => Pathname.new(value)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
# depends on wannabe_bool refining String class
|
42
|
+
rule(:snake_case_key => simple(:key), :boolean => simple(:value)) do
|
43
|
+
{
|
44
|
+
key.to_sym => String(value).to_b
|
45
|
+
}
|
46
|
+
end
|
47
|
+
rule(:snake_case_key => simple(:key), :array => simple(:value)) do
|
48
|
+
{
|
49
|
+
key.to_sym => String(value).split(",")
|
50
|
+
}
|
51
|
+
end
|
38
52
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
end
|
53
|
+
rule(:snake_case_key => simple(:key), :ip_address => subtree(:value)) do
|
54
|
+
{
|
55
|
+
key.to_sym => IPAddr.new((value.values.first.to_s))
|
56
|
+
}
|
57
|
+
end
|
45
58
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
59
|
+
# ini files are trees of a fixed height, if the file handle is the root
|
60
|
+
# subgroups are its children, and subgroup members are the next level of children
|
61
|
+
rule(:group => subtree(:group_members)) do
|
62
|
+
group_title = group_members[0][:group_title].to_sym
|
63
|
+
group_values = Subgroup.new(group_members[1..-1].reduce({}, :merge!))
|
64
|
+
{
|
65
|
+
group_title => group_values
|
66
|
+
}
|
67
|
+
end
|
55
68
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
69
|
+
# where does overrides come from? an argument into #apply on
|
70
|
+
# Transformer, that allows an additional capture outside the AST
|
71
|
+
# to be added to the context of the transform
|
72
|
+
rule(
|
73
|
+
:key_to_be_overridden => subtree(:overridden_key),
|
74
|
+
:optional_key => subtree(:overriding_key),
|
75
|
+
:file_path => subtree(:new_file_path),
|
76
|
+
) do
|
77
|
+
if override.to_sym == overriding_key[:snake_case_key].to_sym
|
78
|
+
{
|
79
|
+
overridden_key[:snake_case_key] => Pathname.new(new_file_path)
|
80
|
+
}
|
81
|
+
else
|
82
|
+
{
|
83
|
+
}
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
74
87
|
end
|
data/lib/figtree/version.rb
CHANGED
data/spec/figtree/parser_spec.rb
CHANGED
@@ -3,79 +3,154 @@ require 'spec_helper'
|
|
3
3
|
module Figtree
|
4
4
|
describe Parser do
|
5
5
|
let(:parser) { Parser.new }
|
6
|
+
let(:string) do
|
7
|
+
"a bb ccc dddd eeeee ffffff\n"
|
8
|
+
end
|
9
|
+
|
6
10
|
it 'can parse newlines' do
|
7
11
|
expect(parser.newline).to parse("\n")
|
12
|
+
expect(parser.newline).to_not parse("\\n")
|
13
|
+
expect(parser.newline).to_not parse("\\\n")
|
14
|
+
end
|
15
|
+
it 'terminates correctly' do
|
16
|
+
expect(parser.terminator).to parse(" #comment")
|
17
|
+
expect(parser.terminator).to parse(" #comment\n")
|
18
|
+
expect(parser.terminator).to parse(" \n")
|
19
|
+
expect(parser.terminator).to parse(" ")
|
20
|
+
expect(parser.unquoted_string).to parse("f #ffoo")
|
21
|
+
expect(parser.unquoted_string).to parse("f #ffoo\n")
|
8
22
|
end
|
9
23
|
it 'can parse group names' do
|
10
24
|
expect(parser.grouper).to parse('[common]')
|
25
|
+
expect(parser.grouper).to parse('[common_also]')
|
11
26
|
end
|
12
27
|
it 'can parse comments' do
|
13
28
|
expect(parser.comment).to parse("; This is a comment\n")
|
29
|
+
expect(parser.comment).to parse("# This is also a comment\n")
|
14
30
|
expect(parser.comment).to parse("; last modified 1 April 2001 by John Doe\n")
|
31
|
+
expect(parser.comment).to parse("#comment \\n")
|
15
32
|
comment_first = File.open('spec/support/wiki_example.ini', &:readline)
|
16
33
|
expect(parser.comment).to parse(comment_first)
|
17
34
|
end
|
18
|
-
it 'can parse comments then groups' do
|
19
|
-
expect(parser.comment_or_group).to parse("; comment\n[groop]\nassignment = present")
|
20
|
-
end
|
21
35
|
it 'can parse snake_case keys' do
|
22
36
|
expect(parser.snake_case_key).to parse('basic_size_limit')
|
23
37
|
end
|
24
|
-
|
25
|
-
|
38
|
+
|
39
|
+
describe 'strings of all kinds' do
|
40
|
+
it 'can parse spaces' do
|
41
|
+
expect(parser.spaces).to parse("#foo")
|
42
|
+
expect(parser.spaces).to parse("# foo")
|
43
|
+
expect(parser.spaces).to parse("# foo\n")
|
44
|
+
expect(parser.spaces).to_not parse(" ")
|
45
|
+
expect(parser.spaces).to_not parse("\s")
|
46
|
+
expect(parser.spaces).to_not parse("a b")
|
47
|
+
end
|
48
|
+
it 'can parse strings' do
|
49
|
+
expect(parser.string).to parse('"hello there, ftp uploading"')
|
50
|
+
end
|
51
|
+
it 'can parse unquoted strings' do
|
52
|
+
expect(parser.unquoted_string).to parse(string)
|
53
|
+
expect(parser.unquoted_string).to parse("multiline \\\nsupport\n")
|
54
|
+
end
|
55
|
+
it 'can parse multiline with comment' do
|
56
|
+
expect(parser.unquoted_string).to parse("a #comment\n")
|
57
|
+
expect(parser.unquoted_string).to parse("a #")
|
58
|
+
expect(parser.unquoted_string).to_not parse("a\nb")
|
59
|
+
expect(parser.unquoted_string).to parse("a \\#comment\n b\n")
|
60
|
+
expect(parser.assignment).to parse("foo = a \\nb\n")
|
61
|
+
expect(parser.assignment).to parse("foo = a \\ # and here, too\nb\n")
|
62
|
+
|
63
|
+
group = "[section_three]\nthree = hello \\\nmultiline\nother = 2"
|
64
|
+
expect(parser.group).to parse(group)
|
65
|
+
|
66
|
+
multiline_only = File.read('spec/support/multiline_only.ini')
|
67
|
+
expect(parser.group).to parse(multiline_only)
|
68
|
+
end
|
26
69
|
end
|
70
|
+
|
27
71
|
it 'can parse arrays' do
|
28
|
-
expect(parser.array).
|
72
|
+
expect(parser.array).to_not parse(',,')
|
73
|
+
expect(parser.array).to_not parse("a\n")
|
74
|
+
expect(parser.array).to_not parse("a,")
|
75
|
+
expect(parser.array).to parse("a,b\n")
|
29
76
|
expect(parser.array).to parse("a,b")
|
30
77
|
expect(parser.array).to parse("a,b,c\n")
|
31
|
-
expect(parser.array).
|
78
|
+
expect(parser.array).to parse("words, with, spaces, after\n")
|
79
|
+
expect(parser.array).to parse("several,diff,words,only,nonumbers\n")
|
32
80
|
expect(parser.array).to parse("array,of,values\n")
|
33
81
|
expect(parser.array).to parse("array,of,values")
|
34
82
|
end
|
83
|
+
|
35
84
|
it 'can parse numbers' do
|
36
85
|
expect(parser.number).to parse("26214400")
|
37
86
|
end
|
87
|
+
|
38
88
|
it 'can parse ip addresses' do
|
39
89
|
expect(parser.ip_address).to parse("FE80:0000:0000:0000:0202:B3FF:FE1E:8329")
|
40
90
|
expect(parser.ip_address).to parse('111.222.3.4')
|
41
|
-
|
91
|
+
expect(parser.ip_address).to parse('192.0.2.62')
|
42
92
|
expect(parser.ip_address).to_not parse('f11.222.3.4')
|
43
93
|
expect(parser.ip_address).to_not parse('111.222.3')
|
44
94
|
end
|
45
95
|
it 'can parse booleans flexibly' do
|
46
96
|
expect(parser.boolean).to parse("no")
|
47
97
|
expect(parser.boolean).to parse("yes")
|
48
|
-
|
49
|
-
|
50
|
-
expect(parser.assignment).to parse('basic_size_limit = 26214400')
|
51
|
-
expect(parser.assignment).to parse('path = /srv/var/tmp/')
|
52
|
-
expect(parser.assignment).to_not parse('path<itscript> = /srv/tmp/')
|
53
|
-
expect(parser.assignment).to parse('name = "hello there, ftp uploading"')
|
54
|
-
expect(parser.assignment).to parse('params = array,of,values')
|
55
|
-
end
|
56
|
-
it 'can parse keys with optional overrides' do
|
57
|
-
expect(parser.snakey_option_key).to parse('path<itscript>')
|
98
|
+
expect(parser.boolean).to parse("true")
|
99
|
+
expect(parser.boolean).to parse("false")
|
58
100
|
end
|
59
101
|
it 'can parse file_paths' do
|
60
102
|
expect(parser.file_path).to parse('/srv/tmp/')
|
103
|
+
expect(parser.file_path).to_not parse(string)
|
61
104
|
end
|
62
|
-
|
63
|
-
|
105
|
+
|
106
|
+
describe 'overriding stuff' do
|
107
|
+
it 'can parse keys with optional overrides' do
|
108
|
+
expect(parser.snakey_option_key).to parse('path<itscript>')
|
109
|
+
end
|
110
|
+
it 'can parse overrides' do
|
111
|
+
expect(parser.override_assignment).to parse('path<itscript> = /srv/tmp/')
|
112
|
+
end
|
64
113
|
end
|
65
114
|
|
66
|
-
describe "
|
115
|
+
describe "building up from root, checking group, etc" do
|
67
116
|
let(:settings_path) { 'spec/support/settings.conf' }
|
68
117
|
let(:multi_group) {
|
69
118
|
[
|
70
119
|
"[common]",
|
71
120
|
"basic_size_limit = 234234",
|
72
121
|
"[rare]",
|
73
|
-
"pepes = 0"
|
122
|
+
"pepes = 0",
|
123
|
+
"and = feels guy"
|
74
124
|
].join("\n") + "\n"
|
75
125
|
}
|
76
126
|
|
127
|
+
it 'can parse assignments' do
|
128
|
+
expect(parser.assignment).to parse('basic_size_limit = 26214400')
|
129
|
+
expect(parser.assignment).to parse('path = /srv/var/tmp/')
|
130
|
+
expect(parser.assignment).to_not parse('path<itscript> = /srv/tmp/')
|
131
|
+
expect(parser.assignment).to parse('name = "hello there, ftp uploading"')
|
132
|
+
expect(parser.assignment).to parse('params = array,of,values')
|
133
|
+
expect(parser.assignment).to parse("hostname = My Computer\n")
|
134
|
+
end
|
135
|
+
it 'can parse comments then groups' do
|
136
|
+
expect(parser.comment_or_group).to parse("; comment\n[groop]\nassignment = 0\n")
|
137
|
+
end
|
138
|
+
it 'parses comment or group' do
|
139
|
+
expect(parser.comment_or_group).to parse("[database]\nserver = 192.0.2.62")
|
140
|
+
end
|
77
141
|
it 'parses a group member' do
|
78
|
-
expect(parser.group_member).to parse("
|
142
|
+
expect(parser.group_member).to parse("basic_size_limit = 26214400\n")
|
143
|
+
end
|
144
|
+
it 'can parse group members with inline comments' do
|
145
|
+
group_with_comments = "[section_two] # you can comment here" +
|
146
|
+
"\none = 42 # and even here!"
|
147
|
+
expect(parser.group).to parse(group_with_comments)
|
148
|
+
end
|
149
|
+
it 'can parse assignment irrespective of spacing' do
|
150
|
+
expect(parser.assignment).
|
151
|
+
to parse("basic_size_limit= 26214400\n")
|
152
|
+
expect(parser.assignment).
|
153
|
+
to parse("basic_size_limit = 26214400\n")
|
79
154
|
end
|
80
155
|
it 'can parse single assignment inside a group' do
|
81
156
|
expect(parser.group).
|
@@ -85,6 +160,10 @@ module Figtree
|
|
85
160
|
expect(parser.group).
|
86
161
|
to parse("[common]\nbasic_size_limit = 26214400\nstudent_size_limit = 52428800\n")
|
87
162
|
end
|
163
|
+
it 'can parse values including strings' do
|
164
|
+
group_member = "hostname = #{string}"
|
165
|
+
expect(parser.group_member).to parse(group_member)
|
166
|
+
end
|
88
167
|
it 'can parse multiple groups' do
|
89
168
|
expect(parser.group).to parse(multi_group)
|
90
169
|
end
|
@@ -12,8 +12,12 @@ module Figtree
|
|
12
12
|
let(:bool_tree) do
|
13
13
|
Parser.new.parse("[ftp]\nenabled = no\n")
|
14
14
|
end
|
15
|
+
let(:string_tree) do
|
16
|
+
Parser.new.parse_with_debug("[database]\nserver = is here\n")
|
17
|
+
Parser.new.parse("[database]\nserver = is here\n")
|
18
|
+
end
|
15
19
|
let(:ip_tree) do
|
16
|
-
Parser.new.parse("[database]\nserver=192.0.2.62")
|
20
|
+
Parser.new.parse("[database]\nserver = 192.0.2.62")
|
17
21
|
end
|
18
22
|
it 'can apply an int type conversion' do
|
19
23
|
expect(Transformer.new.apply(int_tree)).to eq(
|
@@ -42,6 +46,15 @@ module Figtree
|
|
42
46
|
]
|
43
47
|
)
|
44
48
|
end
|
49
|
+
it 'it can apply a string type conversion' do
|
50
|
+
expect(Transformer.new.apply(string_tree)).to eq(
|
51
|
+
[
|
52
|
+
{
|
53
|
+
database: Subgroup.new(server: "is here")
|
54
|
+
}
|
55
|
+
]
|
56
|
+
)
|
57
|
+
end
|
45
58
|
it 'it can apply an ip address type conversion' do
|
46
59
|
expect(Transformer.new.apply(ip_tree)).to eq(
|
47
60
|
[
|
@@ -60,7 +73,7 @@ module Figtree
|
|
60
73
|
expect(Transformer.new.apply(override_tree, override: :production)).to eq(
|
61
74
|
[
|
62
75
|
{
|
63
|
-
|
76
|
+
http: Subgroup.new(path: Pathname.new('/srv/var/tmp/'))
|
64
77
|
}
|
65
78
|
]
|
66
79
|
)
|
data/spec/figtree_spec.rb
CHANGED
@@ -1,6 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
# for the performance test at bottom
|
3
|
-
require 'benchmark'
|
4
2
|
|
5
3
|
describe Figtree do
|
6
4
|
describe '#load_config' do
|
@@ -10,7 +8,7 @@ describe Figtree do
|
|
10
8
|
:basic_size_limit => 26214400,
|
11
9
|
:student_size_limit => 52428800,
|
12
10
|
:paid_users_size_limit => 2147483648,
|
13
|
-
:path => "/srv/var/tmp/",
|
11
|
+
:path => Pathname.new("/srv/var/tmp/"),
|
14
12
|
)
|
15
13
|
end
|
16
14
|
|
@@ -19,7 +17,7 @@ describe Figtree do
|
|
19
17
|
:basic_size_limit => 26214400,
|
20
18
|
:student_size_limit => 52428800,
|
21
19
|
:paid_users_size_limit => 2147483648,
|
22
|
-
:path => "/srv/tmp/",
|
20
|
+
:path => Pathname.new("/srv/tmp/"),
|
23
21
|
)
|
24
22
|
end
|
25
23
|
|
@@ -32,15 +30,15 @@ describe Figtree do
|
|
32
30
|
:basic_size_limit => 26214400,
|
33
31
|
:student_size_limit=> 52428800,
|
34
32
|
:paid_users_size_limit=> 2147483648,
|
35
|
-
:path=> "/srv/var/tmp/"
|
33
|
+
:path=> Pathname.new("/srv/var/tmp/")
|
36
34
|
}
|
37
35
|
)
|
38
36
|
},
|
39
37
|
{
|
40
38
|
ftp: Figtree::Subgroup.new(
|
41
39
|
{
|
42
|
-
:name => "hello there, ftp uploading",
|
43
|
-
:path => "/tmp/",
|
40
|
+
:name => "\"hello there, ftp uploading\"",
|
41
|
+
:path => Pathname.new("/tmp/"),
|
44
42
|
:enabled => false
|
45
43
|
}
|
46
44
|
)
|
@@ -48,8 +46,8 @@ describe Figtree do
|
|
48
46
|
{
|
49
47
|
http: Figtree::Subgroup.new(
|
50
48
|
{
|
51
|
-
:name => "http uploading",
|
52
|
-
:path => "/tmp/",
|
49
|
+
:name => "\"http uploading\"",
|
50
|
+
:path => Pathname.new("/tmp/"),
|
53
51
|
:params => ["array", "of", "values"]
|
54
52
|
}
|
55
53
|
)
|
@@ -70,24 +68,68 @@ describe Figtree do
|
|
70
68
|
end
|
71
69
|
|
72
70
|
it 'can parse the wiki example' do
|
73
|
-
|
71
|
+
wiki_example = Figtree::IniConfig.new('spec/support/wiki_example.ini')
|
74
72
|
expect(wiki_example.database.server).to_not be_nil
|
75
73
|
end
|
76
74
|
|
77
75
|
context "performance" do
|
76
|
+
require 'benchmark'
|
78
77
|
it 'can parse the whole ini file quickly' do
|
79
78
|
expect(
|
80
79
|
Benchmark.realtime do
|
81
80
|
Figtree::IniConfig.new(settings_path)
|
82
81
|
end
|
83
82
|
).to be < 0.025
|
84
|
-
|
83
|
+
# without ip_address parsing this was under 0.014 :(
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
context "checking full transform" do
|
88
|
+
let(:mini_ini_file) { 'spec/support/mini_ini_example.ini' }
|
89
|
+
let(:mini_ini_config) do
|
90
|
+
Figtree::IniConfig.new(
|
91
|
+
{
|
92
|
+
Network: Figtree::Subgroup.new(
|
93
|
+
hostname: "My Computer",
|
94
|
+
address: "dhcp",
|
95
|
+
dns: IPAddr.new("192.168.1.1")
|
96
|
+
)
|
97
|
+
}
|
98
|
+
)
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'parses unquoted strings properly' do
|
102
|
+
expect(Figtree::IniConfig.new(mini_ini_file)).
|
103
|
+
to eq(mini_ini_config)
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
context "comparing to inifile gem" do
|
108
|
+
it 'does not parse anything INIFile gem cant parse' do
|
109
|
+
bad_ini_files = Dir["spec/support/invalid/*.ini"]
|
110
|
+
bad_ini_files.each do |ini_file|
|
111
|
+
#puts "\nfile is: #{ini_file}"
|
112
|
+
expect{ Figtree::IniConfig.new("#{ini_file}") }.
|
113
|
+
to raise_error
|
114
|
+
end
|
115
|
+
end
|
116
|
+
it 'can parse a subset of what INIFile gem can parse' do
|
117
|
+
ini_files = Dir["spec/support/*.ini"]
|
118
|
+
ini_files.each do |ini_file|
|
119
|
+
#puts "\nfile is: #{ini_file}"
|
120
|
+
expect(Figtree::IniConfig.new("#{ini_file}")).
|
121
|
+
to be_a Figtree::IniConfig
|
122
|
+
end
|
85
123
|
end
|
86
124
|
end
|
87
125
|
|
88
126
|
context "invalid ini file" do
|
89
|
-
let(:unparseable_config)
|
90
|
-
|
127
|
+
let(:unparseable_config) do
|
128
|
+
'spec/support/invalid/unparseable_settings.conf'
|
129
|
+
end
|
130
|
+
let(:untransformable_config) do
|
131
|
+
'spec/support/invalid/untransformable_settings.conf'
|
132
|
+
end
|
91
133
|
it 'throws ParseFailed if unparseable' do
|
92
134
|
expect { Figtree::IniConfig.new(unparseable_config) }.
|
93
135
|
to raise_error(Parslet::ParseFailed)
|
data/spec/spec_helper.rb
CHANGED
@@ -14,6 +14,10 @@ Dir[File.join(File.dirname(__FILE__), "..", "lib" , "**.rb")].each do |file|
|
|
14
14
|
require file
|
15
15
|
end
|
16
16
|
|
17
|
+
# because we raise more than one error type from invalid
|
18
|
+
# this should prob be avoided though
|
19
|
+
RSpec::Expectations.configuration.warn_about_potential_false_positives = false
|
20
|
+
|
17
21
|
RSpec.configure do |config|
|
18
22
|
# quiet output from figtree_spec invalid ini context
|
19
23
|
config.before { allow($stderr).to receive(:puts) }
|
@@ -0,0 +1,18 @@
|
|
1
|
+
[section_one]
|
2
|
+
one = 1
|
3
|
+
two = 2
|
4
|
+
|
5
|
+
[section_two]
|
6
|
+
three = "-3"
|
7
|
+
multi = multiline \
|
8
|
+
support
|
9
|
+
|
10
|
+
; comments should be ignored
|
11
|
+
[section_three]
|
12
|
+
four =true
|
13
|
+
five=false # comments can go here
|
14
|
+
six = "6.0" ; and here, too
|
15
|
+
|
16
|
+
[section_five]
|
17
|
+
seven_and_eight= "7 & 8"
|
18
|
+
|
@@ -0,0 +1,13 @@
|
|
1
|
+
; this test file demonstrates escape sequences supported by IniFile
|
2
|
+
[normal]
|
3
|
+
foo = http://en.wikipedia.org/wiki/Foobar
|
4
|
+
|
5
|
+
[escaped]
|
6
|
+
tabs = There is a tab\tcharacter in here somewhere
|
7
|
+
carriage return = Who uses these anyways?\r
|
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? \
|
10
|
+
Stroustrup would not approve!
|
11
|
+
backslash = This string \\t contains \\n no \\r special \\0 characters!
|
12
|
+
quoted = "Escaping works\tinside quoted strings!"
|
13
|
+
|
File without changes
|
File without changes
|
@@ -0,0 +1,23 @@
|
|
1
|
+
[section_one]
|
2
|
+
one = 1
|
3
|
+
two = 2
|
4
|
+
|
5
|
+
[section_two]
|
6
|
+
three = 3
|
7
|
+
|
8
|
+
; comments should be ignored
|
9
|
+
[section_three]
|
10
|
+
three = hello \
|
11
|
+
multiline
|
12
|
+
other = "stuff"
|
13
|
+
|
14
|
+
[section_four]
|
15
|
+
four = hello \ # 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"
|
21
|
+
|
22
|
+
[empty_lines]
|
23
|
+
not_empty=full
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: figtree
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Moore-Niemi
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-10-
|
11
|
+
date: 2015-10-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: parslet
|
@@ -88,7 +88,9 @@ dependencies:
|
|
88
88
|
version: '0.10'
|
89
89
|
description: See README.md
|
90
90
|
email: moore.niemi@gmail.com
|
91
|
-
executables:
|
91
|
+
executables:
|
92
|
+
- console
|
93
|
+
- setup
|
92
94
|
extensions: []
|
93
95
|
extra_rdoc_files: []
|
94
96
|
files:
|
@@ -99,6 +101,8 @@ files:
|
|
99
101
|
- Gemfile.lock
|
100
102
|
- MIT-LICENSE
|
101
103
|
- README.md
|
104
|
+
- bin/console
|
105
|
+
- bin/setup
|
102
106
|
- figtree.gemspec
|
103
107
|
- lib/figtree.rb
|
104
108
|
- lib/figtree/ini_config.rb
|
@@ -110,9 +114,24 @@ files:
|
|
110
114
|
- spec/figtree/transformer_spec.rb
|
111
115
|
- spec/figtree_spec.rb
|
112
116
|
- spec/spec_helper.rb
|
117
|
+
- spec/support/comment.ini
|
118
|
+
- spec/support/good.ini
|
119
|
+
- spec/support/invalid/bad_1.ini
|
120
|
+
- spec/support/invalid/bad_2.ini
|
121
|
+
- spec/support/invalid/browscap.ini
|
122
|
+
- spec/support/invalid/continuation.ini
|
123
|
+
- spec/support/invalid/escape.ini
|
124
|
+
- spec/support/invalid/global.ini
|
125
|
+
- spec/support/invalid/unparseable_settings.conf
|
126
|
+
- spec/support/invalid/untransformable_settings.conf
|
127
|
+
- spec/support/merge.ini
|
128
|
+
- spec/support/mini_ini_example.ini
|
129
|
+
- spec/support/mixed_comment.ini
|
130
|
+
- spec/support/multiline.ini
|
131
|
+
- spec/support/multiline_only.ini
|
132
|
+
- spec/support/param.ini
|
133
|
+
- spec/support/section.ini
|
113
134
|
- spec/support/settings.conf
|
114
|
-
- spec/support/unparseable_settings.conf
|
115
|
-
- spec/support/untransformable_settings.conf
|
116
135
|
- spec/support/wiki_example.ini
|
117
136
|
homepage: https://github.com/mooreniemi/figtree
|
118
137
|
licenses:
|
@@ -144,8 +163,23 @@ test_files:
|
|
144
163
|
- spec/figtree/transformer_spec.rb
|
145
164
|
- spec/figtree_spec.rb
|
146
165
|
- spec/spec_helper.rb
|
166
|
+
- spec/support/comment.ini
|
167
|
+
- spec/support/good.ini
|
168
|
+
- spec/support/invalid/bad_1.ini
|
169
|
+
- spec/support/invalid/bad_2.ini
|
170
|
+
- spec/support/invalid/browscap.ini
|
171
|
+
- spec/support/invalid/continuation.ini
|
172
|
+
- spec/support/invalid/escape.ini
|
173
|
+
- spec/support/invalid/global.ini
|
174
|
+
- spec/support/invalid/unparseable_settings.conf
|
175
|
+
- spec/support/invalid/untransformable_settings.conf
|
176
|
+
- spec/support/merge.ini
|
177
|
+
- spec/support/mini_ini_example.ini
|
178
|
+
- spec/support/mixed_comment.ini
|
179
|
+
- spec/support/multiline.ini
|
180
|
+
- spec/support/multiline_only.ini
|
181
|
+
- spec/support/param.ini
|
182
|
+
- spec/support/section.ini
|
147
183
|
- spec/support/settings.conf
|
148
|
-
- spec/support/unparseable_settings.conf
|
149
|
-
- spec/support/untransformable_settings.conf
|
150
184
|
- spec/support/wiki_example.ini
|
151
185
|
has_rdoc:
|