lutaml-model 0.8.14 → 0.8.16
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/.rubocop_todo.yml +14 -73
- data/Gemfile +3 -5
- data/README.adoc +188 -25
- data/docs/_guides/xml-mapping.adoc +178 -24
- data/docs/_pages/importable_models.adoc +7 -1
- data/lib/lutaml/jsonld/transform.rb +44 -13
- data/lib/lutaml/model/attribute.rb +4 -0
- data/lib/lutaml/model/liquefiable.rb +9 -0
- data/lib/lutaml/model/liquid/indexed_access.rb +33 -0
- data/lib/lutaml/model/liquid.rb +1 -0
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +2 -1
- data/lib/lutaml/rdf/mapping.rb +10 -1
- data/lib/lutaml/rdf/member_rule.rb +29 -4
- data/lib/lutaml/turtle/transform.rb +55 -35
- data/lib/lutaml/xml/adapter/plan_based_builder.rb +3 -1
- data/lib/lutaml/xml/adapter/xml_serializer.rb +15 -5
- data/lib/lutaml/xml/adapter.rb +2 -1
- data/lib/lutaml/xml/builder/base.rb +2 -1
- data/lib/lutaml/xml/data_model.rb +19 -3
- data/lib/lutaml/xml/mapping.rb +3 -1
- data/lib/lutaml/xml/mapping_rule.rb +28 -2
- data/lib/lutaml/xml/model_transform.rb +9 -1
- data/lib/lutaml/xml/serialization/instance_methods.rb +16 -9
- data/lib/lutaml/xml/transformation/element_builder.rb +1 -3
- data/lib/lutaml/xml/transformation/rule_applier.rb +21 -0
- data/lib/lutaml/xml/transformation/rule_compiler.rb +12 -3
- data/lutaml-model.gemspec +1 -1
- data/spec/lutaml/jsonld/transform_spec.rb +149 -0
- data/spec/lutaml/model/liquid/indexed_access_spec.rb +135 -0
- data/spec/lutaml/model/mixed_content_spec.rb +48 -7
- data/spec/lutaml/model/raw_element_spec.rb +533 -0
- data/spec/lutaml/rdf/mapping_spec.rb +71 -6
- data/spec/lutaml/rdf/member_rule_spec.rb +103 -1
- data/spec/lutaml/turtle/transform_spec.rb +144 -0
- metadata +9 -6
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "spec_helper"
|
|
4
|
+
require_relative "../../../lib/lutaml/rdf"
|
|
4
5
|
|
|
5
6
|
RSpec.describe Lutaml::Rdf::MemberRule do
|
|
6
7
|
describe ".new" do
|
|
@@ -26,10 +27,19 @@ RSpec.describe Lutaml::Rdf::MemberRule do
|
|
|
26
27
|
namespace: Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
27
28
|
expect(rule.predicate_name).to eq(:member)
|
|
28
29
|
end
|
|
30
|
+
|
|
31
|
+
it "raises ArgumentError when predicate_name and link both given" do
|
|
32
|
+
expect do
|
|
33
|
+
described_class.new(:items,
|
|
34
|
+
predicate_name: :member,
|
|
35
|
+
namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
|
|
36
|
+
link: "skos:member")
|
|
37
|
+
end.to raise_error(ArgumentError, /mutually exclusive/)
|
|
38
|
+
end
|
|
29
39
|
end
|
|
30
40
|
|
|
31
41
|
describe "#linked?" do
|
|
32
|
-
it "returns false when no
|
|
42
|
+
it "returns false when no linking option" do
|
|
33
43
|
rule = described_class.new(:items)
|
|
34
44
|
expect(rule.linked?).to be(false)
|
|
35
45
|
end
|
|
@@ -40,6 +50,16 @@ RSpec.describe Lutaml::Rdf::MemberRule do
|
|
|
40
50
|
namespace: Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
41
51
|
expect(rule.linked?).to be(true)
|
|
42
52
|
end
|
|
53
|
+
|
|
54
|
+
it "returns true when link is a String" do
|
|
55
|
+
rule = described_class.new(:items, link: "skos:member")
|
|
56
|
+
expect(rule.linked?).to be(true)
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "returns true when link is a Proc" do
|
|
60
|
+
rule = described_class.new(:items, link: ->(m) { "skos:#{m}" })
|
|
61
|
+
expect(rule.linked?).to be(true)
|
|
62
|
+
end
|
|
43
63
|
end
|
|
44
64
|
|
|
45
65
|
describe "#linked_predicate_uri" do
|
|
@@ -54,5 +74,87 @@ RSpec.describe Lutaml::Rdf::MemberRule do
|
|
|
54
74
|
namespace: Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
55
75
|
expect(rule.linked_predicate_uri).to eq("http://www.w3.org/2004/02/skos/core#member")
|
|
56
76
|
end
|
|
77
|
+
|
|
78
|
+
it "returns nil when link is a String (not static)" do
|
|
79
|
+
rule = described_class.new(:items, link: "skos:member")
|
|
80
|
+
expect(rule.linked_predicate_uri).to be_nil
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
describe "#link_predicate_for" do
|
|
85
|
+
let(:mapping) do
|
|
86
|
+
instance = Lutaml::Rdf::Mapping.new
|
|
87
|
+
instance.namespace(
|
|
88
|
+
Lutaml::Rdf::Namespaces::SkosNamespace,
|
|
89
|
+
Lutaml::Rdf::Namespaces::DctermsNamespace,
|
|
90
|
+
)
|
|
91
|
+
instance
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
let(:resolver) { mapping.namespace_set.method(:resolve_compact_iri) }
|
|
95
|
+
|
|
96
|
+
it "resolves String link via resolver" do
|
|
97
|
+
rule = described_class.new(:items, link: "skos:member")
|
|
98
|
+
expect(rule.link_predicate_for(nil, resolver))
|
|
99
|
+
.to eq("http://www.w3.org/2004/02/skos/core#member")
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "resolves Proc link by calling with member" do
|
|
103
|
+
rule = described_class.new(:items,
|
|
104
|
+
link: ->(m) { "skos:#{m.type}" })
|
|
105
|
+
member = Struct.new(:type).new("Concept")
|
|
106
|
+
expect(rule.link_predicate_for(member, resolver))
|
|
107
|
+
.to eq("http://www.w3.org/2004/02/skos/core#Concept")
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
it "returns URI as-is from Proc when prefix not found" do
|
|
111
|
+
rule = described_class.new(:items,
|
|
112
|
+
link: ->(m) { "http://example.org/#{m.id}" })
|
|
113
|
+
member = Struct.new(:id).new("42")
|
|
114
|
+
expect(rule.link_predicate_for(member, resolver))
|
|
115
|
+
.to eq("http://example.org/42")
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "returns nil when no link" do
|
|
119
|
+
rule = described_class.new(:items)
|
|
120
|
+
expect(rule.link_predicate_for(nil, resolver)).to be_nil
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
describe "#resolve_link_uri" do
|
|
125
|
+
let(:mapping) do
|
|
126
|
+
instance = Lutaml::Rdf::Mapping.new
|
|
127
|
+
instance.namespace(Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
128
|
+
instance
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
let(:resolver) { mapping.namespace_set.method(:resolve_compact_iri) }
|
|
132
|
+
|
|
133
|
+
it "uses linked_predicate_uri for static links" do
|
|
134
|
+
rule = described_class.new(:items,
|
|
135
|
+
predicate_name: :member,
|
|
136
|
+
namespace: Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
137
|
+
expect(rule.resolve_link_uri(nil, resolver))
|
|
138
|
+
.to eq("http://www.w3.org/2004/02/skos/core#member")
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "uses link_predicate_for for String links" do
|
|
142
|
+
rule = described_class.new(:items, link: "skos:member")
|
|
143
|
+
expect(rule.resolve_link_uri(nil, resolver))
|
|
144
|
+
.to eq("http://www.w3.org/2004/02/skos/core#member")
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it "uses link_predicate_for for Proc links" do
|
|
148
|
+
rule = described_class.new(:items,
|
|
149
|
+
link: ->(m) { "skos:#{m.type}" })
|
|
150
|
+
member = Struct.new(:type).new("Concept")
|
|
151
|
+
expect(rule.resolve_link_uri(member, resolver))
|
|
152
|
+
.to eq("http://www.w3.org/2004/02/skos/core#Concept")
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
it "returns nil when not linked" do
|
|
156
|
+
rule = described_class.new(:items)
|
|
157
|
+
expect(rule.resolve_link_uri(nil, resolver)).to be_nil
|
|
158
|
+
end
|
|
57
159
|
end
|
|
58
160
|
end
|
|
@@ -585,4 +585,148 @@ RSpec.describe Lutaml::Turtle::Transform do
|
|
|
585
585
|
skip "Heterogeneous collection requires union-typed attribute (not yet supported)"
|
|
586
586
|
end
|
|
587
587
|
end
|
|
588
|
+
|
|
589
|
+
describe "dynamic link predicates" do
|
|
590
|
+
before do
|
|
591
|
+
stub_const("DynChild", Class.new(Lutaml::Model::Serializable) do
|
|
592
|
+
attribute :label, :string
|
|
593
|
+
attribute :cid, :string
|
|
594
|
+
|
|
595
|
+
turtle do
|
|
596
|
+
namespace Lutaml::Rdf::Namespaces::SkosNamespace
|
|
597
|
+
|
|
598
|
+
subject { |m| "http://example.org/child/#{m.cid}" } # rubocop:disable RSpec/NamedSubject, RSpec/MultipleSubjects
|
|
599
|
+
|
|
600
|
+
type "skos:Concept"
|
|
601
|
+
|
|
602
|
+
predicate :prefLabel,
|
|
603
|
+
namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
|
|
604
|
+
to: :label
|
|
605
|
+
end
|
|
606
|
+
end)
|
|
607
|
+
|
|
608
|
+
stub_const("DynParent", Class.new(Lutaml::Model::Serializable) do
|
|
609
|
+
attribute :name, :string
|
|
610
|
+
attribute :children, DynChild, collection: true
|
|
611
|
+
|
|
612
|
+
turtle do
|
|
613
|
+
namespace Lutaml::Rdf::Namespaces::SkosNamespace
|
|
614
|
+
|
|
615
|
+
subject { |m| "http://example.org/parent/#{m.name}" }
|
|
616
|
+
|
|
617
|
+
type "skos:Collection"
|
|
618
|
+
|
|
619
|
+
predicate :prefLabel,
|
|
620
|
+
namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
|
|
621
|
+
to: :name
|
|
622
|
+
|
|
623
|
+
members :children, link: "skos:member"
|
|
624
|
+
end
|
|
625
|
+
end)
|
|
626
|
+
end
|
|
627
|
+
|
|
628
|
+
it "generates linking triples from String link" do
|
|
629
|
+
parent = DynParent.new(
|
|
630
|
+
name: "p1",
|
|
631
|
+
children: [DynChild.new(label: "c1", cid: "a")],
|
|
632
|
+
)
|
|
633
|
+
result = parent.to_turtle
|
|
634
|
+
expect(result).to include("skos:member <http://example.org/child/a>")
|
|
635
|
+
end
|
|
636
|
+
|
|
637
|
+
it "includes child subgraph data" do
|
|
638
|
+
parent = DynParent.new(
|
|
639
|
+
name: "p1",
|
|
640
|
+
children: [DynChild.new(label: "c1", cid: "a")],
|
|
641
|
+
)
|
|
642
|
+
result = parent.to_turtle
|
|
643
|
+
expect(result).to include("skos:prefLabel \"c1\"")
|
|
644
|
+
end
|
|
645
|
+
end
|
|
646
|
+
|
|
647
|
+
describe "recursive prefix collection" do
|
|
648
|
+
before do
|
|
649
|
+
stub_const("SkosNs", Lutaml::Rdf::Namespaces::SkosNamespace)
|
|
650
|
+
stub_const("DctermsNs", Lutaml::Rdf::Namespaces::DctermsNamespace)
|
|
651
|
+
|
|
652
|
+
stub_const("LeafModel", Class.new(Lutaml::Model::Serializable) do
|
|
653
|
+
attribute :value, :string
|
|
654
|
+
attribute :lid, :string
|
|
655
|
+
|
|
656
|
+
turtle do
|
|
657
|
+
namespace DctermsNs
|
|
658
|
+
|
|
659
|
+
subject { |m| "http://example.org/leaf/#{m.lid}" } # rubocop:disable RSpec/NamedSubject, RSpec/MultipleSubjects
|
|
660
|
+
|
|
661
|
+
type "dcterms:Agent"
|
|
662
|
+
|
|
663
|
+
predicate :title, namespace: DctermsNs, to: :value
|
|
664
|
+
end
|
|
665
|
+
end)
|
|
666
|
+
|
|
667
|
+
stub_const("MidModel", Class.new(Lutaml::Model::Serializable) do
|
|
668
|
+
attribute :name, :string
|
|
669
|
+
attribute :mid, :string
|
|
670
|
+
attribute :leaves, LeafModel, collection: true
|
|
671
|
+
|
|
672
|
+
turtle do
|
|
673
|
+
namespace SkosNs, DctermsNs
|
|
674
|
+
|
|
675
|
+
subject { |m| "http://example.org/mid/#{m.mid}" } # rubocop:disable RSpec/NamedSubject, RSpec/MultipleSubjects
|
|
676
|
+
|
|
677
|
+
type "skos:Concept"
|
|
678
|
+
|
|
679
|
+
predicate :prefLabel, namespace: SkosNs, to: :name
|
|
680
|
+
|
|
681
|
+
members :leaves, link: "skos:member"
|
|
682
|
+
end
|
|
683
|
+
end)
|
|
684
|
+
|
|
685
|
+
stub_const("RootModel", Class.new(Lutaml::Model::Serializable) do
|
|
686
|
+
attribute :title, :string
|
|
687
|
+
attribute :mids, MidModel, collection: true
|
|
688
|
+
|
|
689
|
+
turtle do
|
|
690
|
+
namespace SkosNs
|
|
691
|
+
|
|
692
|
+
subject { |m| "http://example.org/root/#{m.title}" }
|
|
693
|
+
|
|
694
|
+
type "skos:Collection"
|
|
695
|
+
|
|
696
|
+
predicate :prefLabel, namespace: SkosNs, to: :title
|
|
697
|
+
|
|
698
|
+
members :mids, link: "skos:member"
|
|
699
|
+
end
|
|
700
|
+
end)
|
|
701
|
+
end
|
|
702
|
+
|
|
703
|
+
it "collects prefixes from all nesting levels" do
|
|
704
|
+
root = RootModel.new(
|
|
705
|
+
title: "r1",
|
|
706
|
+
mids: [MidModel.new(
|
|
707
|
+
name: "m1",
|
|
708
|
+
mid: "a",
|
|
709
|
+
leaves: [LeafModel.new(value: "l1", lid: "x")],
|
|
710
|
+
)],
|
|
711
|
+
)
|
|
712
|
+
result = root.to_turtle
|
|
713
|
+
expect(result).to include("@prefix skos:")
|
|
714
|
+
expect(result).to include("@prefix dcterms:")
|
|
715
|
+
end
|
|
716
|
+
|
|
717
|
+
it "emits triples from all nesting levels" do
|
|
718
|
+
root = RootModel.new(
|
|
719
|
+
title: "r1",
|
|
720
|
+
mids: [MidModel.new(
|
|
721
|
+
name: "m1",
|
|
722
|
+
mid: "a",
|
|
723
|
+
leaves: [LeafModel.new(value: "l1", lid: "x")],
|
|
724
|
+
)],
|
|
725
|
+
)
|
|
726
|
+
result = root.to_turtle
|
|
727
|
+
expect(result).to include("skos:prefLabel \"r1\"")
|
|
728
|
+
expect(result).to include("skos:prefLabel \"m1\"")
|
|
729
|
+
expect(result).to include("dcterms:title \"l1\"")
|
|
730
|
+
end
|
|
731
|
+
end
|
|
588
732
|
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.
|
|
4
|
+
version: 0.8.16
|
|
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-05
|
|
11
|
+
date: 2026-06-05 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: base64
|
|
@@ -90,16 +90,16 @@ dependencies:
|
|
|
90
90
|
name: moxml
|
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
|
92
92
|
requirements:
|
|
93
|
-
- - "
|
|
93
|
+
- - "~>"
|
|
94
94
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 0.1.
|
|
95
|
+
version: 0.1.23
|
|
96
96
|
type: :runtime
|
|
97
97
|
prerelease: false
|
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
99
|
requirements:
|
|
100
|
-
- - "
|
|
100
|
+
- - "~>"
|
|
101
101
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: 0.1.
|
|
102
|
+
version: 0.1.23
|
|
103
103
|
- !ruby/object:Gem::Dependency
|
|
104
104
|
name: ostruct
|
|
105
105
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -476,6 +476,7 @@ files:
|
|
|
476
476
|
- lib/lutaml/model/jsonl.rb
|
|
477
477
|
- lib/lutaml/model/liquefiable.rb
|
|
478
478
|
- lib/lutaml/model/liquid.rb
|
|
479
|
+
- lib/lutaml/model/liquid/indexed_access.rb
|
|
479
480
|
- lib/lutaml/model/liquid/mapping.rb
|
|
480
481
|
- lib/lutaml/model/mapping/listener.rb
|
|
481
482
|
- lib/lutaml/model/mapping/mapping.rb
|
|
@@ -1611,6 +1612,7 @@ files:
|
|
|
1611
1612
|
- spec/lutaml/model/key_value_mapping_spec.rb
|
|
1612
1613
|
- spec/lutaml/model/lazy_collection_spec.rb
|
|
1613
1614
|
- spec/lutaml/model/liquefiable_spec.rb
|
|
1615
|
+
- spec/lutaml/model/liquid/indexed_access_spec.rb
|
|
1614
1616
|
- spec/lutaml/model/liquid_compatibility_spec.rb
|
|
1615
1617
|
- spec/lutaml/model/logger_spec.rb
|
|
1616
1618
|
- spec/lutaml/model/map_all_spec.rb
|
|
@@ -1626,6 +1628,7 @@ files:
|
|
|
1626
1628
|
- spec/lutaml/model/ordered_content_spec.rb
|
|
1627
1629
|
- spec/lutaml/model/polymorphic_spec.rb
|
|
1628
1630
|
- spec/lutaml/model/processing_instruction_spec.rb
|
|
1631
|
+
- spec/lutaml/model/raw_element_spec.rb
|
|
1629
1632
|
- spec/lutaml/model/register_key_value_spec.rb
|
|
1630
1633
|
- spec/lutaml/model/register_methods_spec.rb
|
|
1631
1634
|
- spec/lutaml/model/register_spec.rb
|