toml-rb 0.1.6 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/README.md +7 -5
- data/Rakefile +2 -3
- data/init.rb +1 -1
- data/lib/toml.rb +0 -2
- data/lib/toml/dumper.rb +49 -8
- data/lib/toml/grammars/array.citrus +7 -7
- data/lib/toml/grammars/document.citrus +6 -2
- data/lib/toml/grammars/primitive.citrus +72 -10
- data/lib/toml/keygroup.rb +4 -3
- data/lib/toml/keyvalue.rb +1 -1
- data/lib/toml/parser.rb +4 -0
- data/lib/toml/string.rb +39 -23
- data/lib/toml/table_array.rb +29 -0
- data/test/dumper_test.rb +20 -11
- data/test/errors_test.rb +10 -12
- data/test/example-v0.3.1.toml +180 -0
- data/test/grammar_test.rb +56 -6
- data/test/hard_example.toml +5 -2
- data/test/toml_examples.rb +171 -0
- data/test/toml_test.rb +22 -55
- data/toml-rb.gemspec +13 -13
- metadata +22 -23
data/test/dumper_test.rb
CHANGED
@@ -1,14 +1,13 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
class DumperTest < Test::Unit::TestCase
|
4
|
-
|
5
4
|
def test_dump_empty
|
6
5
|
dumped = TOML.dump({})
|
7
6
|
assert_equal('', dumped)
|
8
7
|
end
|
9
8
|
|
10
9
|
def test_dump_types
|
11
|
-
dumped = TOML.dump(string:
|
10
|
+
dumped = TOML.dump(string: 'TOML "dump"')
|
12
11
|
assert_equal("string = \"TOML \\\"dump\\\"\"\n", dumped)
|
13
12
|
|
14
13
|
dumped = TOML.dump(float: -13.24)
|
@@ -26,7 +25,7 @@ class DumperTest < Test::Unit::TestCase
|
|
26
25
|
dumped = TOML.dump(array: [1, 2, 3])
|
27
26
|
assert_equal("array = [1, 2, 3]\n", dumped)
|
28
27
|
|
29
|
-
dumped = TOML.dump(array: [[1, 2],
|
28
|
+
dumped = TOML.dump(array: [[1, 2], %w(weird one)])
|
30
29
|
assert_equal("array = [[1, 2], [\"weird\", \"one\"]]\n", dumped)
|
31
30
|
|
32
31
|
dumped = TOML.dump(datetime: Time.utc(1986, 8, 28, 15, 15))
|
@@ -34,7 +33,7 @@ class DumperTest < Test::Unit::TestCase
|
|
34
33
|
end
|
35
34
|
|
36
35
|
def test_dump_nested_attributes
|
37
|
-
hash = {nested: {hash: { deep: true}}}
|
36
|
+
hash = { nested: { hash: { deep: true } } }
|
38
37
|
dumped = TOML.dump(hash)
|
39
38
|
assert_equal("[nested.hash]\ndeep = true\n", dumped)
|
40
39
|
|
@@ -42,15 +41,25 @@ class DumperTest < Test::Unit::TestCase
|
|
42
41
|
dumped = TOML.dump(hash)
|
43
42
|
assert_equal("[nested]\nother = 12\n[nested.hash]\ndeep = true\n", dumped)
|
44
43
|
|
45
|
-
hash[:nested].merge!(nest: {again: 'it never ends'})
|
44
|
+
hash[:nested].merge!(nest: { again: 'it never ends' })
|
46
45
|
dumped = TOML.dump(hash)
|
47
|
-
toml =
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
46
|
+
toml = <<-EOS.gsub(/^ {6}/, '')
|
47
|
+
[nested]
|
48
|
+
other = 12
|
49
|
+
[nested.hash]
|
50
|
+
deep = true
|
51
|
+
[nested.nest]
|
52
|
+
again = "it never ends"
|
53
|
+
EOS
|
53
54
|
|
54
55
|
assert_equal(toml, dumped)
|
56
|
+
|
57
|
+
hash = { non: { 'bare."keys"' => { "works" => true } } }
|
58
|
+
dumped = TOML.dump(hash)
|
59
|
+
assert_equal("[non.\"bare.\\\"keys\\\"\"]\nworks = true\n", dumped)
|
60
|
+
|
61
|
+
hash = { hola: [{ chau: 4 }, { chau: 3 }] }
|
62
|
+
dumped = TOML.dump(hash)
|
63
|
+
assert_equal("[[hola]]\nchau = 4\n[[hola]]\nchau = 3\n", dumped)
|
55
64
|
end
|
56
65
|
end
|
data/test/errors_test.rb
CHANGED
@@ -1,10 +1,9 @@
|
|
1
1
|
require_relative 'helper'
|
2
2
|
|
3
3
|
class ErrorsTest < Test::Unit::TestCase
|
4
|
-
|
5
4
|
def test_text_after_keygroup
|
6
5
|
str = "[error] if you didn't catch this, your parser is broken"
|
7
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
6
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
8
7
|
end
|
9
8
|
|
10
9
|
def test_text_after_string
|
@@ -12,11 +11,11 @@ class ErrorsTest < Test::Unit::TestCase
|
|
12
11
|
str += 'keygroup or key value pair has ended should produce an error '
|
13
12
|
str += 'unless it is a comment" like this'
|
14
13
|
|
15
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
14
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
16
15
|
end
|
17
16
|
|
18
17
|
def test_multiline_array_bad_string
|
19
|
-
str
|
18
|
+
str = <<-EOS
|
20
19
|
array = [
|
21
20
|
"This might most likely happen in multiline arrays",
|
22
21
|
Like here,
|
@@ -25,11 +24,11 @@ class ErrorsTest < Test::Unit::TestCase
|
|
25
24
|
] End of array comment, forgot the #
|
26
25
|
EOS
|
27
26
|
|
28
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
27
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
29
28
|
end
|
30
29
|
|
31
30
|
def test_multiline_array_string_not_ended
|
32
|
-
str
|
31
|
+
str = <<-EOS
|
33
32
|
array = [
|
34
33
|
"This might most likely happen in multiline arrays",
|
35
34
|
"or here,
|
@@ -37,11 +36,11 @@ class ErrorsTest < Test::Unit::TestCase
|
|
37
36
|
] End of array comment, forgot the #
|
38
37
|
EOS
|
39
38
|
|
40
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
39
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
41
40
|
end
|
42
41
|
|
43
42
|
def test_text_after_multiline_array
|
44
|
-
str
|
43
|
+
str = <<-EOS
|
45
44
|
array = [
|
46
45
|
"This might most likely happen in multiline arrays",
|
47
46
|
"or here",
|
@@ -49,12 +48,11 @@ class ErrorsTest < Test::Unit::TestCase
|
|
49
48
|
] End of array comment, forgot the #
|
50
49
|
EOS
|
51
50
|
|
52
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
51
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
53
52
|
end
|
54
53
|
|
55
54
|
def test_text_after_number
|
56
|
-
str =
|
57
|
-
assert_raises(TOML::ParseError){ TOML.parse(str) }
|
55
|
+
str = 'number = 3.14 pi <--again forgot the #'
|
56
|
+
assert_raises(TOML::ParseError) { TOML.parse(str) }
|
58
57
|
end
|
59
|
-
|
60
58
|
end
|
@@ -0,0 +1,180 @@
|
|
1
|
+
# Comment
|
2
|
+
# I am a comment. Hear me roar. Roar.
|
3
|
+
|
4
|
+
# Table
|
5
|
+
# Tables (also known as hash tables or dictionaries) are collections of key/value pairs.
|
6
|
+
# They appear in square brackets on a line by themselves.
|
7
|
+
|
8
|
+
[Table]
|
9
|
+
|
10
|
+
key = "value" # Yeah, you can do this.
|
11
|
+
|
12
|
+
# Nested tables are denoted by table names with dots in them. Name your tables whatever crap you please, just don't use #, ., [ or ].
|
13
|
+
|
14
|
+
[dog.tater]
|
15
|
+
type = "pug"
|
16
|
+
|
17
|
+
# You don't need to specify all the super-tables if you don't want to. TOML knows how to do it for you.
|
18
|
+
|
19
|
+
# [x] you
|
20
|
+
# [x.y] don't
|
21
|
+
# [x.y.z] need these
|
22
|
+
[x.y.z.w] # for this to work
|
23
|
+
|
24
|
+
# String
|
25
|
+
# There are four ways to express strings: basic, multi-line basic, literal, and multi-line literal.
|
26
|
+
# All strings must contain only valid UTF-8 characters.
|
27
|
+
|
28
|
+
[String]
|
29
|
+
basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
|
30
|
+
|
31
|
+
[String.Multiline]
|
32
|
+
|
33
|
+
# The following strings are byte-for-byte equivalent:
|
34
|
+
key1 = "One\nTwo"
|
35
|
+
key2 = """One\nTwo"""
|
36
|
+
key3 = """
|
37
|
+
One
|
38
|
+
Two"""
|
39
|
+
|
40
|
+
[String.Multilined.Singleline]
|
41
|
+
|
42
|
+
# The following strings are byte-for-byte equivalent:
|
43
|
+
key1 = "The quick brown fox jumps over the lazy dog."
|
44
|
+
|
45
|
+
key2 = """
|
46
|
+
The quick brown \
|
47
|
+
|
48
|
+
|
49
|
+
fox jumps over \
|
50
|
+
the lazy dog."""
|
51
|
+
|
52
|
+
key3 = """\
|
53
|
+
The quick brown \
|
54
|
+
fox jumps over \
|
55
|
+
the lazy dog.\
|
56
|
+
"""
|
57
|
+
|
58
|
+
[String.Literal]
|
59
|
+
|
60
|
+
# What you see is what you get.
|
61
|
+
winpath = 'C:\Users\nodejs\templates'
|
62
|
+
winpath2 = '\\ServerX\admin$\system32\'
|
63
|
+
quoted = 'Tom "Dubs" Preston-Werner'
|
64
|
+
regex = '<\i\c*\s*>'
|
65
|
+
|
66
|
+
[String.Literal.Multiline]
|
67
|
+
|
68
|
+
regex2 = '''I [dw]on't need \d{2} apples'''
|
69
|
+
lines = '''
|
70
|
+
The first newline is
|
71
|
+
trimmed in raw strings.
|
72
|
+
All other whitespace
|
73
|
+
is preserved.
|
74
|
+
'''
|
75
|
+
|
76
|
+
# Integer
|
77
|
+
# Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
|
78
|
+
# Negative numbers are prefixed with a minus sign.
|
79
|
+
|
80
|
+
[Integer]
|
81
|
+
key1 = +99
|
82
|
+
key2 = 42
|
83
|
+
key3 = 0
|
84
|
+
key4 = -17
|
85
|
+
|
86
|
+
# Float
|
87
|
+
# A float consists of an integer part (which may be prefixed with a plus or minus sign)
|
88
|
+
# followed by a fractional part and/or an exponent part.
|
89
|
+
|
90
|
+
[Float.fractional]
|
91
|
+
|
92
|
+
# fractional
|
93
|
+
key1 = +1.0
|
94
|
+
key2 = 3.1415
|
95
|
+
key3 = -0.01
|
96
|
+
|
97
|
+
[Float.exponent]
|
98
|
+
|
99
|
+
# exponent
|
100
|
+
key1 = 5e+22
|
101
|
+
key2 = 1e6
|
102
|
+
key3 = -2E-2
|
103
|
+
|
104
|
+
[Float.both]
|
105
|
+
|
106
|
+
# both
|
107
|
+
key = 6.626e-34
|
108
|
+
|
109
|
+
# Boolean
|
110
|
+
# Booleans are just the tokens you're used to. Always lowercase.
|
111
|
+
|
112
|
+
[Booleans]
|
113
|
+
True = true
|
114
|
+
False = false
|
115
|
+
|
116
|
+
# Datetime
|
117
|
+
# Datetimes are RFC 3339 dates.
|
118
|
+
|
119
|
+
[Datetime]
|
120
|
+
key1 = 1979-05-27T07:32:00Z
|
121
|
+
key2 = 1979-05-27T00:32:00-07:00
|
122
|
+
key3 = 1979-05-27T00:32:00.999999-07:00
|
123
|
+
|
124
|
+
# Array
|
125
|
+
# Arrays are square brackets with other primitives inside. Whitespace is ignored. Elements are separated by commas. Data types may not be mixed.
|
126
|
+
|
127
|
+
[Array]
|
128
|
+
key1 = [ 1, 2, 3 ]
|
129
|
+
key2 = [ "red", "yellow", "green" ]
|
130
|
+
key3 = [ [ 1, 2 ], [3, 4, 5] ]
|
131
|
+
key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
|
132
|
+
|
133
|
+
#Arrays can also be multiline. So in addition to ignoring whitespace, arrays also ignore newlines between the brackets.
|
134
|
+
# Terminating commas are ok before the closing bracket.
|
135
|
+
|
136
|
+
key5 = [
|
137
|
+
1, 2, 3
|
138
|
+
]
|
139
|
+
key6 = [
|
140
|
+
1,
|
141
|
+
2, # this is ok
|
142
|
+
]
|
143
|
+
|
144
|
+
# Array of Tables
|
145
|
+
# These can be expressed by using a table name in double brackets.
|
146
|
+
# Each table with the same double bracketed name will be an element in the array.
|
147
|
+
# The tables are inserted in the order encountered.
|
148
|
+
|
149
|
+
[[products]]
|
150
|
+
name = "Hammer"
|
151
|
+
sku = 738594937
|
152
|
+
|
153
|
+
[[products]]
|
154
|
+
|
155
|
+
[[products]]
|
156
|
+
name = "Nail"
|
157
|
+
sku = 284758393
|
158
|
+
color = "gray"
|
159
|
+
|
160
|
+
|
161
|
+
# You can create nested arrays of tables as well.
|
162
|
+
|
163
|
+
[[fruit]]
|
164
|
+
name = "apple"
|
165
|
+
|
166
|
+
[fruit.physical]
|
167
|
+
color = "red"
|
168
|
+
shape = "round"
|
169
|
+
|
170
|
+
[[fruit.variety]]
|
171
|
+
name = "red delicious"
|
172
|
+
|
173
|
+
[[fruit.variety]]
|
174
|
+
name = "granny smith"
|
175
|
+
|
176
|
+
[[fruit]]
|
177
|
+
name = "banana"
|
178
|
+
|
179
|
+
[[fruit.variety]]
|
180
|
+
name = "plantain"
|
data/test/grammar_test.rb
CHANGED
@@ -1,12 +1,20 @@
|
|
1
|
+
# encoding: utf-8
|
1
2
|
require_relative 'helper'
|
2
3
|
|
3
4
|
class GrammarTest < Test::Unit::TestCase
|
4
|
-
|
5
5
|
def test_comment
|
6
6
|
match = Document.parse(' # A comment', root: :comment)
|
7
7
|
assert_equal(nil, match.value)
|
8
8
|
end
|
9
9
|
|
10
|
+
def test_key
|
11
|
+
match = Document.parse('bad_key-', root: :key)
|
12
|
+
assert_equal('bad_key-', match.value)
|
13
|
+
|
14
|
+
match = Document.parse('"123.ʎǝʞ.#?"', root: :key)
|
15
|
+
assert_equal('123.ʎǝʞ.#?', match.value)
|
16
|
+
end
|
17
|
+
|
10
18
|
def test_keygroup
|
11
19
|
indentation_alternatives_for('[akey]') do |str|
|
12
20
|
match = Document.parse(str, root: :keygroup)
|
@@ -15,7 +23,15 @@ class GrammarTest < Test::Unit::TestCase
|
|
15
23
|
end
|
16
24
|
|
17
25
|
match = Document.parse('[owner.emancu]', root: :keygroup)
|
18
|
-
assert_equal(
|
26
|
+
assert_equal(%w(owner emancu),
|
27
|
+
match.value.instance_variable_get('@nested_keys'))
|
28
|
+
|
29
|
+
match = Document.parse('["owner.emancu"]', root: :keygroup)
|
30
|
+
assert_equal(%w(owner.emancu),
|
31
|
+
match.value.instance_variable_get('@nested_keys'))
|
32
|
+
|
33
|
+
match = Document.parse('[ owner . emancu ]', root: :keygroup)
|
34
|
+
assert_equal(%w(owner emancu),
|
19
35
|
match.value.instance_variable_get('@nested_keys'))
|
20
36
|
end
|
21
37
|
|
@@ -35,6 +51,19 @@ class GrammarTest < Test::Unit::TestCase
|
|
35
51
|
assert_equal('TOML-Example, should work.', match.value)
|
36
52
|
end
|
37
53
|
|
54
|
+
def test_multiline_string
|
55
|
+
match = Document.parse('"""\tOne\nTwo"""', root: :multiline_string)
|
56
|
+
assert_equal "\tOne\nTwo", match.value
|
57
|
+
|
58
|
+
to_parse = '"""\
|
59
|
+
One \
|
60
|
+
Two\
|
61
|
+
"""'
|
62
|
+
|
63
|
+
match = Document.parse(to_parse, root: :multiline_string)
|
64
|
+
assert_equal "One Two", match.value
|
65
|
+
end
|
66
|
+
|
38
67
|
def test_special_characters
|
39
68
|
match = Document.parse('"\0 \" \t \n \r"', root: :string)
|
40
69
|
assert_equal("\0 \" \t \n \r", match.value)
|
@@ -59,6 +88,12 @@ class GrammarTest < Test::Unit::TestCase
|
|
59
88
|
def test_float
|
60
89
|
match = Document.parse('1.69', root: :number)
|
61
90
|
assert_equal(1.69, match.value)
|
91
|
+
|
92
|
+
match = Document.parse('1e6', root: :number)
|
93
|
+
assert_equal(1e6, match.value)
|
94
|
+
|
95
|
+
match = Document.parse('1.02e-46', root: :number)
|
96
|
+
assert_equal(1.02e-46, match.value)
|
62
97
|
end
|
63
98
|
|
64
99
|
def test_signed_numbers
|
@@ -96,19 +131,35 @@ class GrammarTest < Test::Unit::TestCase
|
|
96
131
|
assert_equal([2.4, 4.72], match.value)
|
97
132
|
|
98
133
|
match = Document.parse('[ "hey", "TOML"]', root: :array)
|
99
|
-
assert_equal(
|
134
|
+
assert_equal(%w(hey TOML), match.value)
|
100
135
|
|
101
136
|
match = Document.parse('[ ["hey", "TOML"], [2,4] ]', root: :array)
|
102
|
-
assert_equal([
|
137
|
+
assert_equal([%w(hey TOML), [2, 4]], match.value)
|
138
|
+
end
|
103
139
|
|
140
|
+
def test_multiline_array
|
104
141
|
multiline_array = "[ \"hey\",\n \"ho\",\n\t \"lets\", \"go\",\n ]"
|
105
142
|
match = Document.parse(multiline_array, root: :array)
|
106
|
-
assert_equal(
|
143
|
+
assert_equal(%w(hey ho lets go), match.value)
|
144
|
+
|
145
|
+
multiline_array = "[\n#1,\n2,\n# 3\n]"
|
146
|
+
match = Document.parse(multiline_array, root: :array)
|
147
|
+
assert_equal([2], match.value)
|
148
|
+
|
149
|
+
multiline_array = "[\n# comment\n#, more comments\n4]"
|
150
|
+
match = Document.parse(multiline_array, root: :array)
|
151
|
+
assert_equal([4], match.value)
|
107
152
|
end
|
108
153
|
|
109
154
|
def test_datetime
|
110
155
|
match = Document.parse('1986-08-28T15:15:00Z', root: :datetime)
|
111
156
|
assert_equal(Time.utc(1986, 8, 28, 15, 15), match.value)
|
157
|
+
|
158
|
+
match = Document.parse('1986-08-28T15:15:00-03:00', root: :datetime)
|
159
|
+
assert_equal(Time.utc(1986, 8, 28, 18, 15), match.value)
|
160
|
+
|
161
|
+
match = Document.parse('1986-08-28T15:15:00.123-03:00', root: :datetime)
|
162
|
+
assert_equal(Time.utc(1986, 8, 28, 18, 15, 0.123), match.value)
|
112
163
|
end
|
113
164
|
|
114
165
|
private
|
@@ -120,4 +171,3 @@ class GrammarTest < Test::Unit::TestCase
|
|
120
171
|
end
|
121
172
|
end
|
122
173
|
end
|
123
|
-
|
data/test/hard_example.toml
CHANGED
@@ -13,13 +13,15 @@ test_string = "You'll hate me after this - #" # " Annoying, isn't it?
|
|
13
13
|
harder_test_string = " And when \"'s are in the string, along with # \"" # "and comments are there too"
|
14
14
|
# Things will get harder
|
15
15
|
|
16
|
-
[the.hard.bit#]
|
17
|
-
what? = "You don't think some user won't do that?"
|
16
|
+
[the.hard."bit#"]
|
17
|
+
"what?" = "You don't think some user won't do that?"
|
18
18
|
multi_line_array = [
|
19
19
|
"]",
|
20
20
|
# ] Oh yes I did
|
21
21
|
]
|
22
22
|
|
23
|
+
[[nested.table.array]]
|
24
|
+
|
23
25
|
# Each of the following keygroups/key value pairs should produce an error. Uncomment to them to test
|
24
26
|
|
25
27
|
#[error] if you didn't catch this, your parser is broken
|
@@ -31,3 +33,4 @@ test_string = "You'll hate me after this - #" # " Annoying, isn't it?
|
|
31
33
|
# and here"
|
32
34
|
# ] End of array comment, forgot the #
|
33
35
|
#number = 3.14 pi <--again forgot the #
|
36
|
+
|