toml-rb 5.0.0 → 6.0.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 +4 -4
- data/README.md +2 -2
- data/lib/toml-rb/datetime.rb +31 -44
- data/lib/toml-rb/dumper.rb +3 -3
- data/lib/toml-rb/inline_table.rb +0 -6
- data/lib/toml-rb/keyvalue.rb +0 -7
- data/lib/toml-rb/parser.rb +256 -4
- data/lib/toml-rb/string.rb +0 -25
- data/lib/toml-rb/table.rb +0 -7
- data/lib/toml-rb/table_array.rb +0 -7
- data/lib/toml-rb/version.rb +1 -1
- data/lib/toml-rb.rb +0 -9
- metadata +2 -26
- data/lib/toml-rb/array.rb +0 -8
- data/lib/toml-rb/grammars/document.citrus +0 -67
- data/lib/toml-rb/grammars/helper.citrus +0 -17
- data/lib/toml-rb/grammars/primitive.citrus +0 -176
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d7514edd12c127a9f4ff3343e7590d4e526a15ebf3b13594d4d9683aea9fa1d0
|
|
4
|
+
data.tar.gz: a689fab092b24d2aadcecd046462af6d0cc741cdec8d4461372c65f6d249411b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e58611d93fbb27112dd505c43edc135500661c088e33cae0b50d6419bf30f814c94d389cc3a71f85072996a61492e74b9b9e9fce00477df5c3cd8e14691980a4
|
|
7
|
+
data.tar.gz: 4c5dff3f4537f96ba315410482dee6100463538be2cefe8c19fd8a1fcbce0db614870c9b0e83d52bc269fce28ef9872e8d9b78317b25fcae1b92a12b28c20cca
|
data/README.md
CHANGED
|
@@ -9,7 +9,7 @@ toml-rb
|
|
|
9
9
|
[](https://codeclimate.com/github/emancu/toml-rb)
|
|
10
10
|
[](https://rubygems.org/gems/toml-rb)
|
|
11
11
|
|
|
12
|
-
A [TOML](https://github.com/toml-lang/toml) parser
|
|
12
|
+
A pure Ruby [TOML](https://github.com/toml-lang/toml) parser and dumper with no runtime dependencies.
|
|
13
13
|
|
|
14
14
|
toml-rb implements [TOML 1.1.0](https://toml.io/en/v1.1.0) and passes all [toml-test](https://github.com/toml-lang/toml-test) v2.2.0 decoder tests for that version.
|
|
15
15
|
|
|
@@ -20,7 +20,7 @@ Installation
|
|
|
20
20
|
|
|
21
21
|
Or add this line to your Gemfile:
|
|
22
22
|
|
|
23
|
-
gem "toml-rb", "~>
|
|
23
|
+
gem "toml-rb", "~> 6.0"
|
|
24
24
|
|
|
25
25
|
Parser Usage
|
|
26
26
|
------------
|
data/lib/toml-rb/datetime.rb
CHANGED
|
@@ -5,63 +5,50 @@ module TomlRB
|
|
|
5
5
|
LocalDate = Class.new(Time)
|
|
6
6
|
LocalTime = Class.new(Time)
|
|
7
7
|
|
|
8
|
-
module
|
|
9
|
-
|
|
10
|
-
year, mon, day = [:year, :mon, :day].map { |s| capture(s).value }
|
|
11
|
-
unless Date.valid_date?(year.to_i, mon.to_i, day.to_i, Date::GREGORIAN)
|
|
12
|
-
raise ParseError, "Invalid date: #{year}-#{mon}-#{day}"
|
|
13
|
-
end
|
|
14
|
-
[year, mon, day]
|
|
15
|
-
end
|
|
16
|
-
end
|
|
8
|
+
module DatetimeParser
|
|
9
|
+
module_function
|
|
17
10
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
hour, min, sec
|
|
21
|
-
|
|
22
|
-
raise ParseError, "Invalid time: #{hour}:#{min}:#{sec}"
|
|
23
|
-
end
|
|
24
|
-
[hour, min, sec, capture(:sec_frac) || "0"]
|
|
25
|
-
end
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
module OffsetDateTimeParser
|
|
29
|
-
def value
|
|
30
|
-
skeleton = captures[:datetime_skeleton].first
|
|
31
|
-
year, mon, day, hour, min, sec, sec_frac = skeleton.value
|
|
32
|
-
offset = (captures[:date_offset].first || "+00:00").to_s
|
|
11
|
+
def offset_datetime(year, mon, day, hour, min, sec, sec_frac, offset)
|
|
12
|
+
validate_date(year, mon, day)
|
|
13
|
+
validate_time(hour, min, sec)
|
|
14
|
+
offset = "+00:00" if offset.casecmp?("Z")
|
|
33
15
|
unless offset[1, 2].to_i.between?(0, 23) && offset[4, 2].to_i.between?(0, 59)
|
|
34
16
|
raise ParseError, "Invalid UTC offset: #{offset}"
|
|
35
17
|
end
|
|
36
|
-
sec = "#{sec}.#{sec_frac}".to_r
|
|
37
18
|
|
|
38
|
-
Time.new(year, mon, day, hour, min, sec, offset)
|
|
19
|
+
Time.new(year, mon, day, hour, min, seconds(sec, sec_frac), offset)
|
|
39
20
|
end
|
|
40
|
-
end
|
|
41
21
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
hour, min, sec, sec_frac
|
|
46
|
-
|
|
22
|
+
def local_datetime(year, mon, day, hour, min, sec, sec_frac)
|
|
23
|
+
validate_date(year, mon, day)
|
|
24
|
+
validate_time(hour, min, sec)
|
|
25
|
+
LocalDateTime.utc(year, mon, day, hour, min, seconds(sec, sec_frac))
|
|
26
|
+
end
|
|
47
27
|
|
|
48
|
-
|
|
28
|
+
def local_date(year, mon, day)
|
|
29
|
+
validate_date(year, mon, day)
|
|
30
|
+
LocalDate.utc(year, mon, day)
|
|
49
31
|
end
|
|
50
|
-
end
|
|
51
32
|
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
LocalDate.local(year, mon, day)
|
|
33
|
+
def local_time(hour, min, sec, sec_frac)
|
|
34
|
+
validate_time(hour, min, sec)
|
|
35
|
+
LocalTime.utc(1970, 1, 1, hour, min, seconds(sec, sec_frac))
|
|
56
36
|
end
|
|
57
|
-
end
|
|
58
37
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
38
|
+
def validate_date(year, mon, day)
|
|
39
|
+
unless Date.valid_date?(year.to_i, mon.to_i, day.to_i, Date::GREGORIAN)
|
|
40
|
+
raise ParseError, "Invalid date: #{year}-#{mon}-#{day}"
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def validate_time(hour, min, sec)
|
|
45
|
+
unless hour.to_i.between?(0, 23) && min.to_i.between?(0, 59) && sec.to_i.between?(0, 60)
|
|
46
|
+
raise ParseError, "Invalid time: #{hour}:#{min}:#{sec || 0}"
|
|
47
|
+
end
|
|
48
|
+
end
|
|
63
49
|
|
|
64
|
-
|
|
50
|
+
def seconds(sec, sec_frac)
|
|
51
|
+
"#{sec || 0}.#{sec_frac || 0}".to_r
|
|
65
52
|
end
|
|
66
53
|
end
|
|
67
54
|
end
|
data/lib/toml-rb/dumper.rb
CHANGED
|
@@ -19,7 +19,7 @@ module TomlRB
|
|
|
19
19
|
attr_reader :toml_str
|
|
20
20
|
|
|
21
21
|
def initialize(hash)
|
|
22
|
-
@toml_str = ""
|
|
22
|
+
@toml_str = +""
|
|
23
23
|
|
|
24
24
|
visit(hash, [])
|
|
25
25
|
end
|
|
@@ -78,7 +78,7 @@ module TomlRB
|
|
|
78
78
|
def dump_simple_pairs(simple_pairs)
|
|
79
79
|
simple_pairs.each do |key, val|
|
|
80
80
|
key = quote_key(key) unless bare_key? key
|
|
81
|
-
@toml_str
|
|
81
|
+
@toml_str << "#{key} = #{to_toml(val)}\n"
|
|
82
82
|
end
|
|
83
83
|
end
|
|
84
84
|
|
|
@@ -108,7 +108,7 @@ module TomlRB
|
|
|
108
108
|
new_prefix = prefix.join(".")
|
|
109
109
|
new_prefix = "[" + new_prefix + "]" if extra_brackets
|
|
110
110
|
|
|
111
|
-
@toml_str
|
|
111
|
+
@toml_str << "[" + new_prefix + "]\n"
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
def to_toml(obj)
|
data/lib/toml-rb/inline_table.rb
CHANGED
data/lib/toml-rb/keyvalue.rb
CHANGED
data/lib/toml-rb/parser.rb
CHANGED
|
@@ -1,5 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "strscan"
|
|
4
|
+
|
|
1
5
|
module TomlRB
|
|
2
6
|
class Parser
|
|
7
|
+
BASIC_STRING = /(?:[^"\\\x00-\x08\x0a-\x1f\x7f]|\\.)*/
|
|
8
|
+
LITERAL_STRING = /[^'\x00-\x08\x0a-\x1f\x7f]*/
|
|
9
|
+
MULTILINE_STRING = /(?:[^"\\\x00-\x08\x0b-\x1f\x7f]|\r\n|\\(?:[^\r]|\r\n)|"{1,2}(?!"))*(?:"{0,2}(?="""))?/
|
|
10
|
+
MULTILINE_LITERAL = /(?:[^'\x00-\x08\x0b-\x1f\x7f]|\r\n|'{1,2}(?!'))*(?:'{0,2}(?='''))?/
|
|
11
|
+
# A UTF-8 regexp raises Encoding::CompatibilityError on binary input with high bytes.
|
|
12
|
+
COMMENT = /[^\x00-\x08\x0a-\x1f\x7f]*/u
|
|
13
|
+
DATETIME = /(\d{4})-(\d\d)-(\d\d)(?:[Tt ]([0-2]\d):([0-6]\d)(?::([0-6]\d)(?:\.(\d{1,9})\d*)?)?([Zz]|[+-]\d\d:\d\d)?)?/
|
|
14
|
+
TIME = /([0-2]\d):([0-6]\d)(?::([0-6]\d)(?:\.(\d{1,9})\d*)?)?/
|
|
15
|
+
PREFIXED_INTEGER = /0x[0-9a-fA-F](?:_?[0-9a-fA-F])*|0o[0-7](?:_?[0-7])*|0b[01](?:_?[01])*/
|
|
16
|
+
DECIMAL = /[+-]?(?:0|[1-9](?:_?\d)*)(\.\d(?:_?\d)*(?:[eE][+-]?\d(?:_?\d)*)?|[eE][+-]?\d(?:_?\d)*)?/
|
|
17
|
+
MAX_NESTING = 100
|
|
18
|
+
|
|
3
19
|
attr_reader :hash
|
|
4
20
|
|
|
5
21
|
def initialize(content, symbolize_keys: false)
|
|
@@ -10,12 +26,13 @@ module TomlRB
|
|
|
10
26
|
@tables = {}.compare_by_identity
|
|
11
27
|
@current = @hash
|
|
12
28
|
@symbolize_keys = symbolize_keys
|
|
29
|
+
@depth = 0
|
|
13
30
|
|
|
14
31
|
begin
|
|
15
|
-
|
|
16
|
-
parsed
|
|
17
|
-
|
|
18
|
-
|
|
32
|
+
@scanner = StringScanner.new(source_text(content))
|
|
33
|
+
# The visitor runs after the whole document is parsed, so a syntax
|
|
34
|
+
# error wins over a key or table that the visitor rejects.
|
|
35
|
+
document.each { |statement| statement.accept_visitor(self) }
|
|
19
36
|
rescue Encoding::CompatibilityError => e
|
|
20
37
|
raise TomlRB::ParseError.new("Encoding error: #{e.message}")
|
|
21
38
|
rescue ArgumentError => e
|
|
@@ -40,5 +57,240 @@ module TomlRB
|
|
|
40
57
|
def visit_keyvalue(keyvalue)
|
|
41
58
|
keyvalue.assign @current, @tables, @symbolize_keys
|
|
42
59
|
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def source_text(source)
|
|
64
|
+
if source.respond_to?(:to_path)
|
|
65
|
+
File.read(source.to_path)
|
|
66
|
+
elsif source.respond_to?(:read)
|
|
67
|
+
source.read
|
|
68
|
+
elsif source.respond_to?(:to_str)
|
|
69
|
+
source.to_str
|
|
70
|
+
else
|
|
71
|
+
raise ArgumentError, "Unable to parse from #{source}"
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def document
|
|
76
|
+
statements = []
|
|
77
|
+
loop do
|
|
78
|
+
@scanner.skip(/(?:[ \t]*\r?\n)*[ \t]*/)
|
|
79
|
+
return statements if @scanner.eos?
|
|
80
|
+
|
|
81
|
+
statements << statement unless @scanner.match?(/#/)
|
|
82
|
+
line_end
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def statement
|
|
87
|
+
if @scanner.match?(/\[/)
|
|
88
|
+
@scanner.match?(/\[\[/) ? table_array : table
|
|
89
|
+
else
|
|
90
|
+
keyvalue
|
|
91
|
+
end
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def table_array
|
|
95
|
+
@scanner.skip(/\[\[[ \t]*/)
|
|
96
|
+
keys = key
|
|
97
|
+
expect(/[ \t]*\]\]/, "']]'")
|
|
98
|
+
TableArray.new(keys)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
def table
|
|
102
|
+
@scanner.skip(/\[[ \t]*/)
|
|
103
|
+
keys = key
|
|
104
|
+
expect(/[ \t]*\]/, "']'")
|
|
105
|
+
Table.new(keys)
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
def keyvalue
|
|
109
|
+
keys = key
|
|
110
|
+
expect(/[ \t]*=[ \t]*/, "'='")
|
|
111
|
+
Keyvalue.new(keys, value)
|
|
112
|
+
end
|
|
113
|
+
|
|
114
|
+
def key
|
|
115
|
+
keys = [simple_key]
|
|
116
|
+
keys << simple_key while @scanner.skip(/[ \t]*\.[ \t]*/)
|
|
117
|
+
keys
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def simple_key
|
|
121
|
+
if (bare = @scanner.scan(/[A-Za-z0-9_-]+/))
|
|
122
|
+
bare
|
|
123
|
+
elsif @scanner.match?(/"/)
|
|
124
|
+
basic_string
|
|
125
|
+
elsif @scanner.match?(/'/)
|
|
126
|
+
literal_string
|
|
127
|
+
else
|
|
128
|
+
syntax_error("a key")
|
|
129
|
+
end
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def value
|
|
133
|
+
case @scanner.peek(1)
|
|
134
|
+
when '"'
|
|
135
|
+
@scanner.match?(/"""/) ? multiline_string : basic_string
|
|
136
|
+
when "'"
|
|
137
|
+
@scanner.match?(/'''/) ? multiline_literal : literal_string
|
|
138
|
+
when "["
|
|
139
|
+
nested { array }
|
|
140
|
+
when "{"
|
|
141
|
+
nested { inline_table }
|
|
142
|
+
when "t"
|
|
143
|
+
expect(/true/, "a value")
|
|
144
|
+
true
|
|
145
|
+
when "f"
|
|
146
|
+
expect(/false/, "a value")
|
|
147
|
+
false
|
|
148
|
+
else
|
|
149
|
+
datetime || local_time || number
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
def basic_string
|
|
154
|
+
@scanner.skip(/"/)
|
|
155
|
+
text = @scanner.scan(BASIC_STRING)
|
|
156
|
+
expect(/"/, %('"'))
|
|
157
|
+
unescape(text)
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
def literal_string
|
|
161
|
+
@scanner.skip(/'/)
|
|
162
|
+
text = @scanner.scan(LITERAL_STRING)
|
|
163
|
+
expect(/'/, %("'"))
|
|
164
|
+
text
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
def multiline_string
|
|
168
|
+
start = @scanner.pos
|
|
169
|
+
@scanner.skip(/"""(?:\r?\n)?/)
|
|
170
|
+
text = @scanner.scan(MULTILINE_STRING)
|
|
171
|
+
@scanner.skip(/"""/) || syntax_error(%('"""' to close the string at #{location(start)}))
|
|
172
|
+
unescape(text)
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
def multiline_literal
|
|
176
|
+
start = @scanner.pos
|
|
177
|
+
@scanner.skip(/'''(?:\r?\n)?/)
|
|
178
|
+
text = @scanner.scan(MULTILINE_LITERAL)
|
|
179
|
+
@scanner.skip(/'''/) || syntax_error(%("'''" to close the string at #{location(start)}))
|
|
180
|
+
text
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
def unescape(text)
|
|
184
|
+
text.include?("\\") ? BasicString.transform_escaped_chars(text) : text
|
|
185
|
+
end
|
|
186
|
+
|
|
187
|
+
def datetime
|
|
188
|
+
return unless @scanner.skip(DATETIME)
|
|
189
|
+
|
|
190
|
+
year, mon, day, hour, min, sec, sec_frac, offset = @scanner.values_at(1, 2, 3, 4, 5, 6, 7, 8)
|
|
191
|
+
if hour.nil?
|
|
192
|
+
DatetimeParser.local_date(year, mon, day)
|
|
193
|
+
elsif offset
|
|
194
|
+
DatetimeParser.offset_datetime(year, mon, day, hour, min, sec, sec_frac, offset)
|
|
195
|
+
else
|
|
196
|
+
DatetimeParser.local_datetime(year, mon, day, hour, min, sec, sec_frac)
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def local_time
|
|
201
|
+
DatetimeParser.local_time(*@scanner.values_at(1, 2, 3, 4)) if @scanner.skip(TIME)
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
def number
|
|
205
|
+
if (text = @scanner.scan(PREFIXED_INTEGER))
|
|
206
|
+
Integer(text)
|
|
207
|
+
elsif (text = @scanner.scan(DECIMAL))
|
|
208
|
+
@scanner[1] ? text.to_f : text.to_i
|
|
209
|
+
elsif (text = @scanner.scan(/[+-]?inf/))
|
|
210
|
+
text.start_with?("-") ? -Float::INFINITY : Float::INFINITY
|
|
211
|
+
elsif @scanner.skip(/[+-]?nan/)
|
|
212
|
+
Float::NAN
|
|
213
|
+
else
|
|
214
|
+
syntax_error("a value")
|
|
215
|
+
end
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def array
|
|
219
|
+
@scanner.skip(/\[/)
|
|
220
|
+
values = []
|
|
221
|
+
loop do
|
|
222
|
+
skip_whitespace_and_comments
|
|
223
|
+
return values if @scanner.skip(/\]/)
|
|
224
|
+
|
|
225
|
+
values << value
|
|
226
|
+
skip_whitespace_and_comments
|
|
227
|
+
return values if @scanner.skip(/\]/)
|
|
228
|
+
|
|
229
|
+
expect(/,/, "',' or ']'")
|
|
230
|
+
end
|
|
231
|
+
end
|
|
232
|
+
|
|
233
|
+
def inline_table
|
|
234
|
+
@scanner.skip(/\{/)
|
|
235
|
+
pairs = []
|
|
236
|
+
loop do
|
|
237
|
+
skip_whitespace_and_comments
|
|
238
|
+
return InlineTable.new(pairs) if @scanner.skip(/\}/)
|
|
239
|
+
|
|
240
|
+
pairs << keyvalue
|
|
241
|
+
skip_whitespace_and_comments
|
|
242
|
+
return InlineTable.new(pairs) if @scanner.skip(/\}/)
|
|
243
|
+
|
|
244
|
+
expect(/,/, "',' or '}'")
|
|
245
|
+
end
|
|
246
|
+
end
|
|
247
|
+
|
|
248
|
+
# Each nested array or inline table recurses, so the limit stops a deep
|
|
249
|
+
# document before it exhausts the stack.
|
|
250
|
+
def nested
|
|
251
|
+
@depth += 1
|
|
252
|
+
syntax_error("at most #{MAX_NESTING} nested arrays and inline tables") if @depth > MAX_NESTING
|
|
253
|
+
yield
|
|
254
|
+
ensure
|
|
255
|
+
@depth -= 1
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def line_end
|
|
259
|
+
return if @scanner.skip(/[ \t]*\r?\n/)
|
|
260
|
+
|
|
261
|
+
@scanner.skip(/[ \t]*/)
|
|
262
|
+
@scanner.skip(COMMENT) if @scanner.skip(/#/)
|
|
263
|
+
new_line
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def skip_whitespace_and_comments
|
|
267
|
+
@scanner.skip(/[ \t\r\n]*/)
|
|
268
|
+
while @scanner.skip(/#/)
|
|
269
|
+
@scanner.skip(COMMENT)
|
|
270
|
+
new_line
|
|
271
|
+
@scanner.skip(/[ \t\r\n]*/)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
def new_line
|
|
276
|
+
@scanner.skip(/\r?\n/) || @scanner.eos? || syntax_error("a new line")
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
def expect(pattern, expected)
|
|
280
|
+
@scanner.skip(pattern) || syntax_error(expected)
|
|
281
|
+
end
|
|
282
|
+
|
|
283
|
+
def syntax_error(expected)
|
|
284
|
+
@scanner.skip(/[ \t]*/)
|
|
285
|
+
found = @scanner.eos? ? "end of input" : @scanner.check(/./m).inspect
|
|
286
|
+
raise ParseError, "Unexpected #{found} at #{location(@scanner.pos)}: expected #{expected}"
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
def location(pos)
|
|
290
|
+
consumed = @scanner.string.byteslice(0, pos)
|
|
291
|
+
line = consumed.count("\n") + 1
|
|
292
|
+
column = consumed.length - (consumed.rindex("\n") || -1)
|
|
293
|
+
"line #{line}, column #{column}"
|
|
294
|
+
end
|
|
43
295
|
end
|
|
44
296
|
end
|
data/lib/toml-rb/string.rb
CHANGED
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
module TomlRB
|
|
2
|
-
# Used in primitive.citrus
|
|
3
2
|
module BasicString
|
|
4
3
|
SPECIAL_CHARS = {
|
|
5
4
|
"\\t" => "\t",
|
|
@@ -12,12 +11,6 @@ module TomlRB
|
|
|
12
11
|
"\\\\" => "\\"
|
|
13
12
|
}.freeze
|
|
14
13
|
|
|
15
|
-
def value
|
|
16
|
-
aux = TomlRB::BasicString.transform_escaped_chars first.value
|
|
17
|
-
|
|
18
|
-
aux[1...-1]
|
|
19
|
-
end
|
|
20
|
-
|
|
21
14
|
# Replace the unicode escaped characters with the corresponding character
|
|
22
15
|
# e.g. \u03B4 => ?
|
|
23
16
|
def self.decode_unicode(str)
|
|
@@ -45,22 +38,4 @@ module TomlRB
|
|
|
45
38
|
fail ParseError.new "Escape sequence #{m} is reserved"
|
|
46
39
|
end
|
|
47
40
|
end
|
|
48
|
-
|
|
49
|
-
module LiteralString
|
|
50
|
-
def value
|
|
51
|
-
first.value[1...-1]
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
module MultilineString
|
|
56
|
-
def value
|
|
57
|
-
TomlRB::BasicString.transform_escaped_chars captures[:text].first.value
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
module MultilineLiteral
|
|
62
|
-
def value
|
|
63
|
-
captures[:text].first.value
|
|
64
|
-
end
|
|
65
|
-
end
|
|
66
41
|
end
|
data/lib/toml-rb/table.rb
CHANGED
data/lib/toml-rb/table_array.rb
CHANGED
data/lib/toml-rb/version.rb
CHANGED
data/lib/toml-rb.rb
CHANGED
|
@@ -1,7 +1,4 @@
|
|
|
1
|
-
require "citrus"
|
|
2
|
-
|
|
3
1
|
require_relative "toml-rb/errors"
|
|
4
|
-
require_relative "toml-rb/array"
|
|
5
2
|
require_relative "toml-rb/string"
|
|
6
3
|
require_relative "toml-rb/datetime"
|
|
7
4
|
require_relative "toml-rb/table"
|
|
@@ -11,12 +8,6 @@ require_relative "toml-rb/keyvalue"
|
|
|
11
8
|
require_relative "toml-rb/parser"
|
|
12
9
|
require_relative "toml-rb/dumper"
|
|
13
10
|
|
|
14
|
-
File.dirname(File.expand_path(__FILE__)).tap do |root|
|
|
15
|
-
Citrus.load "#{root}/toml-rb/grammars/helper.citrus"
|
|
16
|
-
Citrus.load "#{root}/toml-rb/grammars/primitive.citrus"
|
|
17
|
-
Citrus.load "#{root}/toml-rb/grammars/document.citrus"
|
|
18
|
-
end
|
|
19
|
-
|
|
20
11
|
module TomlRB
|
|
21
12
|
# Public: Returns a hash from *TomlRB* content.
|
|
22
13
|
#
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: toml-rb
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 6.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Emiliano Mancuso
|
|
@@ -10,26 +10,6 @@ bindir: bin
|
|
|
10
10
|
cert_chain: []
|
|
11
11
|
date: 2026-09-28 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
|
-
- !ruby/object:Gem::Dependency
|
|
14
|
-
name: citrus
|
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
|
16
|
-
requirements:
|
|
17
|
-
- - "~>"
|
|
18
|
-
- !ruby/object:Gem::Version
|
|
19
|
-
version: '3.0'
|
|
20
|
-
- - ">"
|
|
21
|
-
- !ruby/object:Gem::Version
|
|
22
|
-
version: '3.0'
|
|
23
|
-
type: :runtime
|
|
24
|
-
prerelease: false
|
|
25
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
26
|
-
requirements:
|
|
27
|
-
- - "~>"
|
|
28
|
-
- !ruby/object:Gem::Version
|
|
29
|
-
version: '3.0'
|
|
30
|
-
- - ">"
|
|
31
|
-
- !ruby/object:Gem::Version
|
|
32
|
-
version: '3.0'
|
|
33
13
|
- !ruby/object:Gem::Dependency
|
|
34
14
|
name: minitest
|
|
35
15
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -72,7 +52,7 @@ dependencies:
|
|
|
72
52
|
- - ">="
|
|
73
53
|
- !ruby/object:Gem::Version
|
|
74
54
|
version: '0'
|
|
75
|
-
description:
|
|
55
|
+
description: A TOML 1.1.0 parser and dumper.
|
|
76
56
|
email:
|
|
77
57
|
- emiliano.mancuso@gmail.com
|
|
78
58
|
- lucas.tolchinsky@gmail.com
|
|
@@ -83,13 +63,9 @@ files:
|
|
|
83
63
|
- LICENSE
|
|
84
64
|
- README.md
|
|
85
65
|
- lib/toml-rb.rb
|
|
86
|
-
- lib/toml-rb/array.rb
|
|
87
66
|
- lib/toml-rb/datetime.rb
|
|
88
67
|
- lib/toml-rb/dumper.rb
|
|
89
68
|
- lib/toml-rb/errors.rb
|
|
90
|
-
- lib/toml-rb/grammars/document.citrus
|
|
91
|
-
- lib/toml-rb/grammars/helper.citrus
|
|
92
|
-
- lib/toml-rb/grammars/primitive.citrus
|
|
93
69
|
- lib/toml-rb/inline_table.rb
|
|
94
70
|
- lib/toml-rb/keyvalue.rb
|
|
95
71
|
- lib/toml-rb/parser.rb
|
data/lib/toml-rb/array.rb
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
grammar TomlRB::Document
|
|
2
|
-
include TomlRB::Primitive
|
|
3
|
-
|
|
4
|
-
rule document
|
|
5
|
-
(comment | table_array | table | keyvalue_line | line_break | trailing_space)*
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
rule table_array
|
|
9
|
-
(space? '[[' stripped_key ']]' line_end) <TomlRB::TableArrayParser>
|
|
10
|
-
end
|
|
11
|
-
|
|
12
|
-
rule table
|
|
13
|
-
(space? '[' stripped_key ']' line_end) <TomlRB::TableParser>
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
rule keyvalue_line
|
|
17
|
-
(keyvalue line_end) { capture(:keyvalue).value }
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
rule keyvalue
|
|
21
|
-
(stripped_key '=' space? v:(toml_values) space) <TomlRB::KeyvalueParser>
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
### Values
|
|
25
|
-
|
|
26
|
-
rule inline_table
|
|
27
|
-
(space? '{' array_comments (keyvalue (array_comments ',' array_comments keyvalue)* (array_comments ',')?)? array_comments '}' ) <TomlRB::InlineTableParser>
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
rule array
|
|
31
|
-
("[" array_comments (array_elements (array_comments ",")?)? array_comments "]") <TomlRB::ArrayParser>
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
rule array_array
|
|
35
|
-
(array (space "," array_comments array)*) {
|
|
36
|
-
captures[:array].map(&:value)
|
|
37
|
-
}
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
rule array_elements
|
|
41
|
-
(toml_values (array_comments "," array_comments toml_values)*) {
|
|
42
|
-
captures[:toml_values].map(&:value)
|
|
43
|
-
}
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
### Helpers
|
|
47
|
-
|
|
48
|
-
rule line_end
|
|
49
|
-
(space (comment | line_break | !.))
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
rule trailing_space
|
|
53
|
-
([ \t]+ !.) { nil }
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
rule stripped_key
|
|
57
|
-
(space? key space?) { captures[:key].first.value }
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
rule array_comments
|
|
61
|
-
(indent? (comment indent?)*)
|
|
62
|
-
end
|
|
63
|
-
|
|
64
|
-
rule toml_values
|
|
65
|
-
primitive | inline_table | array
|
|
66
|
-
end
|
|
67
|
-
end
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
grammar TomlRB::Helper
|
|
2
|
-
rule comment
|
|
3
|
-
(space? "#" /[^\x00-\x08\x0a-\x1f\x7f]*(?=\r?\n|\z)/u line_break?) { nil }
|
|
4
|
-
end
|
|
5
|
-
|
|
6
|
-
rule space
|
|
7
|
-
[ \t]*
|
|
8
|
-
end
|
|
9
|
-
|
|
10
|
-
rule indent
|
|
11
|
-
[ \t\r\n]*
|
|
12
|
-
end
|
|
13
|
-
|
|
14
|
-
rule line_break
|
|
15
|
-
(space "\n" space | space "\r\n" space) { nil }
|
|
16
|
-
end
|
|
17
|
-
end
|
|
@@ -1,176 +0,0 @@
|
|
|
1
|
-
grammar TomlRB::Primitive
|
|
2
|
-
include TomlRB::Helper
|
|
3
|
-
|
|
4
|
-
rule primitive
|
|
5
|
-
datetime | bool | number | string
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
##
|
|
9
|
-
# String rules
|
|
10
|
-
##
|
|
11
|
-
|
|
12
|
-
rule string
|
|
13
|
-
multiline_string | multiline_literal | basic_string | literal_string
|
|
14
|
-
end
|
|
15
|
-
|
|
16
|
-
rule basic_string
|
|
17
|
-
(/"(?:[^"\\\x00-\x08\x0a-\x1f\x7f]|\\.)*"/ space) <TomlRB::BasicString>
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
rule literal_string
|
|
21
|
-
(/'[^'\x00-\x08\x0a-\x1f\x7f]*'/ space) <TomlRB::LiteralString>
|
|
22
|
-
end
|
|
23
|
-
|
|
24
|
-
rule multiline_string
|
|
25
|
-
('"""' /\r?\n/? text:/(?:[^"\\\x00-\x08\x0b-\x1f\x7f]|\r\n|\\(?:[^\r]|\r\n)|"{1,2}(?!"))*"{0,2}(?=""")/ '"""' space) <TomlRB::MultilineString>
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
rule multiline_literal
|
|
29
|
-
("'''" /\r?\n/? text:/(?:[^'\x00-\x08\x0b-\x1f\x7f]|\r\n|'{1,2}(?!'))*'{0,2}(?=''')/ "'''" space) <TomlRB::MultilineLiteral>
|
|
30
|
-
end
|
|
31
|
-
|
|
32
|
-
##
|
|
33
|
-
# Date time rules
|
|
34
|
-
##
|
|
35
|
-
|
|
36
|
-
rule datetime
|
|
37
|
-
offset_datetime | local_datetime | local_date | local_time
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
rule offset_datetime
|
|
41
|
-
( skeleton:datetime_skeleton ([Zz] | date_offset) ) <TomlRB::OffsetDateTimeParser>
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
rule local_datetime
|
|
45
|
-
datetime_skeleton <TomlRB::LocalDateTimeParser>
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
rule local_date
|
|
49
|
-
(date_skeleton space) <TomlRB::LocalDateParser>
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
rule local_time
|
|
53
|
-
(time_skeleton space) <TomlRB::LocalTimeParser>
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
rule datetime_skeleton
|
|
57
|
-
(date_skeleton ([Tt]|" ") time_skeleton) {
|
|
58
|
-
capture(:date_skeleton).value + capture(:time_skeleton).value
|
|
59
|
-
}
|
|
60
|
-
end
|
|
61
|
-
|
|
62
|
-
rule date_skeleton
|
|
63
|
-
(year:/\d\d\d\d/ "-" mon:/\d\d/ "-" day:/\d\d/) <TomlRB::DateSkeletonParser>
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
rule time_skeleton
|
|
67
|
-
( hour:([0-2][0-9]) ":" mim:([0-6][0-9]) (":" sec:([0-6][0-9]) ("." sec_frac:(/\d/1*9) /\d/*)?)? ) <TomlRB::TimeSkeletonParser>
|
|
68
|
-
end
|
|
69
|
-
|
|
70
|
-
rule date_offset
|
|
71
|
-
offset:(sign /\d\d/ ":" /\d\d/)
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
##
|
|
75
|
-
# Number rules
|
|
76
|
-
##
|
|
77
|
-
|
|
78
|
-
rule number
|
|
79
|
-
float | integer
|
|
80
|
-
end
|
|
81
|
-
|
|
82
|
-
rule float
|
|
83
|
-
inf | nan | exponential_float | fractional_float
|
|
84
|
-
end
|
|
85
|
-
|
|
86
|
-
rule inf
|
|
87
|
-
(s:sign? 'inf') {
|
|
88
|
-
sign = (capture(:s).value != '-') ? 1 : -1
|
|
89
|
-
sign * Float::INFINITY
|
|
90
|
-
}
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
rule nan
|
|
94
|
-
(sign? 'nan') { Float::NAN }
|
|
95
|
-
end
|
|
96
|
-
|
|
97
|
-
rule exponential_float
|
|
98
|
-
((fractional_float | decimal_integer) [eE] exponent) { to_str.to_f }
|
|
99
|
-
end
|
|
100
|
-
|
|
101
|
-
rule exponent
|
|
102
|
-
sign? [0-9] ([0-9] | '_' [0-9])*
|
|
103
|
-
end
|
|
104
|
-
|
|
105
|
-
rule fractional_float
|
|
106
|
-
(decimal_integer '.' [0-9] ([0-9] | '_' [0-9])*) {
|
|
107
|
-
to_str.to_f
|
|
108
|
-
}
|
|
109
|
-
end
|
|
110
|
-
|
|
111
|
-
rule integer
|
|
112
|
-
hexadecimal_integer | octal_integer | binary_integer | decimal_integer
|
|
113
|
-
end
|
|
114
|
-
|
|
115
|
-
rule hexadecimal_integer
|
|
116
|
-
('0x' [a-fA-F0-9] ([a-fA-F0-9] | '_' [a-fA-F0-9])*) { to_str.to_i(16) }
|
|
117
|
-
end
|
|
118
|
-
|
|
119
|
-
rule octal_integer
|
|
120
|
-
('0o' [0-7] ([0-7] | '_' [0-7])*) { to_str.to_i(8) }
|
|
121
|
-
end
|
|
122
|
-
|
|
123
|
-
rule binary_integer
|
|
124
|
-
('0b' [01] ([01] | '_' [01])*) { to_str.to_i(2) }
|
|
125
|
-
end
|
|
126
|
-
|
|
127
|
-
rule decimal_integer
|
|
128
|
-
(sign? ('0' | [1-9] ([0-9] | '_' [0-9])*)) { to_str.to_i }
|
|
129
|
-
end
|
|
130
|
-
|
|
131
|
-
rule sign
|
|
132
|
-
'+' | '-'
|
|
133
|
-
end
|
|
134
|
-
|
|
135
|
-
##
|
|
136
|
-
# Boolean rules
|
|
137
|
-
##
|
|
138
|
-
|
|
139
|
-
rule bool
|
|
140
|
-
true | false
|
|
141
|
-
end
|
|
142
|
-
|
|
143
|
-
rule true
|
|
144
|
-
'true' { true }
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
rule false
|
|
148
|
-
'false' { false }
|
|
149
|
-
end
|
|
150
|
-
|
|
151
|
-
##
|
|
152
|
-
# Key rules
|
|
153
|
-
##
|
|
154
|
-
|
|
155
|
-
rule key
|
|
156
|
-
dotted_key
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
rule bare_key
|
|
160
|
-
[a-zA-Z0-9_-]+
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
rule quoted_key
|
|
164
|
-
basic_string | literal_string
|
|
165
|
-
end
|
|
166
|
-
|
|
167
|
-
rule single_key
|
|
168
|
-
quoted_key | bare_key
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
rule dotted_key
|
|
172
|
-
(space? single_key space? ("." space? single_key space?)* ) {
|
|
173
|
-
captures[:single_key].map(&:value)
|
|
174
|
-
}
|
|
175
|
-
end
|
|
176
|
-
end
|