toml-rb-hs 1.1.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,94 @@
1
+ unless defined? require_relative
2
+ def require_relative(path)
3
+ require path
4
+ end
5
+ end
6
+
7
+ require_relative 'helper'
8
+
9
+ class ErrorsTest < Minitest::Test
10
+ def test_text_after_keygroup
11
+ str = "[error] if you didn't catch this, your parser is broken"
12
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
13
+ end
14
+
15
+ def test_text_after_string
16
+ str = 'string = "Anything other than tabs, spaces and newline after a '
17
+ str += 'keygroup or key value pair has ended should produce an error '
18
+ str += 'unless it is a comment" like this'
19
+
20
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
21
+ end
22
+
23
+ def test_multiline_array_bad_string
24
+ str = <<-EOS
25
+ array = [
26
+ "This might most likely happen in multiline arrays",
27
+ Like here,
28
+ "or here,
29
+ and here"
30
+ ] End of array comment, forgot the #
31
+ EOS
32
+
33
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
34
+ end
35
+
36
+ def test_multiline_array_string_not_ended
37
+ str = <<-EOS
38
+ array = [
39
+ "This might most likely happen in multiline arrays",
40
+ "or here,
41
+ and here"
42
+ ] End of array comment, forgot the #
43
+ EOS
44
+
45
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
46
+ end
47
+
48
+ def test_text_after_multiline_array
49
+ str = <<-EOS
50
+ array = [
51
+ "This might most likely happen in multiline arrays",
52
+ "or here",
53
+ "and here"
54
+ ] End of array comment, forgot the #
55
+ EOS
56
+
57
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
58
+ end
59
+
60
+ def test_text_after_number
61
+ str = 'number = 3.14 pi <--again forgot the #'
62
+ assert_raises(TomlRB::ParseError) { TomlRB.parse(str) }
63
+ end
64
+
65
+ def test_value_overwrite
66
+ str = "a = 1\na = 2"
67
+ e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
68
+ assert_equal "Key \"a\" is defined more than once", e.message
69
+ assert_equal "a", e.key
70
+
71
+ str = "a = false\na = true"
72
+ assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
73
+ end
74
+
75
+ def test_table_overwrite
76
+ str = "[a]\nb=1\n[a]\nc=2"
77
+ e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
78
+ assert_equal "Key \"a\" is defined more than once", e.message
79
+
80
+ str = "[a]\nb=1\n[a]\nb=1"
81
+ e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
82
+ assert_equal "Key \"a\" is defined more than once", e.message
83
+ end
84
+
85
+ def test_value_overwrite_with_table
86
+ str = "[a]\nb=1\n[a.b]\nc=2"
87
+ e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
88
+ assert_equal "Key \"b\" is defined more than once", e.message
89
+
90
+ str = "[a]\nb=1\n[a.b.c]\nd=3"
91
+ e = assert_raises(TomlRB::ValueOverwriteError) { TomlRB.parse(str) }
92
+ assert_equal "Key \"b\" is defined more than once", e.message
93
+ end
94
+ end
@@ -0,0 +1,244 @@
1
+ ################################################################################
2
+ ## Comment
3
+
4
+ # Speak your mind with the hash symbol. They go from the symbol to the end of
5
+ # the line.
6
+
7
+
8
+ ################################################################################
9
+ ## Table
10
+
11
+ # Tables (also known as hash tables or dictionaries) are collections of
12
+ # key/value pairs. They appear in square brackets on a line by themselves.
13
+
14
+ [table]
15
+
16
+ key = "value" # Yeah, you can do this.
17
+
18
+ # Nested tables are denoted by table names with dots in them. Name your tables
19
+ # whatever crap you please, just don't use #, ., [ or ].
20
+
21
+ [table.subtable]
22
+
23
+ key = "another value"
24
+
25
+ # You don't need to specify all the super-tables if you don't want to. TomlRB
26
+ # knows how to do it for you.
27
+
28
+ # [x] you
29
+ # [x.y] don't
30
+ # [x.y.z] need these
31
+ [x.y.z.w] # for this to work
32
+
33
+
34
+ ################################################################################
35
+ ## Inline Table
36
+
37
+ # Inline tables provide a more compact syntax for expressing tables. They are
38
+ # especially useful for grouped data that can otherwise quickly become verbose.
39
+ # Inline tables are enclosed in curly braces `{` and `}`. No newlines are
40
+ # allowed between the curly braces unless they are valid within a value.
41
+
42
+ [table.inline]
43
+
44
+ name = { first = "Tom", last = "Preston-Werner" }
45
+ point = { x = 1, y = 2 }
46
+
47
+
48
+ ################################################################################
49
+ ## String
50
+
51
+ # There are four ways to express strings: basic, multi-line basic, literal, and
52
+ # multi-line literal. All strings must contain only valid UTF-8 characters.
53
+
54
+ [string.basic]
55
+
56
+ basic = "I'm a string. \"You can quote me\". Name\tJos\u00E9\nLocation\tSF."
57
+
58
+ [string.multiline]
59
+
60
+ # The following strings are byte-for-byte equivalent:
61
+ key1 = "One\nTwo"
62
+ key2 = """One\nTwo"""
63
+ key3 = """
64
+ One
65
+ Two"""
66
+
67
+ [string.multiline.continued]
68
+
69
+ # The following strings are byte-for-byte equivalent:
70
+ key1 = "The quick brown fox jumps over the lazy dog."
71
+
72
+ key2 = """
73
+ The quick brown \
74
+
75
+
76
+ fox jumps over \
77
+ the lazy dog."""
78
+
79
+ key3 = """\
80
+ The quick brown \
81
+ fox jumps over \
82
+ the lazy dog.\
83
+ """
84
+
85
+ [string.literal]
86
+
87
+ # What you see is what you get.
88
+ winpath = 'C:\Users\nodejs\templates'
89
+ winpath2 = '\\ServerX\admin$\system32\'
90
+ quoted = 'Tom "Dubs" Preston-Werner'
91
+ regex = '<\i\c*\s*>'
92
+
93
+
94
+ [string.literal.multiline]
95
+
96
+ regex2 = '''I [dw]on't need \d{2} apples'''
97
+ lines = '''
98
+ The first newline is
99
+ trimmed in raw strings.
100
+ All other whitespace
101
+ is preserved.
102
+ '''
103
+
104
+
105
+ ################################################################################
106
+ ## Integer
107
+
108
+ # Integers are whole numbers. Positive numbers may be prefixed with a plus sign.
109
+ # Negative numbers are prefixed with a minus sign.
110
+
111
+ [integer]
112
+
113
+ key1 = +99
114
+ key2 = 42
115
+ key3 = 0
116
+ key4 = -17
117
+
118
+ [integer.underscores]
119
+
120
+ # For large numbers, you may use underscores to enhance readability. Each
121
+ # underscore must be surrounded by at least one digit.
122
+ key1 = 1_000
123
+ key2 = 5_349_221
124
+ key3 = 1_2_3_4_5 # valid but inadvisable
125
+
126
+
127
+ ################################################################################
128
+ ## Float
129
+
130
+ # A float consists of an integer part (which may be prefixed with a plus or
131
+ # minus sign) followed by a fractional part and/or an exponent part.
132
+
133
+ [float.fractional]
134
+
135
+ key1 = +1.0
136
+ key2 = 3.1415
137
+ key3 = -0.01
138
+
139
+ [float.exponent]
140
+
141
+ key1 = 5e+22
142
+ key2 = 1e6
143
+ key3 = -2E-2
144
+
145
+ [float.both]
146
+
147
+ key = 6.626e-34
148
+
149
+ [float.underscores]
150
+
151
+ key1 = 9_224_617.445_991_228_313
152
+ key2 = 1e1_000
153
+
154
+
155
+ ################################################################################
156
+ ## Boolean
157
+
158
+ # Booleans are just the tokens you're used to. Always lowercase.
159
+
160
+ [boolean]
161
+
162
+ True = true
163
+ False = false
164
+
165
+
166
+ ################################################################################
167
+ ## Datetime
168
+
169
+ # Datetimes are RFC 3339 dates.
170
+
171
+ [datetime]
172
+
173
+ key1 = 1979-05-27T07:32:00Z
174
+ key2 = 1979-05-27T00:32:00-07:00
175
+ key3 = 1979-05-27T00:32:00.999999-07:00
176
+
177
+
178
+ ################################################################################
179
+ ## Array
180
+
181
+ # Arrays are square brackets with other primitives inside. Whitespace is
182
+ # ignored. Elements are separated by commas. Data types may not be mixed.
183
+
184
+ [array]
185
+
186
+ key1 = [ 1, 2, 3 ]
187
+ key2 = [ "red", "yellow", "green" ]
188
+ key3 = [ [ 1, 2 ], [3, 4, 5] ]
189
+ key4 = [ [ 1, 2 ], ["a", "b", "c"] ] # this is ok
190
+
191
+ # Arrays can also be multiline. So in addition to ignoring whitespace, arrays
192
+ # also ignore newlines between the brackets. Terminating commas are ok before
193
+ # the closing bracket.
194
+
195
+ key5 = [
196
+ 1, 2, 3
197
+ ]
198
+ key6 = [
199
+ 1,
200
+ 2, # this is ok
201
+ ]
202
+
203
+
204
+ ################################################################################
205
+ ## Array of Tables
206
+
207
+ # These can be expressed by using a table name in double brackets. Each table
208
+ # with the same double bracketed name will be an element in the array. The
209
+ # tables are inserted in the order encountered.
210
+
211
+ [[products]]
212
+
213
+ name = "Hammer"
214
+ sku = 738594937
215
+
216
+ [[products]]
217
+
218
+ [[products]]
219
+
220
+ name = "Nail"
221
+ sku = 284758393
222
+ color = "gray"
223
+
224
+
225
+ # You can create nested arrays of tables as well.
226
+
227
+ [[fruit]]
228
+ name = "apple"
229
+
230
+ [fruit.physical]
231
+ color = "red"
232
+ shape = "round"
233
+
234
+ [[fruit.variety]]
235
+ name = "red delicious"
236
+
237
+ [[fruit.variety]]
238
+ name = "granny smith"
239
+
240
+ [[fruit]]
241
+ name = "banana"
242
+
243
+ [[fruit.variety]]
244
+ name = "plantain"
data/test/example.toml ADDED
@@ -0,0 +1,49 @@
1
+ # This is a TomlRB document. Boom.
2
+
3
+ title = "TomlRB Example"
4
+
5
+ [owner]
6
+ name = "Tom Preston-Werner"
7
+ organization = "GitHub"
8
+ bio = "GitHub Cofounder & CEO\nLikes tater tots and beer."
9
+ dob = 1979-05-27T07:32:00Z # First class dates? Why not?
10
+
11
+ [database]
12
+ server = "192.168.1.1"
13
+ ports = [ 8001, 8001, 8002 ]
14
+ connection_max = 5000
15
+ enabled = true
16
+
17
+ [servers]
18
+
19
+ # You can indent as you please. Tabs or spaces. TomlRB don't care.
20
+ [servers.alpha]
21
+ ip = "10.0.0.1"
22
+ dc = "eqdc10"
23
+
24
+ [servers.beta]
25
+ ip = "10.0.0.2"
26
+ dc = "eqdc10"
27
+
28
+ [clients]
29
+ data = [ ["gamma", "delta"], [1, 2] ]
30
+
31
+ # Line breaks are OK when inside arrays
32
+ hosts = [
33
+ "alpha",
34
+ "omega"
35
+ ]
36
+
37
+ [amqp]
38
+ exchange = {durable = true, auto_delete = false}
39
+
40
+ [[products]]
41
+ name = "Hammer"
42
+ sku = 738594937
43
+
44
+ [[products]]
45
+
46
+ [[products]]
47
+ name = "Nail"
48
+ sku = 284758393
49
+ color = "gray"
@@ -0,0 +1,246 @@
1
+ # encoding: utf-8
2
+
3
+ unless defined? require_relative
4
+ def require_relative(path)
5
+ require path
6
+ end
7
+ end
8
+
9
+ require_relative 'helper'
10
+
11
+ class GrammarTest < Minitest::Test
12
+ def test_comment
13
+ match = TomlRB::Document.parse(' # A comment', root: :comment)
14
+ assert_equal(nil, match.value)
15
+ end
16
+
17
+ def test_key
18
+ match = TomlRB::Document.parse('bad_key-', root: :key)
19
+ assert_equal('bad_key-', match.value)
20
+
21
+ match = TomlRB::Document.parse('"123.ʎǝʞ.#?"', root: :key)
22
+ assert_equal('123.ʎǝʞ.#?', match.value)
23
+ end
24
+
25
+ def test_keygroup
26
+ indentation_alternatives_for('[akey]') do |str|
27
+ match = TomlRB::Document.parse(str, root: :keygroup)
28
+ assert_equal(TomlRB::Keygroup, match.value.class)
29
+ assert_equal(['akey'], match.value.instance_variable_get('@nested_keys'))
30
+ end
31
+
32
+ match = TomlRB::Document.parse('[owner.emancu]', root: :keygroup)
33
+ assert_equal(%w(owner emancu),
34
+ match.value.instance_variable_get('@nested_keys'))
35
+
36
+ match = TomlRB::Document.parse('["owner.emancu"]', root: :keygroup)
37
+ assert_equal(%w(owner.emancu),
38
+ match.value.instance_variable_get('@nested_keys'))
39
+
40
+ match = TomlRB::Document.parse('["first key"."second key"]', root: :keygroup)
41
+ assert_equal(['first key', 'second key'],
42
+ match.value.instance_variable_get('@nested_keys'))
43
+
44
+ match = TomlRB::Document.parse('[ owner . emancu ]', root: :keygroup)
45
+ assert_equal(%w(owner emancu),
46
+ match.value.instance_variable_get('@nested_keys'))
47
+
48
+ assert_raises Citrus::ParseError do
49
+ TomlRB::Document.parse('[ owner emancu ]', root: :keygroup)
50
+ end
51
+ end
52
+
53
+ def test_keyvalue
54
+ indentation_alternatives_for('key = "value"') do |str|
55
+ match = TomlRB::Document.parse(str, root: :keyvalue)
56
+ assert_equal(TomlRB::Keyvalue, match.value.class)
57
+
58
+ keyvalue = match.value
59
+ assert_equal('key', keyvalue.instance_variable_get('@key'))
60
+ assert_equal('value', keyvalue.instance_variable_get('@value'))
61
+ end
62
+ end
63
+
64
+ def test_string
65
+ match = TomlRB::Document.parse('"TomlRB-Example, should work."', root: :string)
66
+ assert_equal('TomlRB-Example, should work.', match.value)
67
+ end
68
+
69
+ def test_multiline_string
70
+ match = TomlRB::Document.parse('"""\tOne\nTwo"""', root: :multiline_string)
71
+ assert_equal "\tOne\nTwo", match.value
72
+
73
+ to_parse = '"""\
74
+ One \
75
+ Two\
76
+ """'
77
+
78
+ match = TomlRB::Document.parse(to_parse, root: :multiline_string)
79
+ assert_equal "One Two", match.value
80
+ end
81
+
82
+ def test_empty_multiline_string
83
+ to_parse = '""""""'
84
+
85
+ match = TomlRB::Document.parse(to_parse, root: :multiline_string)
86
+ assert_equal '', match.value
87
+ end
88
+
89
+ def test_special_characters
90
+ match = TomlRB::Document.parse('"\0 \" \t \n \r"', root: :string)
91
+ assert_equal("\0 \" \t \n \r", match.value)
92
+
93
+ match = TomlRB::Document.parse('"C:\\\\Documents\\\\nada.exe"', root: :string)
94
+ assert_equal('C:\\Documents\\nada.exe', match.value)
95
+ end
96
+
97
+ def test_bool
98
+ match = TomlRB::Document.parse('true', root: :bool)
99
+ assert_equal(true, match.value)
100
+
101
+ match = TomlRB::Document.parse('false', root: :bool)
102
+ assert_equal(false, match.value)
103
+ end
104
+
105
+ def test_integer
106
+ match = TomlRB::Document.parse('26', root: :number)
107
+ assert_equal(26, match.value)
108
+
109
+ match = TomlRB::Document.parse('1_200_000_999', root: :number)
110
+ assert_equal(1_200_000_999, match.value)
111
+ end
112
+
113
+ def test_float
114
+ match = TomlRB::Document.parse('1.69', root: :number)
115
+ assert_equal(1.69, match.value)
116
+
117
+ match = TomlRB::Document.parse('1_000.69', root: :number)
118
+ assert_equal(1000.69, match.value)
119
+
120
+ match = TomlRB::Document.parse('1e6', root: :number)
121
+ assert_equal(1e6, match.value)
122
+
123
+ match = TomlRB::Document.parse('1.02e-46', root: :number)
124
+ assert_equal(1.02e-46, match.value)
125
+
126
+ match = TomlRB::Document.parse('+1e4_000_000', root: :number)
127
+ assert_equal(1e4_000_000, match.value)
128
+ end
129
+
130
+ def test_signed_numbers
131
+ match = TomlRB::Document.parse('+26', root: :number)
132
+ assert_equal(26, match.value)
133
+
134
+ match = TomlRB::Document.parse('-26', root: :number)
135
+ assert_equal(-26, match.value)
136
+
137
+ match = TomlRB::Document.parse('1.69', root: :number)
138
+ assert_equal(1.69, match.value)
139
+
140
+ match = TomlRB::Document.parse('-1.69', root: :number)
141
+ assert_equal(-1.69, match.value)
142
+ end
143
+
144
+ def test_expressions_with_comments
145
+ match = TomlRB::Document.parse('[shouldwork] # with comment', root: :keygroup)
146
+ assert_equal(['shouldwork'],
147
+ match.value.instance_variable_get('@nested_keys'))
148
+
149
+ match = TomlRB::Document.parse('works = true # with comment', root: :keyvalue).value
150
+ assert_equal('works', match.instance_variable_get('@key'))
151
+ assert_equal(true, match.instance_variable_get('@value'))
152
+ end
153
+
154
+ def test_array
155
+ match = TomlRB::Document.parse('[]', root: :array)
156
+ assert_equal([], match.value)
157
+
158
+ match = TomlRB::Document.parse('[ 2, 4]', root: :array)
159
+ assert_equal([2, 4], match.value)
160
+
161
+ match = TomlRB::Document.parse('[ 2.4, 4.72]', root: :array)
162
+ assert_equal([2.4, 4.72], match.value)
163
+
164
+ match = TomlRB::Document.parse('[ "hey", "TomlRB"]', root: :array)
165
+ assert_equal(%w(hey TomlRB), match.value)
166
+
167
+ match = TomlRB::Document.parse('[ ["hey", "TomlRB"], [2,4] ]', root: :array)
168
+ assert_equal([%w(hey TomlRB), [2, 4]], match.value)
169
+
170
+ match = TomlRB::Document.parse('[ { one = 1 }, { two = 2, three = 3} ]',
171
+ root: :inline_table_array)
172
+ assert_equal([{ 'one' => 1 }, { 'two' => 2, 'three' => 3 }], match.value)
173
+ end
174
+
175
+ def test_empty_array
176
+ # test that [] is parsed as array and not as inline table array
177
+ match = TomlRB::Document.parse("a = []", root: :keyvalue).value
178
+ assert_equal [], match.value
179
+ end
180
+
181
+ def test_multiline_array
182
+ multiline_array = "[ \"hey\",\n \"ho\",\n\t \"lets\", \"go\",\n ]"
183
+ match = TomlRB::Document.parse(multiline_array, root: :array)
184
+ assert_equal(%w(hey ho lets go), match.value)
185
+
186
+ multiline_array = "[\n#1,\n2,\n# 3\n]"
187
+ match = TomlRB::Document.parse(multiline_array, root: :array)
188
+ assert_equal([2], match.value)
189
+
190
+ multiline_array = "[\n# comment\n#, more comments\n4]"
191
+ match = TomlRB::Document.parse(multiline_array, root: :array)
192
+ assert_equal([4], match.value)
193
+
194
+ multiline_array = "[\n 1,\n # 2,\n 3 ,\n]"
195
+ match = TomlRB::Document.parse(multiline_array, root: :array)
196
+ assert_equal([1, 3], match.value)
197
+
198
+ multiline_array = "[\n 1 , # useless comment\n # 2,\n 3 #other comment\n]"
199
+ match = TomlRB::Document.parse(multiline_array, root: :array)
200
+ assert_equal([1, 3], match.value)
201
+ end
202
+
203
+ # Dates are really hard to test from JSON, due the imposibility to represent
204
+ # datetimes without quotes.
205
+ def test_datetime
206
+ match = TomlRB::Document.parse('1986-08-28T15:15:00Z', root: :datetime)
207
+ assert_equal(Time.utc(1986, 8, 28, 15, 15), match.value)
208
+
209
+ match = TomlRB::Document.parse('1986-08-28T15:15:00-03:00', root: :datetime)
210
+ assert_equal(Time.utc(1986, 8, 28, 18, 15), match.value)
211
+
212
+ match = TomlRB::Document.parse('1986-08-28T15:15:00.123-03:00', root: :datetime)
213
+ assert_equal(Time.utc(1986, 8, 28, 18, 15, 0.123), match.value)
214
+
215
+ match = TomlRB::Document.parse('1986-08-28', root: :datetime)
216
+ assert_equal(Time.utc(1986, 8, 28, 0, 0, 0), match.value)
217
+
218
+ match = TomlRB::Document.parse('1986-08-28T15:15:00', root: :datetime)
219
+ assert_equal(Time.utc(1986, 8, 28, 15, 15), match.value)
220
+
221
+ match = TomlRB::Document.parse('1986-08-28T15:15:00.999999', root: :datetime)
222
+ assert_equal(Time.utc(1986, 8, 28, 15, 15, 0.999999), match.value)
223
+ end
224
+
225
+ def test_inline_table
226
+ match = TomlRB::Document.parse('{ }', root: :inline_table)
227
+ assert_equal({}, match.value.value)
228
+
229
+ match = TomlRB::Document.parse('{ simple = true, params = 2 }', root: :inline_table)
230
+ assert_equal({ 'simple' => true, 'params' => 2 }, match.value.value)
231
+
232
+ match = TomlRB::Document.parse('{ nest = { really = { hard = true } } }',
233
+ root: :inline_table)
234
+ assert_equal({ 'nest' => { 'really' => { 'hard' => true } } }, match.value.value)
235
+ assert_equal({ nest: { really: { hard: true } } }, match.value.value(true))
236
+ end
237
+
238
+ private
239
+
240
+ # Creates all the alternatives of valid indentations to test
241
+ def indentation_alternatives_for(str)
242
+ [str, " #{str}", "\t#{str}", "\t\t#{str}"].each do |alternative|
243
+ yield(alternative)
244
+ end
245
+ end
246
+ end