lutaml-model 0.8.174 → 0.8.175

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: d5c88e0fabb05c803bd90e90e239491b158506fbc28a400a5c622947c6b6660f
4
- data.tar.gz: 6963e7357fb635c514dcb65844ca6fba6a72e4db19a254b744dcc43ac38ddade
3
+ metadata.gz: '0658d10c7cba33a11cf0dfbc7105bb1be8661e99a9806800cd967ac2d7b1eff0'
4
+ data.tar.gz: 3964a62ce7c8bda8b35fc957df765bad29074a9f16f82117b3a421373cd43d9c
5
5
  SHA512:
6
- metadata.gz: aac56768d97444e04fe6e92ff1c9e4802daf1dc2d974028a972245db3b83b9c77d81993e13733393d2c0b6024329eb31cb4f36b5af1362c88c6faec41c734488
7
- data.tar.gz: b999e90b67a01d971f782e906863e35c3d17ed6da0fb1f37f2c757d473d27d1b30f7385903dd94d4f0bea8dfc88a3209be24f5b2a45c17a70362c9047912f05e
6
+ metadata.gz: 5494168be6927595ed23a594138ee347e0687d90c41bdba72309f942ea7079eb9cc3fd10c1b86579eb7f87ef5647962afc7304374d09cb5519fc6b6c11307f0b
7
+ data.tar.gz: fcc10b888f2712615ab14c826997f57f7ef1937bda9e0470fd87aff70eaa461e612f6dca7ca272890583a2374149bcc823eb4ba83bdc77a6b7fecd0e0c73ce16
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.174"
5
+ VERSION = "0.8.175"
6
6
  end
7
7
  end
@@ -90,16 +90,72 @@ module Lutaml
90
90
  end
91
91
  private_class_method :syntax_error
92
92
 
93
- # Dump rides the inherited standard (Psych) adapter — this class
94
- # does not override #to_yaml. The native Yeptris::Psych.dump
95
- # does not fold long plain scalars at Psych's 80-column
96
- # boundary, so an override here changes every stored fixture's
97
- # byte format the moment the native lane is selected (the
98
- # 0.8.171 default-flip broke relaton's SAE round-trip spec
99
- # exactly this way: parse parity landed in yeptris 0.6.57+,
100
- # dump folding did not — yeptris#863's remaining scope). Parse
101
- # keeps the native lane, where the parity is real; generation
102
- # returns here when the engine folds at parity.
93
+ # Dump rides the native Yeptris::Psych face when the engine's
94
+ # emitter is byte-parity with the standard adapter, else the
95
+ # inherited standard (Psych) dump. The contract: a stored
96
+ # fixture generated under one adapter must round-trip
97
+ # byte-exactly under the other, or a host whose bundle flips
98
+ # the default engine rewrites every stored YAML (the 0.8.171
99
+ # default-flip broke relaton's SAE suite exactly this way).
100
+ # Parity is capability-based, not version-based: the probe
101
+ # dumps the shape battery through the native face and the
102
+ # standard adapter and compares byte-for-byte. Plain-scalar
103
+ # folding landed in yeptris 0.6.62.1, bare null-valued keys
104
+ # after literal blocks in 0.6.63 (#1264); any engine that
105
+ # misses a shape keeps the standard dump without a version
106
+ # floor.
107
+ def to_yaml(_options = {})
108
+ return super unless self.class.native_dump_parity?
109
+
110
+ require "yeptris/psych"
111
+ Yeptris::Psych.dump(@attributes)
112
+ end
113
+
114
+ # True when the native emitter produces byte-identical output
115
+ # to the standard adapter across the shape battery (the same
116
+ # shapes the adapter spec pins: plain-scalar folding, null
117
+ # keys after literal blocks and quoted siblings, flow, unicode,
118
+ # nesting, multiline). Memoized; any failure — missing psych,
119
+ # engine error, non-parity bytes — reports false so dump rides
120
+ # the standard adapter.
121
+ def self.native_dump_parity?
122
+ return @native_dump_parity unless @native_dump_parity.nil?
123
+
124
+ @native_dump_parity = begin
125
+ require "yeptris/psych"
126
+ dump_parity_shapes.all? do |shape|
127
+ native = Yeptris::Psych.dump(shape)
128
+ # The comparison target is the literal parent class, not
129
+ # this class's to_yaml: the override routes back here
130
+ # while the probe is still unmemoized, recursing to a
131
+ # SystemStackError.
132
+ native == Lutaml::Yaml::Adapter::StandardAdapter.new(shape).to_yaml
133
+ end
134
+ rescue StandardError
135
+ false
136
+ end
137
+ end
138
+
139
+ # The document shapes whose byte treatment historically differs
140
+ # between emitters (leptris/yeptris#863, #1264). Keep in sync
141
+ # with the adapter spec's battery.
142
+ def self.dump_parity_shapes
143
+ [
144
+ {
145
+ "title" => "Taxonomy and Definitions for Terms Related to " \
146
+ "Driving Automation Systems for On-Road Motor " \
147
+ "Vehicles for On-Road Motor Vehicles",
148
+ "roles" => %w[admin dev],
149
+ },
150
+ { "s" => "line1\nline2", "n" => nil },
151
+ { "q" => "has: colon", "n" => nil },
152
+ { "u" => "héllo wörld", "num" => "007", "f" => 1.5, "e" => "" },
153
+ { "deep" => { "deeper" => [{ "x" => "y" }, [4, 5]] } },
154
+ { "multi" => "para one\n\npara two", "dash" => "a - b - c",
155
+ "omitted" => nil },
156
+ { "a" => 1, "b" => [1, 2, 3], "c" => { "d" => true } },
157
+ ]
158
+ end
103
159
  end
104
160
  end
105
161
  end
@@ -60,9 +60,12 @@ RSpec.describe Lutaml::Yaml::Adapter::YeptrisAdapter do
60
60
  # fixture generated under one adapter must round-trip byte-exactly
61
61
  # under the other, or a host whose bundle flips the default engine
62
62
  # rewrites every stored YAML (relaton's SAE suite caught the
63
- # 0.8.171 default flip this way — the native emitter does not fold
64
- # long plain scalars at Psych's 80-column boundary, so generation
65
- # rides the standard adapter until the engine folds at parity).
63
+ # 0.8.171 default flip this way). Generation rides the native face
64
+ # only when the adapter's capability probe (native_dump_parity?)
65
+ # finds the engine byte-identical across the shape battery —
66
+ # plain-scalar folding landed in yeptris 0.6.62.1, bare null keys
67
+ # after literal blocks in 0.6.63 (leptris/yeptris#863, #1264);
68
+ # engines that miss a shape keep the standard dump.
66
69
  describe "byte parity with the standard adapter" do
67
70
  let(:long_scalar) do
68
71
  "Taxonomy and Definitions for Terms Related to Driving Automation " \
@@ -72,14 +75,42 @@ RSpec.describe Lutaml::Yaml::Adapter::YeptrisAdapter do
72
75
  { "title" => long_scalar, "roles" => %w[admin dev] }
73
76
  end
74
77
 
75
- it "folds long plain scalars exactly like the standard adapter" do
76
- standard = Lutaml::Yaml::Adapter::StandardAdapter.new(wrapped_attributes).to_yaml
77
- expect(described_class.new(wrapped_attributes).to_yaml).to eq(standard)
78
+ # The same shapes the capability probe exercises in
79
+ # yeptris_adapter.rb — keep the two lists in sync.
80
+ let(:parity_shapes) do
81
+ [
82
+ wrapped_attributes,
83
+ { "s" => "line1\nline2", "n" => nil },
84
+ { "q" => "has: colon", "n" => nil },
85
+ { "u" => "héllo wörld", "num" => "007", "f" => 1.5, "e" => "" },
86
+ { "deep" => { "deeper" => [{ "x" => "y" }, [4, 5]] } },
87
+ { "multi" => "para one\n\npara two", "dash" => "a - b - c",
88
+ "omitted" => nil },
89
+ { "a" => 1, "b" => [1, 2, 3], "c" => { "d" => true } },
90
+ ]
78
91
  end
79
92
 
80
- it "parses the standard adapter's folded dump back identically" do
81
- standard = Lutaml::Yaml::Adapter::StandardAdapter.new(wrapped_attributes).to_yaml
82
- expect(described_class.parse(standard)).to eq(wrapped_attributes)
93
+ it "dumps every parity shape byte-identically to the standard adapter" do
94
+ parity_shapes.each do |shape|
95
+ standard = Lutaml::Yaml::Adapter::StandardAdapter.new(shape).to_yaml
96
+ expect(described_class.new(shape).to_yaml).to eq(standard)
97
+ end
98
+ end
99
+
100
+ it "parses the standard adapter's dumps back identically" do
101
+ parity_shapes.each do |shape|
102
+ standard = Lutaml::Yaml::Adapter::StandardAdapter.new(shape).to_yaml
103
+ expect(described_class.parse(standard)).to eq(shape)
104
+ end
105
+ end
106
+
107
+ it "opens the native dump lane when the engine answers the probe" do
108
+ skip "engine not fold-parity on this platform" unless
109
+ described_class.native_dump_parity?
110
+
111
+ first = parity_shapes.first
112
+ expect(described_class.new(first).to_yaml)
113
+ .to eq(Yeptris::Psych.dump(first))
83
114
  end
84
115
  end
85
116
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.174
4
+ version: 0.8.175
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2026-11-11 00:00:00.000000000 Z
11
+ date: 2026-11-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: base64