ldp 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +8 -3
- data/Gemfile +3 -1
- data/ldp.gemspec +5 -0
- data/lib/ldp.rb +3 -9
- data/lib/ldp/client.rb +20 -15
- data/lib/ldp/client/methods.rb +4 -6
- data/lib/ldp/container.rb +30 -4
- data/lib/ldp/container/basic.rb +4 -13
- data/lib/ldp/container/direct.rb +11 -6
- data/lib/ldp/container/indirect.rb +9 -3
- data/lib/ldp/error.rb +20 -0
- data/lib/ldp/orm.rb +13 -24
- data/lib/ldp/resource.rb +23 -5
- data/lib/ldp/resource/binary_source.rb +9 -1
- data/lib/ldp/resource/rdf_source.rb +26 -11
- data/lib/ldp/response.rb +117 -88
- data/lib/ldp/uri.rb +39 -23
- data/lib/ldp/version.rb +1 -1
- data/spec/lib/integration/integration_spec.rb +51 -2
- data/spec/lib/ldp/client_spec.rb +20 -11
- data/spec/lib/ldp/resource/binary_source_spec.rb +25 -0
- data/spec/lib/ldp/resource/rdf_source_spec.rb +24 -0
- data/spec/lib/ldp/resource_spec.rb +1 -2
- data/spec/lib/ldp/response_spec.rb +49 -29
- data/spec/spec_helper.rb +10 -0
- metadata +61 -6
- data/lib/ldp/response/paging.rb +0 -57
@@ -28,7 +28,7 @@ module Ldp
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def graph
|
31
|
-
@graph ||= new? ? build_empty_graph :
|
31
|
+
@graph ||= new? ? build_empty_graph : filtered_graph(response_graph)
|
32
32
|
end
|
33
33
|
|
34
34
|
def build_empty_graph
|
@@ -38,34 +38,49 @@ module Ldp
|
|
38
38
|
##
|
39
39
|
# graph_class may be overridden so that a subclass of RDF::Graph
|
40
40
|
# is returned (e.g. an ActiveTriples resource)
|
41
|
-
# @
|
41
|
+
# @return [Class] a class that is an descendant of RDF::Graph
|
42
42
|
def graph_class
|
43
43
|
RDF::Graph
|
44
44
|
end
|
45
45
|
|
46
|
+
##
|
47
|
+
# Parse the graph returned by the LDP server into an RDF::Graph
|
48
|
+
# @return [RDF::Graph]
|
49
|
+
def response_graph
|
50
|
+
@response_graph ||= response_as_graph(get)
|
51
|
+
end
|
52
|
+
|
53
|
+
# Get the body and ensure it's UTF-8 encoded. Since Fedora 9.3 isn't
|
54
|
+
# returning a charset, then Net::HTTP is just returning ASCII-8BIT
|
55
|
+
# See https://github.com/ruby-rdf/rdf-turtle/issues/13
|
56
|
+
# See https://jira.duraspace.org/browse/FCREPO-1750
|
57
|
+
def body
|
58
|
+
body.force_encoding('utf-8')
|
59
|
+
end
|
46
60
|
|
61
|
+
protected
|
62
|
+
|
63
|
+
def interaction_model
|
64
|
+
RDF::Vocab::LDP.Resource unless client.options[:omit_ldpr_interaction_model]
|
65
|
+
end
|
47
66
|
|
48
67
|
private
|
49
68
|
##
|
50
69
|
# @param [Faraday::Response] graph query response
|
51
70
|
# @return [RDF::Graph]
|
52
71
|
def response_as_graph(resp)
|
53
|
-
content_type = resp.headers['Content-Type'] || 'text/turtle'
|
54
|
-
content_type = Array(content_type).first
|
55
|
-
format = Array(RDF::Format.content_types[content_type]).first
|
56
|
-
source = resp.body
|
57
|
-
reader = RDF::Reader.for(content_type:content_type).new(source, base_uri:subject)
|
58
72
|
graph = build_empty_graph
|
59
|
-
|
73
|
+
resp.each_statement do |stmt|
|
60
74
|
graph << stmt
|
61
75
|
end
|
62
76
|
graph
|
63
77
|
end
|
78
|
+
|
64
79
|
##
|
65
80
|
# @param [RDF::Graph] original_graph The graph returned by the LDP server
|
66
|
-
# @return [RDF::Graph] A graph
|
67
|
-
def
|
68
|
-
inlined_resources =
|
81
|
+
# @return [RDF::Graph] A graph stripped of any inlined resources present in the original
|
82
|
+
def filtered_graph(original_graph)
|
83
|
+
inlined_resources = original_graph.query(predicate: RDF::Vocab::LDP.contains).map { |x| x.object }
|
69
84
|
|
70
85
|
# we want to scope this graph to just statements about this model, not contained relations
|
71
86
|
if inlined_resources.empty?
|
data/lib/ldp/response.rb
CHANGED
@@ -1,35 +1,40 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
1
3
|
module Ldp
|
2
|
-
|
3
|
-
|
4
|
+
class Response
|
5
|
+
extend Forwardable
|
4
6
|
|
5
7
|
TYPE = 'type'.freeze
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
|
9
|
+
attr_reader :response
|
10
|
+
|
11
|
+
attr_writer :etag, :last_modified
|
12
|
+
|
13
|
+
def initialize(response)
|
14
|
+
@response = response
|
12
15
|
end
|
13
16
|
|
14
17
|
##
|
15
18
|
# Extract the Link: headers from the HTTP resource
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
19
|
+
def links
|
20
|
+
@links ||= begin
|
21
|
+
h = {}
|
22
|
+
Array(headers['Link'.freeze]).map { |x| x.split(','.freeze) }.flatten.inject(h) do |memo, header|
|
23
|
+
m = header.match(/<(?<link>.*)>;\s?rel="(?<rel>[^"]+)"/)
|
24
|
+
if m
|
25
|
+
memo[m[:rel]] ||= []
|
26
|
+
memo[m[:rel]] << m[:link]
|
27
|
+
end
|
24
28
|
|
25
|
-
|
29
|
+
memo
|
30
|
+
end
|
26
31
|
end
|
27
32
|
end
|
28
33
|
|
29
|
-
def
|
34
|
+
def applied_preferences
|
30
35
|
h = {}
|
31
36
|
|
32
|
-
Array(headers).map { |x| x.split(",") }.flatten.inject(h) do |memo, header|
|
37
|
+
Array(headers['Preference-Applied'.freeze]).map { |x| x.split(",") }.flatten.inject(h) do |memo, header|
|
33
38
|
m = header.match(/(?<key>[^=;]*)(=(?<value>[^;,]*))?(;\s*(?<params>[^,]*))?/)
|
34
39
|
includes = (m[:params].match(/include="(?<include>[^"]+)"/)[:include] || "").split(" ")
|
35
40
|
omits = (m[:params].match(/omit="(?<omit>[^"]+)"/)[:omit] || "").split(" ")
|
@@ -40,101 +45,78 @@ module Ldp
|
|
40
45
|
##
|
41
46
|
# Is the response an LDP resource?
|
42
47
|
|
43
|
-
def
|
44
|
-
Array(links
|
48
|
+
def resource?
|
49
|
+
Array(links[TYPE]).include? RDF::Vocab::LDP.Resource.to_s
|
45
50
|
end
|
46
51
|
|
47
52
|
##
|
48
53
|
# Is the response an LDP container?
|
49
|
-
def
|
54
|
+
def container?
|
50
55
|
[
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
].any? { |x| Array(links
|
56
|
+
RDF::Vocab::LDP.BasicContainer,
|
57
|
+
RDF::Vocab::LDP.DirectContainer,
|
58
|
+
RDF::Vocab::LDP.IndirectContainer
|
59
|
+
].any? { |x| Array(links[TYPE]).include? x.to_s }
|
55
60
|
end
|
56
61
|
|
57
62
|
##
|
58
63
|
# Is the response an LDP RDFSource?
|
59
64
|
# ldp:Container is a subclass of ldp:RDFSource
|
60
|
-
def
|
61
|
-
container?
|
65
|
+
def rdf_source?
|
66
|
+
container? || Array(links[TYPE]).include?(RDF::Vocab::LDP.RDFSource)
|
62
67
|
end
|
63
68
|
|
64
69
|
def dup
|
65
70
|
super.tap do |new_resp|
|
66
|
-
new_resp.send(:extend, Ldp::Response)
|
67
71
|
unless new_resp.instance_variable_get(:@graph).nil?
|
68
|
-
|
69
|
-
new_resp.send(:remove_instance_variable, :@graph)
|
70
|
-
else
|
71
|
-
new_resp.remove_instance_variable(:@graph)
|
72
|
-
end
|
72
|
+
new_resp.remove_instance_variable(:@graph)
|
73
73
|
end
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
77
|
-
##
|
78
|
-
# Link: headers from the HTTP response
|
79
|
-
def links
|
80
|
-
@links ||= Ldp::Response.links(self)
|
81
|
-
end
|
82
|
-
|
83
|
-
##
|
84
|
-
# Is the response an LDP resource?
|
85
|
-
def resource?
|
86
|
-
Ldp::Response.resource?(self)
|
87
|
-
end
|
88
|
-
|
89
|
-
##
|
90
|
-
# Is the response an LDP rdf source?
|
91
|
-
def rdf_source?
|
92
|
-
Ldp::Response.rdf_source?(self)
|
93
|
-
end
|
94
|
-
|
95
|
-
##
|
96
|
-
# Is the response an LDP container
|
97
|
-
def container?
|
98
|
-
Ldp::Response.container?(self)
|
99
|
-
end
|
100
|
-
|
101
|
-
def preferences
|
102
|
-
Ldp::Resource.applied_preferences(headers['Preference-Applied'.freeze])
|
103
|
-
end
|
104
77
|
##
|
105
78
|
# Get the subject for the response
|
106
79
|
def subject
|
107
|
-
|
80
|
+
@subject ||= if has_page?
|
81
|
+
graph.first_object [page_subject, RDF::Vocab::LDP.pageOf, nil]
|
82
|
+
else
|
83
|
+
page_subject
|
84
|
+
end
|
108
85
|
end
|
109
86
|
|
110
87
|
##
|
111
88
|
# Get the URI to the response
|
112
89
|
def page_subject
|
113
|
-
@page_subject ||= RDF::URI.new env[:url]
|
90
|
+
@page_subject ||= RDF::URI.new response.env[:url]
|
114
91
|
end
|
115
92
|
|
116
93
|
##
|
117
94
|
# Is the response paginated?
|
118
95
|
def has_page?
|
119
|
-
rdf_source? && graph.has_statement?(RDF::Statement.new(page_subject, RDF.type,
|
96
|
+
rdf_source? && graph.has_statement?(RDF::Statement.new(page_subject, RDF.type, RDF::Vocab::LDP.Page))
|
97
|
+
end
|
98
|
+
|
99
|
+
def body
|
100
|
+
response.body
|
120
101
|
end
|
121
102
|
|
122
103
|
##
|
123
104
|
# Get the graph for the resource (or a blank graph if there is no metadata for the resource)
|
124
105
|
def graph
|
125
106
|
@graph ||= begin
|
126
|
-
raise UnexpectedContentType, "The resource at #{page_subject} is not an RDFSource" unless rdf_source?
|
127
107
|
graph = RDF::Graph.new
|
108
|
+
each_statement { |s| graph << s }
|
109
|
+
graph
|
110
|
+
end
|
111
|
+
end
|
128
112
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
graph << s
|
133
|
-
end
|
134
|
-
end
|
135
|
-
end
|
113
|
+
def reader(&block)
|
114
|
+
reader_for_content_type.new(body, base_uri: page_subject, &block)
|
115
|
+
end
|
136
116
|
|
137
|
-
|
117
|
+
def each_statement(&block)
|
118
|
+
reader do |reader|
|
119
|
+
reader.each_statement(&block)
|
138
120
|
end
|
139
121
|
end
|
140
122
|
|
@@ -144,20 +126,12 @@ module Ldp
|
|
144
126
|
@etag ||= headers['ETag'.freeze]
|
145
127
|
end
|
146
128
|
|
147
|
-
def etag=(val)
|
148
|
-
@etag = val
|
149
|
-
end
|
150
|
-
|
151
129
|
##
|
152
130
|
# Extract the last modified header for the resource
|
153
131
|
def last_modified
|
154
132
|
@last_modified ||= headers['Last-Modified'.freeze]
|
155
133
|
end
|
156
134
|
|
157
|
-
def last_modified=(val)
|
158
|
-
@last_modified = val
|
159
|
-
end
|
160
|
-
|
161
135
|
##
|
162
136
|
# Extract the Link: rel="type" headers for the resource
|
163
137
|
def types
|
@@ -176,14 +150,69 @@ module Ldp
|
|
176
150
|
preferences[RETURN][:value] == "minimal"
|
177
151
|
end
|
178
152
|
|
179
|
-
|
153
|
+
##
|
154
|
+
# Statements about the page
|
155
|
+
def page
|
156
|
+
@page_graph ||= begin
|
157
|
+
g = RDF::Graph.new
|
158
|
+
|
159
|
+
if resource?
|
160
|
+
res = graph.query RDF::Statement.new(page_subject, nil, nil)
|
161
|
+
|
162
|
+
res.each_statement do |s|
|
163
|
+
g << s
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
g
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
##
|
172
|
+
# Is there a next page?
|
173
|
+
def has_next?
|
174
|
+
next_page != nil
|
175
|
+
end
|
176
|
+
|
177
|
+
##
|
178
|
+
# Get the URI for the next page
|
179
|
+
def next_page
|
180
|
+
graph.first_object [page_subject, RDF::Vocab::LDP.nextPage, nil]
|
181
|
+
end
|
180
182
|
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
183
|
+
##
|
184
|
+
# Get the URI to the first page
|
185
|
+
def first_page
|
186
|
+
if links['first']
|
187
|
+
RDF::URI.new links['first']
|
188
|
+
elsif graph.has_statement? RDf::Statement.new(page_subject, RDF::Vocab::LDP.nextPage, nil)
|
189
|
+
subject
|
187
190
|
end
|
191
|
+
end
|
192
|
+
|
193
|
+
def content_type
|
194
|
+
headers['Content-Type']
|
195
|
+
end
|
196
|
+
|
197
|
+
def content_length
|
198
|
+
headers['Content-Length'].to_i
|
199
|
+
end
|
200
|
+
|
201
|
+
def content_disposition_filename
|
202
|
+
m = headers['Content-Disposition'].match(/filename="(?<filename>[^"]*)";/)
|
203
|
+
URI.decode(m[:filename]) if m
|
204
|
+
end
|
205
|
+
|
206
|
+
private
|
207
|
+
|
208
|
+
def headers
|
209
|
+
response.headers
|
210
|
+
end
|
211
|
+
|
212
|
+
def reader_for_content_type
|
213
|
+
content_type = content_type || 'text/turtle'
|
214
|
+
content_type = Array(content_type).first
|
215
|
+
RDF::Reader.for(content_type: content_type)
|
216
|
+
end
|
188
217
|
end
|
189
218
|
end
|
data/lib/ldp/uri.rb
CHANGED
@@ -1,75 +1,91 @@
|
|
1
1
|
module Ldp::Uri
|
2
|
+
extend Deprecation
|
3
|
+
self.deprecation_horizon = 'ldp version 0.6'
|
2
4
|
|
3
5
|
def uri str
|
4
6
|
RDF::URI.new("http://www.w3.org/ns/ldp#") + str
|
5
7
|
end
|
8
|
+
deprecation_deprecate :uri
|
6
9
|
|
7
10
|
def resource
|
8
|
-
|
11
|
+
RDF::Vocab::LDP.Resource
|
9
12
|
end
|
13
|
+
deprecation_deprecate :resource
|
10
14
|
|
11
15
|
def rdf_source
|
12
|
-
|
16
|
+
RDF::Vocab::LDP.RDFSource
|
13
17
|
end
|
18
|
+
deprecation_deprecate :rdf_source
|
14
19
|
|
15
20
|
def non_rdf_source
|
16
|
-
|
21
|
+
RDF::Vocab::LDP.NonRDFSource
|
17
22
|
end
|
23
|
+
deprecation_deprecate :non_rdf_source
|
18
24
|
|
19
25
|
def container
|
20
|
-
|
26
|
+
RDF::Vocab::LDP.Container
|
21
27
|
end
|
28
|
+
deprecation_deprecate :container
|
22
29
|
|
23
30
|
def basic_container
|
24
|
-
|
31
|
+
RDF::Vocab::LDP.BasicContainer
|
25
32
|
end
|
33
|
+
deprecation_deprecate :basic_container
|
26
34
|
|
27
35
|
def direct_container
|
28
|
-
|
36
|
+
RDF::Vocab::LDP.DirectContainer
|
29
37
|
end
|
38
|
+
deprecation_deprecate :direct_container
|
30
39
|
|
31
40
|
def indirect_container
|
32
|
-
|
41
|
+
RDF::Vocab::LDP.IndirectContainer
|
33
42
|
end
|
43
|
+
deprecation_deprecate :indirect_container
|
34
44
|
|
35
45
|
def contains
|
36
|
-
|
46
|
+
RDF::Vocab::LDP.contains
|
37
47
|
end
|
48
|
+
deprecation_deprecate :contains
|
38
49
|
|
39
50
|
def page
|
40
|
-
|
51
|
+
RDF::Vocab::LDP.Page
|
41
52
|
end
|
53
|
+
deprecation_deprecate :page
|
42
54
|
|
43
55
|
def page_of
|
44
|
-
|
56
|
+
RDF::Vocab::LDP.pageOf
|
45
57
|
end
|
58
|
+
deprecation_deprecate :page_of
|
46
59
|
|
47
60
|
def next_page
|
48
|
-
|
61
|
+
RDF::Vocab::LDP.nextPage
|
49
62
|
end
|
63
|
+
deprecation_deprecate :next_page
|
50
64
|
|
51
65
|
def membership_predicate
|
52
|
-
|
66
|
+
RDF::Vocab::LDP.membershipPredicate
|
53
67
|
end
|
54
|
-
|
68
|
+
deprecation_deprecate :membership_predicate
|
69
|
+
|
55
70
|
def prefer_empty_container
|
56
|
-
|
71
|
+
RDF::Vocab::LDP.PreferEmptyContainer
|
57
72
|
end
|
58
|
-
|
73
|
+
|
59
74
|
def prefer_membership
|
60
|
-
|
75
|
+
RDF::Vocab::LDP.PreferMembership
|
61
76
|
end
|
62
|
-
|
77
|
+
|
63
78
|
def prefer_containment
|
64
|
-
|
79
|
+
RDF::Vocab::LDP.PreferContainment
|
65
80
|
end
|
66
|
-
|
81
|
+
|
67
82
|
def has_member_relation
|
68
|
-
|
83
|
+
RDF::Vocab::LDP.hasMemberRelation
|
69
84
|
end
|
70
|
-
|
85
|
+
deprecation_deprecate :has_member_relation
|
86
|
+
|
71
87
|
def member
|
72
|
-
|
88
|
+
RDF::Vocab::LDP.member
|
73
89
|
end
|
74
|
-
|
90
|
+
deprecation_deprecate :member
|
75
91
|
end
|