toby 1.0.0.pre.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/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: []
|