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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3a68882c3e0ea6d21e3819d632a92e88734bec0f
|
4
|
+
data.tar.gz: a3f31f5e16fc2a60b109bef5f7da218ad008e949
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4111cddaaccda626e39b8ba24619763ca217f97915855ba2fb936e7fcb7ba1f9d6afc78d268393f7c3a67128d6427a0a41f99b2d24d2f09d41e287e5aa1f1ae0
|
7
|
+
data.tar.gz: 173b2d3954e4aa0184a5d87916c637c8348fe185ad561b51cdc28b844d81c14bf820bcdac27551d097f6ccf348c35eaf5c49d20759741ce3cf64571f963dd133
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/ldp.gemspec
CHANGED
@@ -12,6 +12,7 @@ Gem::Specification.new do |spec|
|
|
12
12
|
spec.summary = spec.description
|
13
13
|
spec.homepage = "https://github.com/projecthydra/ldp"
|
14
14
|
spec.license = "APACHE2"
|
15
|
+
spec.required_ruby_version = '~> 2.0'
|
15
16
|
|
16
17
|
spec.files = `git ls-files`.split($/)
|
17
18
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
@@ -20,9 +21,13 @@ Gem::Specification.new do |spec|
|
|
20
21
|
|
21
22
|
spec.add_dependency "faraday"
|
22
23
|
spec.add_dependency "linkeddata", ">= 1.1"
|
24
|
+
spec.add_dependency "rdf-vocab"
|
23
25
|
spec.add_dependency "http_logger"
|
26
|
+
spec.add_dependency "deprecation"
|
24
27
|
spec.add_dependency "slop"
|
25
28
|
spec.add_development_dependency "bundler", "~> 1.3"
|
26
29
|
spec.add_development_dependency "rake"
|
27
30
|
spec.add_development_dependency "rspec"
|
31
|
+
spec.add_development_dependency "coveralls"
|
32
|
+
spec.add_development_dependency "simplecov"
|
28
33
|
end
|
data/lib/ldp.rb
CHANGED
@@ -1,11 +1,14 @@
|
|
1
1
|
require 'ldp/version'
|
2
2
|
require 'linkeddata'
|
3
|
+
require 'rdf/vocab/ldp'
|
3
4
|
require 'logger'
|
4
5
|
require 'singleton'
|
6
|
+
require 'deprecation'
|
5
7
|
|
6
8
|
module Ldp
|
7
9
|
RDF::Graph.send(:include, RDF::Isomorphic)
|
8
10
|
|
11
|
+
require 'ldp/error'
|
9
12
|
require 'ldp/client'
|
10
13
|
require 'ldp/uri'
|
11
14
|
|
@@ -17,15 +20,6 @@ module Ldp
|
|
17
20
|
|
18
21
|
autoload :Orm, 'ldp/orm'
|
19
22
|
|
20
|
-
class HttpError < RuntimeError; end
|
21
|
-
class BadRequest < HttpError; end # 400
|
22
|
-
class NotFound < HttpError; end # 404
|
23
|
-
class Conflict < HttpError; end # 409
|
24
|
-
class Gone < HttpError; end # 410
|
25
|
-
class EtagMismatch < HttpError; end # 412
|
26
|
-
|
27
|
-
class UnexpectedContentType < RuntimeError; end
|
28
|
-
|
29
23
|
# Returned when there is no result (e.g. 404)
|
30
24
|
class NoneClass
|
31
25
|
include Singleton
|
data/lib/ldp/client.rb
CHANGED
@@ -7,24 +7,29 @@ module Ldp
|
|
7
7
|
require 'ldp/client/prefer_headers'
|
8
8
|
include Ldp::Client::Methods
|
9
9
|
|
10
|
-
|
11
|
-
initialize_http_client *http_client
|
12
|
-
end
|
10
|
+
attr_reader :options
|
13
11
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
when data.container?
|
22
|
-
Ldp::Container.new_from_response self, subject, data
|
23
|
-
when data.resource?
|
24
|
-
Resource::RdfSource.new self, subject, data
|
12
|
+
def initialize(*args)
|
13
|
+
http_client, options = if args.length == 2
|
14
|
+
args
|
15
|
+
elsif args.length == 1 && args.first.is_a?(Faraday::Connection)
|
16
|
+
[args.first, {}]
|
17
|
+
elsif args.length == 1
|
18
|
+
[nil, args.first]
|
25
19
|
else
|
26
|
-
|
20
|
+
raise ArgumentError
|
27
21
|
end
|
22
|
+
|
23
|
+
@options = options
|
24
|
+
|
25
|
+
initialize_http_client(http_client || options)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Find or initialize a new LDP resource by URI
|
29
|
+
def find_or_initialize(subject, options = {})
|
30
|
+
data = get(subject, options)
|
31
|
+
|
32
|
+
Ldp::Resource.for(self, subject, data)
|
28
33
|
end
|
29
34
|
|
30
35
|
def logger
|
data/lib/ldp/client/methods.rb
CHANGED
@@ -23,6 +23,8 @@ module Ldp::Client::Methods
|
|
23
23
|
end
|
24
24
|
|
25
25
|
check_for_errors(resp)
|
26
|
+
|
27
|
+
Ldp::Response.new(resp)
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
@@ -48,13 +50,9 @@ module Ldp::Client::Methods
|
|
48
50
|
yield req if block_given?
|
49
51
|
end
|
50
52
|
|
51
|
-
if Ldp::Response.resource? resp
|
52
|
-
Ldp::Response.wrap self, resp
|
53
|
-
else
|
54
|
-
resp
|
55
|
-
end
|
56
|
-
|
57
53
|
check_for_errors(resp)
|
54
|
+
|
55
|
+
Ldp::Response.new(resp)
|
58
56
|
end
|
59
57
|
end
|
60
58
|
|
data/lib/ldp/container.rb
CHANGED
@@ -4,17 +4,27 @@ module Ldp
|
|
4
4
|
require 'ldp/container/direct'
|
5
5
|
require 'ldp/container/indirect'
|
6
6
|
|
7
|
-
def self.
|
7
|
+
def self.for(client, subject, data)
|
8
8
|
case
|
9
|
-
when data.types.include?(
|
9
|
+
when data.types.include?(RDF::Vocab::LDP.IndirectContainer)
|
10
10
|
Ldp::Container::Indirect.new client, subject, data
|
11
|
-
when data.types.include?(
|
11
|
+
when data.types.include?(RDF::Vocab::LDP.DirectContainer)
|
12
12
|
Ldp::Container::Direct.new client, subject, data
|
13
13
|
else
|
14
14
|
Ldp::Container::Basic.new client, subject, data
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
class << self
|
19
|
+
alias new_from_response for
|
20
|
+
end
|
21
|
+
|
22
|
+
def contains
|
23
|
+
@contains ||= Hash[graph.query(predicate: RDF::Vocab::LDP.contains).map do |x|
|
24
|
+
[x.object, Ldp::Resource::RdfSource.new(client, x.object, contained_graph(x.object))]
|
25
|
+
end]
|
26
|
+
end
|
27
|
+
|
18
28
|
##
|
19
29
|
# Add a new resource to the LDP container
|
20
30
|
def add *args
|
@@ -32,7 +42,7 @@ module Ldp
|
|
32
42
|
graph_or_content = args.first
|
33
43
|
else
|
34
44
|
slug = args.first
|
35
|
-
graph_or_content =
|
45
|
+
graph_or_content = build_empty_graph
|
36
46
|
end
|
37
47
|
|
38
48
|
resp = client.post subject, (graph_or_content.is_a?(RDF::Enumerable) ? graph_or_content.dump(:ttl) : graph_or_content) do |req|
|
@@ -41,5 +51,21 @@ module Ldp
|
|
41
51
|
|
42
52
|
client.find_or_initialize resp.headers['Location']
|
43
53
|
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def contained_graph subject
|
58
|
+
g = RDF::Graph.new
|
59
|
+
response_graph.query(subject: subject) do |stmt|
|
60
|
+
g << stmt
|
61
|
+
end
|
62
|
+
g
|
63
|
+
end
|
64
|
+
|
65
|
+
def rdf_source_for(object)
|
66
|
+
g = contained_graph(object)
|
67
|
+
|
68
|
+
Ldp::Resource::RdfSource.new(client, object, (g unless g.empty?))
|
69
|
+
end
|
44
70
|
end
|
45
71
|
end
|
data/lib/ldp/container/basic.rb
CHANGED
@@ -5,19 +5,10 @@ module Ldp
|
|
5
5
|
contains.each { |k, x| yield x }
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
private
|
15
|
-
def contained_graph subject
|
16
|
-
g = RDF::Graph.new
|
17
|
-
get.graph.query(subject: subject) do |stmt|
|
18
|
-
g << stmt
|
19
|
-
end
|
20
|
-
g
|
8
|
+
protected
|
9
|
+
|
10
|
+
def interaction_model
|
11
|
+
RDF::Vocab::LDP.BasicContainer
|
21
12
|
end
|
22
13
|
end
|
23
14
|
end
|
data/lib/ldp/container/direct.rb
CHANGED
@@ -2,15 +2,20 @@ module Ldp
|
|
2
2
|
class Container::Direct < Container::Basic
|
3
3
|
def members
|
4
4
|
return enum_for(:members) unless block_given?
|
5
|
-
|
6
|
-
|
7
|
-
yield
|
5
|
+
|
6
|
+
response_graph.query(subject: subject, predicate: member_relation).map do |x|
|
7
|
+
yield rdf_source_for(x.object)
|
8
8
|
end
|
9
9
|
end
|
10
|
-
|
10
|
+
|
11
11
|
def member_relation
|
12
|
-
|
12
|
+
response_graph.first_object(predicate: RDF::Vocab::LDP.hasMemberRelation) || RDF::Vocab::LDP.member
|
13
|
+
end
|
14
|
+
|
15
|
+
protected
|
16
|
+
|
17
|
+
def interaction_model
|
18
|
+
RDF::Vocab::LDP.DirectContainer
|
13
19
|
end
|
14
|
-
|
15
20
|
end
|
16
21
|
end
|
@@ -2,10 +2,16 @@ module Ldp
|
|
2
2
|
class Container::Indirect < Container::Direct
|
3
3
|
def members
|
4
4
|
return enum_for(:members) unless block_given?
|
5
|
-
|
6
|
-
|
7
|
-
yield
|
5
|
+
|
6
|
+
response_graph.query(predicate: member_relation, object: subject).map do |x|
|
7
|
+
yield rdf_source_for(x.object)
|
8
8
|
end
|
9
9
|
end
|
10
|
+
|
11
|
+
protected
|
12
|
+
|
13
|
+
def interaction_model
|
14
|
+
RDF::Vocab::LDP.IndirectContainer
|
15
|
+
end
|
10
16
|
end
|
11
17
|
end
|
data/lib/ldp/error.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Ldp
|
2
|
+
class Error < StandardError; end
|
3
|
+
|
4
|
+
class HttpError < RuntimeError; end
|
5
|
+
class BadRequest < HttpError; end # 400
|
6
|
+
class NotFound < HttpError; end # 404
|
7
|
+
class Conflict < HttpError; end # 409
|
8
|
+
class Gone < HttpError; end # 410
|
9
|
+
class EtagMismatch < HttpError; end # 412
|
10
|
+
|
11
|
+
class UnexpectedContentType < RuntimeError; end
|
12
|
+
|
13
|
+
class GraphDifferenceException < Ldp::Error
|
14
|
+
attr_reader :diff
|
15
|
+
def initialize message, diff
|
16
|
+
super(message)
|
17
|
+
@diff = diff
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/ldp/orm.rb
CHANGED
@@ -54,22 +54,19 @@ module Ldp
|
|
54
54
|
|
55
55
|
def save
|
56
56
|
Ldp.instrument 'save.orm.ldp', subject: subject_uri do
|
57
|
-
|
58
|
-
|
57
|
+
response = create_or_update
|
58
|
+
|
59
|
+
response.success?
|
59
60
|
end
|
60
|
-
rescue Ldp::HttpError
|
61
|
-
@last_response = e
|
62
|
-
logger.debug e
|
61
|
+
rescue Ldp::HttpError
|
63
62
|
false
|
64
63
|
end
|
65
64
|
|
66
65
|
def save!
|
67
|
-
result =
|
66
|
+
result = create_or_update
|
68
67
|
|
69
68
|
if result.is_a? RDF::Enumerable
|
70
|
-
raise GraphDifferenceException
|
71
|
-
elsif !result
|
72
|
-
raise @last_response
|
69
|
+
raise Ldp::GraphDifferenceException, 'Graph failed to persist', result
|
73
70
|
end
|
74
71
|
|
75
72
|
result
|
@@ -81,26 +78,18 @@ module Ldp
|
|
81
78
|
end
|
82
79
|
end
|
83
80
|
|
84
|
-
|
85
|
-
super
|
86
|
-
end
|
81
|
+
private
|
87
82
|
|
88
|
-
def
|
89
|
-
|
83
|
+
def create_or_update
|
84
|
+
@last_response = resource.save
|
85
|
+
rescue Ldp::HttpError => e
|
86
|
+
@last_response = e
|
87
|
+
logger.debug e
|
88
|
+
raise e
|
90
89
|
end
|
91
90
|
|
92
|
-
private
|
93
|
-
|
94
91
|
def logger
|
95
92
|
Ldp.logger
|
96
93
|
end
|
97
94
|
end
|
98
|
-
|
99
|
-
class GraphDifferenceException < Exception
|
100
|
-
attr_reader :diff
|
101
|
-
def initialize message, diff
|
102
|
-
super(message)
|
103
|
-
@diff = diff
|
104
|
-
end
|
105
|
-
end
|
106
95
|
end
|
data/lib/ldp/resource.rb
CHANGED
@@ -6,6 +6,17 @@ module Ldp
|
|
6
6
|
attr_reader :client, :subject
|
7
7
|
attr_accessor :content
|
8
8
|
|
9
|
+
def self.for(client, subject, response = nil)
|
10
|
+
case
|
11
|
+
when response.container?
|
12
|
+
Ldp::Container.for client, subject, response
|
13
|
+
when response.rdf_source?
|
14
|
+
Resource::RdfSource.new client, subject, response
|
15
|
+
else
|
16
|
+
Resource::BinarySource.new client, subject, response
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
9
20
|
def initialize client, subject, response = nil, base_path = ''
|
10
21
|
@client = client
|
11
22
|
@subject = subject
|
@@ -67,10 +78,10 @@ module Ldp
|
|
67
78
|
# Create a new resource at the URI
|
68
79
|
# @return [RdfSource] the new representation
|
69
80
|
def create &block
|
70
|
-
raise "Can't call create on an existing resource" unless new?
|
81
|
+
raise Ldp::Error, "Can't call create on an existing resource" unless new?
|
71
82
|
verb = subject.nil? ? :post : :put
|
72
83
|
resp = client.send(verb, (subject || @base_path), content) do |req|
|
73
|
-
|
84
|
+
req.headers["Link"] = "<#{interaction_model}>;rel=\"type\"" if interaction_model
|
74
85
|
yield req if block_given?
|
75
86
|
end
|
76
87
|
|
@@ -103,14 +114,21 @@ module Ldp
|
|
103
114
|
new_response.headers['Last-Modified'] == response.headers['Last-Modified']
|
104
115
|
end
|
105
116
|
|
106
|
-
def update_cached_get
|
107
|
-
Response.
|
117
|
+
def update_cached_get(response)
|
118
|
+
response = Response.new(response)
|
119
|
+
|
108
120
|
if response.etag.nil? || response.last_modified.nil?
|
109
|
-
response =
|
121
|
+
response = client.head(subject)
|
110
122
|
end
|
111
123
|
@get.etag = response.etag
|
112
124
|
@get.last_modified = response.last_modified
|
113
125
|
end
|
114
126
|
|
127
|
+
protected
|
128
|
+
|
129
|
+
def interaction_model
|
130
|
+
nil
|
131
|
+
end
|
132
|
+
|
115
133
|
end
|
116
134
|
end
|
@@ -17,7 +17,9 @@ module Ldp
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def described_by
|
20
|
-
|
20
|
+
described_by = Array(head.links["describedby"]).first
|
21
|
+
|
22
|
+
client.find_or_initialize described_by if described_by
|
21
23
|
end
|
22
24
|
|
23
25
|
# Override inspect so that `content` is never shown. It is typically too big to be helpful
|
@@ -26,5 +28,11 @@ module Ldp
|
|
26
28
|
fields = [:subject].map{|field| "#{field}=\"#{self.send(field)}\""}
|
27
29
|
string << fields.join(", ") << ">"
|
28
30
|
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def interaction_model
|
35
|
+
RDF::Vocab::LDP.NonRDFSource
|
36
|
+
end
|
29
37
|
end
|
30
38
|
end
|