rng 0.3.6 → 0.3.7
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 +4 -4
- data/lib/rng/external_ref_resolver.rb +2 -1
- data/lib/rng/rnc_parser.rb +4 -2
- data/lib/rng/rnc_to_rng_converter.rb +1 -1
- data/lib/rng/version.rb +1 -1
- data/spec/rng/rnc_parser_spec.rb +97 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 64d22a32278b59bf3f6913561453c616ac39c259f4ffded1b200efddc50461af
|
|
4
|
+
data.tar.gz: 1fc2453376a3f7f65aa717beb3707e54ff1bdc751ae528ce8132e3f18720cf2b
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dc8735cc2a8a3ae46635100a30ee39e114c762b9bace21955e2d361ad8bcbf65e0a0f10102f81085fea19a13d377ad93e1ac5313c8ae56a3237171712de7f965
|
|
7
|
+
data.tar.gz: 3ac117095690e1065a10921f4093072f151c84454cc0439fcd4a21764978654b8e5963f548969d92d76efb70c9ecca674984aa38fdc3a67cd3bb72c0924d394c
|
|
@@ -235,7 +235,8 @@ module Rng
|
|
|
235
235
|
obj.map { |o| deep_dup(o) }
|
|
236
236
|
when Hash
|
|
237
237
|
obj.each_with_object({}) { |(k, v), h| h[deep_dup(k)] = deep_dup(v) }
|
|
238
|
-
when NilClass, Symbol, Numeric, TrueClass, FalseClass
|
|
238
|
+
when NilClass, Symbol, Numeric, TrueClass, FalseClass,
|
|
239
|
+
Lutaml::Model::UninitializedClass # can't dup instance of singleton
|
|
239
240
|
obj
|
|
240
241
|
else
|
|
241
242
|
obj.dup
|
data/lib/rng/rnc_parser.rb
CHANGED
|
@@ -51,8 +51,9 @@ module Rng
|
|
|
51
51
|
end
|
|
52
52
|
|
|
53
53
|
# Character escapes for strings: \", \\, \n, \r, \t, and RELAX NG class escapes: \i, \c, \d, \w
|
|
54
|
+
# Any other \X sequence is preserved literally (e.g., \+, \-, \. in regex patterns)
|
|
54
55
|
rule(:char_escape) do
|
|
55
|
-
str('\\') >> match('["\\\\ntricdw]').as(:char)
|
|
56
|
+
str('\\') >> (match('["\\\\ntricdw]') | match('[^x]')).as(:char)
|
|
56
57
|
end
|
|
57
58
|
|
|
58
59
|
# Identifier can contain regular chars, dots, hex escapes, or backslash escapes
|
|
@@ -407,7 +408,8 @@ module Rng
|
|
|
407
408
|
|
|
408
409
|
# Choice is handled at content level, not as separate pattern
|
|
409
410
|
rule(:content_item) do
|
|
410
|
-
|
|
411
|
+
(doc_comments >> whitespace).maybe >>
|
|
412
|
+
annotations.maybe >>
|
|
411
413
|
(element_def | attribute_def |
|
|
412
414
|
# Datatype subtraction: identifier - ( value|identifier|choice|annotated )
|
|
413
415
|
(identifier.as(:datatype_name) >>
|
|
@@ -394,7 +394,7 @@ module Rng
|
|
|
394
394
|
elsif part[:char_escape]
|
|
395
395
|
# Map character escape
|
|
396
396
|
char = extract_string(part[:char_escape][:char])
|
|
397
|
-
CHAR_ESCAPE_MAP[char] || char
|
|
397
|
+
CHAR_ESCAPE_MAP[char] || "\\#{char}"
|
|
398
398
|
elsif part[:backslash_escape]
|
|
399
399
|
# Backslash escape in identifier: \x -> x
|
|
400
400
|
if part[:backslash_escape][:escaped_backslash]
|
data/lib/rng/version.rb
CHANGED
data/spec/rng/rnc_parser_spec.rb
CHANGED
|
@@ -415,6 +415,103 @@ RSpec.describe Rng::RncParser do
|
|
|
415
415
|
end
|
|
416
416
|
end
|
|
417
417
|
|
|
418
|
+
context 'with named pattern after ## comment' do
|
|
419
|
+
let(:input) do
|
|
420
|
+
<<~RNC
|
|
421
|
+
document =
|
|
422
|
+
element document {
|
|
423
|
+
## test 1
|
|
424
|
+
test
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
test =
|
|
428
|
+
element sections {
|
|
429
|
+
attribute test { text }?
|
|
430
|
+
}
|
|
431
|
+
RNC
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
let(:grammar) { described_class.parse(input) }
|
|
435
|
+
|
|
436
|
+
it 'parses without error' do
|
|
437
|
+
expect { grammar }.not_to raise_error
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
it 'contains the element document' do
|
|
441
|
+
expect(grammar.define.map(&:name)).to include('document')
|
|
442
|
+
document_def = grammar.define.find { |d| d.name == 'document' }
|
|
443
|
+
expect(document_def.element[0].attr_name).to eq('document')
|
|
444
|
+
end
|
|
445
|
+
|
|
446
|
+
it 'contains the element sections' do
|
|
447
|
+
expect(grammar.define.map(&:name)).to include('test')
|
|
448
|
+
test_def = grammar.define.find { |d| d.name == 'test' }
|
|
449
|
+
expect(test_def.element[0].attr_name).to eq('sections')
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
|
|
453
|
+
context 'with escape sequences in string literals' do
|
|
454
|
+
it 'parses known escapes (\\n, \\t, \\r, \\", \\\\)' do
|
|
455
|
+
input = <<~'RNC'
|
|
456
|
+
start = element value {
|
|
457
|
+
xsd:string { pattern = "hello\nworld\ttab\r\n" }
|
|
458
|
+
}
|
|
459
|
+
RNC
|
|
460
|
+
expect { described_class.parse(input) }.not_to raise_error
|
|
461
|
+
end
|
|
462
|
+
|
|
463
|
+
it 'parses RELAX NG class escapes (\\i, \\c, \\d, \\w)' do
|
|
464
|
+
input = <<~'RNC'
|
|
465
|
+
start = element value {
|
|
466
|
+
xsd:string { pattern = "\\i\\c\\d\\w" }
|
|
467
|
+
}
|
|
468
|
+
RNC
|
|
469
|
+
expect { described_class.parse(input) }.not_to raise_error
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
it 'parses unknown escape sequences (\\+, \\-, \\s, \\., \\,) preserving backslash' do
|
|
473
|
+
input = <<~'RNC'
|
|
474
|
+
start = element value {
|
|
475
|
+
xsd:string { pattern = "[\\+\\-]?\\d{4}" }
|
|
476
|
+
}
|
|
477
|
+
RNC
|
|
478
|
+
expect { described_class.parse(input) }.not_to raise_error
|
|
479
|
+
end
|
|
480
|
+
|
|
481
|
+
it 'parses ISO 8601 regex pattern with multiple escape sequences' do
|
|
482
|
+
input = <<~'RNC'
|
|
483
|
+
ISO8601DateTime = xsd:string { pattern = "([\\+\\-]?\\d{4})((-?)((0[1-9]|1[0-2])((-?)([12]\\d|0[1-9]|3[01]))?|W([0-4]\\d|5[0-2])(-?[1-7])?|(00[1-9]|0[1-9]\\d|[12]\\d{2}|3([0-5]\\d|6[1-6])))([T\\s]((([01]\\d|2[0-3])((:?)[0-5]\\d)?|24:?00)([\\.,]\\d+)?)?((:?)[0-5]\\d([.,]\\d+)?)?([zZ]|([\\+\\-])([01]\\d|2[0-3]):?([0-5]\\d)?)?)?)?)?)?" }
|
|
484
|
+
elem = element elem { ISO8601DateTime }
|
|
485
|
+
RNC
|
|
486
|
+
expect { described_class.parse(input) }.not_to raise_error
|
|
487
|
+
end
|
|
488
|
+
|
|
489
|
+
it 'rejects invalid hex escape \\x{}' do
|
|
490
|
+
# Single-quoted heredoc: \x{} is literal \x{} (one backslash)
|
|
491
|
+
input = <<~'RNC'
|
|
492
|
+
start = element value {
|
|
493
|
+
xsd:string { pattern = "\x{}" }
|
|
494
|
+
}
|
|
495
|
+
RNC
|
|
496
|
+
expect do
|
|
497
|
+
described_class.parse(input)
|
|
498
|
+
end.to raise_error(Parslet::ParseFailed)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
it 'round-trips unknown escape sequences preserving backslash' do
|
|
502
|
+
rnc_input = <<~'RNC'
|
|
503
|
+
start = element value {
|
|
504
|
+
xsd:string { pattern = "[\\+\\-]?\\d{4}" }
|
|
505
|
+
}
|
|
506
|
+
RNC
|
|
507
|
+
grammar = described_class.parse(rnc_input)
|
|
508
|
+
rnc_output = described_class.to_rnc(grammar)
|
|
509
|
+
expect(rnc_output).to include('\\+')
|
|
510
|
+
expect(rnc_output).to include('\\-')
|
|
511
|
+
expect(rnc_output).to include('\\d')
|
|
512
|
+
end
|
|
513
|
+
end
|
|
514
|
+
|
|
418
515
|
context 'with except patterns in anyName' do
|
|
419
516
|
let(:input) do
|
|
420
517
|
<<~RNC
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: rng
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.3.
|
|
4
|
+
version: 0.3.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ribose
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-05-
|
|
11
|
+
date: 2026-05-29 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: lutaml-model
|