toml-rb-hs 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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