lutaml-model 0.8.48 → 0.8.49

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: a482362c928135d0733413ae200b20e5a9a7f05af8faf57696bc4461b093d691
4
- data.tar.gz: 3b22e8a6881ad4a832d90a6b064d6999a5e5b8a969d507fd467d44c66f7c0279
3
+ metadata.gz: 2dab1dcbc2ea77cfd1c61d9ffba4717521b9e97e1f3f6c8dd6f9ce6c7014222f
4
+ data.tar.gz: ed16efadd94ce85b9e52a5c7de822f9c7de7e3c581203280120630e8cdb389ff
5
5
  SHA512:
6
- metadata.gz: a6047ddb9f43fa9a7012e794070891a0d997ca261f2c76f324223a1c1414bab39f1f05b5f627ecde1e21a083b971c4cc002d15928db410e97411b5dcca9a5b97
7
- data.tar.gz: b849ae1daa34c19f6f570d1389a2ea43cf3af5ffba5db32bdef33e53a0b7ba960736b511ecfc5f520a926690134a4247227b1fa7a437923a8774a511569f6e88
6
+ metadata.gz: cd6bbdebb2c812eb849774ac168fe2c194bc21113521be6b4ca8b389ab5f6ebb2743b951478077332a18a2c214f458962c0a89d54e1a26447b3b103b7c2bb153
7
+ data.tar.gz: fddad44bad334a640facc5f6869b91c2a12134da6c79e58b7bed1787e14c03702d5ffd0ffcece27e435fe2f9387a7d13040e45794d178424cd7e56acbf9bb36c
@@ -55,4 +55,50 @@ jobs:
55
55
  run: rake vendor:compile
56
56
 
57
57
  - name: Run performance benchmarks
58
- run: bundle exec rake performance:compare
58
+ run: bundle exec rake performance:compare
59
+ # TODO.max-perf/36: YJIT moves exactly the interpretive paths the
60
+ # model layer still runs. Sequential off/on probes on one runner give
61
+ # a directly comparable pair per commit - a measurement leg, not a
62
+ # gate. The plan fast path shrinks the YJIT win; watch both.
63
+ performance-yjit:
64
+ runs-on: ubuntu-latest
65
+ timeout-minutes: 15
66
+ steps:
67
+ - uses: actions/checkout@v6
68
+ with:
69
+ submodules: "recursive"
70
+
71
+ - name: Set up Ruby
72
+ uses: ruby/setup-ruby@v1
73
+ with:
74
+ ruby-version: '3.4'
75
+ bundler-cache: false
76
+
77
+ - name: Install ragel
78
+ run: sudo apt-get update && sudo apt-get install -y ragel
79
+
80
+ - name: Install ruby-ll (for rake vendor:prepare)
81
+ run: gem install ruby-ll --no-document
82
+
83
+ - name: Generate ragel / ruby-ll outputs in vendored forks
84
+ run: rake vendor:prepare
85
+
86
+ - name: Configure bundler
87
+ run: |
88
+ mkdir -p .bundle
89
+ echo "---" > .bundle/config
90
+ echo 'BUNDLE_BUILD__RUBY___LL: "--with-cflags=-std=gnu17"' >> .bundle/config
91
+
92
+ - name: Install dependencies
93
+ run: bundle install
94
+
95
+ - name: Compile liboga / libll native extensions
96
+ run: rake vendor:compile
97
+
98
+ - name: Probe YJIT off
99
+ run: bundle exec rake performance:probe
100
+
101
+ - name: Probe YJIT on
102
+ env:
103
+ RUBY_YJIT_ENABLE: "1"
104
+ run: bundle exec rake performance:probe
@@ -31,6 +31,36 @@ leptris and yeptris ship prebuilt platform gems for Linux and macOS
31
31
  every platform, including Windows. When a gem is absent, lutaml-model
32
32
  automatically falls back to the standard engine for that format.
33
33
 
34
+ == YJIT doubles the model pipeline
35
+
36
+ The model layer's own work — mapping dispatch, casts, hydration — is
37
+ plain Ruby and exactly the code shape YJIT compiles well; the native
38
+ engines' C work is unaffected either way. On a controlled runner
39
+ (ubuntu-latest, Ruby 3.4, the repository's performance probe):
40
+
41
+ |===
42
+ | op | YJIT off | YJIT on | change
43
+
44
+ | from_yaml | 75.1 i/s | 129.7 i/s | +73%
45
+ | to_yaml | 67.3 i/s | 145.1 i/s | +116%
46
+ | from_json | 73.2 i/s | 128.4 i/s | +75%
47
+ | to_json | 115.4 i/s | 255.5 i/s | +121%
48
+ |===
49
+
50
+ Enable it like any Ruby application does — this is the application's
51
+ call, never a gem's:
52
+
53
+ [source,sh]
54
+ ----
55
+ RUBY_YJIT_ENABLE=1 ruby app.rb
56
+ # or in code, before heavy work:
57
+ RubyVM::YJIT.enable
58
+ ----
59
+
60
+ The opt-in XML plan fast path (see below) moves work out of Ruby and
61
+ into the engine, which shrinks the YJIT win — enabling both is still
62
+ net faster than either alone.
63
+
34
64
  == Selecting adapters explicitly
35
65
 
36
66
  The engines register as ordinary adapter types, so explicit selection and
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Lutaml
4
4
  module Model
5
- VERSION = "0.8.48"
5
+ VERSION = "0.8.49"
6
6
  end
7
7
  end
@@ -200,7 +200,14 @@ module Lutaml
200
200
 
201
201
  def compilable_mapping?(mapping)
202
202
  mapping.root_element &&
203
- !(mapping.respond_to?(:root_mappings) && mapping.root_mappings)
203
+ !(mapping.respond_to?(:root_mappings) && mapping.root_mappings) &&
204
+ # lutaml-model#88: when_attribute partitions route same-name
205
+ # occurrences by attribute value — name-keyed plan rows would
206
+ # hydrate every occurrence into EVERY partition attribute
207
+ # (verified double-capture under the flag). The interpretive
208
+ # filter is the only correct path until the descriptor ABI
209
+ # grows row predicates.
210
+ mapping.mappings.none?(&:when_attribute?)
204
211
  end
205
212
 
206
213
  # Attribute for a rule — delegate rules resolve against their
@@ -517,6 +517,83 @@ RSpec.describe "XML plan fast path" do
517
517
  expect(model.to_xml).to eq(interpretive)
518
518
  end
519
519
 
520
+ # lutaml-model#88: name-keyed plan rows would hydrate every
521
+ # same-name occurrence into EVERY partition attribute (verified
522
+ # double-capture) — discriminator models must take the interpretive
523
+ # path, and a partitioned CHILD model must opt its parent out too.
524
+ it "falls back to the interpretive path for when_attribute models" do
525
+ component = Class.new(Lutaml::Model::Serializable) do
526
+ attribute :text, :string
527
+
528
+ xml do
529
+ element "component"
530
+ map_element "text", to: :text
531
+ end
532
+ end
533
+ stub_const("PlanFastPath::Component", component)
534
+
535
+ partitioned = Class.new(Lutaml::Model::Serializable) do
536
+ attribute :guidance, component, collection: true
537
+ attribute :purpose, component, collection: true
538
+
539
+ xml do
540
+ element "requirement"
541
+ map_element "component", when_attribute: "type",
542
+ to: { "guidance" => :guidance,
543
+ "purpose" => :purpose }
544
+ end
545
+ end
546
+ stub_const("PlanFastPath::Partitioned", partitioned)
547
+
548
+ req = partitioned.from_xml(<<~XML)
549
+ <requirement>
550
+ <component type="guidance"><text>g1</text></component>
551
+ <component type="purpose"><text>p1</text></component>
552
+ <component type="guidance"><text>g2</text></component>
553
+ </requirement>
554
+ XML
555
+
556
+ expect(req.guidance.map(&:text)).to eq(%w[g1 g2])
557
+ expect(req.purpose.map(&:text)).to eq(["p1"])
558
+
559
+ expect(Lutaml::Xml::PlanCompiler.compile(partitioned,
560
+ :default)).to be_nil
561
+ end
562
+
563
+ it "opts a parent out when a child model partitions with when_attribute" do
564
+ component = Class.new(Lutaml::Model::Serializable) do
565
+ attribute :text, :string
566
+
567
+ xml do
568
+ element "component"
569
+ map_element "text", to: :text
570
+ end
571
+ end
572
+ inner = Class.new(Lutaml::Model::Serializable) do
573
+ attribute :guidance, component, collection: true
574
+
575
+ xml do
576
+ element "req"
577
+ map_element "component", to: :guidance,
578
+ when_attribute: { "type" => "guidance" }
579
+ end
580
+ end
581
+ outer = Class.new(Lutaml::Model::Serializable) do
582
+ attribute :req, inner
583
+
584
+ xml do
585
+ element "holder"
586
+ map_element "req", to: :req
587
+ end
588
+ end
589
+ stub_const("PlanFastPath::Nested", outer)
590
+
591
+ doc = outer.from_xml(
592
+ "<holder><req><component type=\"guidance\"><text>g1</text></component></req></holder>",
593
+ )
594
+ expect(doc.req.guidance.map(&:text)).to eq(["g1"])
595
+ end
596
+
520
597
  it "round-trips through both fast paths" do
521
598
  item = Class.new(Lutaml::Model::Serializable) do
522
599
  attribute :id, :integer
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: lutaml-model
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.48
4
+ version: 0.8.49
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ribose Inc.