toby 1.0.0.pre.rc2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/toby.rb +37 -0
- data/lib/toby/grammars/document.citrus +49 -0
- data/lib/toby/grammars/helper.citrus +17 -0
- data/lib/toby/grammars/primitive.citrus +176 -0
- data/lib/toby/parser/datetime.rb +76 -0
- data/lib/toby/parser/match_modules.rb +79 -0
- data/lib/toby/parser/numbers.rb +64 -0
- data/lib/toby/parser/string.rb +77 -0
- data/lib/toby/toml/array.rb +41 -0
- data/lib/toby/toml/inline_table.rb +79 -0
- data/lib/toby/toml/key_value.rb +71 -0
- data/lib/toby/toml/table.rb +128 -0
- data/lib/toby/toml/toml_file.rb +162 -0
- metadata +59 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f1e0acda45cfe119c3d8d9eccf8219e20483f45edf9b03f512d6cbed270bf11c
|
4
|
+
data.tar.gz: 107c270acc1369b4573a55288355ea14fd391560af8263a65d153544109382f8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1aa4a9b1d89719d9fbc70853a8f1ba9b2d2d2a77e40f6f1111ef82bcfbd686a7ef2d94cb0fe220b2c44e2ed169128352e84751771930bba03ed80ce06ea6a631
|
7
|
+
data.tar.gz: b6e7b8136f32fd4a7c64b4eb04a52b036593d25b7238a788c318e5b0e8d33a87b3803daeb4ebbbcfc2c280db194a19f7efab900341f4edd8ebb7e494b9367733
|
data/lib/toby.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'citrus'
|
4
|
+
require 'delegate'
|
5
|
+
require 'stringio'
|
6
|
+
require 'json'
|
7
|
+
|
8
|
+
# Contains all of the code for the Toby gem.
|
9
|
+
module Toby; end
|
10
|
+
|
11
|
+
module Toby
|
12
|
+
# Contains all of code for TOML objects.
|
13
|
+
module TOML; end
|
14
|
+
end
|
15
|
+
|
16
|
+
module Toby
|
17
|
+
# Contains all of the code used for parsing TOML files.
|
18
|
+
# @api private
|
19
|
+
module Parser; end
|
20
|
+
end
|
21
|
+
|
22
|
+
require_relative 'toby/toml/array'
|
23
|
+
require_relative 'toby/toml/inline_table'
|
24
|
+
require_relative 'toby/toml/key_value'
|
25
|
+
require_relative 'toby/toml/table'
|
26
|
+
require_relative 'toby/toml/toml_file'
|
27
|
+
|
28
|
+
require_relative 'toby/parser/string'
|
29
|
+
require_relative 'toby/parser/datetime'
|
30
|
+
require_relative 'toby/parser/match_modules'
|
31
|
+
require_relative 'toby/parser/numbers'
|
32
|
+
|
33
|
+
# The root directory of Toby
|
34
|
+
ROOT = File.dirname(File.expand_path(__FILE__))
|
35
|
+
Citrus.load "#{ROOT}/toby/grammars/helper.citrus"
|
36
|
+
Citrus.load "#{ROOT}/toby/grammars/primitive.citrus"
|
37
|
+
Citrus.load "#{ROOT}/toby/grammars/document.citrus"
|
@@ -0,0 +1,49 @@
|
|
1
|
+
grammar Toby::Document
|
2
|
+
include Toby::Primitive
|
3
|
+
|
4
|
+
rule document
|
5
|
+
(comment | table_array | table | keyvalue | line_break)*
|
6
|
+
end
|
7
|
+
|
8
|
+
rule table_array
|
9
|
+
(space? '[[' stripped_key ']]' comment?) <Toby::Parser::Match::ArrayTable>
|
10
|
+
end
|
11
|
+
|
12
|
+
rule table
|
13
|
+
(space? '[' stripped_key ']' comment?) <Toby::Parser::Match::Table>
|
14
|
+
end
|
15
|
+
|
16
|
+
rule keyvalue
|
17
|
+
(stripped_key '=' space? v:(toml_values) comment?) <Toby::Parser::Match::KeyValue>
|
18
|
+
end
|
19
|
+
|
20
|
+
rule inline_table
|
21
|
+
(space? '{' (keyvalue? (',' keyvalue)*)? space? '}' ) <Toby::Parser::Match::InlineTable>
|
22
|
+
end
|
23
|
+
|
24
|
+
rule array_comments
|
25
|
+
(indent? (comment indent?)*)
|
26
|
+
end
|
27
|
+
|
28
|
+
rule array
|
29
|
+
("[" array_comments (array_elements)? space ","? array_comments "]" indent?) <Toby::Parser::Match::Array>
|
30
|
+
end
|
31
|
+
|
32
|
+
rule array_element
|
33
|
+
primitive | inline_table | array
|
34
|
+
end
|
35
|
+
|
36
|
+
rule array_elements
|
37
|
+
(array_element (space "," array_comments array_element)*) {
|
38
|
+
captures[:array_element].map(&:value)
|
39
|
+
}
|
40
|
+
end
|
41
|
+
|
42
|
+
rule toml_values
|
43
|
+
primitive | inline_table | array
|
44
|
+
end
|
45
|
+
|
46
|
+
rule stripped_key
|
47
|
+
(space? key space?) { captures[:key].first.value }
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
grammar Toby::Helper
|
2
|
+
rule comment
|
3
|
+
(space? "#" (~line_break)* line_break?) <Toby::Parser::Match::Comment>
|
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? "\r\n") { nil }
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
grammar Toby::Primitive
|
2
|
+
include Toby::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
|
+
(/(["])(?:\\?.)*?\1/ space) <Toby::Parser::BasicString>
|
18
|
+
end
|
19
|
+
|
20
|
+
rule literal_string
|
21
|
+
(/(['])(?:\\?.)*?\1/ space) <Toby::Parser::LiteralString>
|
22
|
+
end
|
23
|
+
|
24
|
+
rule multiline_string
|
25
|
+
('"""' line_break* (text:~('"""' !'"')|'') '"""' space) <Toby::Parser::MultilineString>
|
26
|
+
end
|
27
|
+
|
28
|
+
rule multiline_literal
|
29
|
+
("'''" line_break* (text:~("'''" !"'")|'') "'''" space) <Toby::Parser::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 ("Z" | date_offset) ) <Toby::Parser::Match::OffsetDateTime>
|
42
|
+
end
|
43
|
+
|
44
|
+
rule local_datetime
|
45
|
+
datetime_skeleton <Toby::Parser::Match::LocalDateTime>
|
46
|
+
end
|
47
|
+
|
48
|
+
rule local_date
|
49
|
+
(date_skeleton space) <Toby::Parser::Match::LocalDate>
|
50
|
+
end
|
51
|
+
|
52
|
+
rule local_time
|
53
|
+
(time_skeleton space) <Toby::Parser::Match::LocalTime>
|
54
|
+
end
|
55
|
+
|
56
|
+
rule datetime_skeleton
|
57
|
+
(date_skeleton ("T"|" ") 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/) {
|
64
|
+
[:year,:mon,:day].map{ |s| capture(s).value }
|
65
|
+
}
|
66
|
+
end
|
67
|
+
|
68
|
+
rule time_skeleton
|
69
|
+
( hour:([0-2][0-9]) ":" mim:([0-6][0-9]) ":" sec:([0-6][0-9]) ([,\.] sec_frac:(/\d/1*6))? ) {
|
70
|
+
[:hour,:mim,:sec].map{ |s| capture(s).value } + [capture(:sec_frac) || '0']
|
71
|
+
}
|
72
|
+
end
|
73
|
+
|
74
|
+
rule date_offset
|
75
|
+
offset:(sign /\d\d/ ":" /\d\d/)
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# Number rules
|
80
|
+
##
|
81
|
+
|
82
|
+
rule number
|
83
|
+
float | integer
|
84
|
+
end
|
85
|
+
|
86
|
+
rule float
|
87
|
+
inf | nan | exponential_float | fractional_float
|
88
|
+
end
|
89
|
+
|
90
|
+
rule inf
|
91
|
+
(s:sign? 'inf') {
|
92
|
+
sign = (capture(:s).value != '-') ? 1 : -1
|
93
|
+
sign * Float::INFINITY
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
97
|
+
rule nan
|
98
|
+
(sign? 'nan') { Float::NAN }
|
99
|
+
end
|
100
|
+
|
101
|
+
rule exponential_float
|
102
|
+
((fractional_float | demical_integer) [eE] demical_integer) { to_str.to_f }
|
103
|
+
end
|
104
|
+
|
105
|
+
rule fractional_float
|
106
|
+
(demical_integer '.' [0-9_]+) {
|
107
|
+
to_str.to_f
|
108
|
+
}
|
109
|
+
end
|
110
|
+
|
111
|
+
rule integer
|
112
|
+
hexadecimal_integer | octal_integer | binary_integer | demical_integer
|
113
|
+
end
|
114
|
+
|
115
|
+
rule hexadecimal_integer
|
116
|
+
('0x' [a-fA-F0-9_]+) <Toby::Parser::Match::Hexadecimal>
|
117
|
+
end
|
118
|
+
|
119
|
+
rule octal_integer
|
120
|
+
('0o' [0-7_]+) <Toby::Parser::Match::Octal>
|
121
|
+
end
|
122
|
+
|
123
|
+
rule binary_integer
|
124
|
+
('0b' [01_]+) <Toby::Parser::Match::Binary>
|
125
|
+
end
|
126
|
+
|
127
|
+
rule demical_integer
|
128
|
+
(sign? [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
|
@@ -0,0 +1,76 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module Parser
|
5
|
+
# @see https://toml.io/en/v1.0.0-rc.3#offset-date-time
|
6
|
+
class OffsetDateTime < Time
|
7
|
+
def to_s
|
8
|
+
strftime('%Y-%m-%dT%H:%M:%S%z')
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-date-time
|
13
|
+
class LocalDateTime < Time
|
14
|
+
def to_s
|
15
|
+
strftime('%Y-%m-%dT%H:%M:%S')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-date
|
20
|
+
class LocalDate < Time
|
21
|
+
def to_s
|
22
|
+
strftime('%Y-%m-%d')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-time
|
27
|
+
class LocalTime < Time
|
28
|
+
def to_s
|
29
|
+
utc.strftime('%H:%M:%S.%L')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
module Match
|
34
|
+
# @see https://toml.io/en/v1.0.0-rc.3#offset-date-time
|
35
|
+
module OffsetDateTime
|
36
|
+
def value
|
37
|
+
skeleton = captures[:datetime_skeleton].first
|
38
|
+
year, mon, day, hour, min, sec, sec_frac = skeleton.value
|
39
|
+
offset = captures[:date_offset].first || '+00:00'
|
40
|
+
sec = "#{sec}.#{sec_frac}".to_f
|
41
|
+
|
42
|
+
Toby::Parser::OffsetDateTime.new(year, mon, day, hour, min, sec, offset.to_s)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-date-time
|
47
|
+
module LocalDateTime
|
48
|
+
def value
|
49
|
+
year, mon, day = captures[:date_skeleton].first.value
|
50
|
+
hour, min, sec, sec_frac = captures[:time_skeleton].first.value
|
51
|
+
usec = sec_frac.to_s.ljust(6, '0')
|
52
|
+
|
53
|
+
Toby::LocalDateTime.local(year, mon, day, hour, min, sec, usec)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-date
|
58
|
+
module LocalDate
|
59
|
+
def value
|
60
|
+
year, mon, day = captures[:date_skeleton].first.value
|
61
|
+
Toby::Parser::LocalDate.local(year, mon, day)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# @see https://toml.io/en/v1.0.0-rc.3#local-time
|
66
|
+
module LocalTime
|
67
|
+
def value
|
68
|
+
hour, min, sec, sec_frac = captures[:time_skeleton].first.value
|
69
|
+
usec = sec_frac.to_s.ljust(6, '0')
|
70
|
+
|
71
|
+
Toby::Parser::LocalTime.at(3600 * hour.to_i + 60 * min.to_i + sec.to_i, usec.to_i)
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module Parser
|
5
|
+
module Match
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3#inline-table
|
7
|
+
module InlineTable
|
8
|
+
def value
|
9
|
+
kv_array = []
|
10
|
+
|
11
|
+
captures(:keyvalue).each do |kv|
|
12
|
+
kv_array << Toby::TOML::KeyValue.new(kv.keys, kv.value, nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
Toby::TOML::InlineTable.new kv_array
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# @see https://toml.io/en/v1.0.0-rc.3#array
|
20
|
+
module Array
|
21
|
+
def value
|
22
|
+
Toby::TOML::Array.new capture(:array_elements).value
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# @see https://toml.io/en/v1.0.0-rc.3#keyvalue-pair
|
27
|
+
module KeyValue
|
28
|
+
def keys
|
29
|
+
capture(:stripped_key).value
|
30
|
+
end
|
31
|
+
|
32
|
+
def value
|
33
|
+
capture(:v).value
|
34
|
+
end
|
35
|
+
|
36
|
+
def comment
|
37
|
+
capture(:comment)&.stripped_comment
|
38
|
+
end
|
39
|
+
|
40
|
+
def toml_object
|
41
|
+
Toby::TOML::KeyValue.new(
|
42
|
+
keys,
|
43
|
+
value,
|
44
|
+
comment
|
45
|
+
)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @see https://toml.io/en/v1.0.0-rc.3#table
|
50
|
+
module Table
|
51
|
+
def toml_object
|
52
|
+
Toby::TOML::Table.new(
|
53
|
+
capture(:stripped_key).value,
|
54
|
+
capture(:comment)&.stripped_comment,
|
55
|
+
false
|
56
|
+
)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @see https://toml.io/en/v1.0.0-rc.3#array-of-tables
|
61
|
+
module ArrayTable
|
62
|
+
def toml_object
|
63
|
+
Toby::TOML::Table.new(
|
64
|
+
capture(:stripped_key).value,
|
65
|
+
capture(:comment)&.stripped_comment,
|
66
|
+
true
|
67
|
+
)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# @see https://toml.io/en/v1.0.0-rc.3#comment
|
72
|
+
module Comment
|
73
|
+
def stripped_comment
|
74
|
+
value.sub('#', '').strip!
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module Parser
|
5
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
6
|
+
class Hexadecimal < DelegateClass(Integer)
|
7
|
+
def to_s
|
8
|
+
hex = to_i.to_s(16)
|
9
|
+
"0x#{hex}"
|
10
|
+
end
|
11
|
+
|
12
|
+
def inspect
|
13
|
+
to_s
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
18
|
+
class Binary < DelegateClass(Integer)
|
19
|
+
def to_s
|
20
|
+
binary = to_i.to_s(2)
|
21
|
+
"0b#{binary}"
|
22
|
+
end
|
23
|
+
|
24
|
+
def inspect
|
25
|
+
to_s
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
30
|
+
class Octal < DelegateClass(Integer)
|
31
|
+
def to_s
|
32
|
+
octal = to_i.to_s(8)
|
33
|
+
"0b#{octal}"
|
34
|
+
end
|
35
|
+
|
36
|
+
def inspect
|
37
|
+
to_s
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module Match
|
42
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
43
|
+
module Hexadecimal
|
44
|
+
def value
|
45
|
+
Toby::Parser::Hexadecimal.new(to_str.to_i(16))
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
50
|
+
module Binary
|
51
|
+
def value
|
52
|
+
Toby::Parser::Binary.new(to_str.to_i(2))
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
# @see https://toml.io/en/v1.0.0-rc.3#integer
|
57
|
+
module Octal
|
58
|
+
def value
|
59
|
+
Toby::Parser::Octal.new(to_str.to_i(8))
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module Parser
|
5
|
+
# Used in primitive.citrus
|
6
|
+
module BasicString
|
7
|
+
SPECIAL_CHARS = {
|
8
|
+
'\\0' => "\0",
|
9
|
+
'\\t' => "\t",
|
10
|
+
'\\b' => "\b",
|
11
|
+
'\\f' => "\f",
|
12
|
+
'\\n' => "\n",
|
13
|
+
'\\r' => "\r",
|
14
|
+
'\\"' => '"',
|
15
|
+
'\\\\' => '\\'
|
16
|
+
}.freeze
|
17
|
+
|
18
|
+
def value
|
19
|
+
aux = Toby::Parser::BasicString.transform_escaped_chars first.value
|
20
|
+
|
21
|
+
aux[1...-1]
|
22
|
+
end
|
23
|
+
|
24
|
+
# Replace the unicode escaped characters with the corresponding character
|
25
|
+
# e.g. \u03B4 => ?
|
26
|
+
def self.decode_unicode(str)
|
27
|
+
[str[2..-1].to_i(16)].pack('U')
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.transform_escaped_chars(str)
|
31
|
+
str.gsub(/\\(u[\da-fA-F]{4}|U[\da-fA-F]{8}|.)/) do |m|
|
32
|
+
if m.size == 2
|
33
|
+
SPECIAL_CHARS[m] || parse_error(m)
|
34
|
+
else
|
35
|
+
decode_unicode(m).force_encoding('UTF-8')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.parse_error(sequence)
|
41
|
+
raise ParseError, "Escape sequence #{sequence} is reserved"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# @see https://toml.io/en/v1.0.0-rc.3#string
|
46
|
+
module LiteralString
|
47
|
+
def value
|
48
|
+
first.value[1...-1]
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
# @see https://toml.io/en/v1.0.0-rc.3#string
|
53
|
+
module MultilineString
|
54
|
+
def value
|
55
|
+
return '' if captures[:text].empty?
|
56
|
+
|
57
|
+
aux = captures[:text].first.value
|
58
|
+
|
59
|
+
# Remove spaces on multilined Singleline strings
|
60
|
+
aux.gsub!(/\\\r?\n[\n\t\r ]*/, '')
|
61
|
+
|
62
|
+
Toby::Parser::BasicString.transform_escaped_chars aux
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
# @see https://toml.io/en/v1.0.0-rc.3#string
|
67
|
+
module MultilineLiteral
|
68
|
+
def value
|
69
|
+
return '' if captures[:text].empty?
|
70
|
+
|
71
|
+
aux = captures[:text].first.value
|
72
|
+
|
73
|
+
aux.gsub(/\\\r?\n[\n\t\r ]*/, '')
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module TOML
|
5
|
+
# Represents an array value
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3#array
|
7
|
+
class Array < ::Array
|
8
|
+
# @return [String] Array in valid TOML format
|
9
|
+
def dump
|
10
|
+
output = StringIO.new
|
11
|
+
|
12
|
+
output.print '[ '
|
13
|
+
|
14
|
+
dumped_array = map do |val|
|
15
|
+
val.respond_to?(:dump) ? val.dump : val
|
16
|
+
end
|
17
|
+
|
18
|
+
output.print dumped_array.join(', ')
|
19
|
+
output.print ' ]'
|
20
|
+
|
21
|
+
output.string
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param options [Hash] The options hash for the object's #to_hash method when applicable
|
25
|
+
# (see Toby::TOML::TOMLFile#to_hash)
|
26
|
+
# @return [Array] Returns the value of #value, the value of #to_hash,
|
27
|
+
# or the object itself for every object in the Toby::TOML::Array
|
28
|
+
def to_hash(options = {})
|
29
|
+
map do |obj|
|
30
|
+
if obj.respond_to?(:value)
|
31
|
+
obj.value
|
32
|
+
elsif obj.respond_to?(:to_hash)
|
33
|
+
obj.to_hash(options)
|
34
|
+
else
|
35
|
+
obj
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module TOML
|
5
|
+
# Represents an inline-table value
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3#inline-table
|
7
|
+
class InlineTable < Array
|
8
|
+
# @return [String] Inline table in valid TOML format
|
9
|
+
def dump
|
10
|
+
output = StringIO.new
|
11
|
+
|
12
|
+
output.print '{'
|
13
|
+
|
14
|
+
each do |kv|
|
15
|
+
dumped_value = kv.value.respond_to?(:dump) ? kv.value.dump : kv.value
|
16
|
+
|
17
|
+
dotted_keys = kv.split_keys.map { |key| kv.bare_key?(key) ? key : kv.quote_key(key) }.join('.')
|
18
|
+
|
19
|
+
output.print " #{dotted_keys} = #{dumped_value},"
|
20
|
+
end
|
21
|
+
|
22
|
+
output.string.gsub(/,$/, ' }')
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Hash] TOML table represented as a hash.
|
26
|
+
# @option options [TrueClass, FalseClass] :dotted_keys (false) If true, dotted keys are not expanded/nested.
|
27
|
+
# @example
|
28
|
+
# Given the following TOML:
|
29
|
+
# table = {a.b.c = 123}
|
30
|
+
#
|
31
|
+
# #to_hash returns { "table" => {"a" => { "b" => { "c" => 123 } } } }
|
32
|
+
# #to_hash(dotted_keys: true) returns {'some.dotted.keys' => {'some.value'} => 123}
|
33
|
+
def to_hash(options = {})
|
34
|
+
if options[:dotted_keys]
|
35
|
+
to_dotted_keys_hash
|
36
|
+
else
|
37
|
+
to_split_keys_hash
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
# @api private
|
44
|
+
def to_split_keys_hash
|
45
|
+
output_hash = {}
|
46
|
+
|
47
|
+
last_hash = output_hash
|
48
|
+
last_last_hash = nil
|
49
|
+
|
50
|
+
each do |kv|
|
51
|
+
kv.split_keys.each_with_index do |key, i|
|
52
|
+
last_last_hash = last_hash
|
53
|
+
|
54
|
+
if i < (kv.split_keys.size - 1) # not the last key
|
55
|
+
last_hash[key] ||= {}
|
56
|
+
last_last_hash = last_hash
|
57
|
+
last_hash = last_hash[key]
|
58
|
+
else
|
59
|
+
last_hash[key] = kv.value.respond_to?(:to_hash) ? kv.value.to_hash(options) : kv.value
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
output_hash
|
65
|
+
end
|
66
|
+
|
67
|
+
# @api private
|
68
|
+
def to_dotted_keys_hash
|
69
|
+
output_hash = {}
|
70
|
+
|
71
|
+
each do |kv|
|
72
|
+
output_hash[kv.key] = kv.value.respond_to?(:to_hash) ? kv.value.to_hash(options) : kv.value
|
73
|
+
end
|
74
|
+
|
75
|
+
output_hash
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module TOML
|
5
|
+
# Represents a TOML key-value pair
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3#keyvalue-pair
|
7
|
+
class KeyValue
|
8
|
+
# @return [String] The key of the key-value pair.
|
9
|
+
attr_reader :key
|
10
|
+
|
11
|
+
# @return [::Array] The dotted keys of the key-value pair.
|
12
|
+
attr_reader :split_keys
|
13
|
+
|
14
|
+
# @return [String, Integer, Float, Time, Toby::TOML::Array, Toby::TOML::InlineTable] The value of the
|
15
|
+
# key-value pair.
|
16
|
+
attr_accessor :value
|
17
|
+
|
18
|
+
# @return [Toby::TOML::Table] The table the key-value pair belongs to.
|
19
|
+
attr_accessor :table
|
20
|
+
|
21
|
+
# @return [::Array<String>] The header comments above the key-value pair.
|
22
|
+
attr_accessor :header_comments
|
23
|
+
|
24
|
+
# @return [String] The comment in-line with the key-value pair
|
25
|
+
attr_accessor :inline_comment
|
26
|
+
|
27
|
+
# @param split_keys [::Array] Dotted keys of the key-value pair.
|
28
|
+
# @param value [String, Integer, Float, Time, Toby::TOML::Array, Toby::TOML::InlineTable] The value of the
|
29
|
+
# key-value pair.
|
30
|
+
# @param inline_comment [String] The comment in-line with the key-value pair.
|
31
|
+
def initialize(split_keys, value, inline_comment)
|
32
|
+
@split_keys = split_keys
|
33
|
+
@key = split_keys.join('.')
|
34
|
+
|
35
|
+
@value = value
|
36
|
+
@header_comments = []
|
37
|
+
@inline_comment = inline_comment
|
38
|
+
@table = table
|
39
|
+
end
|
40
|
+
|
41
|
+
# @return [String] The key-value pair in valid TOML
|
42
|
+
def dump
|
43
|
+
output = StringIO.new
|
44
|
+
|
45
|
+
dumped_value = value.respond_to?(:dump) ? value.dump : value
|
46
|
+
|
47
|
+
dotted_keys = split_keys.map { |key| bare_key?(key) ? key : quote_key(key) }.join('.')
|
48
|
+
|
49
|
+
output.puts "\n##{header_comments.join("\n#")}" unless header_comments.empty?
|
50
|
+
|
51
|
+
output.puts "#{dotted_keys} = #{dumped_value}#{" ##{inline_comment}" if inline_comment}"
|
52
|
+
|
53
|
+
output.string
|
54
|
+
end
|
55
|
+
|
56
|
+
# @api private
|
57
|
+
# from toml-rb
|
58
|
+
# https://github.com/emancu/toml-rb/blob/ca5bf9563f1ef2c467bd43eec1d035e83b61ac88/lib/toml-rb/dumper.rb
|
59
|
+
def bare_key?(key)
|
60
|
+
!!key.to_s.match(/^[a-zA-Z0-9_-]*$/)
|
61
|
+
end
|
62
|
+
|
63
|
+
# @api private
|
64
|
+
# from toml-rb
|
65
|
+
# https://github.com/emancu/toml-rb/blob/ca5bf9563f1ef2c467bd43eec1d035e83b61ac88/lib/toml-rb/dumper.rb
|
66
|
+
def quote_key(key)
|
67
|
+
"\"#{key.gsub('"', '\\"')}\""
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module TOML
|
5
|
+
# Represents a TOML table
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3#table
|
7
|
+
# @see https://toml.io/en/v1.0.0-rc.3#array-of-tables
|
8
|
+
class Table
|
9
|
+
# @return [::Array] The dotted keys of the table name.
|
10
|
+
attr_reader :split_keys
|
11
|
+
|
12
|
+
# @return [String] The name of table.
|
13
|
+
attr_reader :name
|
14
|
+
|
15
|
+
# @return [::Array<Toby::TOML::KeyValue>] The key-value pairs within the table.
|
16
|
+
attr_accessor :key_values
|
17
|
+
|
18
|
+
# @return [::Array<String>] The header comments above the table.
|
19
|
+
attr_accessor :header_comments
|
20
|
+
|
21
|
+
# @return [String] The comment in-line with the table name.
|
22
|
+
attr_accessor :inline_comment
|
23
|
+
|
24
|
+
# @param split_keys [::Array] Dotted keys of the table name.
|
25
|
+
# @param inline_comment [String] The comment in-line with the key-value pair.
|
26
|
+
# @param is_array_table [TrueClass, FalseClass] Whether the table is an array-table or not
|
27
|
+
def initialize(split_keys, inline_comment, is_array_table)
|
28
|
+
@split_keys = split_keys
|
29
|
+
@name = split_keys&.join('.')
|
30
|
+
@inline_comment = inline_comment
|
31
|
+
@is_array_table = is_array_table
|
32
|
+
|
33
|
+
@header_comments = []
|
34
|
+
@key_values = []
|
35
|
+
end
|
36
|
+
|
37
|
+
# @return [TrueClass, FalseClass] Whether the table is an array-table or not
|
38
|
+
def array_table?
|
39
|
+
@is_array_table
|
40
|
+
end
|
41
|
+
|
42
|
+
# @return [Hash] TOML table represented as a hash.
|
43
|
+
# @option options [TrueClass, FalseClass] :dotted_keys (false) If true, dotted keys are not expanded/nested.
|
44
|
+
# @example
|
45
|
+
# Given the following TOML:
|
46
|
+
# [some.dotted.keys]
|
47
|
+
# some.value = 123
|
48
|
+
#
|
49
|
+
# #to_hash returns {'some' => {'dotted' => {'keys' => {'some' => {'value' => 123} } } } } }
|
50
|
+
# #to_hash(dotted_keys: true) returns in {'some.dotted.keys' => {'some.value'} => 123}
|
51
|
+
def to_hash(options = {})
|
52
|
+
if options[:dotted_keys]
|
53
|
+
to_dotted_keys_hash(options)
|
54
|
+
else
|
55
|
+
to_split_keys_hash(options)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [String] Table in valid TOML format
|
60
|
+
def dump
|
61
|
+
output = StringIO.new
|
62
|
+
|
63
|
+
dotted_keys = split_keys.map { |key| bare_key?(key) ? key : quote_key(key) }.join('.')
|
64
|
+
|
65
|
+
output.puts "\n##{header_comments.join("\n#")}" unless header_comments.empty?
|
66
|
+
|
67
|
+
if array_table?
|
68
|
+
output.puts "[[#{dotted_keys}]]#{" ##{inline_comment}" if inline_comment}"
|
69
|
+
else
|
70
|
+
output.puts "[#{dotted_keys}]#{" ##{inline_comment}" if inline_comment}"
|
71
|
+
end
|
72
|
+
|
73
|
+
key_values.each do |kv|
|
74
|
+
output.puts kv.dump
|
75
|
+
end
|
76
|
+
|
77
|
+
output.string
|
78
|
+
end
|
79
|
+
|
80
|
+
# @api private
|
81
|
+
# from toml-rb
|
82
|
+
# https://github.com/emancu/toml-rb/blob/ca5bf9563f1ef2c467bd43eec1d035e83b61ac88/lib/toml-rb/dumper.rb
|
83
|
+
def bare_key?(key)
|
84
|
+
!!key.to_s.match(/^[a-zA-Z0-9_-]*$/)
|
85
|
+
end
|
86
|
+
|
87
|
+
# @api private
|
88
|
+
# from toml-rb
|
89
|
+
# https://github.com/emancu/toml-rb/blob/ca5bf9563f1ef2c467bd43eec1d035e83b61ac88/lib/toml-rb/dumper.rb
|
90
|
+
def quote_key(key)
|
91
|
+
"\"#{key.gsub('"', '\\"')}\""
|
92
|
+
end
|
93
|
+
|
94
|
+
private
|
95
|
+
|
96
|
+
# @api private
|
97
|
+
def to_dotted_keys_hash(options)
|
98
|
+
output_hash = {}
|
99
|
+
|
100
|
+
key_values.each do |kv|
|
101
|
+
output_hash[kv.key] = kv.value.respond_to?(:to_hash) ? kv.value.to_hash(options) : kv.value
|
102
|
+
end
|
103
|
+
|
104
|
+
output_hash
|
105
|
+
end
|
106
|
+
|
107
|
+
# @api private
|
108
|
+
def to_split_keys_hash(options)
|
109
|
+
output_hash = {}
|
110
|
+
|
111
|
+
key_values.each do |kv|
|
112
|
+
last_hash = output_hash
|
113
|
+
|
114
|
+
kv.split_keys.each_with_index do |key, i|
|
115
|
+
if i < (kv.split_keys.size - 1) # not the last key
|
116
|
+
last_hash[key] ||= {}
|
117
|
+
last_hash = last_hash[key]
|
118
|
+
else
|
119
|
+
last_hash[key] = kv.value.respond_to?(:to_hash) ? kv.value.to_hash(options) : kv.value
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
output_hash
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,162 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
|
3
|
+
module Toby
|
4
|
+
module TOML
|
5
|
+
# Represents an entire TOML file
|
6
|
+
# @see https://toml.io/en/v1.0.0-rc.3
|
7
|
+
class TOMLFile < Toby::TOML::Table
|
8
|
+
# @return [Array<Toby::TOML::Table>] The tables in the TOML file
|
9
|
+
attr_reader :tables
|
10
|
+
|
11
|
+
# @param input_string [String] The TOML file to parse.
|
12
|
+
def initialize(input_string)
|
13
|
+
super(nil, '', false)
|
14
|
+
|
15
|
+
@tables = [self]
|
16
|
+
matches = Toby::Document.parse(input_string).matches
|
17
|
+
|
18
|
+
@comment_buffer = []
|
19
|
+
|
20
|
+
matches.each do |m|
|
21
|
+
if m.respond_to? :toml_object
|
22
|
+
toml_object_handler(m.toml_object)
|
23
|
+
|
24
|
+
elsif m.respond_to? :stripped_comment
|
25
|
+
@comment_buffer << m.stripped_comment
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# @return [Hash] TOML table represented as a hash.
|
32
|
+
# @option options [TrueClass, FalseClass] :dotted_keys (false) If true, dotted keys are not expanded/nested.
|
33
|
+
# @example
|
34
|
+
# Given the following TOML:
|
35
|
+
# [some.dotted.keys]
|
36
|
+
# some.value = 123
|
37
|
+
#
|
38
|
+
# #to_hash returns {'some' => {'dotted' => {'keys' => {'some' => {'value' => 123} } } } } }
|
39
|
+
# #to_hash(dotted_keys: true) returns {'some.dotted.keys' => {'some.value'} => 123}
|
40
|
+
def to_hash(options = {})
|
41
|
+
if options[:dotted_keys]
|
42
|
+
to_dotted_keys_hash(options)
|
43
|
+
else
|
44
|
+
to_split_keys_hash(options)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# @return [String] The entire TOML file in valid TOML format.
|
49
|
+
def dump
|
50
|
+
output = StringIO.new
|
51
|
+
|
52
|
+
key_values.each do |kv|
|
53
|
+
output.puts kv.dump
|
54
|
+
end
|
55
|
+
|
56
|
+
tables.each do |table|
|
57
|
+
next if table.is_a? Toby::TOML::TOMLFile
|
58
|
+
|
59
|
+
output.puts table.dump
|
60
|
+
end
|
61
|
+
|
62
|
+
output.string
|
63
|
+
end
|
64
|
+
|
65
|
+
# @return [String] The TOML file in valid JSON in accordance with the TOML spec
|
66
|
+
def to_json(*_args)
|
67
|
+
to_hash.to_json
|
68
|
+
end
|
69
|
+
|
70
|
+
# @return [NilClass] A file can't have an inline comment, so this will always return nil
|
71
|
+
def inline_comment
|
72
|
+
nil
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
# @api private
|
78
|
+
def to_dotted_keys_hash(options)
|
79
|
+
output_hash = {}
|
80
|
+
|
81
|
+
tables.each do |tbl|
|
82
|
+
if tbl.name.nil?
|
83
|
+
output_hash = super
|
84
|
+
|
85
|
+
elsif tbl.array_table?
|
86
|
+
output_hash[tbl.name] ||= []
|
87
|
+
output_hash[tbl.name] << tbl.to_hash(options)
|
88
|
+
|
89
|
+
else
|
90
|
+
output_hash[tbl.name] = tbl.to_hash(options)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
output_hash
|
95
|
+
end
|
96
|
+
|
97
|
+
# @api private
|
98
|
+
def to_split_keys_hash(options)
|
99
|
+
output_hash = {}
|
100
|
+
|
101
|
+
tables.each do |tbl|
|
102
|
+
if tbl.name.nil?
|
103
|
+
output_hash = super
|
104
|
+
|
105
|
+
elsif tbl.array_table?
|
106
|
+
last_hash = output_hash
|
107
|
+
|
108
|
+
tbl.split_keys.each_with_index do |key, i|
|
109
|
+
if i < (tbl.split_keys.size - 1) # not the last key
|
110
|
+
last_hash[key] ||= {}
|
111
|
+
last_hash = last_hash[key]
|
112
|
+
elsif last_hash.is_a? ::Array
|
113
|
+
last_hash.last[key] ||= []
|
114
|
+
last_hash.last[key] << tbl.to_hash(options)
|
115
|
+
else
|
116
|
+
last_hash[key] ||= []
|
117
|
+
last_hash[key] << tbl.to_hash(options)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
else
|
122
|
+
|
123
|
+
last_hash = output_hash
|
124
|
+
last_last_hash = nil
|
125
|
+
|
126
|
+
tbl.split_keys.each_with_index do |key, i|
|
127
|
+
last_last_hash = last_hash
|
128
|
+
if i < (tbl.split_keys.size - 1) # not the last key
|
129
|
+
last_hash[key] ||= {}
|
130
|
+
last_last_hash = last_hash
|
131
|
+
last_hash = last_hash[key]
|
132
|
+
elsif last_hash.is_a? ::Array
|
133
|
+
last_last_hash.last[key] = tbl.to_hash(options)
|
134
|
+
else
|
135
|
+
last_hash[key] = tbl.to_hash(options)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
output_hash
|
142
|
+
end
|
143
|
+
|
144
|
+
# @api private
|
145
|
+
def toml_object_handler(obj)
|
146
|
+
if obj.respond_to?(:header_comments) && !@comment_buffer.empty?
|
147
|
+
obj.header_comments = @comment_buffer
|
148
|
+
@comment_buffer = []
|
149
|
+
end
|
150
|
+
|
151
|
+
case obj
|
152
|
+
when Toby::TOML::Table
|
153
|
+
@tables << obj
|
154
|
+
|
155
|
+
when Toby::TOML::KeyValue
|
156
|
+
@tables.last.key_values << obj
|
157
|
+
|
158
|
+
end
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
metadata
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: toby
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.0.pre.rc2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Joe Polny
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-01-31 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Toby is a TOML 1.0.0 parser for Ruby that allows the parsing, editing,
|
14
|
+
and dumping of the TOML file format (including comments). Toby also supports conversion
|
15
|
+
from TOML to a Ruby Hash or JSON.
|
16
|
+
email:
|
17
|
+
executables: []
|
18
|
+
extensions: []
|
19
|
+
extra_rdoc_files: []
|
20
|
+
files:
|
21
|
+
- lib/toby.rb
|
22
|
+
- lib/toby/grammars/document.citrus
|
23
|
+
- lib/toby/grammars/helper.citrus
|
24
|
+
- lib/toby/grammars/primitive.citrus
|
25
|
+
- lib/toby/parser/datetime.rb
|
26
|
+
- lib/toby/parser/match_modules.rb
|
27
|
+
- lib/toby/parser/numbers.rb
|
28
|
+
- lib/toby/parser/string.rb
|
29
|
+
- lib/toby/toml/array.rb
|
30
|
+
- lib/toby/toml/inline_table.rb
|
31
|
+
- lib/toby/toml/key_value.rb
|
32
|
+
- lib/toby/toml/table.rb
|
33
|
+
- lib/toby/toml/toml_file.rb
|
34
|
+
homepage: https://github.com/joe-p/toby
|
35
|
+
licenses:
|
36
|
+
- MIT
|
37
|
+
metadata:
|
38
|
+
source_code_uri: https://github.com/joe-p/toby
|
39
|
+
bug_tracker_uri: https://github.com/joe-p/toby/issues
|
40
|
+
post_install_message:
|
41
|
+
rdoc_options: []
|
42
|
+
require_paths:
|
43
|
+
- lib
|
44
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">"
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: 1.3.1
|
54
|
+
requirements: []
|
55
|
+
rubygems_version: 3.1.4
|
56
|
+
signing_key:
|
57
|
+
specification_version: 4
|
58
|
+
summary: A TOML Parser for Ruby. TOML + Ruby = Toby.
|
59
|
+
test_files: []
|