rdf-ldp 0.9.2 → 0.9.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +34 -0
- data/VERSION +1 -1
- data/app/lamprey.rb +119 -40
- data/bin/lamprey +15 -1
- data/lib/rack/ldp.rb +18 -20
- data/lib/rdf/ldp.rb +3 -2
- data/lib/rdf/ldp/container.rb +15 -9
- data/lib/rdf/ldp/direct_container.rb +5 -3
- data/lib/rdf/ldp/indirect_container.rb +5 -3
- data/lib/rdf/ldp/interaction_model.rb +39 -29
- data/lib/rdf/ldp/non_rdf_source.rb +4 -2
- data/lib/rdf/ldp/resource.rb +20 -18
- data/lib/rdf/ldp/spec.rb +6 -0
- 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/storage_adapters/file_storage_adapter.rb +4 -4
- data/lib/rdf/ldp/version.rb +16 -3
- metadata +37 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 5a633f094bb28ab5b2fc03dec3fbfdf5e0735a0c
|
4
|
+
data.tar.gz: 61979520bcc04f1966a46eb9ee41f250e7c80128
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c9e086f88098b88693e86f90ccef8b1e35c123c2b4122cf4f4cc1a3d14db744ae77fe5bf7d6ad8f3bfadec3e026723bf60b488cc91fb64cb7bc586bfc1a3d0aa
|
7
|
+
data.tar.gz: e245c4c5bf3d764dfb5c67e9cef1d9e0820adecec5c93c461a73c923c9ddee690ed99cb4c7ffd5a25c8fd5046bd1ff7102e00911a02bee1855256c52bc473022
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -103,6 +103,40 @@ And run your server with:
|
|
103
103
|
$ rackup
|
104
104
|
```
|
105
105
|
|
106
|
+
Testing
|
107
|
+
-------
|
108
|
+
|
109
|
+
RSpec shared examples for the required behaviors of LDP resource and container
|
110
|
+
types are included in `rdf/ldp/spec` for use in customized implementations.
|
111
|
+
Running these example sets will help ensure LDP compliance for specialized
|
112
|
+
resource behaviors.
|
113
|
+
|
114
|
+
This test suite is provided provisionally and may be incomplete or overly
|
115
|
+
strict. Please [report issues](https://github.com/ruby-rdf/rdf-ldp/issues)
|
116
|
+
encountered during its use.
|
117
|
+
|
118
|
+
```ruby
|
119
|
+
require 'rdf/ldp/spec'
|
120
|
+
|
121
|
+
describe MyResource do
|
122
|
+
it_behaves_like 'a Resource'
|
123
|
+
end
|
124
|
+
|
125
|
+
describe MyRDFSource do
|
126
|
+
it_behaves_like 'an RDFSource'
|
127
|
+
end
|
128
|
+
|
129
|
+
# ...
|
130
|
+
|
131
|
+
describe MyIndirectContainer do
|
132
|
+
it_behaves_like 'an IndirectContainer'
|
133
|
+
end
|
134
|
+
```
|
135
|
+
|
136
|
+
We recommend running the official
|
137
|
+
[LDP testsuite](https://github.com/cbeer/ldp_testsuite_wrapper), as integration
|
138
|
+
tests in addition to the above examples.
|
139
|
+
|
106
140
|
Compliance
|
107
141
|
----------
|
108
142
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.3
|
data/app/lamprey.rb
CHANGED
@@ -1,54 +1,133 @@
|
|
1
1
|
require 'rack/ldp'
|
2
2
|
require 'sinatra/base'
|
3
3
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
set :repository, RDF::Repository.new
|
15
|
-
end
|
4
|
+
module RDF
|
5
|
+
##
|
6
|
+
# A basic implementation of an LDP Server.
|
7
|
+
class Lamprey < Sinatra::Base
|
8
|
+
use Rack::Lint
|
9
|
+
use Rack::LDP::ContentNegotiation
|
10
|
+
use Rack::LDP::Errors
|
11
|
+
use Rack::LDP::Responses
|
12
|
+
use Rack::ConditionalGet
|
13
|
+
use Rack::LDP::Requests
|
16
14
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
15
|
+
get '/*' do
|
16
|
+
if settings.repository.empty?
|
17
|
+
RDF::LDP::Container
|
18
|
+
.new(RDF::URI(request.url), settings.repository)
|
19
|
+
.create(StringIO.new, 'text/turtle')
|
20
|
+
end
|
22
21
|
|
23
|
-
|
24
|
-
|
25
|
-
end
|
22
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
23
|
+
end
|
26
24
|
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
patch '/*' do
|
26
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
27
|
+
end
|
30
28
|
|
31
|
-
|
32
|
-
begin
|
29
|
+
post '/*' do
|
33
30
|
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
34
|
-
rescue RDF::LDP::NotFound
|
35
|
-
model = request.env.fetch('HTTP_LINK', '')
|
36
|
-
RDF::LDP::Resource.interaction_model(model)
|
37
|
-
.new(RDF::URI(request.url), settings.repository)
|
38
31
|
end
|
39
|
-
end
|
40
32
|
|
41
|
-
|
42
|
-
|
43
|
-
|
33
|
+
put '/*' do
|
34
|
+
begin
|
35
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
36
|
+
rescue RDF::LDP::NotFound
|
37
|
+
model = request.env.fetch('HTTP_LINK', '')
|
44
38
|
|
45
|
-
|
46
|
-
|
47
|
-
|
39
|
+
RDF::LDP::Resource
|
40
|
+
.interaction_model(model)
|
41
|
+
.new(RDF::URI(request.url), settings.repository)
|
42
|
+
end
|
43
|
+
end
|
48
44
|
|
49
|
-
|
50
|
-
|
51
|
-
|
45
|
+
options '/*' do
|
46
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
47
|
+
end
|
48
|
+
|
49
|
+
head '/*' do
|
50
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
51
|
+
end
|
52
|
+
|
53
|
+
delete '/*' do
|
54
|
+
RDF::LDP::Resource.find(RDF::URI(request.url), settings.repository)
|
55
|
+
end
|
56
|
+
|
57
|
+
##
|
58
|
+
# @example Configuring Lamprey server
|
59
|
+
# Lamprey::Config
|
60
|
+
# .register_repository!(:my_repo, RDF::Repository)
|
61
|
+
#
|
62
|
+
# Lamprey::Config.configure!(repository: :my_repo)
|
63
|
+
class Config
|
64
|
+
##
|
65
|
+
# @see #new
|
66
|
+
# @see #configure!
|
67
|
+
def self.configure!(**options)
|
68
|
+
new(**options).configure!
|
69
|
+
end
|
70
|
+
|
71
|
+
##
|
72
|
+
# Registers a repository for use with the {#build_repository} method.
|
73
|
+
#
|
74
|
+
# @example Registering a custom repository
|
75
|
+
# MyRepository = Class.new(RDF::Repository)
|
76
|
+
#
|
77
|
+
# Lamprey::Config.register_repository!(:my_repo, MyRepository)
|
78
|
+
#
|
79
|
+
# @param name [Symbol]
|
80
|
+
# @param klass [Class]
|
81
|
+
# @return [void]
|
82
|
+
def self.register_repository!(name, klass)
|
83
|
+
@@repositories[name] = klass
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# @!attribute [rw] options
|
88
|
+
attr_accessor :options
|
52
89
|
|
53
|
-
|
90
|
+
@@repositories = { default: RDF::Repository }
|
91
|
+
|
92
|
+
##
|
93
|
+
# @param repository [RDF::Repository]
|
94
|
+
def initialize(repository: :default)
|
95
|
+
@options = {}
|
96
|
+
@options[:repository] = repository
|
97
|
+
end
|
98
|
+
|
99
|
+
##
|
100
|
+
# Builds the repository as given in the configuration.
|
101
|
+
#
|
102
|
+
# @return [RDF::Repository] a repository instance
|
103
|
+
def build_repository
|
104
|
+
@@repositories.fetch(options[:repository]) do
|
105
|
+
warn "#{options[:repository]} is not a configured repository. Use "\
|
106
|
+
'`Lamprey::Config.register_repository!` to register it before '\
|
107
|
+
'configuration. Falling back on the default: ' \
|
108
|
+
"#{@@repositories[:default]}."
|
109
|
+
@@repositories[:default]
|
110
|
+
end.new
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# Configures {RDF::Lamprey} with {#options}.
|
115
|
+
#
|
116
|
+
# @return [void]
|
117
|
+
def configure!
|
118
|
+
repository = build_repository
|
119
|
+
unless repository.persistent?
|
120
|
+
warn "#{repository} is not a persistent repository. "\
|
121
|
+
'Data will be lost on server shutdown.'
|
122
|
+
end
|
123
|
+
|
124
|
+
RDF::Lamprey.configure { |config| config.set :repository, repository }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
# Set defaults in case user does not configure values
|
129
|
+
Config.configure!
|
130
|
+
|
131
|
+
run! if app_file == $PROGRAM_NAME
|
132
|
+
end
|
54
133
|
end
|
data/bin/lamprey
CHANGED
@@ -1,5 +1,19 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
|
2
|
+
$LOAD_PATH
|
3
|
+
.unshift(File.expand_path(File.join(File.dirname(__FILE__), '..', 'app')))
|
3
4
|
require 'lamprey'
|
5
|
+
require 'optparse'
|
6
|
+
|
7
|
+
options = {}
|
8
|
+
|
9
|
+
OptionParser.new do |opts|
|
10
|
+
opts.banner = 'Usage: lamprey [options]'
|
11
|
+
|
12
|
+
opts.on('-rREPO', '--repository=REPO', 'Set the repository') do |repo|
|
13
|
+
options[:repository] = repo.to_sym
|
14
|
+
end
|
15
|
+
end.parse!
|
16
|
+
|
17
|
+
RDF::Lamprey::Config.configure!(**options)
|
4
18
|
|
5
19
|
RDF::Lamprey.run!
|
data/lib/rack/ldp.rb
CHANGED
@@ -14,15 +14,15 @@ module Rack
|
|
14
14
|
# Provides Rack middleware for handling Linked Data Platform requirements
|
15
15
|
# when passed {RDF::LDP::Resource} and its subclasses as response objects.
|
16
16
|
#
|
17
|
-
# Response objects that are not an {RDF::LDP::Resource} are passed over
|
17
|
+
# Response objects that are not an {RDF::LDP::Resource} are passed over
|
18
18
|
# without alteration, allowing server implementers to mix LDP interaction
|
19
19
|
# patterns with others on the same server.
|
20
20
|
#
|
21
|
-
# The suite can be mix-and-matched as needed. This allows easy swap in of
|
21
|
+
# The suite can be mix-and-matched as needed. This allows easy swap in of
|
22
22
|
# custom handlers for parts of the behavior. It is recommended that you use
|
23
23
|
# {Rack::LDP::ContentNegotiation}, {Rack::LDP::Errors}, {Rack::LDP::Responses}
|
24
|
-
# and {Rack::LDP::Reousets} as the outer middleware layers. With these in
|
25
|
-
# place, you can handle requests as needed in your application, giving
|
24
|
+
# and {Rack::LDP::Reousets} as the outer middleware layers. With these in
|
25
|
+
# place, you can handle requests as needed in your application, giving
|
26
26
|
# responses conforming to the core {RDF::LDP::Resource} interface.
|
27
27
|
#
|
28
28
|
# @example
|
@@ -33,7 +33,7 @@ module Rack
|
|
33
33
|
# use Rack::LDP::Requests
|
34
34
|
# # ...
|
35
35
|
# end
|
36
|
-
#
|
36
|
+
#
|
37
37
|
# @see http://www.w3.org/TR/ldp/ the LDP specification
|
38
38
|
module LDP
|
39
39
|
##
|
@@ -46,17 +46,15 @@ module Rack
|
|
46
46
|
end
|
47
47
|
|
48
48
|
##
|
49
|
-
# Catches {RDF::LDP::RequestError} and its various subclasses, building an
|
50
|
-
# appropriate response
|
49
|
+
# Catches {RDF::LDP::RequestError} and its various subclasses, building an
|
50
|
+
# appropriate response
|
51
51
|
#
|
52
52
|
# @param [Array] env a rack env array
|
53
53
|
# @return [Array] a rack env array with added headers
|
54
54
|
def call(env)
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
return [err.status, err.headers, [err.message]]
|
59
|
-
end
|
55
|
+
@app.call(env)
|
56
|
+
rescue RDF::LDP::RequestError => err
|
57
|
+
return [err.status, err.headers, [err.message]]
|
60
58
|
end
|
61
59
|
end
|
62
60
|
|
@@ -94,7 +92,7 @@ module Rack
|
|
94
92
|
end
|
95
93
|
|
96
94
|
##
|
97
|
-
# Handles a Rack protocol request. Sends appropriate request to the
|
95
|
+
# Handles a Rack protocol request. Sends appropriate request to the
|
98
96
|
# object, alters response accordingly.
|
99
97
|
#
|
100
98
|
# @param [Array] env a rack env array
|
@@ -103,19 +101,19 @@ module Rack
|
|
103
101
|
status, headers, response = @app.call(env)
|
104
102
|
return [status, headers, response] unless
|
105
103
|
response.is_a? RDF::LDP::Resource
|
106
|
-
|
104
|
+
|
107
105
|
response
|
108
106
|
.send(:request, env['REQUEST_METHOD'].to_sym, status, headers, env)
|
109
107
|
end
|
110
108
|
end
|
111
109
|
|
112
110
|
##
|
113
|
-
# Specializes {Rack::LinkedData::ContentNegotiation}, making the default
|
111
|
+
# Specializes {Rack::LinkedData::ContentNegotiation}, making the default
|
114
112
|
# return type 'text/turtle'.
|
115
113
|
#
|
116
114
|
# @see Rack::LinkedData::ContentNegotiation}, making
|
117
115
|
class ContentNegotiation < Rack::LinkedData::ContentNegotiation
|
118
|
-
DEFAULT_PREFIXES =
|
116
|
+
DEFAULT_PREFIXES =
|
119
117
|
Hash[*RDF::Vocabulary.map { |v| [v.__prefix__, v.to_uri] }.flatten]
|
120
118
|
.freeze
|
121
119
|
|
@@ -126,13 +124,13 @@ module Rack
|
|
126
124
|
end
|
127
125
|
|
128
126
|
##
|
129
|
-
# The default LinkedData Conneg doesn't support wildcard operators. We
|
130
|
-
# patch in support for 'text/*' manually, giving Turtle. This should be
|
127
|
+
# The default LinkedData Conneg doesn't support wildcard operators. We
|
128
|
+
# patch in support for 'text/*' manually, giving Turtle. This should be
|
131
129
|
# considered helpful by LDP clients.
|
132
|
-
#
|
130
|
+
#
|
133
131
|
# @see Rack::LinkedData::ContentNegotiation#find_writer_for_content_type
|
134
132
|
def find_writer_for_content_type(content_type)
|
135
|
-
return [RDF::Writer.for(:ttl), 'text/turtle'] if
|
133
|
+
return [RDF::Writer.for(:ttl), 'text/turtle'] if
|
136
134
|
content_type == 'text/*'
|
137
135
|
super
|
138
136
|
end
|
data/lib/rdf/ldp.rb
CHANGED
@@ -22,11 +22,12 @@ module RDF
|
|
22
22
|
# @see http://www.w3.org/TR/ldp/ for the Linked Data platform specification
|
23
23
|
module LDP
|
24
24
|
InteractionModel.register(RDF::LDP::RDFSource, default: true)
|
25
|
-
InteractionModel.register(RDF::LDP::Container,
|
25
|
+
InteractionModel.register(RDF::LDP::Container,
|
26
|
+
for: RDF::Vocab::LDP.BasicContainer)
|
26
27
|
InteractionModel.register(RDF::LDP::DirectContainer)
|
27
28
|
InteractionModel.register(RDF::LDP::IndirectContainer)
|
28
29
|
InteractionModel.register(RDF::LDP::NonRDFSource)
|
29
|
-
|
30
|
+
|
30
31
|
CONTAINER_CLASSES = {
|
31
32
|
basic: RDF::Vocab::LDP.BasicContainer.freeze,
|
32
33
|
direct: RDF::LDP::DirectContainer.to_uri.freeze,
|
data/lib/rdf/ldp/container.rb
CHANGED
@@ -82,8 +82,8 @@ module RDF::LDP
|
|
82
82
|
# membership triples as appropriate for the container type.
|
83
83
|
#
|
84
84
|
# If a transaction is passed as the second argument, the removal of the
|
85
|
-
# containment triple is completed when the transaction closes; otherwise it
|
86
|
-
# handled atomically.
|
85
|
+
# containment triple is completed when the transaction closes; otherwise it
|
86
|
+
# is handled atomically.
|
87
87
|
#
|
88
88
|
# @param [RDF::Term] a new member for this container
|
89
89
|
# @param transaction [RDF::Transaction] an active transaction as context for
|
@@ -157,7 +157,7 @@ module RDF::LDP
|
|
157
157
|
|
158
158
|
raise UnsupportedMediaType unless method
|
159
159
|
|
160
|
-
temp_data
|
160
|
+
temp_data = RDF::Repository.new << graph.statements
|
161
161
|
temp_graph = RDF::Graph.new(graph_name: graph.name, data: temp_data)
|
162
162
|
send(method, env['rack.input'], temp_graph)
|
163
163
|
|
@@ -204,14 +204,18 @@ module RDF::LDP
|
|
204
204
|
predicate: CONTAINS_URI)
|
205
205
|
|
206
206
|
tx_containment.each do |statement|
|
207
|
-
|
208
|
-
|
209
|
-
|
207
|
+
unless existing_triples.include?(statement)
|
208
|
+
raise(Conflict, 'Attempted to write unacceptable LDP ' \
|
209
|
+
"containment-triple: #{statement}")
|
210
|
+
end
|
210
211
|
end
|
211
212
|
|
212
213
|
deletes = existing_triples.reject { |st| tx_containment.include?(st) }
|
214
|
+
|
215
|
+
return if deletes.empty?
|
216
|
+
|
213
217
|
raise(Conflict, 'Cannot remove containment triples in updates. ' \
|
214
|
-
"Attepted to remove #{deletes}")
|
218
|
+
"Attepted to remove #{deletes}")
|
215
219
|
end
|
216
220
|
|
217
221
|
##
|
@@ -224,9 +228,11 @@ module RDF::LDP
|
|
224
228
|
"containment-triple: #{st}")
|
225
229
|
end
|
226
230
|
end
|
231
|
+
|
232
|
+
return if existing_triples.empty?
|
233
|
+
|
227
234
|
raise(Conflict, 'Cannot remove containment triples in updates. ' \
|
228
|
-
"Attepted to remove #{existing_triples}")
|
229
|
-
existing_triples.empty?
|
235
|
+
"Attepted to remove #{existing_triples}")
|
230
236
|
end
|
231
237
|
end
|
232
238
|
end
|
@@ -65,7 +65,8 @@ module RDF::LDP
|
|
65
65
|
#
|
66
66
|
# @see RDF::LDP::Container#add
|
67
67
|
def add(resource, transaction = nil)
|
68
|
-
process_membership_resource(resource,
|
68
|
+
process_membership_resource(resource,
|
69
|
+
transaction) do |container, quad, subject|
|
69
70
|
super(subject, transaction) # super handles nil transaction case
|
70
71
|
target = transaction || container.graph
|
71
72
|
target.insert(quad)
|
@@ -79,7 +80,8 @@ module RDF::LDP
|
|
79
80
|
#
|
80
81
|
# @see RDF::LDP::Container#remove
|
81
82
|
def remove(resource, transaction = nil)
|
82
|
-
process_membership_resource(resource,
|
83
|
+
process_membership_resource(resource,
|
84
|
+
transaction) do |container, quad, subject|
|
83
85
|
super(subject, transaction) # super handles nil transaction case
|
84
86
|
target = transaction || container.graph
|
85
87
|
target.delete(quad)
|
@@ -156,7 +158,7 @@ module RDF::LDP
|
|
156
158
|
resource
|
157
159
|
end
|
158
160
|
|
159
|
-
def process_membership_resource(resource,
|
161
|
+
def process_membership_resource(resource, _transaction = nil, member = nil)
|
160
162
|
membership_triple = make_membership_triple((member || resource).to_uri)
|
161
163
|
|
162
164
|
membership_triple.graph_name = subject_uri
|