kdl 1.0.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +7 -1
- data/.gitignore +1 -0
- data/.gitmodules +4 -0
- data/Gemfile +6 -1
- data/README.md +51 -7
- data/Rakefile +6 -1
- data/bin/kdl +1 -1
- data/kdl.gemspec +2 -2
- data/lib/kdl/document.rb +58 -2
- data/lib/kdl/kdl.tab.rb +303 -228
- data/lib/kdl/kdl.yy +57 -49
- data/lib/kdl/node.rb +113 -12
- data/lib/kdl/parser_common.rb +26 -0
- data/lib/kdl/string_dumper.rb +30 -33
- data/lib/kdl/tokenizer.rb +350 -113
- data/lib/kdl/types/base64.rb +1 -1
- data/lib/kdl/types/country/iso3166_countries.rb +1 -1
- data/lib/kdl/types/country/iso3166_subdivisions.rb +1 -1
- data/lib/kdl/types/country.rb +2 -2
- data/lib/kdl/types/currency/iso4217_currencies.rb +1 -1
- data/lib/kdl/types/currency.rb +1 -1
- data/lib/kdl/types/date_time.rb +3 -3
- data/lib/kdl/types/decimal.rb +1 -1
- data/lib/kdl/types/duration/iso8601_parser.rb +1 -1
- data/lib/kdl/types/duration.rb +1 -1
- data/lib/kdl/types/email/parser.rb +2 -2
- data/lib/kdl/types/email.rb +1 -1
- data/lib/kdl/types/hostname/validator.rb +1 -1
- data/lib/kdl/types/hostname.rb +1 -1
- data/lib/kdl/types/ip.rb +1 -1
- data/lib/kdl/types/irl/parser.rb +1 -1
- data/lib/kdl/types/irl.rb +1 -1
- data/lib/kdl/types/regex.rb +1 -1
- data/lib/kdl/types/url.rb +1 -1
- data/lib/kdl/types/url_template.rb +1 -1
- data/lib/kdl/types/uuid.rb +1 -1
- data/lib/kdl/v1/document.rb +17 -0
- data/lib/kdl/v1/kdl.tab.rb +594 -0
- data/lib/kdl/v1/kdl.yy +89 -0
- data/lib/kdl/v1/node.rb +30 -0
- data/lib/kdl/v1/string_dumper.rb +28 -0
- data/lib/kdl/v1/tokenizer.rb +296 -0
- data/lib/kdl/v1/value.rb +89 -0
- data/lib/kdl/v1.rb +11 -0
- data/lib/kdl/value.rb +81 -12
- data/lib/kdl/version.rb +1 -1
- data/lib/kdl.rb +40 -1
- metadata +13 -4
@@ -0,0 +1,28 @@
|
|
1
|
+
module KDL
|
2
|
+
module V1
|
3
|
+
module StringDumper
|
4
|
+
include ::KDL::StringDumper
|
5
|
+
|
6
|
+
def call(string)
|
7
|
+
%("#{string.each_char.map { |char| escape(char) }.join}")
|
8
|
+
end
|
9
|
+
|
10
|
+
def stringify_identifier(ident)
|
11
|
+
if bare_identifier?(ident)
|
12
|
+
ident
|
13
|
+
else
|
14
|
+
call(ident)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def bare_identifier?(name)
|
21
|
+
escape_chars = '\\\/(){}<>;\[\]=,"'
|
22
|
+
name =~ /^([^0-9\-+\s#{escape_chars}][^\s#{escape_chars}]*|[\-+](?!true|false|null)[^0-9\s#{escape_chars}][^\s#{escape_chars}]*)$/
|
23
|
+
end
|
24
|
+
|
25
|
+
extend self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,296 @@
|
|
1
|
+
module KDL
|
2
|
+
module V1
|
3
|
+
class Tokenizer < KDL::Tokenizer
|
4
|
+
NON_IDENTIFIER_CHARS = Regexp.escape "#{SYMBOLS.keys.join}()/\\<>[]\",#{WHITESPACE.join}#{OTHER_NON_IDENTIFIER_CHARS.join}"
|
5
|
+
IDENTIFIER_CHARS = /[^#{NON_IDENTIFIER_CHARS}]/
|
6
|
+
INITIAL_IDENTIFIER_CHARS = /[^#{NON_IDENTIFIER_CHARS}0-9]/
|
7
|
+
|
8
|
+
def next_token
|
9
|
+
@context = nil
|
10
|
+
@previous_context = nil
|
11
|
+
@line_at_start = @line
|
12
|
+
@column_at_start = @column
|
13
|
+
loop do
|
14
|
+
c = self[@index]
|
15
|
+
case @context
|
16
|
+
when nil
|
17
|
+
case c
|
18
|
+
when '"'
|
19
|
+
self.context = :string
|
20
|
+
@buffer = ''
|
21
|
+
traverse(1)
|
22
|
+
when 'r'
|
23
|
+
if @str[@index + 1] == '"'
|
24
|
+
self.context = :rawstring
|
25
|
+
traverse(2)
|
26
|
+
@rawstring_hashes = 0
|
27
|
+
@buffer = ''
|
28
|
+
next
|
29
|
+
elsif @str[@index + 1] == '#'
|
30
|
+
i = @index + 1
|
31
|
+
@rawstring_hashes = 0
|
32
|
+
while @str[i] == '#'
|
33
|
+
@rawstring_hashes += 1
|
34
|
+
i += 1
|
35
|
+
end
|
36
|
+
if @str[i] == '"'
|
37
|
+
self.context = :rawstring
|
38
|
+
@index = i + 1
|
39
|
+
@buffer = ''
|
40
|
+
next
|
41
|
+
end
|
42
|
+
end
|
43
|
+
self.context = :ident
|
44
|
+
@buffer = c
|
45
|
+
traverse(1)
|
46
|
+
when '-'
|
47
|
+
n = self[@index + 1]
|
48
|
+
if n =~ /[0-9]/
|
49
|
+
n2 = self[@index + 2]
|
50
|
+
if n == '0' && n2 =~ /[box]/
|
51
|
+
self.context = integer_context(n2)
|
52
|
+
traverse(3)
|
53
|
+
else
|
54
|
+
self.context = :decimal
|
55
|
+
traverse(1)
|
56
|
+
end
|
57
|
+
else
|
58
|
+
self.context = :ident
|
59
|
+
traverse(1)
|
60
|
+
end
|
61
|
+
@buffer = c
|
62
|
+
when /[0-9+]/
|
63
|
+
n = self[@index + 1]
|
64
|
+
if c == '0' && n =~ /[box]/
|
65
|
+
traverse(2)
|
66
|
+
@buffer = ''
|
67
|
+
self.context = integer_context(n)
|
68
|
+
else
|
69
|
+
self.context = :decimal
|
70
|
+
@buffer = c
|
71
|
+
traverse(1)
|
72
|
+
end
|
73
|
+
when '\\'
|
74
|
+
t = Tokenizer.new(@str, @index + 1)
|
75
|
+
la = t.next_token
|
76
|
+
if la[0] == :NEWLINE || la[0] == :EOF || (la[0] == :WS && (lan = t.next_token[0]) == :NEWLINE || lan == :EOF)
|
77
|
+
traverse_to(t.index)
|
78
|
+
@buffer = "#{c}#{la[1].value}"
|
79
|
+
@buffer += "\n" if lan == :NEWLINE
|
80
|
+
self.context = :whitespace
|
81
|
+
else
|
82
|
+
raise_error "Unexpected '\\' (#{la[0]})"
|
83
|
+
end
|
84
|
+
when *SYMBOLS.keys
|
85
|
+
return token(SYMBOLS[c], c).tap { traverse(1) }
|
86
|
+
when *NEWLINES, "\r"
|
87
|
+
nl = expect_newline
|
88
|
+
return token(:NEWLINE, nl).tap do
|
89
|
+
traverse(nl.length)
|
90
|
+
end
|
91
|
+
when "/"
|
92
|
+
if self[@index + 1] == '/'
|
93
|
+
self.context = :single_line_comment
|
94
|
+
traverse(2)
|
95
|
+
elsif self[@index + 1] == '*'
|
96
|
+
self.context = :multi_line_comment
|
97
|
+
@comment_nesting = 1
|
98
|
+
traverse(2)
|
99
|
+
elsif self[@index + 1] == '-'
|
100
|
+
return token(:SLASHDASH, '/-').tap { traverse(2) }
|
101
|
+
else
|
102
|
+
self.context = :ident
|
103
|
+
@buffer = c
|
104
|
+
traverse(1)
|
105
|
+
end
|
106
|
+
when *WHITESPACE
|
107
|
+
self.context = :whitespace
|
108
|
+
@buffer = c
|
109
|
+
traverse(1)
|
110
|
+
when nil
|
111
|
+
return [false, token(:EOF, :EOF)[1]] if @done
|
112
|
+
|
113
|
+
@done = true
|
114
|
+
return token(:EOF, :EOF)
|
115
|
+
when INITIAL_IDENTIFIER_CHARS
|
116
|
+
self.context = :ident
|
117
|
+
@buffer = c
|
118
|
+
traverse(1)
|
119
|
+
when '('
|
120
|
+
@type_context = true
|
121
|
+
return token(:LPAREN, c).tap { traverse(1) }
|
122
|
+
when ')'
|
123
|
+
@type_context = false
|
124
|
+
return token(:RPAREN, c).tap { traverse(1) }
|
125
|
+
else
|
126
|
+
raise_error "Unexpected character #{c.inspect}"
|
127
|
+
end
|
128
|
+
when :ident
|
129
|
+
case c
|
130
|
+
when IDENTIFIER_CHARS
|
131
|
+
traverse(1)
|
132
|
+
@buffer += c
|
133
|
+
else
|
134
|
+
case @buffer
|
135
|
+
when 'true' then return token(:TRUE, true)
|
136
|
+
when 'false' then return token(:FALSE, false)
|
137
|
+
when 'null' then return token(:NULL, nil)
|
138
|
+
else return token(:IDENT, @buffer)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
when :string
|
142
|
+
case c
|
143
|
+
when '\\'
|
144
|
+
c2 = self[@index + 1]
|
145
|
+
if c2.match?(NEWLINES_PATTERN)
|
146
|
+
i = 2
|
147
|
+
while self[@index + i].match?(NEWLINES_PATTERN)
|
148
|
+
i+=1
|
149
|
+
end
|
150
|
+
traverse(i)
|
151
|
+
else
|
152
|
+
@buffer += c
|
153
|
+
@buffer += c2
|
154
|
+
traverse(2)
|
155
|
+
end
|
156
|
+
when '"'
|
157
|
+
return token(:STRING, unescape(@buffer)).tap { traverse(1) }
|
158
|
+
when nil
|
159
|
+
raise_error "Unterminated string literal"
|
160
|
+
else
|
161
|
+
@buffer += c
|
162
|
+
traverse(1)
|
163
|
+
end
|
164
|
+
when :rawstring
|
165
|
+
raise_error "Unterminated rawstring literal" if c.nil?
|
166
|
+
|
167
|
+
if c == '"'
|
168
|
+
h = 0
|
169
|
+
h += 1 while self[@index + 1 + h] == '#' && h < @rawstring_hashes
|
170
|
+
if h == @rawstring_hashes
|
171
|
+
return token(:RAWSTRING, @buffer).tap { traverse(1 + h) }
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
@buffer += c
|
176
|
+
traverse(1)
|
177
|
+
when :decimal
|
178
|
+
case c
|
179
|
+
when /[0-9.\-+_eE]/
|
180
|
+
traverse(1)
|
181
|
+
@buffer += c
|
182
|
+
else
|
183
|
+
return parse_decimal(@buffer)
|
184
|
+
end
|
185
|
+
when :hexadecimal
|
186
|
+
case c
|
187
|
+
when /[0-9a-fA-F_]/
|
188
|
+
traverse(1)
|
189
|
+
@buffer += c
|
190
|
+
else
|
191
|
+
return parse_hexadecimal(@buffer)
|
192
|
+
end
|
193
|
+
when :octal
|
194
|
+
case c
|
195
|
+
when /[0-7_]/
|
196
|
+
traverse(1)
|
197
|
+
@buffer += c
|
198
|
+
else
|
199
|
+
return parse_octal(@buffer)
|
200
|
+
end
|
201
|
+
when :binary
|
202
|
+
case c
|
203
|
+
when /[01_]/
|
204
|
+
traverse(1)
|
205
|
+
@buffer += c
|
206
|
+
else
|
207
|
+
return parse_binary(@buffer)
|
208
|
+
end
|
209
|
+
when :single_line_comment
|
210
|
+
case c
|
211
|
+
when *NEWLINES, "\r"
|
212
|
+
self.context = nil
|
213
|
+
@column_at_start = @column
|
214
|
+
next
|
215
|
+
when nil
|
216
|
+
@done = true
|
217
|
+
return token(:EOF, :EOF)
|
218
|
+
else
|
219
|
+
traverse(1)
|
220
|
+
end
|
221
|
+
when :multi_line_comment
|
222
|
+
if c == '/' && self[@index + 1] == '*'
|
223
|
+
@comment_nesting += 1
|
224
|
+
traverse(2)
|
225
|
+
elsif c == '*' && self[@index + 1] == '/'
|
226
|
+
@comment_nesting -= 1
|
227
|
+
traverse(2)
|
228
|
+
if @comment_nesting == 0
|
229
|
+
revert_context
|
230
|
+
end
|
231
|
+
else
|
232
|
+
traverse(1)
|
233
|
+
end
|
234
|
+
when :whitespace
|
235
|
+
if WHITESPACE.include?(c)
|
236
|
+
traverse(1)
|
237
|
+
@buffer += c
|
238
|
+
elsif c == "/" && self[@index + 1] == '*'
|
239
|
+
self.context = :multi_line_comment
|
240
|
+
@comment_nesting = 1
|
241
|
+
traverse(2)
|
242
|
+
elsif c == "\\"
|
243
|
+
t = Tokenizer.new(@str, @index + 1)
|
244
|
+
la = t.next_token
|
245
|
+
if la[0] == :NEWLINE || la[0] == :EOF || (la[0] == :WS && (lan = t.next_token[0]) == :NEWLINE || lan == :EOF)
|
246
|
+
traverse_to(t.index)
|
247
|
+
@buffer += "#{c}#{la[1].value}"
|
248
|
+
@buffer += "\n" if lan == :NEWLINE
|
249
|
+
else
|
250
|
+
raise_error "Unexpected '\\' (#{la[0]})"
|
251
|
+
end
|
252
|
+
else
|
253
|
+
return token(:WS, @buffer)
|
254
|
+
end
|
255
|
+
else
|
256
|
+
# :nocov:
|
257
|
+
raise_error "Unknown context `#{@context}'"
|
258
|
+
# :nocov:
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
private
|
264
|
+
|
265
|
+
def allowed_in_type?(val)
|
266
|
+
%i[ident string rawstring].include?(val)
|
267
|
+
end
|
268
|
+
|
269
|
+
def allowed_after_type?(val)
|
270
|
+
!%i[single_line_comment multi_line_comment].include?(val)
|
271
|
+
end
|
272
|
+
|
273
|
+
def unescape(string)
|
274
|
+
string.gsub(/\\[^u]/) do |m|
|
275
|
+
case m
|
276
|
+
when '\n' then "\n"
|
277
|
+
when '\r' then "\r"
|
278
|
+
when '\t' then "\t"
|
279
|
+
when '\\\\' then "\\"
|
280
|
+
when '\"' then "\""
|
281
|
+
when '\b' then "\b"
|
282
|
+
when '\f' then "\f"
|
283
|
+
when '\/' then "/"
|
284
|
+
else raise_error "Unexpected escape #{m.inspect}"
|
285
|
+
end
|
286
|
+
end.gsub(/\\u\{[0-9a-fA-F]{0,6}\}/) do |m|
|
287
|
+
i = Integer(m[3..-2], 16)
|
288
|
+
if i < 0 || i > 0x10FFFF
|
289
|
+
raise_error "Invalid code point #{u}"
|
290
|
+
end
|
291
|
+
i.chr(Encoding::UTF_8)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
end
|
295
|
+
end
|
296
|
+
end
|
data/lib/kdl/v1/value.rb
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
module KDL
|
2
|
+
module V1
|
3
|
+
class Value < ::KDL::Value
|
4
|
+
module Methods
|
5
|
+
def to_s
|
6
|
+
return stringify_value unless type
|
7
|
+
|
8
|
+
"(#{StringDumper.stringify_identifier type})#{stringify_value}"
|
9
|
+
end
|
10
|
+
|
11
|
+
def ==(other)
|
12
|
+
return self == other.value if other.is_a?(self.class.superclass)
|
13
|
+
|
14
|
+
value == other
|
15
|
+
end
|
16
|
+
|
17
|
+
def version
|
18
|
+
1
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_v1
|
22
|
+
self
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_v2
|
26
|
+
self.class.superclass.new(value, format:, type:)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
include Methods
|
31
|
+
|
32
|
+
class Int < ::KDL::Value::Int
|
33
|
+
include Methods
|
34
|
+
end
|
35
|
+
|
36
|
+
class Float < ::KDL::Value::Float
|
37
|
+
include Methods
|
38
|
+
|
39
|
+
def stringify_value
|
40
|
+
if value.nan? || value.infinite?
|
41
|
+
warn "[WARNING] Attempting to serialize non-finite Float using KDL v1"
|
42
|
+
return Null.stringify_value
|
43
|
+
end
|
44
|
+
super
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class Boolean < ::KDL::Value::Boolean
|
49
|
+
include Methods
|
50
|
+
|
51
|
+
def stringify_value
|
52
|
+
value.to_s
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
class String < ::KDL::Value::String
|
57
|
+
include Methods
|
58
|
+
|
59
|
+
def stringify_value
|
60
|
+
StringDumper.call(value)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
class NullImpl < ::KDL::Value::NullImpl
|
65
|
+
include Methods
|
66
|
+
|
67
|
+
def stringify_value
|
68
|
+
"null"
|
69
|
+
end
|
70
|
+
|
71
|
+
def to_v2
|
72
|
+
type ? ::KDL::Value::NullImpl.new(type:) : ::KDL::Value::Null
|
73
|
+
end
|
74
|
+
end
|
75
|
+
Null = NullImpl.new
|
76
|
+
|
77
|
+
def self.from(value)
|
78
|
+
case value
|
79
|
+
when ::String then String.new(value)
|
80
|
+
when Integer then Int.new(value)
|
81
|
+
when ::Float then Float.new(value)
|
82
|
+
when TrueClass, FalseClass then Boolean.new(value)
|
83
|
+
when NilClass then Null
|
84
|
+
else raise Error("Unsupported value type: #{value.class}")
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
89
|
+
end
|
data/lib/kdl/v1.rb
ADDED
data/lib/kdl/value.rb
CHANGED
@@ -15,18 +15,30 @@ module KDL
|
|
15
15
|
result = parser.call(self, type)
|
16
16
|
return self.as_type(type) if result.nil?
|
17
17
|
|
18
|
-
unless result.is_a?(::KDL::Value)
|
19
|
-
raise ArgumentError, "expected parser to return an instance of ::KDL::Value, got `#{result.class}'"
|
18
|
+
unless result.is_a?(::KDL::Value::Custom)
|
19
|
+
raise ArgumentError, "expected parser to return an instance of ::KDL::Value::Custom, got `#{result.class}'"
|
20
20
|
end
|
21
21
|
|
22
22
|
result
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
|
+
def ==(other)
|
27
|
+
return self == other.value if other.is_a?(self.class)
|
28
|
+
|
29
|
+
value == other
|
30
|
+
end
|
31
|
+
|
26
32
|
def to_s
|
27
33
|
return stringify_value unless type
|
28
34
|
|
29
|
-
"(#{StringDumper.
|
35
|
+
"(#{StringDumper.call type})#{stringify_value}"
|
36
|
+
end
|
37
|
+
|
38
|
+
def inspect
|
39
|
+
return value.inspect unless type
|
40
|
+
|
41
|
+
"(#{type.inspect})#{value.inspect}"
|
30
42
|
end
|
31
43
|
|
32
44
|
def stringify_value
|
@@ -35,18 +47,40 @@ module KDL
|
|
35
47
|
value.to_s
|
36
48
|
end
|
37
49
|
|
50
|
+
def version
|
51
|
+
2
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_v2
|
55
|
+
self
|
56
|
+
end
|
57
|
+
|
58
|
+
def method_missing(name, *args, **kwargs, &block)
|
59
|
+
value.public_send(name, *args, **kwargs, &block)
|
60
|
+
end
|
61
|
+
|
62
|
+
def respond_to_missing?(name, include_all = false)
|
63
|
+
value.respond_to?(name, include_all)
|
64
|
+
end
|
65
|
+
|
38
66
|
class Int < Value
|
39
|
-
def
|
40
|
-
|
67
|
+
def to_v1
|
68
|
+
V1::Value::Int.new(value, format:, type:)
|
41
69
|
end
|
42
70
|
end
|
43
71
|
|
44
72
|
class Float < Value
|
45
73
|
def ==(other)
|
46
|
-
other.is_a?(Float)
|
74
|
+
return self == other.value if other.is_a?(Float)
|
75
|
+
return other.nan? if value.nan?
|
76
|
+
|
77
|
+
value == other
|
47
78
|
end
|
48
79
|
|
49
80
|
def stringify_value
|
81
|
+
return '#nan' if value.nan?
|
82
|
+
return '#inf' if value == ::Float::INFINITY
|
83
|
+
return '#-inf' if value == -::Float::INFINITY
|
50
84
|
return super.upcase unless value.is_a?(BigDecimal)
|
51
85
|
|
52
86
|
sign, digits, _, exponent = value.split
|
@@ -55,11 +89,22 @@ module KDL
|
|
55
89
|
s += "E#{exponent.negative? ? '' : '+'}#{exponent - 1}"
|
56
90
|
s
|
57
91
|
end
|
92
|
+
|
93
|
+
def to_v1
|
94
|
+
if value.nan? || value.infinite?
|
95
|
+
warn "[WARNING] Converting non-finite Float to KDL v1"
|
96
|
+
end
|
97
|
+
V1::Value::Float.new(value, format:, type:)
|
98
|
+
end
|
58
99
|
end
|
59
100
|
|
60
101
|
class Boolean < Value
|
61
|
-
def
|
62
|
-
|
102
|
+
def stringify_value
|
103
|
+
"##{value}"
|
104
|
+
end
|
105
|
+
|
106
|
+
def to_v1
|
107
|
+
V1::Value::Boolean.new(value, format:, type:)
|
63
108
|
end
|
64
109
|
end
|
65
110
|
|
@@ -68,8 +113,8 @@ module KDL
|
|
68
113
|
StringDumper.call(value)
|
69
114
|
end
|
70
115
|
|
71
|
-
def
|
72
|
-
|
116
|
+
def to_v1
|
117
|
+
V1::Value::String.new(value, format:, type:)
|
73
118
|
end
|
74
119
|
end
|
75
120
|
|
@@ -79,15 +124,39 @@ module KDL
|
|
79
124
|
end
|
80
125
|
|
81
126
|
def stringify_value
|
82
|
-
"null"
|
127
|
+
"#null"
|
83
128
|
end
|
84
129
|
|
85
130
|
def ==(other)
|
86
|
-
other.is_a?(NullImpl)
|
131
|
+
other.is_a?(NullImpl) || other.nil?
|
132
|
+
end
|
133
|
+
|
134
|
+
def to_v1
|
135
|
+
type ? V1::Value::NullImpl.new(type:) : V1::Value::Null
|
87
136
|
end
|
88
137
|
end
|
89
138
|
Null = NullImpl.new
|
90
139
|
|
140
|
+
class Custom < Value
|
141
|
+
attr_reader :oriinal_value
|
142
|
+
|
143
|
+
def self.call(value, type)
|
144
|
+
new(value, type:)
|
145
|
+
end
|
146
|
+
|
147
|
+
def version
|
148
|
+
nil
|
149
|
+
end
|
150
|
+
|
151
|
+
def to_v1
|
152
|
+
self
|
153
|
+
end
|
154
|
+
|
155
|
+
def to_v2
|
156
|
+
self
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
91
160
|
def self.from(value)
|
92
161
|
case value
|
93
162
|
when ::String then String.new(value)
|
data/lib/kdl/version.rb
CHANGED
data/lib/kdl.rb
CHANGED
@@ -5,10 +5,49 @@ require "kdl/value"
|
|
5
5
|
require "kdl/node"
|
6
6
|
require "kdl/string_dumper"
|
7
7
|
require "kdl/types"
|
8
|
+
require "kdl/parser_common"
|
8
9
|
require "kdl/kdl.tab"
|
10
|
+
require "kdl/v1"
|
9
11
|
|
10
12
|
module KDL
|
13
|
+
class << self
|
14
|
+
attr_accessor :default_version
|
15
|
+
attr_accessor :default_output_version
|
16
|
+
end
|
17
|
+
|
11
18
|
def self.parse_document(input, options = {})
|
12
|
-
|
19
|
+
warn "[DEPRECATION] `KDL.parse_document' is deprecated. Please use `KDL.parse' instead."
|
20
|
+
parse(input, **options)
|
21
|
+
end
|
22
|
+
|
23
|
+
def self.parse(input, version: default_version, output_version: default_output_version, **options)
|
24
|
+
case version
|
25
|
+
when 2
|
26
|
+
Parser.new(output_module: output_module(output_version || 2), **options).parse(input)
|
27
|
+
when 1
|
28
|
+
V1::Parser.new.parse(input, output_module: output_module(output_version || 1), **options)
|
29
|
+
else
|
30
|
+
auto_parse(input, output_version:, **options)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.load_file(filespec, **options)
|
35
|
+
parse(File.read(filespec, encoding: Encoding::UTF_8), **options)
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.auto_parse(input, output_version: default_output_version, **options)
|
39
|
+
parse(input, version: 2, output_version: output_version || 2, **options)
|
40
|
+
rescue => e
|
41
|
+
parse(input, version: 1, output_version: output_version || 1, **options) rescue raise e
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.output_module(version)
|
45
|
+
case version
|
46
|
+
when 1 then KDL::V1
|
47
|
+
when 2 then KDL
|
48
|
+
else
|
49
|
+
warn "Unknown output_version `#{version}', defaulting to v2"
|
50
|
+
KDL
|
51
|
+
end
|
13
52
|
end
|
14
53
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kdl
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Danielle Smith
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-12-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: racc
|
@@ -92,6 +92,7 @@ files:
|
|
92
92
|
- lib/kdl/kdl.tab.rb
|
93
93
|
- lib/kdl/kdl.yy
|
94
94
|
- lib/kdl/node.rb
|
95
|
+
- lib/kdl/parser_common.rb
|
95
96
|
- lib/kdl/string_dumper.rb
|
96
97
|
- lib/kdl/tokenizer.rb
|
97
98
|
- lib/kdl/types.rb
|
@@ -116,6 +117,14 @@ files:
|
|
116
117
|
- lib/kdl/types/url.rb
|
117
118
|
- lib/kdl/types/url_template.rb
|
118
119
|
- lib/kdl/types/uuid.rb
|
120
|
+
- lib/kdl/v1.rb
|
121
|
+
- lib/kdl/v1/document.rb
|
122
|
+
- lib/kdl/v1/kdl.tab.rb
|
123
|
+
- lib/kdl/v1/kdl.yy
|
124
|
+
- lib/kdl/v1/node.rb
|
125
|
+
- lib/kdl/v1/string_dumper.rb
|
126
|
+
- lib/kdl/v1/tokenizer.rb
|
127
|
+
- lib/kdl/v1/value.rb
|
119
128
|
- lib/kdl/value.rb
|
120
129
|
- lib/kdl/version.rb
|
121
130
|
homepage: https://kdl.dev
|
@@ -133,14 +142,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
133
142
|
requirements:
|
134
143
|
- - ">="
|
135
144
|
- !ruby/object:Gem::Version
|
136
|
-
version:
|
145
|
+
version: 3.1.0
|
137
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
138
147
|
requirements:
|
139
148
|
- - ">="
|
140
149
|
- !ruby/object:Gem::Version
|
141
150
|
version: '0'
|
142
151
|
requirements: []
|
143
|
-
rubygems_version: 3.5.
|
152
|
+
rubygems_version: 3.5.22
|
144
153
|
signing_key:
|
145
154
|
specification_version: 4
|
146
155
|
summary: KDL Document Language
|