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.
- checksums.yaml +4 -4
- data/.github/workflows/dependent-tests.yml +3 -1
- data/.rubocop.yml +18 -0
- data/.rubocop_todo.yml +12 -18
- data/Gemfile +2 -0
- data/README.adoc +114 -2
- data/docs/_guides/index.adoc +18 -0
- data/docs/_guides/jsonld-serialization.adoc +217 -0
- data/docs/_guides/rdf-serialization.adoc +344 -0
- data/docs/_guides/turtle-serialization.adoc +224 -0
- data/docs/_pages/serialization_adapters.adoc +31 -0
- data/docs/_references/index.adoc +1 -0
- data/docs/_references/rdf-namespaces.adoc +243 -0
- data/docs/index.adoc +3 -2
- data/lib/lutaml/jsonld/adapter.rb +23 -0
- data/lib/lutaml/jsonld/context.rb +69 -0
- data/lib/lutaml/jsonld/term_definition.rb +39 -0
- data/lib/lutaml/jsonld/transform.rb +174 -0
- data/lib/lutaml/jsonld.rb +23 -0
- data/lib/lutaml/model/format_registry.rb +10 -1
- data/lib/lutaml/model/serialize/format_conversion.rb +17 -1
- data/lib/lutaml/model/version.rb +1 -1
- data/lib/lutaml/model.rb +6 -0
- data/lib/lutaml/rdf/error.rb +7 -0
- data/lib/lutaml/rdf/iri.rb +44 -0
- data/lib/lutaml/rdf/language_tagged.rb +11 -0
- data/lib/lutaml/rdf/literal.rb +62 -0
- data/lib/lutaml/rdf/mapping.rb +71 -0
- data/lib/lutaml/rdf/mapping_rule.rb +35 -0
- data/lib/lutaml/rdf/member_rule.rb +13 -0
- data/lib/lutaml/rdf/namespace.rb +58 -0
- data/lib/lutaml/rdf/namespace_set.rb +69 -0
- data/lib/lutaml/rdf/namespaces/dcterms_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/owl_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/rdf_namespace.rb +14 -0
- data/lib/lutaml/rdf/namespaces/rdfs_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/skos_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces/xsd_namespace.rb +12 -0
- data/lib/lutaml/rdf/namespaces.rb +14 -0
- data/lib/lutaml/rdf/transform.rb +36 -0
- data/lib/lutaml/rdf.rb +19 -0
- data/lib/lutaml/turtle/adapter.rb +35 -0
- data/lib/lutaml/turtle/mapping.rb +7 -0
- data/lib/lutaml/turtle/transform.rb +158 -0
- data/lib/lutaml/turtle.rb +22 -0
- data/spec/lutaml/integration/edge_cases_spec.rb +109 -0
- data/spec/lutaml/integration/multi_format_spec.rb +106 -0
- data/spec/lutaml/integration/round_trip_spec.rb +170 -0
- data/spec/lutaml/jsonld/adapter_spec.rb +46 -0
- data/spec/lutaml/jsonld/context_spec.rb +114 -0
- data/spec/lutaml/jsonld/term_definition_spec.rb +55 -0
- data/spec/lutaml/jsonld/transform_spec.rb +211 -0
- data/spec/lutaml/rdf/graph_serialization_spec.rb +137 -0
- data/spec/lutaml/rdf/iri_spec.rb +73 -0
- data/spec/lutaml/rdf/literal_spec.rb +98 -0
- data/spec/lutaml/rdf/mapping_spec.rb +164 -0
- data/spec/lutaml/rdf/member_rule_spec.rb +17 -0
- data/spec/lutaml/rdf/namespace_set_spec.rb +115 -0
- data/spec/lutaml/rdf/namespace_spec.rb +241 -0
- data/spec/lutaml/rdf/rdf_transform_spec.rb +82 -0
- data/spec/lutaml/turtle/adapter_spec.rb +47 -0
- data/spec/lutaml/turtle/mapping_spec.rb +123 -0
- data/spec/lutaml/turtle/transform_spec.rb +273 -0
- 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
|