kdl 2.0.2 → 2.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: be3bacf1ec9d5292dfa518987c77b5d40eed8e67305bd4888118a633b8fa45f0
4
- data.tar.gz: 7da6c65eff791761f4ff0d36182fa98aa715359d301830c447b0717095061bea
3
+ metadata.gz: 24483470a3eb179aeb4a3e2e759693a4e818316cb7cb6c3b019b22b2318504af
4
+ data.tar.gz: 73ce32af9afa6ebcd4be7a73add2ee1077e08aad71425863b75b1581613a2628
5
5
  SHA512:
6
- metadata.gz: 0af1a1c13a2b88bdd2266f1ff5d057da2a26ea87027c64c5507054962564ac76e005927b4e69480da79a4ba16c55b2e749b9d30debd880e3cead808e66a8824d
7
- data.tar.gz: f707eea04e876c2c6c781203a2d00e5675f8ae8c414e48a4f9413f8f614eedaf208c0a5411481b24b756f6954b625fe37f2105a3de6d12ef79bc059d3eb8a60e
6
+ metadata.gz: b2ea10129c13825376583228ce0d5e91f888c89e6adb0787f02c1f046801d79809b0fa2997799b30237493b70717c1bc5423eefc360d07387333709157f6690b
7
+ data.tar.gz: fbbf3d6e8d148ab9a67855ed8751d31b1f28adc1a4798309c6dc6344d02042c655997ab9abfe833b32686f58cc1fb9da4024bb56e62794d14c7b0c1b201fedc4
@@ -0,0 +1,76 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDL
4
+ class Builder < BasicObject
5
+ class Error < ::KDL::Error; end
6
+
7
+ def initialize
8
+ @nesting = []
9
+ @document = Document.new
10
+ end
11
+
12
+ def document(&block)
13
+ yield if block
14
+ @document
15
+ end
16
+
17
+ def node(name = nil, *args, type: nil, **props, &block)
18
+ n = Node.new(name&.to_s || "node", type:)
19
+ @nesting << n
20
+ args.each do |value|
21
+ case value
22
+ when ::Hash
23
+ value.each { |k, v| prop k, v }
24
+ else arg value
25
+ end
26
+ end
27
+ props.each do |key, value|
28
+ prop key, value
29
+ end
30
+ yield if block
31
+ @nesting.pop
32
+ if parent = current_node
33
+ parent.children << n
34
+ else
35
+ @document << n
36
+ end
37
+ n
38
+ end
39
+ alias _ node
40
+
41
+ def arg(value, type: nil)
42
+ if n = current_node
43
+ val = Value.from(value)
44
+ val = val.as_type(type) if type
45
+ n.arguments << val
46
+ val
47
+ else
48
+ raise Error, "Can't do argument, not inside Node"
49
+ end
50
+ end
51
+
52
+ def prop(key, value, type: nil)
53
+ key = key.to_s
54
+ if n = current_node
55
+ val = Value.from(value)
56
+ val = val.as_type(type) if type
57
+ n.properties[key] = val
58
+ val
59
+ else
60
+ raise Error, "Can't do property, not inside Node"
61
+ end
62
+ end
63
+
64
+ def method_missing(name, *args, **props, &block)
65
+ node name, *args, **props, &block
66
+ end
67
+
68
+ private
69
+
70
+ def current_node
71
+ return nil if @nesting.empty?
72
+
73
+ @nesting.last
74
+ end
75
+ end
76
+ end
data/lib/kdl/document.rb CHANGED
@@ -6,7 +6,7 @@ module KDL
6
6
 
7
7
  attr_accessor :nodes
8
8
 
9
- def initialize(nodes)
9
+ def initialize(nodes = [])
10
10
  @nodes = nodes
11
11
  end
12
12
 
@@ -21,6 +21,10 @@ module KDL
21
21
  end
22
22
  end
23
23
 
24
+ def <<(node)
25
+ nodes << node
26
+ end
27
+
24
28
  def arg(key)
25
29
  self[key]&.arguments&.first&.value
26
30
  end
data/lib/kdl/error.rb CHANGED
@@ -1,13 +1,24 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KDL
4
- class Error < StandardError; end
4
+ class Error < StandardError
5
+ attr_reader :filename, :line, :column
6
+
7
+ def initialize(message, filename = nil, line = nil, column = nil)
8
+ message += " (#{line}:#{column})" if line
9
+ message = "#{[filename, line, column].compact.join(':')}: #{message}" if filename
10
+ super(message)
11
+ @filename = filename
12
+ @line = line
13
+ @column = column
14
+ end
15
+ end
5
16
 
6
17
  class VersionMismatchError < Error
7
18
  attr_reader :version, :parser_version
8
19
 
9
- def initialize(message, version = nil, parser_version = nil)
10
- super(message)
20
+ def initialize(message, version = nil, parser_version = nil, filename = nil)
21
+ super(message, filename, 1, 1)
11
22
  @version = version
12
23
  @parser_version = parser_version
13
24
  end
@@ -16,9 +27,11 @@ module KDL
16
27
  class UnsupportedVersionError < Error
17
28
  attr_reader :version
18
29
 
19
- def initialize(message, version = nil)
20
- super(message)
30
+ def initialize(message, version = nil, filename = nil)
31
+ super(message, filename, 1, 1)
21
32
  @version = version
22
33
  end
23
34
  end
35
+
36
+ class ParseError < Error; end
24
37
  end
data/lib/kdl/kdl.yy CHANGED
@@ -86,8 +86,8 @@ rule
86
86
  2
87
87
  end
88
88
 
89
- def parse(str)
90
- @tokenizer = ::KDL::Tokenizer.new(str)
89
+ def parse(str, filename: nil)
90
+ @tokenizer = ::KDL::Tokenizer.new(str, filename:)
91
91
  check_version
92
92
  do_parse
93
93
  end
data/lib/kdl/node.rb CHANGED
@@ -48,6 +48,10 @@ module KDL
48
48
  end
49
49
  end
50
50
 
51
+ def <<(node)
52
+ children << node
53
+ end
54
+
51
55
  def child(key)
52
56
  case key
53
57
  when Integer
@@ -21,8 +21,12 @@ module KDL
21
21
  def check_version
22
22
  return unless doc_version = @tokenizer.version_directive
23
23
  if doc_version != parser_version
24
- raise VersionMismatchError.new("Version mismatch, document specified v#{doc_version}, but this is a v#{parser_version} parser", doc_version, parser_version)
24
+ raise VersionMismatchError.new("version mismatch, document specified v#{doc_version}, but this is a v#{parser_version} parser", doc_version, parser_version)
25
25
  end
26
26
  end
27
+
28
+ def on_error(t, val, vstack)
29
+ raise KDL::ParseError.new("unexpected #{token_to_str(t)} #{val&.value.inspect}", @tokenizer.filename, val&.line, val&.column)
30
+ end
27
31
  end
28
32
  end
data/lib/kdl/tokenizer.rb CHANGED
@@ -4,12 +4,6 @@ require 'bigdecimal'
4
4
 
5
5
  module KDL
6
6
  class Tokenizer
7
- class Error < ::KDL::Error
8
- def initialize(message, line, column)
9
- super("#{message} (#{line}:#{column})")
10
- end
11
- end
12
-
13
7
  class Token
14
8
  attr_reader :type, :value, :line, :column, :meta
15
9
 
@@ -30,10 +24,9 @@ module KDL
30
24
  def to_s
31
25
  "#{value.inspect} (#{line}:#{column})"
32
26
  end
33
- alias inspect to_s
34
27
  end
35
28
 
36
- attr_reader :index
29
+ attr_reader :index, :filename
37
30
 
38
31
  SYMBOLS = {
39
32
  '{' => :LBRACE,
@@ -72,13 +65,14 @@ module KDL
72
65
 
73
66
  VERSION_PATTERN = /\A\/-[#{WHITESPACE.join}]*kdl-version[#{WHITESPACE.join}]+(\d+)[#{WHITESPACE.join}]*[#{NEWLINES.join}]/
74
67
 
75
- def initialize(str, start = 0)
68
+ def initialize(str, start = 0, filename: nil)
76
69
  @str = debom(str)
77
- @context = nil
78
- @rawstring_hashes = nil
79
70
  @start = start
80
71
  @index = start
81
72
  @buffer = +""
73
+ @filename = filename
74
+ @context = nil
75
+ @rawstring_hashes = nil
82
76
  @done = false
83
77
  @previous_context = nil
84
78
  @line = 1
@@ -201,7 +195,7 @@ module KDL
201
195
  traverse(1)
202
196
  end
203
197
  when '\\'
204
- t = Tokenizer.new(@str, @index + 1)
198
+ t = Tokenizer.new(@str, @index + 1, filename:)
205
199
  la = t.next_token
206
200
  if la[0] == :NEWLINE || la[0] == :EOF || (la[0] == :WS && (lan = t.next_token[0]) == :NEWLINE || lan == :EOF)
207
201
  traverse_to(t.index)
@@ -433,7 +427,7 @@ module KDL
433
427
  @comment_nesting = 1
434
428
  traverse(2)
435
429
  elsif c == "\\"
436
- t = Tokenizer.new(@str, @index + 1)
430
+ t = Tokenizer.new(@str, @index + 1, filename:)
437
431
  la = t.next_token
438
432
  if la[0] == :NEWLINE || la[0] == :EOF || (la[0] == :WS && (lan = t.next_token[0]) == :NEWLINE || lan == :EOF)
439
433
  traverse_to(t.index)
@@ -446,7 +440,7 @@ module KDL
446
440
  return token(:WS, -@buffer)
447
441
  end
448
442
  when :equals
449
- t = Tokenizer.new(@str, @index)
443
+ t = Tokenizer.new(@str, @index, filename:)
450
444
  la = t.next_token
451
445
  if la[0] == :WS
452
446
  @buffer << la[1].value
@@ -488,9 +482,9 @@ module KDL
488
482
 
489
483
  def raise_error(error)
490
484
  case error
491
- when String then raise Error.new(error, @line, @column)
485
+ when String then raise ParseError.new(error, @filename, @line, @column)
492
486
  when Error then raise error
493
- else raise Error.new(error.message, @line, @column)
487
+ else raise ParseError.new(error.message, @filename, @line, @column)
494
488
  end
495
489
  end
496
490
 
data/lib/kdl/v1/kdl.yy CHANGED
@@ -81,9 +81,9 @@ rule
81
81
  1
82
82
  end
83
83
 
84
- def parse(str, **options)
84
+ def parse(str, filename: nil, **options)
85
85
  init(**options)
86
- @tokenizer = ::KDL::V1::Tokenizer.new(str)
86
+ @tokenizer = ::KDL::V1::Tokenizer.new(str, filename:)
87
87
  check_version
88
88
  do_parse
89
89
  end
data/lib/kdl/v1/value.rb CHANGED
@@ -83,7 +83,7 @@ module KDL
83
83
  when ::Float then Float.new(value)
84
84
  when TrueClass, FalseClass then Boolean.new(value)
85
85
  when NilClass then Null
86
- else raise Error("Unsupported value type: #{value.class}")
86
+ else raise Error("unsupported value type: #{value.class}")
87
87
  end
88
88
  end
89
89
  end
data/lib/kdl/value.rb CHANGED
@@ -167,7 +167,7 @@ module KDL
167
167
  when ::Float then Float.new(value)
168
168
  when TrueClass, FalseClass then Boolean.new(value)
169
169
  when NilClass then Null
170
- else raise Error("Unsupported value type: #{value.class}")
170
+ else raise Error, "unsupported value type: #{value.class}"
171
171
  end
172
172
  end
173
173
  end
data/lib/kdl/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module KDL
4
- VERSION = "2.0.2"
4
+ VERSION = "2.1.0"
5
5
  end
data/lib/kdl.rb CHANGED
@@ -10,6 +10,7 @@ require "kdl/string_dumper"
10
10
  require "kdl/types"
11
11
  require "kdl/parser_common"
12
12
  require "kdl/kdl.tab"
13
+ require "kdl/builder"
13
14
  require "kdl/v1"
14
15
 
15
16
  module KDL
@@ -23,28 +24,30 @@ module KDL
23
24
  parse(input, **options)
24
25
  end
25
26
 
26
- def self.parse(input, version: default_version, output_version: default_output_version, **options)
27
+ def self.parse(input, version: default_version, output_version: default_output_version, filename: nil, **options)
27
28
  case version
28
29
  when 2
29
- Parser.new(output_module: output_module(output_version || 2), **options).parse(input)
30
+ Parser.new(output_module: output_module(output_version || 2), **options).parse(input, filename:)
30
31
  when 1
31
- V1::Parser.new.parse(input, output_module: output_module(output_version || 1), **options)
32
+ V1::Parser.new.parse(input, output_module: output_module(output_version || 1), filename:, **options)
32
33
  when nil
33
34
  auto_parse(input, output_version:, **options)
34
35
  else
35
- raise UnsupportedVersionError.new("Unsupported version '#{version}'", version)
36
+ raise UnsupportedVersionError.new("unsupported version '#{version}'", version)
36
37
  end
37
38
  end
38
39
 
39
40
  def self.load_file(filespec, **options)
40
- parse(File.read(filespec, encoding: Encoding::UTF_8), **options)
41
+ File.open(filespec, 'r:BOM|UTF-8') do |file|
42
+ parse(file.read, **options, filename: file.to_path)
43
+ end
41
44
  end
42
45
 
43
46
  def self.auto_parse(input, output_version: default_output_version, **options)
44
47
  parse(input, version: 2, output_version: output_version || 2, **options)
45
48
  rescue VersionMismatchError => e
46
49
  parse(input, version: e.version, output_version: output_version || e.version, **options)
47
- rescue Tokenizer::Error, Racc::ParseError => e
50
+ rescue ParseError => e
48
51
  parse(input, version: 1, output_version: output_version || 1, **options) rescue raise e
49
52
  end
50
53
 
@@ -53,8 +56,20 @@ module KDL
53
56
  when 1 then KDL::V1
54
57
  when 2 then KDL
55
58
  else
56
- warn "Unknown output_version `#{version}', defaulting to v2"
59
+ warn "[WARNING] Unknown output_version '#{version}', defaulting to v2"
57
60
  KDL
58
61
  end
59
62
  end
63
+
64
+ def self.build(&block)
65
+ builder = Builder.new
66
+ if block.arity >= 1
67
+ builder.document do
68
+ yield builder
69
+ end
70
+ else
71
+ builder.instance_exec(&block)
72
+ builder.document
73
+ end
74
+ end
60
75
  end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: kdl
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.2
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Danielle Smith
8
8
  bindir: exe
9
9
  cert_chain: []
10
- date: 2025-01-29 00:00:00.000000000 Z
10
+ date: 2025-09-04 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
13
  name: racc
@@ -87,6 +87,7 @@ files:
87
87
  - bin/setup
88
88
  - kdl.gemspec
89
89
  - lib/kdl.rb
90
+ - lib/kdl/builder.rb
90
91
  - lib/kdl/document.rb
91
92
  - lib/kdl/error.rb
92
93
  - lib/kdl/kdl.tab.rb