lutaml-model 0.8.4 → 0.8.6

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 (94) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/dependent-tests.yml +5 -0
  3. data/.rubocop.yml +18 -0
  4. data/.rubocop_todo.yml +91 -22
  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/_migrations/0-8-0-namespace-restructuring.adoc +90 -0
  12. data/docs/_pages/serialization_adapters.adoc +31 -0
  13. data/docs/_references/index.adoc +1 -0
  14. data/docs/_references/rdf-namespaces.adoc +243 -0
  15. data/docs/index.adoc +3 -2
  16. data/lib/lutaml/jsonld/adapter.rb +23 -0
  17. data/lib/lutaml/jsonld/context.rb +69 -0
  18. data/lib/lutaml/jsonld/term_definition.rb +39 -0
  19. data/lib/lutaml/jsonld/transform.rb +174 -0
  20. data/lib/lutaml/jsonld.rb +23 -0
  21. data/lib/lutaml/model/format_registry.rb +10 -1
  22. data/lib/lutaml/model/serialize/format_conversion.rb +17 -1
  23. data/lib/lutaml/model/version.rb +1 -1
  24. data/lib/lutaml/model.rb +6 -0
  25. data/lib/lutaml/rdf/error.rb +7 -0
  26. data/lib/lutaml/rdf/iri.rb +44 -0
  27. data/lib/lutaml/rdf/language_tagged.rb +11 -0
  28. data/lib/lutaml/rdf/literal.rb +62 -0
  29. data/lib/lutaml/rdf/mapping.rb +71 -0
  30. data/lib/lutaml/rdf/mapping_rule.rb +35 -0
  31. data/lib/lutaml/rdf/member_rule.rb +13 -0
  32. data/lib/lutaml/rdf/namespace.rb +58 -0
  33. data/lib/lutaml/rdf/namespace_set.rb +69 -0
  34. data/lib/lutaml/rdf/namespaces/dcterms_namespace.rb +12 -0
  35. data/lib/lutaml/rdf/namespaces/owl_namespace.rb +12 -0
  36. data/lib/lutaml/rdf/namespaces/rdf_namespace.rb +14 -0
  37. data/lib/lutaml/rdf/namespaces/rdfs_namespace.rb +12 -0
  38. data/lib/lutaml/rdf/namespaces/skos_namespace.rb +12 -0
  39. data/lib/lutaml/rdf/namespaces/xsd_namespace.rb +12 -0
  40. data/lib/lutaml/rdf/namespaces.rb +14 -0
  41. data/lib/lutaml/rdf/transform.rb +36 -0
  42. data/lib/lutaml/rdf.rb +19 -0
  43. data/lib/lutaml/turtle/adapter.rb +35 -0
  44. data/lib/lutaml/turtle/mapping.rb +7 -0
  45. data/lib/lutaml/turtle/transform.rb +158 -0
  46. data/lib/lutaml/turtle.rb +22 -0
  47. data/lib/lutaml/xml/adapter/adapter_helpers.rb +1 -42
  48. data/lib/lutaml/xml/adapter/base_adapter.rb +48 -458
  49. data/lib/lutaml/xml/adapter/namespace_data.rb +0 -17
  50. data/lib/lutaml/xml/adapter/namespace_uri_collector.rb +71 -0
  51. data/lib/lutaml/xml/adapter/nokogiri_adapter.rb +5 -1110
  52. data/lib/lutaml/xml/adapter/oga_adapter.rb +6 -846
  53. data/lib/lutaml/xml/adapter/ox_adapter.rb +7 -884
  54. data/lib/lutaml/xml/adapter/plan_based_builder.rb +929 -0
  55. data/lib/lutaml/xml/adapter/rexml_adapter.rb +10 -864
  56. data/lib/lutaml/xml/adapter/xml_parser.rb +86 -0
  57. data/lib/lutaml/xml/adapter/xml_serializer.rb +291 -0
  58. data/lib/lutaml/xml/adapter.rb +0 -1
  59. data/lib/lutaml/xml/adapter_element.rb +7 -1
  60. data/lib/lutaml/xml/builder/base.rb +0 -1
  61. data/lib/lutaml/xml/data_model.rb +9 -1
  62. data/lib/lutaml/xml/document.rb +3 -1
  63. data/lib/lutaml/xml/element.rb +13 -10
  64. data/lib/lutaml/xml/serialization/format_conversion.rb +19 -42
  65. data/lib/lutaml/xml/serialization/instance_methods.rb +26 -35
  66. data/lib/lutaml/xml/transformation/custom_method_wrapper.rb +34 -55
  67. data/lib/lutaml/xml/transformation/rule_applier.rb +1 -1
  68. data/lib/lutaml/xml/xml_element.rb +24 -20
  69. data/spec/lutaml/integration/edge_cases_spec.rb +109 -0
  70. data/spec/lutaml/integration/multi_format_spec.rb +106 -0
  71. data/spec/lutaml/integration/round_trip_spec.rb +170 -0
  72. data/spec/lutaml/jsonld/adapter_spec.rb +46 -0
  73. data/spec/lutaml/jsonld/context_spec.rb +114 -0
  74. data/spec/lutaml/jsonld/term_definition_spec.rb +55 -0
  75. data/spec/lutaml/jsonld/transform_spec.rb +211 -0
  76. data/spec/lutaml/rdf/graph_serialization_spec.rb +137 -0
  77. data/spec/lutaml/rdf/iri_spec.rb +73 -0
  78. data/spec/lutaml/rdf/literal_spec.rb +98 -0
  79. data/spec/lutaml/rdf/mapping_spec.rb +164 -0
  80. data/spec/lutaml/rdf/member_rule_spec.rb +17 -0
  81. data/spec/lutaml/rdf/namespace_set_spec.rb +115 -0
  82. data/spec/lutaml/rdf/namespace_spec.rb +241 -0
  83. data/spec/lutaml/rdf/rdf_transform_spec.rb +82 -0
  84. data/spec/lutaml/turtle/adapter_spec.rb +47 -0
  85. data/spec/lutaml/turtle/mapping_spec.rb +123 -0
  86. data/spec/lutaml/turtle/transform_spec.rb +273 -0
  87. data/spec/lutaml/xml/adapter/base_adapter_regression_spec.rb +151 -0
  88. data/spec/lutaml/xml/adapter/order_spec.rb +150 -0
  89. data/spec/lutaml/xml/clear_parse_state_spec.rb +139 -0
  90. data/spec/lutaml/xml/doubly_defined_namespace_spec.rb +0 -2
  91. data/spec/lutaml/xml/schema/compiler_spec.rb +75 -69
  92. data/spec/lutaml/xml/transformation/custom_method_wrapper_spec.rb +213 -14
  93. metadata +58 -3
  94. data/lib/lutaml/xml/adapter/xml_serialization.rb +0 -145
@@ -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
@@ -0,0 +1,123 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "spec_helper"
4
+ require "lutaml/turtle"
5
+
6
+ RSpec.describe Lutaml::Turtle::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 "sets subject generator block" do
22
+ mapping.subject { |obj| "http://example.org/#{obj.name}" }
23
+ expect(mapping.rdf_subject).to be_a(Proc)
24
+ end
25
+ end
26
+
27
+ describe "#type" do
28
+ it "sets RDF type" do
29
+ mapping.type("skos:Concept")
30
+ expect(mapping.rdf_type).to eq("skos:Concept")
31
+ end
32
+ end
33
+
34
+ describe "#predicate" do
35
+ it "registers MappingRule with namespace reference" do
36
+ mapping.predicate(
37
+ :prefLabel,
38
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
39
+ to: :name,
40
+ )
41
+ expect(mapping.rdf_predicates.length).to eq(1)
42
+ rule = mapping.rdf_predicates.first
43
+ expect(rule).to be_a(Lutaml::Rdf::MappingRule)
44
+ expect(rule.predicate_name).to eq("prefLabel")
45
+ expect(rule.to).to eq(:name)
46
+ expect(rule.lang_tagged).to be(false)
47
+ end
48
+
49
+ it "registers MappingRule with lang_tagged option" do
50
+ mapping.predicate(
51
+ :prefLabel,
52
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace,
53
+ to: :name,
54
+ lang_tagged: true,
55
+ )
56
+ expect(mapping.rdf_predicates.first.lang_tagged).to be(true)
57
+ end
58
+
59
+ it "registers multiple predicates" do
60
+ mapping.predicate(:prefLabel,
61
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
62
+ mapping.predicate(:source,
63
+ namespace: Lutaml::Rdf::Namespaces::DctermsNamespace, to: :source)
64
+ expect(mapping.rdf_predicates.length).to eq(2)
65
+ end
66
+
67
+ it "resolves predicate URI" do
68
+ mapping.predicate(:prefLabel,
69
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
70
+ rule = mapping.rdf_predicates.first
71
+ expect(rule.uri).to eq("http://www.w3.org/2004/02/skos/core#prefLabel")
72
+ end
73
+
74
+ it "produces prefixed name" do
75
+ mapping.predicate(:prefLabel,
76
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
77
+ rule = mapping.rdf_predicates.first
78
+ expect(rule.prefixed_name).to eq("skos:prefLabel")
79
+ end
80
+
81
+ it "validates namespace is a Rdf::Namespace subclass" do
82
+ expect do
83
+ mapping.predicate(:foo, namespace: String, to: :bar)
84
+ end.to raise_error(ArgumentError, /Rdf::Namespace/)
85
+ end
86
+
87
+ it "validates :to is required" do
88
+ expect do
89
+ mapping.predicate(:foo,
90
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: nil)
91
+ end.to raise_error(ArgumentError, /required/)
92
+ end
93
+ end
94
+
95
+ describe "#deep_dup" do
96
+ before do
97
+ mapping.namespace(
98
+ Lutaml::Rdf::Namespaces::SkosNamespace,
99
+ Lutaml::Rdf::Namespaces::DctermsNamespace,
100
+ )
101
+ mapping.subject { |m| "http://example.org/#{m.name}" }
102
+ mapping.type("skos:Concept")
103
+ mapping.predicate(:prefLabel,
104
+ namespace: Lutaml::Rdf::Namespaces::SkosNamespace, to: :name)
105
+ end
106
+
107
+ it "copies all fields" do
108
+ duped = mapping.deep_dup
109
+ expect(duped.namespace_set.size).to eq(2)
110
+ expect(duped.rdf_subject).to be_a(Proc)
111
+ expect(duped.rdf_type).to eq("skos:Concept")
112
+ expect(duped.rdf_predicates.length).to eq(1)
113
+ end
114
+
115
+ it "does not share predicate state with original" do
116
+ duped = mapping.deep_dup
117
+ duped.predicate(:source,
118
+ namespace: Lutaml::Rdf::Namespaces::DctermsNamespace, to: :source)
119
+ expect(mapping.rdf_predicates.length).to eq(1)
120
+ expect(duped.rdf_predicates.length).to eq(2)
121
+ end
122
+ end
123
+ end