rdf-ldp 0.9.2 → 2.1.0
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 +5 -5
- data/CHANGELOG.md +10 -0
- data/CREDITS +1 -0
- data/README.md +66 -10
- data/UNLICENSE +1 -1
- data/VERSION +1 -1
- data/app/lamprey.rb +119 -40
- data/bin/lamprey +15 -1
- data/lib/rack/ldp.rb +23 -25
- data/lib/rdf/ldp/container.rb +32 -22
- data/lib/rdf/ldp/direct_container.rb +9 -7
- data/lib/rdf/ldp/indirect_container.rb +8 -6
- data/lib/rdf/ldp/interaction_model.rb +39 -29
- data/lib/rdf/ldp/non_rdf_source.rb +10 -6
- data/lib/rdf/ldp/rdf_source.rb +3 -3
- data/lib/rdf/ldp/resource.rb +33 -31
- data/lib/rdf/ldp/spec/container.rb +337 -0
- data/lib/rdf/ldp/spec/direct_container.rb +245 -0
- data/lib/rdf/ldp/spec/indirect_container.rb +152 -0
- data/lib/rdf/ldp/spec/non_rdf_source.rb +138 -0
- data/lib/rdf/ldp/spec/rdf_source.rb +370 -0
- data/lib/rdf/ldp/spec/resource.rb +242 -0
- data/lib/rdf/ldp/spec.rb +6 -0
- data/lib/rdf/ldp/storage_adapters/file_storage_adapter.rb +4 -4
- data/lib/rdf/ldp/version.rb +16 -3
- data/lib/rdf/ldp.rb +4 -3
- metadata +89 -55
@@ -0,0 +1,337 @@
|
|
1
|
+
require 'rdf/ldp/spec/rdf_source'
|
2
|
+
|
3
|
+
shared_examples 'a Container' do
|
4
|
+
it_behaves_like 'an RDFSource'
|
5
|
+
|
6
|
+
let(:uri) { RDF::URI('http://ex.org/moomin') }
|
7
|
+
subject { described_class.new(uri) }
|
8
|
+
|
9
|
+
it { is_expected.to be_container }
|
10
|
+
|
11
|
+
describe '#container_class' do
|
12
|
+
it 'returns a uri' do
|
13
|
+
expect(subject.container_class).to be_a RDF::URI
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#containment_triples' do
|
18
|
+
let(:resource) { RDF::URI('http://ex.org/mymble') }
|
19
|
+
|
20
|
+
it 'returns a uri' do
|
21
|
+
subject.add_containment_triple(resource)
|
22
|
+
expect(subject.containment_triples)
|
23
|
+
.to contain_exactly(an_instance_of(RDF::Statement))
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe '#add' do
|
28
|
+
let(:resource) { RDF::URI('http://ex.org/mymble') }
|
29
|
+
before { subject.create(StringIO.new, 'application/n-triples') }
|
30
|
+
|
31
|
+
it 'returns self' do
|
32
|
+
expect(subject.add(resource)).to eq subject
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'containment triple is added to graph' do
|
36
|
+
expect(subject.add(resource).graph)
|
37
|
+
.to include subject.make_containment_triple(resource)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
describe '#add_containment_triple' do
|
42
|
+
let(:resource) { RDF::URI('http://ex.org/mymble') }
|
43
|
+
|
44
|
+
it 'returns self' do
|
45
|
+
expect(subject.add_containment_triple(resource)).to eq subject
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'containment triple is added to graph' do
|
49
|
+
expect(subject.add_containment_triple(resource).graph)
|
50
|
+
.to include subject.make_containment_triple(resource)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#remove_containment_triple' do
|
55
|
+
before { subject.add_containment_triple(resource) }
|
56
|
+
|
57
|
+
let(:resource) { RDF::URI('http://ex.org/mymble') }
|
58
|
+
|
59
|
+
it 'returns self' do
|
60
|
+
expect(subject.remove_containment_triple(resource)).to eq subject
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'membership triple is added to graph' do
|
64
|
+
expect(subject.remove_containment_triple(resource).graph)
|
65
|
+
.not_to include subject.make_containment_triple(resource)
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'updates last_modified for container' do
|
69
|
+
expect { subject.remove_containment_triple(resource) }
|
70
|
+
.to change { subject.last_modified }
|
71
|
+
end
|
72
|
+
|
73
|
+
it 'updates etag for container' do
|
74
|
+
expect { subject.remove_containment_triple(resource) }
|
75
|
+
.to change { subject.etag }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
describe '#make_containment_triple' do
|
80
|
+
let(:resource) { uri / 'papa' }
|
81
|
+
|
82
|
+
it 'returns a statement' do
|
83
|
+
expect(subject.make_containment_triple(resource)).to be_a RDF::Statement
|
84
|
+
end
|
85
|
+
|
86
|
+
it 'statement subject *or* object is #subject_uri' do
|
87
|
+
sub = subject.make_containment_triple(resource).subject
|
88
|
+
obj = subject.make_containment_triple(resource).object
|
89
|
+
expect([sub, obj]).to include subject.subject_uri
|
90
|
+
end
|
91
|
+
|
92
|
+
it 'converts Resource classes to URI' do
|
93
|
+
sub = subject.make_containment_triple(subject).subject
|
94
|
+
obj = subject.make_containment_triple(subject).object
|
95
|
+
expect([sub, obj]).to include subject.subject_uri
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe '#request' do
|
100
|
+
let(:graph) { RDF::Graph.new }
|
101
|
+
|
102
|
+
let(:env) do
|
103
|
+
{ 'rack.input' => StringIO.new(graph.dump(:ntriples)),
|
104
|
+
'CONTENT_TYPE' => 'application/n-triples' }
|
105
|
+
end
|
106
|
+
|
107
|
+
let(:statement) do
|
108
|
+
RDF::Statement(subject.subject_uri,
|
109
|
+
RDF::Vocab::LDP.contains,
|
110
|
+
'moomin')
|
111
|
+
end
|
112
|
+
|
113
|
+
context 'with :PATCH',
|
114
|
+
if: described_class.private_method_defined?(:patch) do
|
115
|
+
|
116
|
+
it 'raises conflict error when editing containment triples' do
|
117
|
+
patch_statement = statement.clone
|
118
|
+
patch_statement.object = 'snorkmaiden'
|
119
|
+
patch = '@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> .' \
|
120
|
+
"\n\nAdd { #{statement.subject.to_base} " \
|
121
|
+
"#{statement.predicate.to_base} #{statement.object.to_base} } ."
|
122
|
+
env = { 'CONTENT_TYPE' => 'text/ldpatch',
|
123
|
+
'rack.input' => StringIO.new(patch) }
|
124
|
+
|
125
|
+
expect { subject.request(:patch, 200, {}, env) }
|
126
|
+
.to raise_error RDF::LDP::Conflict
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
context 'with :PUT',
|
131
|
+
if: described_class.private_method_defined?(:put) do
|
132
|
+
context 'when PUTing containment triples' do
|
133
|
+
it 'when creating a resource raises a Conflict error' do
|
134
|
+
graph << statement
|
135
|
+
|
136
|
+
expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
|
137
|
+
.to raise_error RDF::LDP::Conflict
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'when resource exists raises a Conflict error' do
|
141
|
+
subject.create(StringIO.new, 'application/n-triples')
|
142
|
+
graph << statement
|
143
|
+
expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
|
144
|
+
.to raise_error RDF::LDP::Conflict
|
145
|
+
end
|
146
|
+
|
147
|
+
it 'can put existing containment triple' do
|
148
|
+
subject.create(StringIO.new, 'application/n-triples')
|
149
|
+
subject.graph << statement
|
150
|
+
graph << statement
|
151
|
+
expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env).first)
|
152
|
+
.to eq 200
|
153
|
+
end
|
154
|
+
|
155
|
+
it 'writes data when putting existing containment triple' do
|
156
|
+
subject.create(StringIO.new, 'application/n-triples')
|
157
|
+
subject.graph << statement
|
158
|
+
graph << statement
|
159
|
+
|
160
|
+
new_st = RDF::Statement(RDF::URI('http://example.org/new_moomin'),
|
161
|
+
RDF::Vocab::DC.title,
|
162
|
+
'moomin')
|
163
|
+
graph << new_st
|
164
|
+
expect(subject.request(:PUT, 200, { 'abc' => 'def' }, env).last.graph)
|
165
|
+
.to have_statement new_st
|
166
|
+
end
|
167
|
+
|
168
|
+
it 'raises conflict error when without existing containment triples' do
|
169
|
+
subject.create(StringIO.new, 'application/n-triples')
|
170
|
+
subject.graph << statement
|
171
|
+
expect { subject.request(:PUT, 200, { 'abc' => 'def' }, env) }
|
172
|
+
.to raise_error RDF::LDP::Conflict
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
context 'when POST is implemented',
|
178
|
+
if: described_class.private_method_defined?(:post) do
|
179
|
+
let(:graph) { RDF::Graph.new }
|
180
|
+
before { subject.create(StringIO.new, 'application/n-triples') }
|
181
|
+
|
182
|
+
let(:env) do
|
183
|
+
{ 'rack.input' => StringIO.new(graph.dump(:ntriples)),
|
184
|
+
'CONTENT_TYPE' => 'application/n-triples' }
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'returns status 201' do
|
188
|
+
expect(subject.request(:POST, 200, {}, env).first).to eq 201
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'gives created resource as body' do
|
192
|
+
expect(subject.request(:POST, 200, {}, env).last)
|
193
|
+
.to be_a RDF::LDP::Resource
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'generates an id' do
|
197
|
+
expect(subject.request(:POST, 200, {}, env).last.subject_uri)
|
198
|
+
.to be_starts_with subject.subject_uri.to_s
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'adds containment statement to resource' do
|
202
|
+
expect { subject.request(:POST, 200, {}, env) }
|
203
|
+
.to change { subject.containment_triples.count }.from(0).to(1)
|
204
|
+
end
|
205
|
+
|
206
|
+
it 'updates last_modified for container' do
|
207
|
+
expect { subject.request(:POST, 200, {}, env) }
|
208
|
+
.to change { subject.last_modified }
|
209
|
+
end
|
210
|
+
|
211
|
+
it 'updates etag for container' do
|
212
|
+
expect { subject.request(:POST, 200, {}, env) }
|
213
|
+
.to change { subject.etag }
|
214
|
+
end
|
215
|
+
|
216
|
+
context 'with Container interaction model' do
|
217
|
+
it 'creates a basic container' do
|
218
|
+
env['HTTP_LINK'] = "<#{RDF::LDP::Container.to_uri}>;rel=\"type\""
|
219
|
+
expect(subject.request(:POST, 200, {}, env).last)
|
220
|
+
.to be_a RDF::LDP::Container
|
221
|
+
end
|
222
|
+
|
223
|
+
context 'BasicContainer' do
|
224
|
+
it 'creates a basic container' do
|
225
|
+
env['HTTP_LINK'] =
|
226
|
+
'<http://www.w3.org/ns/ldp#BasicContainer>;rel="type"'
|
227
|
+
expect(subject.request(:POST, 200, {}, env).last)
|
228
|
+
.to be_a RDF::LDP::Container
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
context 'DirectContainer' do
|
233
|
+
it 'creates a direct container' do
|
234
|
+
env['HTTP_LINK'] =
|
235
|
+
"<#{RDF::LDP::DirectContainer.to_uri}>;rel=\"type\""
|
236
|
+
|
237
|
+
expect(subject.request(:POST, 200, {}, env).last)
|
238
|
+
.to be_a RDF::LDP::DirectContainer
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'IndirectContainer' do
|
243
|
+
it 'creates a indirect container' do
|
244
|
+
env['HTTP_LINK'] =
|
245
|
+
"<#{RDF::LDP::IndirectContainer.to_uri}>;rel=\"type\""
|
246
|
+
|
247
|
+
expect(subject.request(:POST, 200, {}, env).last)
|
248
|
+
.to be_a RDF::LDP::IndirectContainer
|
249
|
+
end
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'with a Slug' do
|
254
|
+
it 'creates resource with Slug' do
|
255
|
+
env['HTTP_SLUG'] = 'snork'
|
256
|
+
expect(subject.request(:POST, 200, {}, env).last.subject_uri)
|
257
|
+
.to eq subject.subject_uri / env['HTTP_SLUG']
|
258
|
+
end
|
259
|
+
|
260
|
+
it 'mints a uri when empty Slug is given' do
|
261
|
+
env['HTTP_SLUG'] = ''
|
262
|
+
expect(subject.request(:POST, 200, {}, env).last.subject_uri)
|
263
|
+
.to be_starts_with subject.subject_uri
|
264
|
+
end
|
265
|
+
|
266
|
+
it 'raises a 409 Conflict when slug is already taken' do
|
267
|
+
env['HTTP_SLUG'] = 'snork'
|
268
|
+
subject.request(:POST, 200, {}, env)
|
269
|
+
|
270
|
+
expect { subject.request(:POST, 200, {}, env) }
|
271
|
+
.to raise_error RDF::LDP::Conflict
|
272
|
+
end
|
273
|
+
|
274
|
+
it 'raises a 409 Conflict when slug is already taken but destroyed' do
|
275
|
+
env['HTTP_SLUG'] = 'snork'
|
276
|
+
created = subject.request(:POST, 200, {}, env).last
|
277
|
+
allow(created).to receive(:destroyed?).and_return true
|
278
|
+
|
279
|
+
expect { subject.request(:POST, 200, {}, env) }
|
280
|
+
.to raise_error RDF::LDP::Conflict
|
281
|
+
end
|
282
|
+
|
283
|
+
it 'raises a 406 NotAcceptable if slug has a uri fragment `#`' do
|
284
|
+
env['HTTP_SLUG'] = 'snork#maiden'
|
285
|
+
|
286
|
+
expect { subject.request(:POST, 200, {}, env) }
|
287
|
+
.to raise_error RDF::LDP::NotAcceptable
|
288
|
+
end
|
289
|
+
|
290
|
+
it 'url-encodes Slug' do
|
291
|
+
env['HTTP_SLUG'] = 'snork maiden'
|
292
|
+
expect(subject.request(:POST, 200, {}, env).last.subject_uri)
|
293
|
+
.to eq subject.subject_uri / 'snork%20maiden'
|
294
|
+
end
|
295
|
+
end
|
296
|
+
|
297
|
+
context 'with graph content' do
|
298
|
+
before do
|
299
|
+
graph << RDF::Statement(uri, RDF::Vocab::DC.title, 'moomin')
|
300
|
+
graph << RDF::Statement(RDF::Node.new, RDF::Vocab::DC.creator, 'tove')
|
301
|
+
graph <<
|
302
|
+
RDF::Statement(RDF::Node.new, RDF.type, RDF::Vocab::FOAF.Person)
|
303
|
+
end
|
304
|
+
|
305
|
+
it 'parses graph into created resource' do
|
306
|
+
expect(subject.request(:POST, 200, {}, env).last.to_response)
|
307
|
+
.to be_isomorphic_with graph
|
308
|
+
end
|
309
|
+
|
310
|
+
it 'adds a Location header' do
|
311
|
+
expect(subject.request(:POST, 200, {}, env)[1]['Location'])
|
312
|
+
.to start_with subject.subject_uri.to_s
|
313
|
+
end
|
314
|
+
|
315
|
+
context 'with quads' do
|
316
|
+
let(:graph) do
|
317
|
+
RDF::Graph.new(graph_name: subject.subject_uri,
|
318
|
+
data: RDF::Repository.new)
|
319
|
+
end
|
320
|
+
|
321
|
+
let(:env) do
|
322
|
+
{ 'rack.input' => StringIO.new(graph.dump(:nquads)),
|
323
|
+
'CONTENT_TYPE' => 'application/n-quads' }
|
324
|
+
end
|
325
|
+
|
326
|
+
it 'parses graph into created resource without regard for context' do
|
327
|
+
context_free_graph = RDF::Graph.new
|
328
|
+
context_free_graph << graph.statements
|
329
|
+
|
330
|
+
expect(subject.request(:POST, 200, {}, env).last.to_response)
|
331
|
+
.to be_isomorphic_with context_free_graph
|
332
|
+
end
|
333
|
+
end
|
334
|
+
end
|
335
|
+
end
|
336
|
+
end
|
337
|
+
end
|
@@ -0,0 +1,245 @@
|
|
1
|
+
require 'rdf/ldp/spec/container'
|
2
|
+
|
3
|
+
# @todo: make this set of examples less opinionated about #add behavior.
|
4
|
+
# Break #add tests into another group shared between DirectContainer &
|
5
|
+
# IndirectContainer. This way other implementations can use these specs
|
6
|
+
# but make different intrepretations of loose parts in the LDP spec.
|
7
|
+
shared_examples 'a DirectContainer' do
|
8
|
+
it_behaves_like 'a Container'
|
9
|
+
|
10
|
+
let(:uri) { RDF::URI('http://ex.org/moomin') }
|
11
|
+
let(:repo) { RDF::Repository.new }
|
12
|
+
subject { described_class.new(uri, repo) }
|
13
|
+
|
14
|
+
let(:has_member_statement) do
|
15
|
+
RDF::Statement(subject.subject_uri,
|
16
|
+
RDF::Vocab::LDP.hasMemberRelation,
|
17
|
+
RDF::Vocab::DC.hasPart)
|
18
|
+
end
|
19
|
+
|
20
|
+
let(:is_member_of_statement) do
|
21
|
+
RDF::Statement(subject.subject_uri,
|
22
|
+
RDF::Vocab::LDP.isMemberOfRelation,
|
23
|
+
RDF::Vocab::DC.isPartOf)
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#add' do
|
27
|
+
let(:added) { described_class.new(added_uri, repo) }
|
28
|
+
let(:added_uri) { RDF::URI('http://ex.org/too-ticky') }
|
29
|
+
|
30
|
+
context 'when the membership resource does not exist' do
|
31
|
+
before do
|
32
|
+
subject.create(StringIO.new, 'application/n-triples')
|
33
|
+
|
34
|
+
subject.graph.update has_member_statement
|
35
|
+
subject.graph.update RDF::Statement(subject.subject_uri,
|
36
|
+
RDF::Vocab::LDP.membershipResource,
|
37
|
+
membership_resource_uri)
|
38
|
+
end
|
39
|
+
|
40
|
+
let(:membership_resource_uri) do
|
41
|
+
RDF::URI('http://example.com/moomin_resource')
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'adds membership triple to the container' do
|
45
|
+
expect { subject.add(added) }
|
46
|
+
.to change { subject.graph.statements }
|
47
|
+
.to include subject.make_membership_triple(added_uri)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'when the membership resource exists' do
|
52
|
+
before { subject.create(StringIO.new, 'application/n-triples') }
|
53
|
+
|
54
|
+
it 'adds membership triple to container' do
|
55
|
+
expect(subject.add(added).graph)
|
56
|
+
.to have_statement subject.make_membership_triple(added_uri)
|
57
|
+
end
|
58
|
+
|
59
|
+
it 'updates last_modified for membership resource' do
|
60
|
+
expect { subject.add(added).graph }
|
61
|
+
.to change { subject.last_modified }
|
62
|
+
end
|
63
|
+
|
64
|
+
it 'updates etag for for membership resource' do
|
65
|
+
expect { subject.add(added).graph }
|
66
|
+
.to change { subject.etag }
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'adds membership triple to container for custom membership resource' do
|
70
|
+
repo = RDF::Repository.new
|
71
|
+
subject = described_class.new(uri, repo)
|
72
|
+
mem_rs = RDF::LDP::RDFSource.new(RDF::URI('http://ex.org/mymble'),
|
73
|
+
repo)
|
74
|
+
|
75
|
+
g = RDF::Graph.new << RDF::Statement(subject.subject_uri,
|
76
|
+
RDF::Vocab::LDP.membershipResource,
|
77
|
+
mem_rs.subject_uri)
|
78
|
+
|
79
|
+
subject.create(StringIO.new(g.dump(:ntriples)), 'application/n-triples')
|
80
|
+
mem_rs.create(StringIO.new, 'application/n-triples')
|
81
|
+
|
82
|
+
subject.add(added)
|
83
|
+
|
84
|
+
expect(subject.graph)
|
85
|
+
.to have_statement subject.make_membership_triple(added_uri)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'adds membership triple to membership resource with #fragment' do
|
89
|
+
repo = RDF::Repository.new
|
90
|
+
subject = described_class.new(uri, repo)
|
91
|
+
|
92
|
+
mem_rs = subject.subject_uri / '#membership'
|
93
|
+
|
94
|
+
g = RDF::Graph.new << RDF::Statement(subject.subject_uri,
|
95
|
+
RDF::Vocab::LDP.membershipResource,
|
96
|
+
mem_rs)
|
97
|
+
|
98
|
+
subject.create(StringIO.new(g.dump(:ttl)), 'application/n-triples')
|
99
|
+
expect(subject.add(added).graph)
|
100
|
+
.to have_statement subject.make_membership_triple(added_uri)
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'adds membership triple to container for LDP-NR membership resource' do
|
104
|
+
repo = RDF::Repository.new
|
105
|
+
container = described_class.new(uri, repo)
|
106
|
+
|
107
|
+
nr = RDF::LDP::NonRDFSource.new('http://example.org/moomin_file',
|
108
|
+
repo)
|
109
|
+
|
110
|
+
g = RDF::Graph.new << RDF::Statement(subject.subject_uri,
|
111
|
+
RDF::Vocab::LDP.membershipResource,
|
112
|
+
nr.to_uri)
|
113
|
+
|
114
|
+
container
|
115
|
+
.create(StringIO.new(g.dump(:ntriples)), 'application/n-triples')
|
116
|
+
|
117
|
+
nr.create(StringIO.new, 'application/n-triples')
|
118
|
+
|
119
|
+
container.add(added)
|
120
|
+
expect(container.graph)
|
121
|
+
.to have_statement container.make_membership_triple(added_uri)
|
122
|
+
end
|
123
|
+
|
124
|
+
context 'with multiple membership resources' do
|
125
|
+
it 'raises an error' do
|
126
|
+
subject.graph << RDF::Statement(subject.subject_uri,
|
127
|
+
RDF::Vocab::LDP.membershipResource,
|
128
|
+
subject.subject_uri)
|
129
|
+
subject.graph << RDF::Statement(subject.subject_uri,
|
130
|
+
RDF::Vocab::LDP.membershipResource,
|
131
|
+
(subject.subject_uri / 'moomin'))
|
132
|
+
|
133
|
+
expect { subject.add(added) }
|
134
|
+
.to raise_error RDF::LDP::RequestError
|
135
|
+
expect(subject.containment_triples).to be_empty
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe '#remove' do
|
142
|
+
let(:added) { described_class.new(added_uri, repo) }
|
143
|
+
let(:added_uri) { RDF::URI('http://ex.org/too-ticky') }
|
144
|
+
|
145
|
+
context 'when the membership resource exists' do
|
146
|
+
before { subject.create(StringIO.new, 'application/n-triples') }
|
147
|
+
|
148
|
+
it 'removes membership triple to membership resource' do
|
149
|
+
subject.graph << subject.make_membership_triple(added_uri)
|
150
|
+
expect(subject.remove(added_uri).graph)
|
151
|
+
.not_to have_statement subject.make_membership_triple(added_uri)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
|
156
|
+
describe '#membership_constant_uri' do
|
157
|
+
it 'when created defaults to #subject_uri' do
|
158
|
+
subject.create(StringIO.new, 'application/n-triples')
|
159
|
+
expect(subject.membership_constant_uri).to eq subject.subject_uri
|
160
|
+
expect(subject.graph)
|
161
|
+
.to have_statement RDF::Statement(subject.subject_uri,
|
162
|
+
RDF::Vocab::LDP.membershipResource,
|
163
|
+
subject.subject_uri)
|
164
|
+
end
|
165
|
+
|
166
|
+
it 'gives membership resource' do
|
167
|
+
membership_resource = (subject.subject_uri / '#too-ticky')
|
168
|
+
subject.graph << RDF::Statement(subject.subject_uri,
|
169
|
+
RDF::Vocab::LDP.membershipResource,
|
170
|
+
membership_resource)
|
171
|
+
expect(subject.membership_constant_uri).to eq membership_resource
|
172
|
+
end
|
173
|
+
|
174
|
+
it 'raises an error if multiple are present' do
|
175
|
+
membership_resource = (subject.subject_uri / '#too-ticky')
|
176
|
+
subject.graph << RDF::Statement(subject.subject_uri,
|
177
|
+
RDF::Vocab::LDP.membershipResource,
|
178
|
+
membership_resource)
|
179
|
+
|
180
|
+
subject.graph << RDF::Statement(subject.subject_uri,
|
181
|
+
RDF::Vocab::LDP.membershipResource,
|
182
|
+
subject.subject_uri)
|
183
|
+
|
184
|
+
expect { subject.membership_constant_uri }
|
185
|
+
.to raise_error RDF::LDP::RequestError
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe '#membership_predicate' do
|
190
|
+
it 'when created returns a uri' do
|
191
|
+
subject.create(StringIO.new, 'application/n-triples')
|
192
|
+
expect(subject.membership_predicate).to be_a RDF::URI
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'gives assigned member relation predicate for hasMember' do
|
196
|
+
subject.graph << has_member_statement
|
197
|
+
|
198
|
+
expect(subject.membership_predicate).to eq RDF::Vocab::DC.hasPart
|
199
|
+
end
|
200
|
+
|
201
|
+
it 'gives assigned member relation predicate for isMemberOf' do
|
202
|
+
subject.graph << is_member_of_statement
|
203
|
+
|
204
|
+
expect(subject.membership_predicate).to eq RDF::Vocab::DC.isPartOf
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'raises an error if multiple relation predicates are present' do
|
208
|
+
subject.graph << has_member_statement
|
209
|
+
subject.graph << is_member_of_statement
|
210
|
+
|
211
|
+
expect { subject.membership_predicate }
|
212
|
+
.to raise_error RDF::LDP::RequestError
|
213
|
+
end
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#make_membership_triple' do
|
217
|
+
context 'with hasMember' do
|
218
|
+
before do
|
219
|
+
g = RDF::Graph.new << has_member_statement
|
220
|
+
subject.create(StringIO.new(g.dump(:ntriples)), 'application/n-triples')
|
221
|
+
end
|
222
|
+
|
223
|
+
it 'is constant - predicate - derived' do
|
224
|
+
expect(subject.make_membership_triple(uri))
|
225
|
+
.to eq RDF::Statement(subject.membership_constant_uri,
|
226
|
+
subject.membership_predicate,
|
227
|
+
uri)
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
context 'with isMemberOf' do
|
232
|
+
before do
|
233
|
+
g = RDF::Graph.new << is_member_of_statement
|
234
|
+
subject.create(StringIO.new(g.dump(:ntriples)), 'application/n-triples')
|
235
|
+
end
|
236
|
+
|
237
|
+
it 'is derived - predicate - constant' do
|
238
|
+
expect(subject.make_membership_triple(uri))
|
239
|
+
.to eq RDF::Statement(uri,
|
240
|
+
subject.membership_predicate,
|
241
|
+
subject.membership_constant_uri)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
end
|
245
|
+
end
|