ld4l-open_annotation_rdf 0.0.4
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 +7 -0
- data/.gitignore +23 -0
- data/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile +11 -0
- data/LICENSE.txt +14 -0
- data/README.md +231 -0
- data/Rakefile +2 -0
- data/ld4l-open_annotation_rdf.gemspec +46 -0
- data/lib/ld4l/open_annotation_rdf.rb +66 -0
- data/lib/ld4l/open_annotation_rdf/annotation.rb +82 -0
- data/lib/ld4l/open_annotation_rdf/comment_annotation.rb +47 -0
- data/lib/ld4l/open_annotation_rdf/comment_body.rb +24 -0
- data/lib/ld4l/open_annotation_rdf/configuration.rb +127 -0
- data/lib/ld4l/open_annotation_rdf/semantic_tag_annotation.rb +66 -0
- data/lib/ld4l/open_annotation_rdf/semantic_tag_body.rb +70 -0
- data/lib/ld4l/open_annotation_rdf/tag_annotation.rb +98 -0
- data/lib/ld4l/open_annotation_rdf/tag_body.rb +83 -0
- data/lib/ld4l/open_annotation_rdf/version.rb +5 -0
- data/lib/ld4l/open_annotation_rdf/vocab/cnt.rb +6 -0
- data/lib/ld4l/open_annotation_rdf/vocab/dctypes.rb +5 -0
- data/lib/ld4l/open_annotation_rdf/vocab/oa.rb +23 -0
- data/spec/ld4l/open_annotation_rdf/annotation_spec.rb +603 -0
- data/spec/ld4l/open_annotation_rdf/comment_annotation_spec.rb +559 -0
- data/spec/ld4l/open_annotation_rdf/comment_body_spec.rb +371 -0
- data/spec/ld4l/open_annotation_rdf/configuration_spec.rb +194 -0
- data/spec/ld4l/open_annotation_rdf/semantic_tag_annotation_spec.rb +619 -0
- data/spec/ld4l/open_annotation_rdf/semantic_tag_body_spec.rb +412 -0
- data/spec/ld4l/open_annotation_rdf/tag_annotation_spec.rb +672 -0
- data/spec/ld4l/open_annotation_rdf/tag_body_spec.rb +430 -0
- data/spec/ld4l/open_annotation_rdf_spec.rb +57 -0
- data/spec/spec_helper.rb +21 -0
- metadata +201 -0
@@ -0,0 +1,412 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ld4l/open_annotation_rdf/vocab/dctypes'
|
3
|
+
require 'ld4l/open_annotation_rdf/vocab/oa'
|
4
|
+
|
5
|
+
|
6
|
+
describe 'LD4L::OpenAnnotationRDF::SemanticTagBody' do
|
7
|
+
|
8
|
+
subject { LD4L::OpenAnnotationRDF::SemanticTagBody.new }
|
9
|
+
|
10
|
+
describe 'rdf_subject' do
|
11
|
+
it "should be a blank node if we haven't set it" do
|
12
|
+
expect(subject.rdf_subject.node?).to be true
|
13
|
+
end
|
14
|
+
|
15
|
+
it "should be settable when it has not been set yet" do
|
16
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
17
|
+
expect(subject.rdf_subject).to eq RDF::URI('http://example.org/moomin')
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should append to base URI when setting to non-URI subject" do
|
21
|
+
subject.set_subject! '123'
|
22
|
+
expect(subject.rdf_subject).to eq RDF::URI("#{LD4L::OpenAnnotationRDF::SemanticTagBody.base_uri}123")
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'when changing subject' do
|
26
|
+
before do
|
27
|
+
subject << RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland'))
|
28
|
+
subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject)
|
29
|
+
subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land')
|
30
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'should update graph subjects' do
|
34
|
+
expect(subject.has_statement?(RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland')))).to be true
|
35
|
+
end
|
36
|
+
|
37
|
+
it 'should update graph objects' do
|
38
|
+
expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject))).to be true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should leave other uris alone' do
|
42
|
+
expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land'))).to be true
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe 'created with URI subject' do
|
47
|
+
before do
|
48
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should not be settable' do
|
52
|
+
expect{ subject.set_subject! RDF::URI('http://example.org/moomin2') }.to raise_error
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
|
58
|
+
# -------------------------------------------------
|
59
|
+
# START -- Test attributes specific to this model
|
60
|
+
# -------------------------------------------------
|
61
|
+
|
62
|
+
describe 'type' do
|
63
|
+
it "should be set to text and astext from new" do
|
64
|
+
expect(subject.type.size).to eq 1
|
65
|
+
expect(subject.type).to include RDFVocabularies::OA.SemanticTag
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
describe '#localname_prefix' do
|
70
|
+
it "should return default prefix" do
|
71
|
+
prefix = LD4L::OpenAnnotationRDF::SemanticTagBody.localname_prefix
|
72
|
+
expect(prefix).to eq "stb"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "#annotations_using" do
|
77
|
+
|
78
|
+
context "when term value is nil" do
|
79
|
+
it "should throw invalid arguement exception" do
|
80
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using(nil) }.to raise_error
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
context "when term value is a string of 0 length" do
|
85
|
+
it "should throw invalid arguement exception" do
|
86
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using("") }.to raise_error
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context "when term is not a string or uri" do
|
91
|
+
it "should throw invalid arguement exception" do
|
92
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using(3) }.to raise_error
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when terms exist in the repository" do
|
97
|
+
before(:all) do
|
98
|
+
# Create inmemory repository
|
99
|
+
sta = LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta1')
|
100
|
+
sta.setTerm(RDF::URI("http://example.org/EXISTING_term"))
|
101
|
+
sta.persist!
|
102
|
+
sta = LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta2')
|
103
|
+
sta.setTerm(RDF::URI("http://example.org/EXISTING_term"))
|
104
|
+
sta.persist!
|
105
|
+
stb = LD4L::OpenAnnotationRDF::SemanticTagBody.new('http://example.org/UNUSED_term')
|
106
|
+
stb.persist!
|
107
|
+
end
|
108
|
+
after(:all) do
|
109
|
+
LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta1').destroy!
|
110
|
+
LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta2').destroy!
|
111
|
+
LD4L::OpenAnnotationRDF::SemanticTagBody.new('http://example.org/UNUSED_term').destroy!
|
112
|
+
end
|
113
|
+
|
114
|
+
context "and term is passed as string URI" do
|
115
|
+
it "should find annotations using the term" do
|
116
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using('http://example.org/EXISTING_term')
|
117
|
+
expect( annotations.include?(RDF::URI('http://example.org/sta1')) ).to be true
|
118
|
+
expect( annotations.include?(RDF::URI('http://example.org/sta2')) ).to be true
|
119
|
+
expect( annotations.size ).to be 2
|
120
|
+
end
|
121
|
+
|
122
|
+
it "should find 0 annotations for unused term" do
|
123
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using('http://example.org/UNUSED_term')
|
124
|
+
expect( annotations ).to eq []
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should find 0 annotations for non-existent term" do
|
128
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using('http://example.org/NONEXISTING_term')
|
129
|
+
expect( annotations ).to eq []
|
130
|
+
end
|
131
|
+
end
|
132
|
+
|
133
|
+
context "and term is passed as RDF::URI" do
|
134
|
+
it "should find annotations using the term" do
|
135
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using(RDF::URI('http://example.org/EXISTING_term'))
|
136
|
+
expect( annotations.include?(RDF::URI('http://example.org/sta1')) ).to be true
|
137
|
+
expect( annotations.include?(RDF::URI('http://example.org/sta2')) ).to be true
|
138
|
+
expect( annotations.size ).to be 2
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should find 0 annotations for unused term" do
|
142
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using(RDF::URI('http://example.org/UNUSED_term'))
|
143
|
+
expect( annotations ).to eq []
|
144
|
+
end
|
145
|
+
|
146
|
+
it "should find 0 annotations for non-existent term" do
|
147
|
+
annotations = LD4L::OpenAnnotationRDF::SemanticTagBody.annotations_using(RDF::URI'http://example.org/NONEXISTING_term')
|
148
|
+
expect( annotations ).to eq []
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
describe "#destroy_if_unused" do
|
155
|
+
context "when term is nil" do
|
156
|
+
it "should throw invalid arguement exception" do
|
157
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused(nil) }.to raise_error
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
context "when term is a string of 0 length" do
|
162
|
+
it "should throw invalid arguement exception" do
|
163
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused("") }.to raise_error
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
context "when term is not a string or uri" do
|
168
|
+
it "should throw invalid arguement exception" do
|
169
|
+
expect{ LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused(3) }.to raise_error
|
170
|
+
end
|
171
|
+
end
|
172
|
+
|
173
|
+
context "when terms exist in the repository" do
|
174
|
+
before(:all) do
|
175
|
+
# Create inmemory repository
|
176
|
+
sta = LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta1')
|
177
|
+
sta.setTerm(RDF::URI("http://example.org/EXISTING_term"))
|
178
|
+
sta.persist!
|
179
|
+
sta = LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta2')
|
180
|
+
sta.setTerm(RDF::URI("http://example.org/EXISTING_term"))
|
181
|
+
sta.persist!
|
182
|
+
stb = LD4L::OpenAnnotationRDF::SemanticTagBody.new('http://example.org/UNUSED_term')
|
183
|
+
stb.persist!
|
184
|
+
end
|
185
|
+
after(:all) do
|
186
|
+
LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta1').destroy!
|
187
|
+
LD4L::OpenAnnotationRDF::SemanticTagAnnotation.new('http://example.org/sta2').destroy!
|
188
|
+
LD4L::OpenAnnotationRDF::SemanticTagBody.new('http://example.org/UNUSED_term').destroy!
|
189
|
+
end
|
190
|
+
|
191
|
+
context "and term is passed as string URI" do
|
192
|
+
it "should not destroy if used by any annotations" do
|
193
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused('http://example.org/EXISTING_term') ).to be false
|
194
|
+
end
|
195
|
+
|
196
|
+
it "should destory if not used by any annotations" do
|
197
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused('http://example.org/UNUSED_term') ).to be true
|
198
|
+
end
|
199
|
+
|
200
|
+
it "will destory if term doesn't exist" do
|
201
|
+
# NOTE: ActiveTriples.destroy! persists the object to be destroyed before destroying it
|
202
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused('http://example.org/NONEXISTENT_term') ).to be true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
context "and term is passed as RDF::URI" do
|
207
|
+
it "should not destroy if used by any annotations" do
|
208
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused(RDF::URI('http://example.org/EXISTING_term')) ).to be false
|
209
|
+
end
|
210
|
+
|
211
|
+
it "should destory if not used by any annotations" do
|
212
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused(RDF::URI('http://example.org/UNUSED_term')) ).to be true
|
213
|
+
end
|
214
|
+
|
215
|
+
it "will destory if term doesn't exist" do
|
216
|
+
# NOTE: ActiveTriples.destroy! persists the object to be destroyed before destroying it
|
217
|
+
expect( LD4L::OpenAnnotationRDF::SemanticTagBody.destroy_if_unused(RDF::URI('http://example.org/NONEXISTENT_term')) ).to be true
|
218
|
+
end
|
219
|
+
end
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
# -----------------------------------------------
|
224
|
+
# END -- Test attributes specific to this model
|
225
|
+
# -----------------------------------------------
|
226
|
+
|
227
|
+
|
228
|
+
describe "#persisted?" do
|
229
|
+
context 'with a repository' do
|
230
|
+
before do
|
231
|
+
# Create inmemory repository
|
232
|
+
repository = RDF::Repository.new
|
233
|
+
allow(subject).to receive(:repository).and_return(repository)
|
234
|
+
end
|
235
|
+
|
236
|
+
context "when the object is new" do
|
237
|
+
it "should return false" do
|
238
|
+
expect(subject).not_to be_persisted
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context "when it is saved" do
|
243
|
+
before do
|
244
|
+
subject.persist!
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should return true" do
|
248
|
+
expect(subject).to be_persisted
|
249
|
+
end
|
250
|
+
|
251
|
+
context "and then reloaded" do
|
252
|
+
before do
|
253
|
+
subject.reload
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should be persisted" do
|
257
|
+
expect(subject).to be_persisted
|
258
|
+
end
|
259
|
+
end
|
260
|
+
end
|
261
|
+
end
|
262
|
+
end
|
263
|
+
|
264
|
+
describe "#persist!" do
|
265
|
+
context "when the repository is set" do
|
266
|
+
context "and the item is not a blank node" do
|
267
|
+
|
268
|
+
subject {LD4L::OpenAnnotationRDF::SemanticTagBody.new("123")}
|
269
|
+
|
270
|
+
before do
|
271
|
+
# Create inmemory repository
|
272
|
+
@repo = RDF::Repository.new
|
273
|
+
allow(subject.class).to receive(:repository).and_return(nil)
|
274
|
+
allow(subject).to receive(:repository).and_return(@repo)
|
275
|
+
subject.persist!
|
276
|
+
end
|
277
|
+
|
278
|
+
it "should persist to the repository" do
|
279
|
+
expect(@repo.statements.first).to eq subject.statements.first
|
280
|
+
end
|
281
|
+
|
282
|
+
it "should delete from the repository" do
|
283
|
+
subject.reload
|
284
|
+
subject.persist!
|
285
|
+
subject.reload
|
286
|
+
expect(@repo.statements.to_a.length).to eq 1 # Only the 1 type statements
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
end
|
291
|
+
|
292
|
+
describe '#destroy!' do
|
293
|
+
before do
|
294
|
+
subject << RDF::Statement(RDF::DC.LicenseDocument, RDF::DC.title, 'LICENSE')
|
295
|
+
end
|
296
|
+
|
297
|
+
subject { LD4L::OpenAnnotationRDF::SemanticTagBody.new('456')}
|
298
|
+
|
299
|
+
it 'should return true' do
|
300
|
+
expect(subject.destroy!).to be true
|
301
|
+
expect(subject.destroy).to be true
|
302
|
+
end
|
303
|
+
|
304
|
+
it 'should delete the graph' do
|
305
|
+
subject.destroy
|
306
|
+
expect(subject).to be_empty
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
describe '#rdf_label' do
|
311
|
+
subject {LD4L::OpenAnnotationRDF::SemanticTagBody.new("123")}
|
312
|
+
|
313
|
+
it 'should return an array of label values' do
|
314
|
+
expect(subject.rdf_label).to be_kind_of Array
|
315
|
+
end
|
316
|
+
|
317
|
+
it 'should return the default label as URI when no title property exists' do
|
318
|
+
expect(subject.rdf_label).to eq [RDF::URI("#{LD4L::OpenAnnotationRDF::SemanticTagBody.base_uri}123")]
|
319
|
+
end
|
320
|
+
|
321
|
+
it 'should prioritize configured label values' do
|
322
|
+
custom_label = RDF::URI('http://example.org/custom_label')
|
323
|
+
subject.class.configure :rdf_label => custom_label
|
324
|
+
subject << RDF::Statement(subject.rdf_subject, custom_label, RDF::Literal('New Label'))
|
325
|
+
expect(subject.rdf_label).to eq ['New Label']
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
describe '#solrize' do
|
330
|
+
it 'should return a label for bnodes' do
|
331
|
+
expect(subject.solrize).to eq subject.rdf_label
|
332
|
+
end
|
333
|
+
|
334
|
+
it 'should return a string of the resource uri' do
|
335
|
+
subject.set_subject! 'http://example.org/moomin'
|
336
|
+
expect(subject.solrize).to eq 'http://example.org/moomin'
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
describe 'big complex graphs' do
|
341
|
+
before do
|
342
|
+
class DummyPerson < ActiveTriples::Resource
|
343
|
+
configure :type => RDF::URI('http://example.org/Person')
|
344
|
+
property :foafname, :predicate => RDF::FOAF.name
|
345
|
+
property :publications, :predicate => RDF::FOAF.publications, :class_name => 'DummyDocument'
|
346
|
+
property :knows, :predicate => RDF::FOAF.knows, :class_name => DummyPerson
|
347
|
+
end
|
348
|
+
|
349
|
+
class DummyDocument < ActiveTriples::Resource
|
350
|
+
configure :type => RDF::URI('http://example.org/Document')
|
351
|
+
property :title, :predicate => RDF::DC.title
|
352
|
+
property :creator, :predicate => RDF::DC.creator, :class_name => 'DummyPerson'
|
353
|
+
end
|
354
|
+
|
355
|
+
LD4L::OpenAnnotationRDF::SemanticTagBody.property :item, :predicate => RDF::DC.relation, :class_name => DummyDocument
|
356
|
+
end
|
357
|
+
|
358
|
+
subject { LD4L::OpenAnnotationRDF::SemanticTagBody.new }
|
359
|
+
|
360
|
+
let (:document1) do
|
361
|
+
d = DummyDocument.new
|
362
|
+
d.title = 'Document One'
|
363
|
+
d
|
364
|
+
end
|
365
|
+
|
366
|
+
let (:document2) do
|
367
|
+
d = DummyDocument.new
|
368
|
+
d.title = 'Document Two'
|
369
|
+
d
|
370
|
+
end
|
371
|
+
|
372
|
+
let (:person1) do
|
373
|
+
p = DummyPerson.new
|
374
|
+
p.foafname = 'Alice'
|
375
|
+
p
|
376
|
+
end
|
377
|
+
|
378
|
+
let (:person2) do
|
379
|
+
p = DummyPerson.new
|
380
|
+
p.foafname = 'Bob'
|
381
|
+
p
|
382
|
+
end
|
383
|
+
|
384
|
+
let (:data) { <<END
|
385
|
+
_:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeClass> .
|
386
|
+
_:1 <http://purl.org/dc/terms/relation> _:2 .
|
387
|
+
_:2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Document> .
|
388
|
+
_:2 <http://purl.org/dc/terms/title> "Document One" .
|
389
|
+
_:2 <http://purl.org/dc/terms/creator> _:3 .
|
390
|
+
_:2 <http://purl.org/dc/terms/creator> _:4 .
|
391
|
+
_:4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
|
392
|
+
_:4 <http://xmlns.com/foaf/0.1/name> "Bob" .
|
393
|
+
_:3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
|
394
|
+
_:3 <http://xmlns.com/foaf/0.1/name> "Alice" .
|
395
|
+
_:3 <http://xmlns.com/foaf/0.1/knows> _:4 ."
|
396
|
+
END
|
397
|
+
}
|
398
|
+
|
399
|
+
after do
|
400
|
+
Object.send(:remove_const, "DummyDocument")
|
401
|
+
Object.send(:remove_const, "DummyPerson")
|
402
|
+
end
|
403
|
+
|
404
|
+
it 'should allow access to deep nodes' do
|
405
|
+
document1.creator = [person1, person2]
|
406
|
+
document2.creator = person1
|
407
|
+
person1.knows = person2
|
408
|
+
subject.item = [document1]
|
409
|
+
expect(subject.item.first.creator.first.knows.first.foafname).to eq ['Bob']
|
410
|
+
end
|
411
|
+
end
|
412
|
+
end
|
@@ -0,0 +1,672 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
# TODO: Uses CommentBody as the annotation body, which is wrong. Should be URI into controlled vocabulary.
|
4
|
+
|
5
|
+
describe 'LD4L::OpenAnnotationRDF::TagAnnotation' do
|
6
|
+
|
7
|
+
subject { LD4L::OpenAnnotationRDF::TagAnnotation.new }
|
8
|
+
|
9
|
+
describe 'rdf_subject' do
|
10
|
+
it "should be a blank node if we haven't set it" do
|
11
|
+
expect(subject.rdf_subject.node?).to be true
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should be settable when it has not been set yet" do
|
15
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
16
|
+
expect(subject.rdf_subject).to eq RDF::URI('http://example.org/moomin')
|
17
|
+
end
|
18
|
+
|
19
|
+
it "should append to base URI when setting to non-URI subject" do
|
20
|
+
subject.set_subject! '123'
|
21
|
+
expect(subject.rdf_subject).to eq RDF::URI("#{LD4L::OpenAnnotationRDF::TagAnnotation.base_uri}123")
|
22
|
+
end
|
23
|
+
|
24
|
+
describe 'when changing subject' do
|
25
|
+
before do
|
26
|
+
subject << RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland'))
|
27
|
+
subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject)
|
28
|
+
subject << RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land')
|
29
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'should update graph subjects' do
|
33
|
+
expect(subject.has_statement?(RDF::Statement.new(subject.rdf_subject, RDF::DC.title, RDF::Literal('Comet in Moominland')))).to be true
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'should update graph objects' do
|
37
|
+
expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.isPartOf, subject.rdf_subject))).to be true
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'should leave other uris alone' do
|
41
|
+
expect(subject.has_statement?(RDF::Statement.new(RDF::URI('http://example.org/moomin_comics'), RDF::DC.relation, 'http://example.org/moomin_land'))).to be true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe 'created with URI subject' do
|
46
|
+
before do
|
47
|
+
subject.set_subject! RDF::URI('http://example.org/moomin')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'should not be settable' do
|
51
|
+
expect{ subject.set_subject! RDF::URI('http://example.org/moomin2') }.to raise_error
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
|
57
|
+
# -------------------------------------------------
|
58
|
+
# START -- Test attributes specific to this model
|
59
|
+
# -------------------------------------------------
|
60
|
+
|
61
|
+
describe 'type' do
|
62
|
+
it "should be an RDFVocabularies::OA.Annotation" do
|
63
|
+
expect(subject.type.first.value).to eq RDFVocabularies::OA.Annotation.value
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
describe 'hasTarget' do
|
68
|
+
it "should be empty array if we haven't set it" do
|
69
|
+
expect(subject.hasTarget).to match_array([])
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should be settable" do
|
73
|
+
subject.hasTarget = RDF::URI("http://example.org/b123")
|
74
|
+
expect(subject.hasTarget.first.rdf_subject.to_s).to eq "http://example.org/b123"
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should be changeable" do
|
78
|
+
subject.hasTarget = RDF::URI("http://example.org/b123")
|
79
|
+
subject.hasTarget = RDF::URI("http://example.org/b123_NEW")
|
80
|
+
expect(subject.hasTarget.first.rdf_subject.to_s).to eq "http://example.org/b123_NEW"
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe 'hasBody' do
|
85
|
+
# NOTE: Preferred method to set body is to use setTag method which will
|
86
|
+
# create the appropriate annotation body object and triples.
|
87
|
+
it "should be empty array if we haven't set it" do
|
88
|
+
expect(subject.hasBody).to match_array([])
|
89
|
+
end
|
90
|
+
|
91
|
+
it "should be settable" do
|
92
|
+
a_open_annotation_body = LD4L::OpenAnnotationRDF::TagBody.new('foo')
|
93
|
+
subject.hasBody = a_open_annotation_body
|
94
|
+
expect(subject.hasBody.first).to eq a_open_annotation_body
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should be changeable" do
|
98
|
+
orig_open_annotation_body = LD4L::OpenAnnotationRDF::TagBody.new('foo')
|
99
|
+
new_open_annotation_body = LD4L::OpenAnnotationRDF::TagBody.new('bar')
|
100
|
+
subject.hasBody = orig_open_annotation_body
|
101
|
+
subject.hasBody = new_open_annotation_body
|
102
|
+
expect(subject.hasBody.first).to eq new_open_annotation_body
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#setTag' do
|
107
|
+
# TODO Need fuller set of tests for all potential behaviours.
|
108
|
+
before do
|
109
|
+
@repo = RDF::Repository.new
|
110
|
+
allow(subject.class).to receive(:repository).and_return(nil)
|
111
|
+
allow(subject).to receive(:repository).and_return(@repo)
|
112
|
+
end
|
113
|
+
|
114
|
+
context "when new value is nil" do
|
115
|
+
it "should throw invalid arguement exception" do
|
116
|
+
expect{ subject.setTag(nil) }.to raise_error
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
context "when new value is a string of 0 length" do
|
121
|
+
it "should throw invalid arguement exception" do
|
122
|
+
expect{ subject.setTag("") }.to raise_error
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
context "when new value is not a string" do
|
127
|
+
it "should throw invalid arguement exception" do
|
128
|
+
expect{ subject.setTag(3) }.to raise_error
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
context "when new value is same as old value" do
|
133
|
+
it "should return the existing TagBody unchanged" do
|
134
|
+
tb1 = subject.setTag('foo')
|
135
|
+
tb2 = subject.setTag('foo')
|
136
|
+
expect(tb2).to eq tb1
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context "when config enforces unique tags" do
|
141
|
+
before do
|
142
|
+
LD4L::OpenAnnotationRDF.configuration.unique_tags = true
|
143
|
+
end
|
144
|
+
after do
|
145
|
+
LD4L::OpenAnnotationRDF.configuration.reset_unique_tags
|
146
|
+
end
|
147
|
+
|
148
|
+
context "and tag doesn't already exist as a TagBody" do
|
149
|
+
it "should create an instance of LD4L::OpenAnnotationRDF::TagBody and set hasBody property to it" do
|
150
|
+
# verify tag value doesn't already exist
|
151
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.fetch_by_tag_value('foo')
|
152
|
+
expect(tb).to be_nil
|
153
|
+
|
154
|
+
subject.setTag('foo')
|
155
|
+
expect(subject.hasBody.first.tag.first).to eq 'foo'
|
156
|
+
expect(subject.getBody.tag.first).to eq 'foo'
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
context "and tag already exists as a TagBody" do
|
161
|
+
before do
|
162
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.new('http://example.org/existing_tag')
|
163
|
+
tb.tag = 'foo'
|
164
|
+
tb.persist!
|
165
|
+
expect(tb).to be_persisted
|
166
|
+
end
|
167
|
+
it "should resume the existing LD4L::OpenAnnotationRDF::TagBody and set hasBody property to it" do
|
168
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.new('http://example.org/existing_tag')
|
169
|
+
expect(tb.tag).to eq ['foo']
|
170
|
+
expect(tb).to be_persisted
|
171
|
+
|
172
|
+
subject.setTag('foo')
|
173
|
+
expect(subject.hasBody.first.rdf_subject.to_s).to eq 'http://example.org/existing_tag'
|
174
|
+
expect(subject.getBody.rdf_subject.to_s).to eq 'http://example.org/existing_tag'
|
175
|
+
expect(subject.getBody.rdf_subject).to eq tb.rdf_subject
|
176
|
+
# NOTE: body is considered not persisted because it's parent, the annotation, is not persisted
|
177
|
+
expect(subject.getBody).not_to be_persisted
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
context "when config does not enforce unique tags" do
|
183
|
+
before do
|
184
|
+
LD4L::OpenAnnotationRDF.configuration.unique_tags = false
|
185
|
+
end
|
186
|
+
after do
|
187
|
+
LD4L::OpenAnnotationRDF.configuration.reset_unique_tags
|
188
|
+
end
|
189
|
+
|
190
|
+
context "and tag doesn't already exist as a TagBody" do
|
191
|
+
it "should create an instance of LD4L::OpenAnnotationRDF::TagBody and set hasBody property to it" do
|
192
|
+
# verify tag value doesn't already exist
|
193
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.fetch_by_tag_value('new_foo')
|
194
|
+
expect(tb).to be_nil
|
195
|
+
|
196
|
+
subject.setTag('new_foo')
|
197
|
+
expect(subject.hasBody.first.tag.first).to eq 'new_foo'
|
198
|
+
expect(subject.getBody.tag.first).to eq 'new_foo'
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
context "and tag already exists as a TagBody" do
|
203
|
+
before do
|
204
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.new('http://example.org/existing_tag')
|
205
|
+
tb.tag = 'foo'
|
206
|
+
tb.persist!
|
207
|
+
expect(tb).to be_persisted
|
208
|
+
end
|
209
|
+
it "should create an instance of LD4L::OpenAnnotationRDF::TagBody and set hasBody property to it" do
|
210
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.new('http://example.org/existing_tag')
|
211
|
+
expect(tb.tag).to eq ['foo']
|
212
|
+
expect(tb).to be_persisted
|
213
|
+
|
214
|
+
subject.setTag('foo')
|
215
|
+
expect(subject.hasBody.first.rdf_subject.to_s).not_to eq 'http://example.org/existing_tag'
|
216
|
+
expect(subject.getBody.rdf_subject.to_s).not_to eq 'http://example.org/existing_tag'
|
217
|
+
expect(subject.getBody.rdf_subject).not_to eq tb.rdf_subject
|
218
|
+
# NOTE: body is considered not persisted because it's parent, the annotation, is not persisted
|
219
|
+
expect(subject.getBody).not_to be_persisted
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
224
|
+
|
225
|
+
describe 'annotatedBy' do
|
226
|
+
it "should be empty array if we haven't set it" do
|
227
|
+
expect(subject.annotatedBy).to match_array([])
|
228
|
+
end
|
229
|
+
|
230
|
+
it "should be settable" do
|
231
|
+
a_person = LD4L::FoafRDF::Person.new('1')
|
232
|
+
subject.annotatedBy = a_person
|
233
|
+
expect(subject.annotatedBy.first).to eq a_person
|
234
|
+
end
|
235
|
+
|
236
|
+
it "should be changeable" do
|
237
|
+
orig_person = LD4L::FoafRDF::Person.new('1')
|
238
|
+
new_person = LD4L::FoafRDF::Person.new('2')
|
239
|
+
subject.annotatedBy = orig_person
|
240
|
+
subject.annotatedBy = new_person
|
241
|
+
expect(subject.annotatedBy.first).to eq new_person
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
245
|
+
describe 'annotatedAt' do
|
246
|
+
it "should be empty array if we haven't set it" do
|
247
|
+
expect(subject.annotatedAt).to match_array([])
|
248
|
+
end
|
249
|
+
|
250
|
+
it "should be settable" do
|
251
|
+
a_time = Time::now.strftime("%Y-%m-%dT%H:%M:%S.%L%z")
|
252
|
+
subject.annotatedAt = a_time
|
253
|
+
expect(subject.annotatedAt.first).to eq a_time
|
254
|
+
end
|
255
|
+
|
256
|
+
it "should be changeable" do
|
257
|
+
orig_time = Time.local(2014, 6, 1, 8, 30).strftime("%Y-%m-%dT%H:%M:%S.%L%z")
|
258
|
+
new_time = Time.now.strftime("%Y-%m-%dT%H:%M:%S.%L%z")
|
259
|
+
subject.annotatedAt = orig_time
|
260
|
+
subject.annotatedAt = new_time
|
261
|
+
expect(subject.annotatedAt.first).to eq new_time
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
describe 'motivatedBy' do
|
266
|
+
it "should be OA.tagging if we haven't set it" do
|
267
|
+
expect(subject.motivatedBy.first.rdf_subject).to eq RDFVocabularies::OA.tagging
|
268
|
+
end
|
269
|
+
|
270
|
+
it "should be settable" do
|
271
|
+
subject.motivatedBy = RDFVocabularies::OA.describing
|
272
|
+
expect(subject.motivatedBy.first.rdf_subject).to eq RDFVocabularies::OA.describing
|
273
|
+
end
|
274
|
+
|
275
|
+
it "should be changeable" do
|
276
|
+
subject.motivatedBy = RDFVocabularies::OA.describing
|
277
|
+
subject.motivatedBy = RDFVocabularies::OA.classifying
|
278
|
+
expect(subject.motivatedBy.first.rdf_subject).to eq RDFVocabularies::OA.classifying
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
describe '#localname_prefix' do
|
283
|
+
it "should return default prefix" do
|
284
|
+
prefix = LD4L::OpenAnnotationRDF::TagAnnotation.localname_prefix
|
285
|
+
expect(prefix).to eq "ta"
|
286
|
+
end
|
287
|
+
end
|
288
|
+
|
289
|
+
# -----------------------------------------------
|
290
|
+
# END -- Test attributes specific to this model
|
291
|
+
# -----------------------------------------------
|
292
|
+
|
293
|
+
|
294
|
+
describe "#persisted?" do
|
295
|
+
context 'with a repository' do
|
296
|
+
before do
|
297
|
+
# Create inmemory repository
|
298
|
+
repository = RDF::Repository.new
|
299
|
+
allow(subject).to receive(:repository).and_return(repository)
|
300
|
+
end
|
301
|
+
|
302
|
+
context "when the object is new" do
|
303
|
+
it "should return false" do
|
304
|
+
expect(subject).not_to be_persisted
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
context "when it is saved" do
|
309
|
+
before do
|
310
|
+
subject.motivatedBy = RDFVocabularies::OA.commenting
|
311
|
+
subject.persist!
|
312
|
+
end
|
313
|
+
|
314
|
+
it "should return true" do
|
315
|
+
expect(subject).to be_persisted
|
316
|
+
end
|
317
|
+
|
318
|
+
context "and then modified" do
|
319
|
+
before do
|
320
|
+
subject.motivatedBy = RDFVocabularies::OA.tagging
|
321
|
+
end
|
322
|
+
|
323
|
+
it "should return true" do
|
324
|
+
expect(subject).to be_persisted
|
325
|
+
end
|
326
|
+
end
|
327
|
+
context "and then reloaded" do
|
328
|
+
before do
|
329
|
+
subject.reload
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should reset the motivatedBy" do
|
333
|
+
expect(subject.motivatedBy.first.rdf_subject.to_s).to eq RDFVocabularies::OA.commenting.to_s
|
334
|
+
end
|
335
|
+
|
336
|
+
it "should be persisted" do
|
337
|
+
expect(subject).to be_persisted
|
338
|
+
end
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
342
|
+
end
|
343
|
+
|
344
|
+
describe "#persist!" do
|
345
|
+
context "when the repository is set" do
|
346
|
+
context "and the annotation is not a blank node" do
|
347
|
+
|
348
|
+
subject {LD4L::OpenAnnotationRDF::TagAnnotation.new("123")}
|
349
|
+
|
350
|
+
before do
|
351
|
+
# Create inmemory repository
|
352
|
+
@repo = RDF::Repository.new
|
353
|
+
allow(subject.class).to receive(:repository).and_return(nil)
|
354
|
+
allow(subject).to receive(:repository).and_return(@repo)
|
355
|
+
subject.motivatedBy = RDFVocabularies::OA.commenting
|
356
|
+
subject.persist!
|
357
|
+
end
|
358
|
+
|
359
|
+
it "should persist to the repository" do
|
360
|
+
expect(@repo.statements.first).to eq subject.statements.first
|
361
|
+
end
|
362
|
+
|
363
|
+
it "should delete from the repository" do
|
364
|
+
subject.reload
|
365
|
+
expect(subject.motivatedBy.first.rdf_subject.to_s).to eq RDFVocabularies::OA.commenting.to_s
|
366
|
+
subject.motivatedBy = []
|
367
|
+
expect(subject.motivatedBy).to eq []
|
368
|
+
subject.persist!
|
369
|
+
subject.reload
|
370
|
+
expect(subject.annotatedAt).to eq []
|
371
|
+
expect(@repo.statements.to_a.length).to eq 1 # Only the type statement
|
372
|
+
end
|
373
|
+
|
374
|
+
context "and body is set" do
|
375
|
+
before do
|
376
|
+
subject.setTag('foo')
|
377
|
+
subject.persist!
|
378
|
+
end
|
379
|
+
it "should persist body to the repository" do
|
380
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.new(subject.getBody.rdf_subject)
|
381
|
+
expect(tb).to be_persisted
|
382
|
+
tb = LD4L::OpenAnnotationRDF::TagBody.fetch_by_tag_value('foo')
|
383
|
+
expect(tb).to be_persisted
|
384
|
+
expect(subject.getBody.rdf_subject.to_s).to eq tb.rdf_subject.to_s
|
385
|
+
end
|
386
|
+
end
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe '#destroy!' do
|
392
|
+
before do
|
393
|
+
subject << RDF::Statement(RDF::DC.LicenseDocument, RDF::DC.title, 'LICENSE')
|
394
|
+
end
|
395
|
+
|
396
|
+
subject { LD4L::OpenAnnotationRDF::TagAnnotation.new('123') }
|
397
|
+
|
398
|
+
it 'should return true' do
|
399
|
+
expect(subject.destroy!).to be true
|
400
|
+
expect(subject.destroy).to be true
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'should delete the graph' do
|
404
|
+
subject.destroy
|
405
|
+
expect(subject).to be_empty
|
406
|
+
end
|
407
|
+
|
408
|
+
context 'with a parent' do
|
409
|
+
before do
|
410
|
+
subject.annotatedBy = child
|
411
|
+
end
|
412
|
+
|
413
|
+
let(:child) do
|
414
|
+
LD4L::FoafRDF::Person.new('456')
|
415
|
+
end
|
416
|
+
|
417
|
+
it 'should empty the graph and remove it from the parent' do
|
418
|
+
child.destroy
|
419
|
+
expect(subject.annotatedBy).to be_empty
|
420
|
+
end
|
421
|
+
|
422
|
+
it 'should remove its whole graph from the parent' do
|
423
|
+
child.destroy
|
424
|
+
child.each_statement do |s|
|
425
|
+
expect(subject.statements).not_to include s
|
426
|
+
end
|
427
|
+
end
|
428
|
+
end
|
429
|
+
|
430
|
+
context 'with annotation body' do
|
431
|
+
# TODO Need fuller set of tests for all potential behaviours.
|
432
|
+
before do
|
433
|
+
subject.setTag('foo')
|
434
|
+
end
|
435
|
+
|
436
|
+
context 'and body is set on the annotation' do
|
437
|
+
let(:child) do
|
438
|
+
subject.getBody
|
439
|
+
end
|
440
|
+
|
441
|
+
it 'should empty the graph and remove it from the parent' do
|
442
|
+
child.destroy
|
443
|
+
expect(subject.hasBody).to be_empty
|
444
|
+
end
|
445
|
+
|
446
|
+
it 'should remove its whole graph from the parent' do
|
447
|
+
child.destroy
|
448
|
+
child.each_statement do |s|
|
449
|
+
expect(subject.statements).not_to include s
|
450
|
+
end
|
451
|
+
end
|
452
|
+
end
|
453
|
+
end
|
454
|
+
end
|
455
|
+
|
456
|
+
describe 'attributes' do
|
457
|
+
before do
|
458
|
+
subject.annotatedBy = annotatedBy
|
459
|
+
subject.motivatedBy = 'commenting'
|
460
|
+
end
|
461
|
+
|
462
|
+
subject {LD4L::OpenAnnotationRDF::TagAnnotation.new("123")}
|
463
|
+
|
464
|
+
let(:annotatedBy) { LD4L::FoafRDF::Person.new('456') }
|
465
|
+
|
466
|
+
it 'should return an attributes hash' do
|
467
|
+
expect(subject.attributes).to be_a Hash
|
468
|
+
end
|
469
|
+
|
470
|
+
it 'should contain data' do
|
471
|
+
expect(subject.attributes['motivatedBy']).to eq ['commenting']
|
472
|
+
end
|
473
|
+
|
474
|
+
it 'should contain child objects' do
|
475
|
+
expect(subject.attributes['annotatedBy']).to eq [annotatedBy]
|
476
|
+
end
|
477
|
+
|
478
|
+
context 'with unmodeled data' do
|
479
|
+
before do
|
480
|
+
subject << RDF::Statement(subject.rdf_subject, RDF::DC.contributor, 'Tove Jansson')
|
481
|
+
subject << RDF::Statement(subject.rdf_subject, RDF::DC.relation, RDF::URI('http://example.org/moomi'))
|
482
|
+
node = RDF::Node.new
|
483
|
+
subject << RDF::Statement(RDF::URI('http://example.org/moomi'), RDF::DC.relation, node)
|
484
|
+
subject << RDF::Statement(node, RDF::DC.title, 'bnode')
|
485
|
+
end
|
486
|
+
|
487
|
+
it 'should include data with URIs as attribute names' do
|
488
|
+
expect(subject.attributes[RDF::DC.contributor.to_s]).to eq ['Tove Jansson']
|
489
|
+
end
|
490
|
+
|
491
|
+
it 'should return generic Resources' do
|
492
|
+
expect(subject.attributes[RDF::DC.relation.to_s].first).to be_a ActiveTriples::Resource
|
493
|
+
end
|
494
|
+
|
495
|
+
it 'should build deep data for Resources' do
|
496
|
+
expect(subject.attributes[RDF::DC.relation.to_s].first.get_values(RDF::DC.relation).
|
497
|
+
first.get_values(RDF::DC.title)).to eq ['bnode']
|
498
|
+
end
|
499
|
+
|
500
|
+
it 'should include deep data in serializable_hash' do
|
501
|
+
expect(subject.serializable_hash[RDF::DC.relation.to_s].first.get_values(RDF::DC.relation).
|
502
|
+
first.get_values(RDF::DC.title)).to eq ['bnode']
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
506
|
+
describe 'attribute_serialization' do
|
507
|
+
describe '#to_json' do
|
508
|
+
it 'should return a string with correct objects' do
|
509
|
+
json_hash = JSON.parse(subject.to_json)
|
510
|
+
expect(json_hash['annotatedBy'].first['id']).to eq annotatedBy.rdf_subject.to_s
|
511
|
+
end
|
512
|
+
end
|
513
|
+
end
|
514
|
+
end
|
515
|
+
|
516
|
+
describe 'property methods' do
|
517
|
+
it 'should set and get properties' do
|
518
|
+
subject.motivatedBy = 'commenting'
|
519
|
+
expect(subject.motivatedBy).to eq ['commenting']
|
520
|
+
end
|
521
|
+
end
|
522
|
+
|
523
|
+
describe 'child nodes' do
|
524
|
+
it 'should return an object of the correct class when the value is built from the base URI' do
|
525
|
+
subject.annotatedBy = LD4L::FoafRDF::Person.new('456')
|
526
|
+
expect(subject.annotatedBy.first).to be_kind_of LD4L::FoafRDF::Person
|
527
|
+
end
|
528
|
+
|
529
|
+
it 'should return an object with the correct URI when created with a URI' do
|
530
|
+
subject.annotatedBy = LD4L::FoafRDF::Person.new("http://vivo.cornell.edu/individual/JohnSmith")
|
531
|
+
expect(subject.annotatedBy.first.rdf_subject).to eq RDF::URI("http://vivo.cornell.edu/individual/JohnSmith")
|
532
|
+
end
|
533
|
+
|
534
|
+
it 'should return an object of the correct class when the value is a bnode' do
|
535
|
+
subject.annotatedBy = LD4L::FoafRDF::Person.new
|
536
|
+
expect(subject.annotatedBy.first).to be_kind_of LD4L::FoafRDF::Person
|
537
|
+
end
|
538
|
+
end
|
539
|
+
|
540
|
+
describe '#type' do
|
541
|
+
it 'should return the type configured on the parent class' do
|
542
|
+
expect(subject.type).to eq [LD4L::OpenAnnotationRDF::TagAnnotation.type]
|
543
|
+
end
|
544
|
+
|
545
|
+
it 'should set the type' do
|
546
|
+
subject.type = RDF::URI('http://example.org/AnotherClass')
|
547
|
+
expect(subject.type).to eq [RDF::URI('http://example.org/AnotherClass')]
|
548
|
+
end
|
549
|
+
|
550
|
+
it 'should be the type in the graph' do
|
551
|
+
subject.query(:subject => subject.rdf_subject, :predicate => RDF.type).statements do |s|
|
552
|
+
expect(s.object).to eq RDF::URI('http://example.org/AnotherClass')
|
553
|
+
end
|
554
|
+
end
|
555
|
+
end
|
556
|
+
|
557
|
+
describe '#rdf_label' do
|
558
|
+
subject {LD4L::OpenAnnotationRDF::TagAnnotation.new("123")}
|
559
|
+
|
560
|
+
it 'should return an array of label values' do
|
561
|
+
expect(subject.rdf_label).to be_kind_of Array
|
562
|
+
end
|
563
|
+
|
564
|
+
it 'should return the default label as URI when no title property exists' do
|
565
|
+
expect(subject.rdf_label).to eq [RDF::URI("#{LD4L::OpenAnnotationRDF::TagAnnotation.base_uri}123")]
|
566
|
+
end
|
567
|
+
|
568
|
+
it 'should prioritize configured label values' do
|
569
|
+
custom_label = RDF::URI('http://example.org/custom_label')
|
570
|
+
subject.class.configure :rdf_label => custom_label
|
571
|
+
subject << RDF::Statement(subject.rdf_subject, custom_label, RDF::Literal('New Label'))
|
572
|
+
expect(subject.rdf_label).to eq ['New Label']
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
describe '#solrize' do
|
577
|
+
it 'should return a label for bnodes' do
|
578
|
+
expect(subject.solrize).to eq subject.rdf_label
|
579
|
+
end
|
580
|
+
|
581
|
+
it 'should return a string of the resource uri' do
|
582
|
+
subject.set_subject! 'http://example.org/moomin'
|
583
|
+
expect(subject.solrize).to eq 'http://example.org/moomin'
|
584
|
+
end
|
585
|
+
end
|
586
|
+
|
587
|
+
describe 'editing the graph' do
|
588
|
+
it 'should write properties when statements are added' do
|
589
|
+
subject << RDF::Statement.new(subject.rdf_subject, RDFVocabularies::OA.motivatedBy, 'commenting')
|
590
|
+
expect(subject.motivatedBy).to include 'commenting'
|
591
|
+
end
|
592
|
+
|
593
|
+
it 'should delete properties when statements are removed' do
|
594
|
+
subject << RDF::Statement.new(subject.rdf_subject, RDFVocabularies::OA.annotatedBy, 'John Smith')
|
595
|
+
subject.delete RDF::Statement.new(subject.rdf_subject, RDFVocabularies::OA.annotatedBy, 'John Smith')
|
596
|
+
expect(subject.annotatedBy).to eq []
|
597
|
+
end
|
598
|
+
end
|
599
|
+
|
600
|
+
describe 'big complex graphs' do
|
601
|
+
before do
|
602
|
+
class DummyPerson < ActiveTriples::Resource
|
603
|
+
configure :type => RDF::URI('http://example.org/Person')
|
604
|
+
property :foafname, :predicate => RDF::FOAF.name
|
605
|
+
property :publications, :predicate => RDF::FOAF.publications, :class_name => 'DummyDocument'
|
606
|
+
property :knows, :predicate => RDF::FOAF.knows, :class_name => DummyPerson
|
607
|
+
end
|
608
|
+
|
609
|
+
class DummyDocument < ActiveTriples::Resource
|
610
|
+
configure :type => RDF::URI('http://example.org/Document')
|
611
|
+
property :title, :predicate => RDF::DC.title
|
612
|
+
property :creator, :predicate => RDF::DC.creator, :class_name => 'DummyPerson'
|
613
|
+
end
|
614
|
+
|
615
|
+
LD4L::OpenAnnotationRDF::TagAnnotation.property :item, :predicate => RDF::DC.relation, :class_name => DummyDocument
|
616
|
+
end
|
617
|
+
|
618
|
+
subject { LD4L::OpenAnnotationRDF::TagAnnotation.new }
|
619
|
+
|
620
|
+
let (:document1) do
|
621
|
+
d = DummyDocument.new
|
622
|
+
d.title = 'Document One'
|
623
|
+
d
|
624
|
+
end
|
625
|
+
|
626
|
+
let (:document2) do
|
627
|
+
d = DummyDocument.new
|
628
|
+
d.title = 'Document Two'
|
629
|
+
d
|
630
|
+
end
|
631
|
+
|
632
|
+
let (:person1) do
|
633
|
+
p = DummyPerson.new
|
634
|
+
p.foafname = 'Alice'
|
635
|
+
p
|
636
|
+
end
|
637
|
+
|
638
|
+
let (:person2) do
|
639
|
+
p = DummyPerson.new
|
640
|
+
p.foafname = 'Bob'
|
641
|
+
p
|
642
|
+
end
|
643
|
+
|
644
|
+
let (:data) { <<END
|
645
|
+
_:1 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/SomeClass> .
|
646
|
+
_:1 <http://purl.org/dc/terms/relation> _:2 .
|
647
|
+
_:2 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Document> .
|
648
|
+
_:2 <http://purl.org/dc/terms/title> "Document One" .
|
649
|
+
_:2 <http://purl.org/dc/terms/creator> _:3 .
|
650
|
+
_:2 <http://purl.org/dc/terms/creator> _:4 .
|
651
|
+
_:4 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
|
652
|
+
_:4 <http://xmlns.com/foaf/0.1/name> "Bob" .
|
653
|
+
_:3 <http://www.w3.org/1999/02/22-rdf-syntax-ns#type> <http://example.org/Person> .
|
654
|
+
_:3 <http://xmlns.com/foaf/0.1/name> "Alice" .
|
655
|
+
_:3 <http://xmlns.com/foaf/0.1/knows> _:4 ."
|
656
|
+
END
|
657
|
+
}
|
658
|
+
|
659
|
+
after do
|
660
|
+
Object.send(:remove_const, "DummyDocument")
|
661
|
+
Object.send(:remove_const, "DummyPerson")
|
662
|
+
end
|
663
|
+
|
664
|
+
it 'should allow access to deep nodes' do
|
665
|
+
document1.creator = [person1, person2]
|
666
|
+
document2.creator = person1
|
667
|
+
person1.knows = person2
|
668
|
+
subject.item = [document1]
|
669
|
+
expect(subject.item.first.creator.first.knows.first.foafname).to eq ['Bob']
|
670
|
+
end
|
671
|
+
end
|
672
|
+
end
|