ldp 0.4.1 → 0.5.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 +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
|