lutaml-model 0.8.4 → 0.8.5

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.
Files changed (64) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-tests.yml +3 -1
  3. data/.rubocop.yml +18 -0
  4. data/.rubocop_todo.yml +12 -18
  5. data/Gemfile +2 -0
  6. data/README.adoc +114 -2
  7. data/docs/_guides/index.adoc +18 -0
  8. data/docs/_guides/jsonld-serialization.adoc +217 -0
  9. data/docs/_guides/rdf-serialization.adoc +344 -0
  10. data/docs/_guides/turtle-serialization.adoc +224 -0
  11. data/docs/_pages/serialization_adapters.adoc +31 -0
  12. data/docs/_references/index.adoc +1 -0
  13. data/docs/_references/rdf-namespaces.adoc +243 -0
  14. data/docs/index.adoc +3 -2
  15. data/lib/lutaml/jsonld/adapter.rb +23 -0
  16. data/lib/lutaml/jsonld/context.rb +69 -0
  17. data/lib/lutaml/jsonld/term_definition.rb +39 -0
  18. data/lib/lutaml/jsonld/transform.rb +174 -0
  19. data/lib/lutaml/jsonld.rb +23 -0
  20. data/lib/lutaml/model/format_registry.rb +10 -1
  21. data/lib/lutaml/model/serialize/format_conversion.rb +17 -1
  22. data/lib/lutaml/model/version.rb +1 -1
  23. data/lib/lutaml/model.rb +6 -0
  24. data/lib/lutaml/rdf/error.rb +7 -0
  25. data/lib/lutaml/rdf/iri.rb +44 -0
  26. data/lib/lutaml/rdf/language_tagged.rb +11 -0
  27. data/lib/lutaml/rdf/literal.rb +62 -0
  28. data/lib/lutaml/rdf/mapping.rb +71 -0
  29. data/lib/lutaml/rdf/mapping_rule.rb +35 -0
  30. data/lib/lutaml/rdf/member_rule.rb +13 -0
  31. data/lib/lutaml/rdf/namespace.rb +58 -0
  32. data/lib/lutaml/rdf/namespace_set.rb +69 -0
  33. data/lib/lutaml/rdf/namespaces/dcterms_namespace.rb +12 -0
  34. data/lib/lutaml/rdf/namespaces/owl_namespace.rb +12 -0
  35. data/lib/lutaml/rdf/namespaces/rdf_namespace.rb +14 -0
  36. data/lib/lutaml/rdf/namespaces/rdfs_namespace.rb +12 -0
  37. data/lib/lutaml/rdf/namespaces/skos_namespace.rb +12 -0
  38. data/lib/lutaml/rdf/namespaces/xsd_namespace.rb +12 -0
  39. data/lib/lutaml/rdf/namespaces.rb +14 -0
  40. data/lib/lutaml/rdf/transform.rb +36 -0
  41. data/lib/lutaml/rdf.rb +19 -0
  42. data/lib/lutaml/turtle/adapter.rb +35 -0
  43. data/lib/lutaml/turtle/mapping.rb +7 -0
  44. data/lib/lutaml/turtle/transform.rb +158 -0
  45. data/lib/lutaml/turtle.rb +22 -0
  46. data/spec/lutaml/integration/edge_cases_spec.rb +109 -0
  47. data/spec/lutaml/integration/multi_format_spec.rb +106 -0
  48. data/spec/lutaml/integration/round_trip_spec.rb +170 -0
  49. data/spec/lutaml/jsonld/adapter_spec.rb +46 -0
  50. data/spec/lutaml/jsonld/context_spec.rb +114 -0
  51. data/spec/lutaml/jsonld/term_definition_spec.rb +55 -0
  52. data/spec/lutaml/jsonld/transform_spec.rb +211 -0
  53. data/spec/lutaml/rdf/graph_serialization_spec.rb +137 -0
  54. data/spec/lutaml/rdf/iri_spec.rb +73 -0
  55. data/spec/lutaml/rdf/literal_spec.rb +98 -0
  56. data/spec/lutaml/rdf/mapping_spec.rb +164 -0
  57. data/spec/lutaml/rdf/member_rule_spec.rb +17 -0
  58. data/spec/lutaml/rdf/namespace_set_spec.rb +115 -0
  59. data/spec/lutaml/rdf/namespace_spec.rb +241 -0
  60. data/spec/lutaml/rdf/rdf_transform_spec.rb +82 -0
  61. data/spec/lutaml/turtle/adapter_spec.rb +47 -0
  62. data/spec/lutaml/turtle/mapping_spec.rb +123 -0
  63. data/spec/lutaml/turtle/transform_spec.rb +273 -0
  64. metadata +50 -1
@@ -0,0 +1,164 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/rdf"
5
+
6
+ RSpec.describe Lutaml::Rdf::Mapping do
7
+ subject(:mapping) { described_class.new }
8
+
9
+ describe "#namespace" do
10
+ it "builds a NamespaceSet from namespace classes" do
11
+ mapping.namespace(
12
+ Lutaml::Rdf::Namespaces::SkosNamespace,
13
+ Lutaml::Rdf::Namespaces::DctermsNamespace,
14
+ )
15
+ expect(mapping.namespace_set.size).to eq(2)
16
+ expect(mapping.namespace_set["skos"]).to eq(Lutaml::Rdf::Namespaces::SkosNamespace)
17
+ end
18
+ end
19
+
20
+ describe "#subject" do
21
+ it "stores subject generator proc" do
22
+ mapping.subject { |obj| "http://example.org/#{obj.name}" }
23
+ expect(mapping.rdf_subject).to be_a(Proc)
24
+ end
25
+
26
+ it "returns nil when no subject block given" do
27
+ expect(mapping.rdf_subject).to be_nil
28
+ end
29
+ end
30
+
31
+ describe "#type" do
32
+ it "stores RDF type" do
33
+ mapping.type("skos:Concept")
34
+ expect(mapping.rdf_type).to eq("skos:Concept")
35
+ end
36
+ end
37
+
38
+ describe "#predicate" do
39
+ it "creates MappingRule with namespace reference" do
40
+ mapping.predicate(
41
+ :prefLabel,
42
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
43
+ to: :name,
44
+ )
45
+ expect(mapping.rdf_predicates.length).to eq(1)
46
+ rule = mapping.rdf_predicates.first
47
+ expect(rule).to be_a(Lutaml::Rdf::MappingRule)
48
+ expect(rule.predicate_name).to eq("prefLabel")
49
+ expect(rule.to).to eq(:name)
50
+ expect(rule.lang_tagged).to be(false)
51
+ end
52
+
53
+ it "creates MappingRule with lang_tagged option" do
54
+ mapping.predicate(
55
+ :prefLabel,
56
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
57
+ to: :name,
58
+ lang_tagged: true,
59
+ )
60
+ expect(mapping.rdf_predicates.first.lang_tagged).to be(true)
61
+ end
62
+
63
+ it "registers multiple predicates" do
64
+ mapping.predicate(:prefLabel,
65
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
66
+ mapping.predicate(:source,
67
+ namespace: Lutaml::Rdf::Namespaces::DctermsNamespace, to: :source)
68
+ expect(mapping.rdf_predicates.length).to eq(2)
69
+ end
70
+
71
+ it "resolves predicate URI" do
72
+ mapping.predicate(:prefLabel,
73
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
74
+ expect(mapping.rdf_predicates.first.uri).to eq("http://www.w3.org/2004/02/skos/core#prefLabel")
75
+ end
76
+
77
+ it "produces prefixed name" do
78
+ mapping.predicate(:prefLabel,
79
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
80
+ expect(mapping.rdf_predicates.first.prefixed_name).to eq("skos:prefLabel")
81
+ end
82
+
83
+ it "validates namespace is a Rdf::Namespace subclass" do
84
+ expect do
85
+ mapping.predicate(:foo, namespace: String, to: :bar)
86
+ end.to raise_error(ArgumentError, /Rdf::Namespace/)
87
+ end
88
+
89
+ it "validates :to is required" do
90
+ expect do
91
+ mapping.predicate(:foo,
92
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: nil)
93
+ end.to raise_error(ArgumentError, /required/)
94
+ end
95
+ end
96
+
97
+ describe "#members" do
98
+ it "creates MemberRule" do
99
+ mapping.members(:items)
100
+ expect(mapping.rdf_members.length).to eq(1)
101
+ expect(mapping.rdf_members.first.attr_name).to eq(:items)
102
+ end
103
+ end
104
+
105
+ describe "#mappings" do
106
+ it "returns the predicate list" do
107
+ mapping.predicate(:prefLabel,
108
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
109
+ mapping.predicate(:definition,
110
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :desc)
111
+ expect(mapping.mappings).to eq(mapping.rdf_predicates)
112
+ end
113
+ end
114
+
115
+ describe "#finalize" do
116
+ it "is a no-op that accepts a mapper class" do
117
+ expect { mapping.finalize(String) }.not_to raise_error
118
+ end
119
+ end
120
+
121
+ describe "#finalized?" do
122
+ it "returns true" do
123
+ expect(mapping.finalized?).to be(true)
124
+ end
125
+ end
126
+
127
+ describe "#map_element" do
128
+ it "raises IncorrectMappingArgumentsError" do
129
+ expect do
130
+ mapping.map_element("name", to: :name)
131
+ end.to raise_error(Lutaml::Model::IncorrectMappingArgumentsError,
132
+ /predicate/)
133
+ end
134
+ end
135
+
136
+ describe "#deep_dup" do
137
+ before do
138
+ mapping.namespace(
139
+ Lutaml::Rdf::Namespaces::SkosNamespace,
140
+ Lutaml::Rdf::Namespaces::DctermsNamespace,
141
+ )
142
+ mapping.subject { |m| "http://example.org/#{m.name}" }
143
+ mapping.type("skos:Concept")
144
+ mapping.predicate(:prefLabel,
145
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
146
+ end
147
+
148
+ it "copies all fields" do
149
+ duped = mapping.deep_dup
150
+ expect(duped.namespace_set.size).to eq(2)
151
+ expect(duped.rdf_subject).to be_a(Proc)
152
+ expect(duped.rdf_type).to eq("skos:Concept")
153
+ expect(duped.rdf_predicates.length).to eq(1)
154
+ end
155
+
156
+ it "does not share predicate state with original" do
157
+ duped = mapping.deep_dup
158
+ duped.predicate(:source,
159
+ namespace: Lutaml::Rdf::Namespaces::DctermsNamespace, to: :source)
160
+ expect(mapping.rdf_predicates.length).to eq(1)
161
+ expect(duped.rdf_predicates.length).to eq(2)
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+
5
+ RSpec.describe Lutaml::Rdf::MemberRule do
6
+ describe ".new" do
7
+ it "stores attr_name as symbol" do
8
+ rule = described_class.new(:concepts)
9
+ expect(rule.attr_name).to eq(:concepts)
10
+ end
11
+
12
+ it "converts string attr_name to symbol" do
13
+ rule = described_class.new("concepts")
14
+ expect(rule.attr_name).to eq(:concepts)
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,115 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/rdf"
5
+
6
+ RSpec.describe Lutaml::Rdf::NamespaceSet do
7
+ subject(:set) do
8
+ described_class.new(
9
+ Lutaml::Rdf::Namespaces::SkosNamespace,
10
+ Lutaml::Rdf::Namespaces::DctermsNamespace,
11
+ )
12
+ end
13
+
14
+ describe "construction" do
15
+ it "accepts namespace classes" do
16
+ expect(set.size).to eq(2)
17
+ end
18
+
19
+ it "is enumerable" do
20
+ expect(set.map(&:prefix)).to contain_exactly("skos", "dcterms")
21
+ end
22
+ end
23
+
24
+ describe "#add" do
25
+ it "adds a namespace" do
26
+ set.add(Lutaml::Rdf::Namespaces::XsdNamespace)
27
+ expect(set.size).to eq(3)
28
+ end
29
+
30
+ it "allows adding same class twice" do
31
+ set.add(Lutaml::Rdf::Namespaces::SkosNamespace)
32
+ expect(set.size).to eq(2)
33
+ end
34
+
35
+ it "raises on prefix collision with different class" do
36
+ duplicate = Class.new(Lutaml::Rdf::Namespace)
37
+ duplicate.uri "http://other.org/"
38
+ duplicate.prefix "skos"
39
+ expect { set.add(duplicate) }.to raise_error(ArgumentError, /conflicts/)
40
+ end
41
+
42
+ it "returns self for chaining" do
43
+ result = set.add(Lutaml::Rdf::Namespaces::XsdNamespace)
44
+ expect(result).to eq(set)
45
+ end
46
+ end
47
+
48
+ describe "#[]" do
49
+ it "looks up by prefix" do
50
+ expect(set["skos"]).to eq(Lutaml::Rdf::Namespaces::SkosNamespace)
51
+ end
52
+
53
+ it "returns nil for unknown prefix" do
54
+ expect(set["unknown"]).to be_nil
55
+ end
56
+ end
57
+
58
+ describe "#resolve_compact_iri" do
59
+ it "resolves known compact IRI" do
60
+ expect(set.resolve_compact_iri("skos:Concept"))
61
+ .to eq("http://www.w3.org/2004/02/skos/core#Concept")
62
+ end
63
+
64
+ it "returns value for unknown prefix" do
65
+ expect(set.resolve_compact_iri("foo:Bar")).to eq("foo:Bar")
66
+ end
67
+
68
+ it "returns value for no-colon string" do
69
+ expect(set.resolve_compact_iri("Concept")).to eq("Concept")
70
+ end
71
+ end
72
+
73
+ describe "#compact" do
74
+ it "compacts full URI to prefixed form" do
75
+ expect(set.compact("http://www.w3.org/2004/02/skos/core#Concept"))
76
+ .to eq("skos:Concept")
77
+ end
78
+
79
+ it "returns nil for unknown URI" do
80
+ expect(set.compact("http://unknown.org/Thing")).to be_nil
81
+ end
82
+ end
83
+
84
+ describe "#to_hash" do
85
+ it "returns prefix => uri mapping" do
86
+ h = set.to_hash
87
+ expect(h["skos"]).to eq("http://www.w3.org/2004/02/skos/core#")
88
+ expect(h["dcterms"]).to eq("http://purl.org/dc/terms/")
89
+ end
90
+ end
91
+
92
+ describe "#merge" do
93
+ it "adds namespaces from another set" do
94
+ other = described_class.new(Lutaml::Rdf::Namespaces::XsdNamespace)
95
+ result = set.merge(other)
96
+ expect(result.size).to eq(3)
97
+ expect(result["xsd"]).to eq(Lutaml::Rdf::Namespaces::XsdNamespace)
98
+ end
99
+
100
+ it "returns self" do
101
+ other = described_class.new(Lutaml::Rdf::Namespaces::XsdNamespace)
102
+ expect(set.merge(other)).to equal(set)
103
+ end
104
+
105
+ it "skips duplicate prefixes" do
106
+ other = described_class.new(Lutaml::Rdf::Namespaces::SkosNamespace)
107
+ set.merge(other)
108
+ expect(set.size).to eq(2)
109
+ end
110
+
111
+ it "returns self when merging with itself" do
112
+ expect(set.merge(set)).to equal(set)
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,241 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/rdf"
5
+
6
+ RSpec.describe Lutaml::Rdf::Namespace do
7
+ describe "base class" do
8
+ it "stores uri at class level" do
9
+ ns = Class.new(described_class)
10
+ ns.uri "http://example.org/ns/"
11
+ expect(ns.uri).to eq("http://example.org/ns/")
12
+ end
13
+
14
+ it "stores prefix at class level" do
15
+ ns = Class.new(described_class)
16
+ ns.prefix "ex"
17
+ expect(ns.prefix).to eq("ex")
18
+ end
19
+
20
+ it "casts prefix to string" do
21
+ ns = Class.new(described_class)
22
+ ns.prefix :ex
23
+ expect(ns.prefix).to eq("ex")
24
+ end
25
+
26
+ it "freezes uri" do
27
+ ns = Class.new(described_class)
28
+ ns.uri "http://example.org/ns/"
29
+ expect(ns.uri).to be_frozen
30
+ end
31
+
32
+ it "freezes prefix" do
33
+ ns = Class.new(described_class)
34
+ ns.prefix "ex"
35
+ expect(ns.prefix).to be_frozen
36
+ end
37
+
38
+ it "raises FrozenError when uri set twice" do
39
+ ns = Class.new(described_class)
40
+ ns.uri "http://first.org/"
41
+ expect { ns.uri "http://second.org/" }.to raise_error(FrozenError)
42
+ end
43
+
44
+ it "raises FrozenError when prefix set twice" do
45
+ ns = Class.new(described_class)
46
+ ns.prefix "a"
47
+ expect { ns.prefix "b" }.to raise_error(FrozenError)
48
+ end
49
+
50
+ describe "#[]" do
51
+ it "resolves local name to full URI" do
52
+ ns = Class.new(described_class)
53
+ ns.uri "http://example.org/ns/"
54
+ expect(ns["someName"]).to eq("http://example.org/ns/someName")
55
+ end
56
+ end
57
+
58
+ describe ".prefixed" do
59
+ it "resolves local name to compact form" do
60
+ ns = Class.new(described_class)
61
+ ns.prefix "ex"
62
+ expect(ns.prefixed("someName")).to eq("ex:someName")
63
+ end
64
+ end
65
+
66
+ it "each subclass has independent state" do
67
+ ns1 = Class.new(described_class)
68
+ ns1.uri "http://ns1.org/"
69
+ ns1.prefix "ns1"
70
+
71
+ ns2 = Class.new(described_class)
72
+ ns2.uri "http://ns2.org/"
73
+ ns2.prefix "ns2"
74
+
75
+ expect(ns1.uri).to eq("http://ns1.org/")
76
+ expect(ns2.uri).to eq("http://ns2.org/")
77
+ expect(ns1.prefix).to eq("ns1")
78
+ expect(ns2.prefix).to eq("ns2")
79
+ end
80
+
81
+ describe "equality" do
82
+ it "equals another namespace class with same uri and prefix" do
83
+ a = Class.new(described_class)
84
+ a.uri "http://example.org/"
85
+ a.prefix "ex"
86
+
87
+ b = Class.new(described_class)
88
+ b.uri "http://example.org/"
89
+ b.prefix "ex"
90
+
91
+ expect(a).to eq(b)
92
+ end
93
+
94
+ it "does not equal with different uri" do
95
+ a = Class.new(described_class)
96
+ a.uri "http://a.org/"
97
+ a.prefix "ex"
98
+
99
+ b = Class.new(described_class)
100
+ b.uri "http://b.org/"
101
+ b.prefix "ex"
102
+
103
+ expect(a).not_to eq(b)
104
+ end
105
+ end
106
+
107
+ describe "#to_s" do
108
+ it "includes class name, prefix, and uri" do
109
+ ns = Class.new(described_class)
110
+ ns.uri "http://example.org/"
111
+ ns.prefix "ex"
112
+ expect(ns.to_s).to include("prefix: \"ex\"")
113
+ expect(ns.to_s).to include("uri: \"http://example.org/\"")
114
+ end
115
+ end
116
+ end
117
+
118
+ describe ".resolve_compact_iri" do
119
+ let(:namespaces) do
120
+ [
121
+ Lutaml::Rdf::Namespaces::SkosNamespace,
122
+ Lutaml::Rdf::Namespaces::DctermsNamespace,
123
+ ]
124
+ end
125
+
126
+ it "resolves known prefix to full URI" do
127
+ expect(described_class.resolve_compact_iri("skos:Concept", namespaces))
128
+ .to eq("http://www.w3.org/2004/02/skos/core#Concept")
129
+ end
130
+
131
+ it "returns value as-is when prefix is unknown" do
132
+ expect(described_class.resolve_compact_iri("unknown:Thing", namespaces))
133
+ .to eq("unknown:Thing")
134
+ end
135
+
136
+ it "returns value as-is when no colon present" do
137
+ expect(described_class.resolve_compact_iri("Concept", namespaces))
138
+ .to eq("Concept")
139
+ end
140
+ end
141
+
142
+ describe "W3C namespace classes" do
143
+ describe Lutaml::Rdf::Namespaces::SkosNamespace do
144
+ subject(:ns) { described_class }
145
+
146
+ it "has SKOS URI" do
147
+ expect(ns.uri).to eq("http://www.w3.org/2004/02/skos/core#")
148
+ end
149
+
150
+ it "has skos prefix" do
151
+ expect(ns.prefix).to eq("skos")
152
+ end
153
+
154
+ it "resolves prefLabel to full URI" do
155
+ expect(ns["prefLabel"]).to eq("http://www.w3.org/2004/02/skos/core#prefLabel")
156
+ end
157
+
158
+ it "resolves Concept to compact form" do
159
+ expect(ns.prefixed("Concept")).to eq("skos:Concept")
160
+ end
161
+ end
162
+
163
+ describe Lutaml::Rdf::Namespaces::DctermsNamespace do
164
+ subject(:ns) { described_class }
165
+
166
+ it "has DCTERMS URI" do
167
+ expect(ns.uri).to eq("http://purl.org/dc/terms/")
168
+ end
169
+
170
+ it "has dcterms prefix" do
171
+ expect(ns.prefix).to eq("dcterms")
172
+ end
173
+
174
+ it "resolves source to compact form" do
175
+ expect(ns.prefixed("source")).to eq("dcterms:source")
176
+ end
177
+ end
178
+
179
+ describe Lutaml::Rdf::Namespaces::RdfNamespace do
180
+ subject(:ns) { described_class }
181
+
182
+ it "has RDF URI" do
183
+ expect(ns.uri).to eq("http://www.w3.org/1999/02/22-rdf-syntax-ns#")
184
+ end
185
+
186
+ it "has rdf prefix" do
187
+ expect(ns.prefix).to eq("rdf")
188
+ end
189
+
190
+ it "resolves type to compact form" do
191
+ expect(ns.prefixed("type")).to eq("rdf:type")
192
+ end
193
+ end
194
+
195
+ describe Lutaml::Rdf::Namespaces::RdfSyntaxNamespace do
196
+ it "is the same class as RdfNamespace alias" do
197
+ expect(described_class).to eq(Lutaml::Rdf::Namespaces::RdfNamespace)
198
+ end
199
+ end
200
+
201
+ describe Lutaml::Rdf::Namespaces::RdfsNamespace do
202
+ subject(:ns) { described_class }
203
+
204
+ it "has RDFS URI" do
205
+ expect(ns.uri).to eq("http://www.w3.org/2000/01/rdf-schema#")
206
+ end
207
+
208
+ it "has rdfs prefix" do
209
+ expect(ns.prefix).to eq("rdfs")
210
+ end
211
+ end
212
+
213
+ describe Lutaml::Rdf::Namespaces::OwlNamespace do
214
+ subject(:ns) { described_class }
215
+
216
+ it "has OWL URI" do
217
+ expect(ns.uri).to eq("http://www.w3.org/2002/07/owl#")
218
+ end
219
+
220
+ it "has owl prefix" do
221
+ expect(ns.prefix).to eq("owl")
222
+ end
223
+ end
224
+
225
+ describe Lutaml::Rdf::Namespaces::XsdNamespace do
226
+ subject(:ns) { described_class }
227
+
228
+ it "has XSD URI" do
229
+ expect(ns.uri).to eq("http://www.w3.org/2001/XMLSchema#")
230
+ end
231
+
232
+ it "has xsd prefix" do
233
+ expect(ns.prefix).to eq("xsd")
234
+ end
235
+
236
+ it "resolves date to compact form" do
237
+ expect(ns.prefixed("date")).to eq("xsd:date")
238
+ end
239
+ end
240
+ end
241
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/rdf"
5
+
6
+ RSpec.describe Lutaml::Rdf::Transform do
7
+ let(:transform) { described_class.new(nil) }
8
+
9
+ describe "#resolve_subject_uri" do
10
+ it "returns nil when mapping has no subject" do
11
+ mapping = Lutaml::Rdf::Mapping.new
12
+ expect(transform.send(:resolve_subject_uri, mapping, double)).to be_nil
13
+ end
14
+
15
+ it "calls subject proc with instance" do
16
+ mapping = Lutaml::Rdf::Mapping.new
17
+ mapping.subject { |i| "http://example.org/#{i}" }
18
+
19
+ result = transform.send(:resolve_subject_uri, mapping, "test")
20
+ expect(result).to eq("http://example.org/test")
21
+ end
22
+ end
23
+
24
+ describe "#resolve_type_uri" do
25
+ it "returns nil when mapping has no type" do
26
+ mapping = Lutaml::Rdf::Mapping.new
27
+ expect(transform.send(:resolve_type_uri, mapping)).to be_nil
28
+ end
29
+
30
+ it "resolves compact IRI to full URI" do
31
+ mapping = Lutaml::Rdf::Mapping.new
32
+ stub_const("TestNs", Class.new(Lutaml::Rdf::Namespace) do
33
+ uri "http://example.org/"
34
+ prefix "ex"
35
+ end)
36
+ mapping.namespace(TestNs)
37
+ mapping.type "ex:Thing"
38
+
39
+ result = transform.send(:resolve_type_uri, mapping)
40
+ expect(result).to eq("http://example.org/Thing")
41
+ end
42
+ end
43
+
44
+ describe "#resolve_type_compact" do
45
+ it "returns the compact form" do
46
+ mapping = Lutaml::Rdf::Mapping.new
47
+ mapping.type "skos:Concept"
48
+
49
+ expect(transform.send(:resolve_type_compact,
50
+ mapping)).to eq("skos:Concept")
51
+ end
52
+ end
53
+
54
+ describe "#extract_language" do
55
+ it "extracts language from LanguageTagged objects" do
56
+ literal = Lutaml::Rdf::Literal.new("hello", language: "eng")
57
+ expect(transform.send(:extract_language, literal)).to eq("eng")
58
+ end
59
+
60
+ it "returns nil for plain strings" do
61
+ expect(transform.send(:extract_language, "hello")).to be_nil
62
+ end
63
+
64
+ it "returns nil for non-LanguageTagged objects" do
65
+ expect(transform.send(:extract_language, 42)).to be_nil
66
+ end
67
+ end
68
+
69
+ describe "#build_instance" do
70
+ it "constructs a model instance with resolved register" do
71
+ stub_const("BuildTestModel", Class.new(Lutaml::Model::Serializable) do
72
+ attribute :name, :string
73
+ end)
74
+
75
+ context = BuildTestModel
76
+ t = described_class.new(context)
77
+ instance = t.send(:build_instance, { name: "test" }, {})
78
+ expect(instance).to be_a(BuildTestModel)
79
+ expect(instance.name).to eq("test")
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/turtle"
5
+
6
+ RSpec.describe Lutaml::Turtle::Adapter do
7
+ describe ".parse" do
8
+ it "parses valid Turtle into RDF::Graph" do
9
+ turtle = <<~TURTLE
10
+ @prefix skos: <http://www.w3.org/2004/02/skos/core#> .
11
+ <http://example.org/1> a skos:Concept ;
12
+ skos:prefLabel "test"@en .
13
+ TURTLE
14
+
15
+ graph = described_class.parse(turtle)
16
+ expect(graph).to be_a(RDF::Graph)
17
+ expect(graph.count).to eq(2)
18
+ end
19
+
20
+ it "produces empty graph for invalid Turtle" do
21
+ # RDF::Turtle::Reader logs errors instead of raising
22
+ graph = described_class.parse("not valid turtle !!!")
23
+ expect(graph).to be_a(RDF::Graph)
24
+ expect(graph.count).to eq(0)
25
+ end
26
+ end
27
+
28
+ describe "#to_turtle" do
29
+ it "returns string data as-is" do
30
+ adapter = described_class.new("some turtle content")
31
+ expect(adapter.to_turtle).to eq("some turtle content")
32
+ end
33
+
34
+ it "serializes RDF::Enumerable to string" do
35
+ graph = RDF::Graph.new
36
+ graph << RDF::Statement.new(
37
+ RDF::URI("http://example.org/1"),
38
+ RDF::URI("http://www.w3.org/2004/02/skos/core#prefLabel"),
39
+ RDF::Literal.new("test"),
40
+ )
41
+ adapter = described_class.new(graph)
42
+ result = adapter.to_turtle
43
+ expect(result).to include("http://example.org/1")
44
+ expect(result).to include("test")
45
+ end
46
+ end
47
+ end