kdl 1.0.6 → 2.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby.yml +8 -1
  3. data/.gitignore +1 -0
  4. data/.gitmodules +4 -0
  5. data/Gemfile +6 -1
  6. data/README.md +67 -7
  7. data/Rakefile +6 -1
  8. data/bin/kdl +1 -1
  9. data/kdl.gemspec +2 -2
  10. data/lib/kdl/document.rb +60 -2
  11. data/lib/kdl/error.rb +24 -0
  12. data/lib/kdl/kdl.tab.rb +305 -231
  13. data/lib/kdl/kdl.yy +57 -49
  14. data/lib/kdl/node.rb +116 -13
  15. data/lib/kdl/parser_common.rb +28 -0
  16. data/lib/kdl/string_dumper.rb +32 -33
  17. data/lib/kdl/tokenizer.rb +387 -136
  18. data/lib/kdl/types/base64.rb +3 -1
  19. data/lib/kdl/types/country/iso3166_countries.rb +3 -1
  20. data/lib/kdl/types/country/iso3166_subdivisions.rb +3 -1
  21. data/lib/kdl/types/country.rb +4 -2
  22. data/lib/kdl/types/currency/iso4217_currencies.rb +3 -1
  23. data/lib/kdl/types/currency.rb +3 -1
  24. data/lib/kdl/types/date_time.rb +5 -3
  25. data/lib/kdl/types/decimal.rb +3 -1
  26. data/lib/kdl/types/duration/iso8601_parser.rb +3 -1
  27. data/lib/kdl/types/duration.rb +3 -1
  28. data/lib/kdl/types/email/parser.rb +10 -8
  29. data/lib/kdl/types/email.rb +3 -1
  30. data/lib/kdl/types/hostname/validator.rb +3 -1
  31. data/lib/kdl/types/hostname.rb +3 -1
  32. data/lib/kdl/types/ip.rb +3 -1
  33. data/lib/kdl/types/irl/parser.rb +10 -8
  34. data/lib/kdl/types/irl.rb +3 -1
  35. data/lib/kdl/types/regex.rb +3 -1
  36. data/lib/kdl/types/url.rb +3 -1
  37. data/lib/kdl/types/url_template.rb +6 -4
  38. data/lib/kdl/types/uuid.rb +3 -1
  39. data/lib/kdl/types.rb +2 -0
  40. data/lib/kdl/v1/document.rb +19 -0
  41. data/lib/kdl/v1/kdl.tab.rb +594 -0
  42. data/lib/kdl/v1/kdl.yy +89 -0
  43. data/lib/kdl/v1/node.rb +32 -0
  44. data/lib/kdl/v1/string_dumper.rb +30 -0
  45. data/lib/kdl/v1/tokenizer.rb +298 -0
  46. data/lib/kdl/v1/value.rb +91 -0
  47. data/lib/kdl/v1.rb +13 -0
  48. data/lib/kdl/value.rb +87 -15
  49. data/lib/kdl/version.rb +3 -1
  50. data/lib/kdl.rb +47 -1
  51. metadata +14 -7
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: def27c3b00371120b10ced4e07cf10500c2e1968d4912d0fb17b925989292e1d
4
- data.tar.gz: e3cbf6c787d14fecc6c746826b299ffac1a553be7fca8de12f93c53727568d12
3
+ metadata.gz: 323bc0f1637f5dea4aaa671d7582c87118d8a7500557fbbec5907d34082d0914
4
+ data.tar.gz: abd85e1a66342b328ad9da3946a14565ee300a0f5e77c5c5418cbc931cf8fe38
5
5
  SHA512:
6
- metadata.gz: 0235d846c7c031867ff0141cca46e56c156c093a6d33529156c833319ee1dbf95a25c7f2ad117884278b1a8c17495bddb6a29ecacfdea54d4ae0be4d4d52f96d
7
- data.tar.gz: d6916fc08c7f66441ee9b96660602e8fc40ddb3e0e2bd1278e55a51826d9f2edd0c402c70e0d4d10e7513f2f17e81d5b30f0223c1f9a33b1196ebcad9f4404a4
6
+ metadata.gz: 9fafe1a9343387a093c324f84cccd47378a635c950f9892b9456d23f2c75fe2341ebb68ea09e0043b0672430fc0c799fb13263447ddb4586539cd5f306357c4b
7
+ data.tar.gz: 3cf0863f0e7751890f394f7f5d759adf980ca7b4fec872c40a1b75f71a08e380681bc8ed93e917567bbab337281b4c03a1a8f34760bd9fa66aefd67187a59a0e
@@ -15,9 +15,10 @@ on:
15
15
 
16
16
  jobs:
17
17
  test:
18
+ continue-on-error: ${{ matrix.ruby == 'head' }}
18
19
  strategy:
19
20
  matrix:
20
- ruby: [2.5, 2.6, 2.7, 3.0, 3.1, 3.2, 3.3, head]
21
+ ruby: [3.1, 3.2, 3.3, 3.4, head]
21
22
 
22
23
  runs-on: ubuntu-latest
23
24
 
@@ -25,12 +26,18 @@ jobs:
25
26
  - uses: actions/checkout@v2
26
27
  with:
27
28
  submodules: true
29
+
28
30
  - name: Set up Ruby
29
31
  uses: ruby/setup-ruby@v1
30
32
  with:
31
33
  ruby-version: ${{ matrix.ruby }}
32
34
  bundler-cache: true # install and cache dependencies
35
+
33
36
  - name: Build parser
34
37
  run: bundle exec racc lib/kdl/kdl.yy
38
+
35
39
  - name: Run tests
36
40
  run: bundle exec rake test
41
+
42
+ - name: Report Coveralls
43
+ uses: coverallsapp/github-action@v2
data/.gitignore CHANGED
@@ -10,4 +10,5 @@
10
10
  Gemfile.lock
11
11
 
12
12
  lib/kdl/kdl.tab.rb
13
+ lib/kdl/v1/kdl.tab.rb
13
14
  kdl.output
data/.gitmodules CHANGED
@@ -1,3 +1,7 @@
1
1
  [submodule "test/kdl-org"]
2
2
  path = test/kdl-org
3
3
  url = git@github.com:kdl-org/kdl
4
+ [submodule "test/v1/kdl-org"]
5
+ path = test/v1/kdl-org
6
+ url = git@github.com:kdl-org/kdl
7
+ branch = release/v1
data/Gemfile CHANGED
@@ -4,4 +4,9 @@ source "https://rubygems.org"
4
4
  gemspec
5
5
 
6
6
  gem "rake", "~> 12.0"
7
- gem "minitest", "~> 5.0"
7
+
8
+ group :test do
9
+ gem "minitest", "~> 5.0"
10
+ gem "simplecov", require: false
11
+ gem "coveralls_reborn", require: false
12
+ end
data/README.md CHANGED
@@ -1,6 +1,8 @@
1
1
  # KDL
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/kdl.svg)](https://badge.fury.io/rb/kdl)
3
4
  [![Actions Status](https://github.com/danini-the-panini/kdl-rb/workflows/Ruby/badge.svg)](https://github.com/danini-the-panini/kdl-rb/actions)
5
+ [![Coverage Status](https://coveralls.io/repos/github/danini-the-panini/kdl-rb/badge.svg?branch=main)](https://coveralls.io/github/danini-the-panini/kdl-rb?branch=main)
4
6
 
5
7
  This is a Ruby implementation of the [KDL Document Language](https://kdl.dev)
6
8
 
@@ -25,22 +27,80 @@ Or install it yourself as:
25
27
  ```ruby
26
28
  require 'kdl'
27
29
 
28
- KDL.parse_document(a_string) #=> KDL::Document
30
+ KDL.parse(a_string) #=> KDL::Document
31
+ KDL.load_file('path/to/file') #=> KDL::Document
29
32
  ```
30
33
 
31
34
  You can optionally provide your own type annotation handlers:
32
35
 
33
36
  ```ruby
34
- KDL.parse_document(a_string, type_parsers: {
35
- 'foo' => -> (value, type) {
36
- Foo.new(value.value, type: type)
37
- }
37
+ class Foo < KDL::Value::Custom
38
+ end
39
+
40
+ KDL.parse(a_string, type_parsers: {
41
+ 'foo' => Foo
38
42
  })
39
43
  ```
40
44
 
41
- The `foo` proc will be called with instances of Value or Node with the type annotation `(foo)`.
45
+ The `foo` custom type will be called with instances of Value or Node with the type annotation `(foo)`.
46
+
47
+ Custom types are expected to have a `call` method that takes the Value or Node, and the type annotation itself, as arguments, and is expected to return either an instance of `KDL::Value::Custom` or `KDL::Node::Custom` (depending on the input type) or `nil` to return the original value as is. Take a look at [the built in custom types](lib/kdl/types) as a reference.
48
+
49
+ You can also disable type annotation parsing entirely (including the built in ones):
50
+
51
+ ```ruby
52
+ KDL.parse(a_string, parse_types: false)
53
+ ```
54
+
55
+ ## KDL v1
56
+
57
+ kdl-rb maintains backwards compatibility with the KDL v1 spec. By default, KDL will attempt to parse a file with the v1 parser if it fails to parse with v2. This behaviour can be changed by specifying the `version` option:
58
+
59
+ ```ruby
60
+ KDL.parse(a_string, version: 2)
61
+ ```
62
+
63
+ The resulting document will also serialize back to the same version it was parsed as. For example, if you parse a v2 document and call `to_s` on it, it will output a v2 document, and similarly with v1. This behaviour can be changed by specifying the `output_version` option:
64
+
65
+ ```ruby
66
+ KDL.parse(a_string, output_version: 2)
67
+ ```
68
+
69
+ This allows you to to convert documents between versions:
70
+
71
+ ```ruby
72
+ KDL.parse('foo "bar" true', version: 1, output_version: 2).to_s #=> 'foo bar #true'
73
+ ```
74
+
75
+ You can also convert an already parsed document between versions with `to_v1` and `to_v2`:
42
76
 
43
- Parsers are expected to have a `call` method that takes the Value or Node, and the type annotation itself, as arguments, and is expected to return either an instance of Value or Node (depending on the input type) or `nil` to return the original value as is. Take a look at [the built in parsers](lib/kdl/types) as a reference.
77
+ ```ruby
78
+ doc = KDL.parse('foo "bar" true', version: 1)
79
+ doc.version #=> 1
80
+ doc.to_v2.to_s #=> 'foo bar #true'
81
+ ```
82
+
83
+ You can also set the default version globally:
84
+
85
+ ```ruby
86
+ KDL.default_version = 2
87
+ KDL.default_output_version = 2
88
+ ```
89
+
90
+ You can still force automatic version detection with `auto_parse`:
91
+
92
+ ```ruby
93
+ KDL.default_version = 2
94
+ KDL.parse('foo "bar" true') #=> Error
95
+ KDL.auto_parse('foo "bar" true') #=> KDL::V1::Document
96
+ ```
97
+
98
+ Version directives are also respected:
99
+
100
+ ```ruby
101
+ KDL.parse("/- kdl-version 2\nfoo bar", version: 1)
102
+ #=> Version mismatch, document specified v2, but this is a v1 parser (Racc::ParseError)
103
+ ```
44
104
 
45
105
  ## Development
46
106
 
data/Rakefile CHANGED
@@ -6,7 +6,12 @@ file 'lib/kdl/kdl.tab.rb' => ['lib/kdl/kdl.yy'] do
6
6
  end
7
7
  task :racc => 'lib/kdl/kdl.tab.rb'
8
8
 
9
- Rake::TestTask.new(:test => :racc) do |t|
9
+ file 'lib/kdl/v1/kdl.tab.rb' => ['lib/kdl/v1/kdl.yy'] do
10
+ raise "racc command failed (v1)" unless system 'bin/racc lib/kdl/v1/kdl.yy'
11
+ end
12
+ task :racc_v1 => 'lib/kdl/v1/kdl.tab.rb'
13
+
14
+ Rake::TestTask.new(:test => [:racc, :racc_v1]) do |t|
10
15
  t.libs << 'test'
11
16
  t.libs << 'lib'
12
17
  t.test_files = FileList['test/**/*_test.rb']
data/bin/kdl CHANGED
@@ -5,4 +5,4 @@ require "kdl"
5
5
 
6
6
  system 'bin/rake racc'
7
7
 
8
- puts KDL.parse_document(ARGF.read).to_s
8
+ puts KDL.parse(ARGF.read).to_s
data/kdl.gemspec CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
10
10
  spec.description = %q{Ruby implementation of the KDL Document Language Spec}
11
11
  spec.homepage = "https://kdl.dev"
12
12
  spec.license = "MIT"
13
- spec.required_ruby_version = Gem::Requirement.new(">= 2.5.0")
13
+ spec.required_ruby_version = Gem::Requirement.new(">= 3.1.0")
14
14
 
15
15
  spec.metadata["homepage_uri"] = spec.homepage
16
16
  spec.metadata["source_code_uri"] = "https://github.com/danini-the-panini/kdl-rb"
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
20
20
  # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
21
21
  spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
22
22
  `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
23
- end + ['lib/kdl/kdl.tab.rb']
23
+ end + ['lib/kdl/kdl.tab.rb', 'lib/kdl/v1/kdl.tab.rb']
24
24
  spec.bindir = "exe"
25
25
  spec.require_paths = ["lib"]
26
26
 
data/lib/kdl/document.rb CHANGED
@@ -1,13 +1,59 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module KDL
2
4
  class Document
5
+ include Enumerable
6
+
3
7
  attr_accessor :nodes
4
-
8
+
5
9
  def initialize(nodes)
6
10
  @nodes = nodes
7
11
  end
8
12
 
13
+ def [](key)
14
+ case key
15
+ when Integer
16
+ nodes[key]
17
+ when String, Symbol
18
+ nodes.find { _1.name == key.to_s }
19
+ else
20
+ raise ArgumentError, "document can only be indexed by Integer, String, or Symbol"
21
+ end
22
+ end
23
+
24
+ def arg(key)
25
+ self[key]&.arguments&.first&.value
26
+ end
27
+
28
+ def args(key)
29
+ self[key]&.arguments&.map(&:value)
30
+ end
31
+
32
+ def each_arg(key, &block)
33
+ args(key)&.each(&block)
34
+ end
35
+
36
+ def dash_vals(key)
37
+ self[key]
38
+ &.children
39
+ &.select { _1.name == "-" }
40
+ &.map { _1.arguments.first&.value }
41
+ end
42
+
43
+ def each_dash_val(key, &block)
44
+ dash_vals(key)&.each(&block)
45
+ end
46
+
47
+ def each(&block)
48
+ nodes.each(&block)
49
+ end
50
+
9
51
  def to_s
10
- @nodes.map(&:to_s).join("\n") + "\n"
52
+ nodes.map(&:to_s).join("\n") + "\n"
53
+ end
54
+
55
+ def inspect
56
+ nodes.map(&:inspect).join("\n") + "\n"
11
57
  end
12
58
 
13
59
  def ==(other)
@@ -15,5 +61,17 @@ module KDL
15
61
 
16
62
  nodes == other.nodes
17
63
  end
64
+
65
+ def version
66
+ 2
67
+ end
68
+
69
+ def to_v2
70
+ self
71
+ end
72
+
73
+ def to_v1
74
+ KDL::V1::Document.new(nodes.map(&:to_v1))
75
+ end
18
76
  end
19
77
  end
data/lib/kdl/error.rb ADDED
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module KDL
4
+ class Error < StandardError; end
5
+
6
+ class VersionMismatchError < Error
7
+ attr_reader :version, :parser_version
8
+
9
+ def initialize(message, version = nil, parser_version = nil)
10
+ super(message)
11
+ @version = version
12
+ @parser_version = parser_version
13
+ end
14
+ end
15
+
16
+ class UnsupportedVersionError < Error
17
+ attr_reader :version
18
+
19
+ def initialize(message, version = nil)
20
+ super(message)
21
+ @version = version
22
+ end
23
+ end
24
+ end