ldp 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 63183c29706de20d216c7ac0701f1c487ac198a1
4
- data.tar.gz: e08f80b008698907385b8060d4d2dcaed42ede20
3
+ metadata.gz: 85a6fa5082ce00c5b29780ec58bdc216286a5cfe
4
+ data.tar.gz: 884e4e0ea864ddf64270eff48c9ae1fca7d7d70b
5
5
  SHA512:
6
- metadata.gz: c7ff75b126b3fcf65c11c3a2a5265551f6bb9ea579c9775038a6b5a2decf64799ff8a898473c96be70232671526ffcabf278538dca1b49a98b5246c31ac4c44e
7
- data.tar.gz: ecd3068a5a86397768f428e142be9832b587f5474629fb2c0c68a3364128ea1a9b67fb15471323f0ddaba2e0c09ada6f00cc898670481f8ab6a393d914902a41
6
+ metadata.gz: 7061275707496fd834cc225c3fe6ff1ac6eaf7bd8d01ef63677b8fbd30c24c1038a16ee0646c35b59e452f2c988d2c8d908c1c1011c200812dc3b379cbcc7212
7
+ data.tar.gz: 40a58400110d941f10212a0b56bfa4cca92d0244372a4e7769a9fdda746c7444de04eefac95cf3f04863d4d31b52ab980b25ed5a2c1562b2424113951a1a4c05
data/.travis.yml ADDED
@@ -0,0 +1,6 @@
1
+ language: ruby
2
+ rvm:
3
+ - 1.9.3
4
+ - 2.0.0
5
+ - 2.1.0
6
+ - jruby-19mode
data/Gemfile CHANGED
@@ -3,4 +3,5 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in ldp-client.gemspec
4
4
  gemspec
5
5
 
6
- gem "byebug"
6
+ gem 'byebug', :platforms => [:mri_20]
7
+
data/README.md CHANGED
@@ -1,12 +1,14 @@
1
- # Ldp::Client
1
+ # Ldp.rb
2
2
 
3
- TODO: Write a gem description
3
+ [![Build Status](https://travis-ci.org/cbeer/ldp.png?branch=master)](https://travis-ci.org/cbeer/ldp)
4
+
5
+ Linked Data Platform client library for Ruby
4
6
 
5
7
  ## Installation
6
8
 
7
9
  Add this line to your application's Gemfile:
8
10
 
9
- gem 'ldp-client'
11
+ gem 'ldp'
10
12
 
11
13
  And then execute:
12
14
 
@@ -14,11 +16,31 @@ And then execute:
14
16
 
15
17
  Or install it yourself as:
16
18
 
17
- $ gem install ldp-client
19
+ $ gem install ldp
18
20
 
19
21
  ## Usage
20
22
 
21
- TODO: Write usage instructions here
23
+ ```ruby
24
+ host = 'http://localhost:8080'
25
+ client = Ldp::Client.new(host)
26
+ resource = Ldp::Resource.new(client, host + '/rest/node/to/update')
27
+ orm = Ldp::Orm.new(resource)
28
+
29
+ # view the current title(s)
30
+ orm.orm.value(RDF::DC11.title)
31
+
32
+ # update the title
33
+ orm.graph.delete([orm.resource.subject_uri, RDF::DC11.title, nil])
34
+ orm.graph.insert([orm.resource.subject_uri, RDF::DC11.title, 'a new title'])
35
+
36
+ # save changes
37
+ orm.save
38
+ ```
39
+
40
+ ### Fedora Commons notes
41
+ Due to some discrepancies with alpha version of Fedora Commons, you may need to do some things differently:
42
+ * [Can't load resources from Fedora 4](https://github.com/cbeer/ldp/issues/1)
43
+ * [orm.save with an rdf:type doesn't work with Fedora 4.0.0-alpha-3](https://github.com/cbeer/ldp/issues/2)
22
44
 
23
45
  ## Contributing
24
46
 
data/Rakefile CHANGED
@@ -1 +1,6 @@
1
1
  require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/ldp.gemspec CHANGED
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
19
19
  spec.require_paths = ["lib"]
20
20
 
21
21
  spec.add_dependency "faraday"
22
- spec.add_dependency "linkeddata"
22
+ spec.add_dependency "linkeddata", ">= 1.1"
23
23
  spec.add_development_dependency "bundler", "~> 1.3"
24
24
  spec.add_development_dependency "rake"
25
25
  spec.add_development_dependency "rspec"
data/lib/ldp.rb CHANGED
@@ -1,21 +1,20 @@
1
1
  require 'ldp/version'
2
+ require 'linkeddata'
2
3
 
3
4
  module Ldp
4
- require 'ldp/client'
5
-
6
- def self.resource
7
- RDF::URI.new("http://www.w3.org/ns/ldp/Resource")
8
- end
5
+ RDF::Graph.send(:include, RDF::Isomorphic)
9
6
 
10
- def self.container
11
- RDF::URI.new("http://www.w3.org/ns/ldp/Container")
12
- end
7
+ require 'ldp/client'
8
+ require 'ldp/uri'
13
9
 
14
- def self.inlinedResource
15
- RDF::URI.new("http://www.w3.org/ns/ldp/inlinedResource")
16
- end
10
+ extend Uri
17
11
 
18
12
  autoload :Response, 'ldp/response'
19
13
  autoload :Resource, 'ldp/resource'
20
14
  autoload :Container, 'ldp/container'
21
- end
15
+
16
+ autoload :Orm, 'ldp/orm'
17
+
18
+ class NotFound < StandardError; end
19
+
20
+ end
data/lib/ldp/client.rb CHANGED
@@ -1,8 +1,11 @@
1
1
  require 'faraday'
2
- require 'linkeddata'
3
2
 
4
3
  module Ldp
5
4
  class Client
5
+
6
+ require 'ldp/client/methods'
7
+
8
+ include Ldp::Client::Methods
6
9
 
7
10
  attr_reader :http
8
11
 
@@ -14,10 +17,11 @@ module Ldp
14
17
  end
15
18
  end
16
19
 
20
+ # Find or initialize a new LDP resource by URI
17
21
  def find_or_initialize subject
18
22
  data = get(subject)
19
23
 
20
- if !data.is_a? Response
24
+ unless data.is_a? Response
21
25
  raise "#{subject} is not an LDP Resource"
22
26
  end
23
27
 
@@ -28,43 +32,5 @@ module Ldp
28
32
  end
29
33
  end
30
34
 
31
- def get url
32
- resp = http.get do |req|
33
- req.url url
34
- yield req if block_given?
35
- end
36
-
37
- if Response.resource? resp
38
- Response.wrap self, resp
39
- else
40
- resp
41
- end
42
- end
43
-
44
- def delete url
45
- http.delete do |req|
46
- req.url url
47
- yield req if block_given?
48
- end
49
- end
50
-
51
- def post url, body
52
- http.post do |req|
53
- req.url url
54
- req.headers['Content-Type'] = 'text/turtle'
55
- req.body = body
56
- yield req if block_given?
57
- end
58
- end
59
-
60
- def put url, body
61
- http.put do |req|
62
- req.url url
63
- req.headers['Content-Type'] = 'text/turtle'
64
- req.body = body
65
- yield req if block_given?
66
- end
67
- end
68
-
69
35
  end
70
36
  end
@@ -0,0 +1,44 @@
1
+ module Ldp::Client::Methods
2
+
3
+ # Get a LDP Resource by URI
4
+ def get url
5
+ resp = http.get do |req|
6
+ req.url url
7
+ yield req if block_given?
8
+ end
9
+
10
+ if Ldp::Response.resource? resp
11
+ Ldp::Response.wrap self, resp
12
+ else
13
+ resp
14
+ end
15
+ end
16
+
17
+ # Delete a LDP Resource by URI
18
+ def delete url
19
+ http.delete do |req|
20
+ req.url url
21
+ yield req if block_given?
22
+ end
23
+ end
24
+
25
+ # Post TTL to an LDP Resource
26
+ def post url, body = nil, headers = {}
27
+ http.post do |req|
28
+ req.url url
29
+ req.headers = {"Content-Type"=>"text/turtle"}.merge headers
30
+ req.body = body
31
+ yield req if block_given?
32
+ end
33
+ end
34
+
35
+ # Update an LDP resource with TTL by URI
36
+ def put url, body
37
+ http.put do |req|
38
+ req.url url
39
+ req.headers['Content-Type'] = 'text/turtle'
40
+ req.body = body
41
+ yield req if block_given?
42
+ end
43
+ end
44
+ end
data/lib/ldp/container.rb CHANGED
@@ -1,7 +1,31 @@
1
1
  module Ldp
2
2
  class Container < Resource
3
- def add graph
4
- client.post subject, graph.dump(:ttl)
3
+ ##
4
+ # Add a resource to the LDP container
5
+ def add *args
6
+ # slug, graph
7
+ # graph
8
+ # slug
9
+
10
+ case
11
+ when (args.length > 2 || args.length == 0)
12
+
13
+ when (args.length == 2)
14
+ slug, graph = args
15
+ when (args.first.is_a? RDF::Graph)
16
+ slug = nil
17
+ graph = args.first
18
+ else
19
+ slug = args.first
20
+ graph = RDF::Graph.new
21
+ end
22
+
23
+ resp = client.post subject, graph.dump(:ttl) do |req|
24
+ req.headers['Slug'] = slug
25
+ end
26
+
27
+ subject = resp.headers['Location']
28
+ return client.find_or_initialize subject
5
29
  end
6
30
  end
7
31
  end
data/lib/ldp/orm.rb ADDED
@@ -0,0 +1,87 @@
1
+ module Ldp
2
+ class Orm
3
+
4
+ attr_reader :resource
5
+ attr_reader :last_response
6
+
7
+ def initialize resource
8
+ @resource = resource
9
+ end
10
+
11
+ def graph
12
+ resource.graph
13
+ end
14
+
15
+ def value predicate
16
+ graph.query(:subject => resource.subject_uri, :predicate => predicate).map do |stmt|
17
+ stmt.object
18
+ end
19
+ end
20
+
21
+ def query *args, &block
22
+ graph.query *args, &block
23
+ end
24
+
25
+ def reload
26
+ Ldp::Orm.new resource.reload
27
+ end
28
+
29
+ def create
30
+ nil
31
+ end
32
+
33
+ def save
34
+ @last_response = resource.update
35
+
36
+ diff = Ldp::Resource.check_for_differences_and_reload_resource self
37
+
38
+ if diff.any?
39
+ diff
40
+ else
41
+ @last_response.success?
42
+ end
43
+ end
44
+
45
+ def save!
46
+ result = save
47
+
48
+ if result.is_a? RDF::Graph
49
+ raise GraphDifferenceException.new "", result
50
+ elsif !result
51
+ raise SaveException.new "", @last_response
52
+ end
53
+
54
+ result
55
+ end
56
+
57
+ def delete
58
+ resource.delete
59
+ end
60
+
61
+ def method_missing meth, *args, &block
62
+ super
63
+ end
64
+
65
+ def respond_to?(meth)
66
+ super
67
+ end
68
+
69
+ end
70
+
71
+ class GraphDifferenceException < Exception
72
+ attr_reader :diff
73
+ def initialize message, diff
74
+ super(message)
75
+ @diff = diff
76
+ end
77
+ end
78
+
79
+ class SaveException < Exception
80
+ attr_reader :response
81
+ def initialize message, response
82
+ super(message)
83
+ @response = response
84
+ end
85
+ end
86
+ end
87
+
data/lib/ldp/resource.rb CHANGED
@@ -1,11 +1,81 @@
1
1
  module Ldp
2
2
  class Resource
3
+
3
4
  attr_reader :client, :subject
4
5
 
5
- def initialize client, subject, data = nil
6
+ ##
7
+ # Create a new LDP resource with a blank RDF graph
8
+ def self.create client, subject
9
+ self.new client, subject, RDF::Graph.new
10
+ end
11
+
12
+ def initialize client, subject, graph_or_response = nil
6
13
  @client = client
7
14
  @subject = subject
8
- @get = data
15
+
16
+ @graph = graph_or_response if graph_or_response.is_a? RDF::Graph
17
+ @get = graph_or_response if graph_or_response.is_a? Ldp::Response
18
+ end
19
+
20
+ ##
21
+ # Get the graph subject as a URI
22
+ def subject_uri
23
+ @subject_uri ||= RDF::URI.new subject
24
+ end
25
+
26
+ ##
27
+ # Reload the LDP resource
28
+ def reload
29
+ Ldp::Resource.new client, subject
30
+ end
31
+
32
+ ##
33
+ # Is the resource new, or does it exist in the LDP server?
34
+ def new?
35
+ get
36
+ end
37
+
38
+ ##
39
+ # Have we retrieved the content already?
40
+ def retrieved_content?
41
+ @get
42
+ end
43
+
44
+ ##
45
+ # Get the resource
46
+ def get
47
+ @get ||= client.get(subject).tap do |result|
48
+ raise NotFound if result.status == 404
49
+ end
50
+ end
51
+
52
+ ##
53
+ # Delete the resource
54
+ def delete
55
+ client.delete subject do |req|
56
+ req.headers['If-Match'] = get.etag if retrieved_content?
57
+ end
58
+ end
59
+
60
+ ##
61
+ # Create a new resource at the URI
62
+ def create
63
+ raise "" if new?
64
+ resp = client.post '', graph.dump(:ttl) do |req|
65
+ req.headers['Slug'] = subject
66
+ end
67
+
68
+ @subject = resp.headers['Location']
69
+ @subject_uri = nil
70
+ end
71
+
72
+ ##
73
+ # Update the stored graph
74
+ def update new_graph = nil
75
+ new_graph ||= graph
76
+ client.put subject, new_graph.dump(:ttl) do |req|
77
+ req.headers['If-Match'] = get.etag if retrieved_content?
78
+ end
9
79
  end
10
80
 
11
81
  def graph
@@ -14,11 +84,11 @@ module Ldp
14
84
 
15
85
  inlinedResources = get.graph.query(:predicate => Ldp.inlinedResource).map { |x| x.object }
16
86
 
17
- unless inlinedResource.empty?
87
+ unless inlinedResources.empty?
18
88
  new_graph = RDF::Graph.new
19
89
 
20
90
  original_graph.each_statement do |s|
21
- unless inlinedResource.include? s.subject
91
+ unless inlinedResources.include? s.subject
22
92
  new_graph << s
23
93
  end
24
94
  end
@@ -30,29 +100,31 @@ module Ldp
30
100
  end
31
101
  end
32
102
 
33
- def get
34
- @get ||= client.get subject
35
- end
103
+ def self.check_for_differences_and_reload_resource old_object
104
+ new_object = old_object.reload
36
105
 
37
- def delete
38
- client.delete subject do |req|
39
- if @get
40
- req.headers['If-Match'] << get.headers['ETag']
106
+ bijection = new_object.graph.bijection_to(old_object.graph)
107
+ diff = RDF::Graph.new
108
+
109
+ old_object.graph.each do |statement|
110
+ if statement.has_blank_nodes?
111
+ subject = bijection.fetch(statement.subject, false) if statement.subject.node?
112
+ object = bijection.fetch(statement.object, false) if statement.object.node?
113
+ bijection_statement = RDF::Statement.new :subject => subject || statemnet.subject, :predicate => statement.predicate, :object => object || statement.object
114
+
115
+ diff << statement if subject === false or object === false or new_object.graph.has_statement?(bijection_statement)
116
+ elsif !new_object.graph.has_statement? statement
117
+ diff << statement
41
118
  end
42
119
  end
43
120
 
44
- @get = nil
45
- @graph = nil
121
+ diff
46
122
  end
47
123
 
48
- def update
49
- client.put subject, graph.dump(:ttl) do |req|
50
- if @get
51
- req.headers['If-Match'] << get.headers['ETag']
52
- end
53
- end
54
- @get = nil
55
- @graph = nil
124
+ ##
125
+ # Reload this resource as an LDP container
126
+ def as_container
127
+ Ldp::Container.new client, subject, @graph || @get
56
128
  end
57
129
  end
58
- end
130
+ end
data/lib/ldp/response.rb CHANGED
@@ -1,17 +1,22 @@
1
1
  module Ldp
2
2
  module Response
3
+
4
+ ##
5
+ # Wrap the raw Faraday respone with our LDP extensions
3
6
  def self.wrap client, raw_resp
4
7
  raw_resp.send(:extend, Ldp::Response)
5
8
  raw_resp.ldp_client = client
6
9
  raw_resp
7
10
  end
8
11
 
12
+ ##
13
+ # Extract the Link: headers from the HTTP resource
9
14
  def self.links raw_resp
10
- Array(raw_resp.headers["Link"]).inject({}) do |memo, header|
15
+ h = Hash.new { |hash, key| hash[key] = [] }
16
+ Array(raw_resp.headers["Link"]).map { |x| x.split(", ") }.flatten.inject(h) do |memo, header|
11
17
  v = header.scan(/(.*);\s?rel="([^"]+)"/)
12
18
 
13
19
  if v.length == 1
14
- memo[v.first.last] ||= []
15
20
  memo[v.first.last] << v.first.first
16
21
  end
17
22
 
@@ -19,25 +24,63 @@ module Ldp
19
24
  end
20
25
  end
21
26
 
27
+ ##
28
+ # Is the response an LDP resource?
22
29
  def self.resource? raw_resp
23
- links(raw_resp).fetch("type", []).include? Ldp.resource
30
+ links(raw_resp).fetch("type", []).include? Ldp.resource.to_s
31
+ end
32
+
33
+ ##
34
+ # Is the response an LDP resource?
35
+ def resource?
36
+ Ldp::Response.resource?(self)
37
+ end
38
+
39
+ ##
40
+ # Is the response an LDP container
41
+ def container?
42
+ graph.has_statement? RDF::Statement.new(subject, RDF.type, Ldp.container)
24
43
  end
25
44
 
45
+ ##
46
+ # Get the subject for the response
47
+ def subject
48
+ @subject ||= if has_page?
49
+ graph.first_object [page_subject, Ldp.page_of, nil]
50
+ else
51
+ page_subject
52
+ end
53
+ end
54
+
55
+ ##
56
+ # Get the URI to the response
57
+ def page_subject
58
+ @page_subject ||= RDF::URI.new env[:url]
59
+ end
60
+
61
+ ##
62
+ # Set the LDP client for this resource
26
63
  def ldp_client= client
27
64
  @ldp_client = client
28
65
  end
29
66
 
67
+ ##
68
+ # Get the LDP client
30
69
  def ldp_client
31
70
  @ldp_client
32
71
  end
33
72
 
73
+ ##
74
+ # Get the graph for the resource (or a blank graph if there is no metadata for the resource)
34
75
  def graph
35
76
  @graph ||= begin
36
77
  graph = RDF::Graph.new
37
78
 
38
- RDF::Reader.for(:ttl).new(StringIO.new(body), :base_uri => subject) do |reader|
39
- reader.each_statement do |s|
40
- graph << s
79
+ if resource?
80
+ RDF::Reader.for(:ttl).new(StringIO.new(body), :base_uri => page_subject) do |reader|
81
+ reader.each_statement do |s|
82
+ graph << s
83
+ end
41
84
  end
42
85
  end
43
86
 
@@ -45,52 +88,90 @@ module Ldp
45
88
  end
46
89
  end
47
90
 
91
+ ##
92
+ # Extract the ETag for the resource
48
93
  def etag
49
-
94
+ headers['ETag']
50
95
  end
51
96
 
97
+ ##
98
+ # Extract the last modified header for the resource
52
99
  def last_modified
53
-
100
+ headers['Last-Modified']
54
101
  end
55
102
 
103
+ ##
104
+ # Statements about the page
56
105
  def page
106
+ @page_graph ||= begin
107
+ g = RDF::Graph.new
108
+
109
+ if resource?
110
+ res = graph.query RDF::Statement.new(page_subject, nil, nil)
57
111
 
112
+ res.each_statement do |s|
113
+ g << s
114
+ end
115
+ end
116
+
117
+ g
118
+ end
58
119
  end
59
120
 
60
- def paginated?
121
+ ##
122
+ # Is the response paginated?
123
+ def has_page?
124
+ graph.has_statement? RDF::Statement.new(page_subject, RDF.type, Ldp.page)
125
+ end
61
126
 
127
+ ##
128
+ # Is there a next page?
129
+ def has_next?
130
+ next_page != nil
62
131
  end
63
132
 
133
+ ##
134
+ # Get the URI for the next page
64
135
  def next_page
65
-
136
+ graph.first_object [page_subject, Ldp.nextPage, nil]
66
137
  end
67
138
 
139
+ ##
140
+ # Get the URI to the first page
68
141
  def first_page
69
-
142
+ if links['first']
143
+ RDF::URI.new links['first']
144
+ elsif graph.has_statement? RDf::Statement.new(page_subject, Ldp.nextPage, nil)
145
+ subject
146
+ end
70
147
  end
71
148
 
149
+ ##
150
+ # Get a list of inlined resources
72
151
  def resources
73
-
152
+ graph.query RDF::Statement.new(page_subject, Ldp.inlinedResource, nil)
74
153
  end
75
154
 
155
+ ##
156
+ # Get a list of member resources
76
157
  def members
77
-
78
- end
79
-
80
- def resource?
81
- Ldp::Response.resource?(self)
158
+ graph.query RDF::Statement.new(page_subject, membership_predicate, nil)
82
159
  end
83
160
 
84
- def container?
85
- graph.has_statement? RDF::Statement.new(subject, RDF.type, Ldp.container)
161
+ ##
162
+ # Predicate to use to determine container membership
163
+ def membership_predicate
164
+ graph.first_object [page_subject, Ldp.membership_predicate, nil]
86
165
  end
87
166
 
88
167
  def sort
89
168
 
90
169
  end
91
170
 
92
- def subject
93
- RDF::URI.new env[:url]
171
+ ##
172
+ # Link: headers from the HTTP response
173
+ def links
174
+ Ldp::Response.links(self)
94
175
  end
95
176
  end
96
177
  end
data/lib/ldp/uri.rb ADDED
@@ -0,0 +1,35 @@
1
+ module Ldp::Uri
2
+
3
+ def uri str
4
+ RDF::URI.new("http://www.w3.org/ns/ldp#") + str
5
+ end
6
+
7
+ def resource
8
+ uri("Resource")
9
+ end
10
+
11
+ def container
12
+ uri("Container")
13
+ end
14
+
15
+ def page
16
+ uri("Page")
17
+ end
18
+
19
+ def page_of
20
+ uri("pageOf")
21
+ end
22
+
23
+ def next_page
24
+ uri("nextPage")
25
+ end
26
+
27
+ def inlinedResource
28
+ uri("inlinedResource")
29
+ end
30
+
31
+ def membership_predicate
32
+ uri("membershipPredicate")
33
+ end
34
+
35
+ end
data/lib/ldp/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Ldp
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Integration tests" do
4
+
5
+ end
@@ -6,6 +6,14 @@ describe "Ldp::Client" do
6
6
  graph.dump(:ttl)
7
7
  end
8
8
 
9
+
10
+ let(:paginatedGraph) do
11
+ graph = RDF::Graph.new << [RDF::URI.new(""), RDF::DC.title, "Hello, world!"]
12
+ graph << [RDF::URI.new("?firstPage"), RDF.type, Ldp.page]
13
+ graph << [RDF::URI.new("?firstPage"), Ldp.page_of, RDF::URI.new("")]
14
+ graph.dump(:ttl)
15
+ end
16
+
9
17
  let(:simple_container_graph) do
10
18
  graph = RDF::Graph.new << [RDF::URI.new(""), RDF.type, Ldp.container]
11
19
  graph.dump(:ttl)
@@ -13,9 +21,11 @@ describe "Ldp::Client" do
13
21
 
14
22
  let(:conn_stubs) do
15
23
  stubs = Faraday::Adapter::Test::Stubs.new do |stub|
16
- stub.get('/a_resource') {[ 200, {"Link" => "http://www.w3.org/ns/ldp/Resource;rel=\"type\""}, simple_graph ]}
17
- stub.get('/a_container') {[ 200, {"Link" => "http://www.w3.org/ns/ldp/Resource;rel=\"type\""}, simple_container_graph ]}
18
-
24
+ stub.get('/a_resource') {[ 200, {"Link" => "http://www.w3.org/ns/ldp#Resource;rel=\"type\""}, simple_graph ]}
25
+ stub.get('/a_container') {[ 200, {"Link" => "http://www.w3.org/ns/ldp#Resource;rel=\"type\""}, simple_container_graph ]}
26
+ stub.put("/a_resource") { [204]}
27
+ stub.delete("/a_resource") { [204]}
28
+ stub.post("/a_container") { [201, {"Location" => "http://example.com/a_container/subresource"}]}
19
29
  end
20
30
  end
21
31
 
@@ -53,11 +63,69 @@ describe "Ldp::Client" do
53
63
  expect(resp.resource?).to be_true
54
64
  end
55
65
 
56
- describe "response" do
66
+ it "should accept a block to change the HTTP request" do
67
+ expect { |b| subject.get "a_resource", &b }.to yield_control
68
+ end
69
+ end
70
+
71
+ describe "delete" do
72
+ it "should DELETE the subject from the HTTP endpoint" do
73
+ resp = subject.delete "a_resource"
74
+ expect(resp.status).to eq(204)
75
+ end
76
+
77
+ it "should accept a block to change the HTTP request" do
78
+ expect { |b| subject.delete "a_resource", &b }.to yield_control
79
+ end
80
+ end
81
+
82
+ describe "post" do
83
+ it "should POST to the subject at the HTTP endpoint" do
84
+ resp = subject.post "a_container"
85
+ expect(resp.status).to eq(201)
86
+ expect(resp.headers[:Location]).to eq("http://example.com/a_container/subresource")
87
+ end
88
+
89
+ it "should set content" do
90
+ subject.post "a_container", 'foo' do |req|
91
+ expect(req.body).to eq 'foo'
92
+ end
93
+ end
94
+
95
+ it "should set default Content-type" do
96
+ subject.post "a_container", 'foo' do |req|
97
+ expect(req.headers).to eq({ "Content-Type" => "text/turtle" })
98
+ end
99
+ end
100
+
101
+ it "should set headers" do
102
+ subject.post "a_container", 'foo', {'Content-Type' => 'application/pdf'} do |req|
103
+ expect(req.headers).to eq({ "Content-Type" => "application/pdf" })
104
+ end
105
+ end
106
+
107
+ it "should set headers passed as arguments" do
108
+ resp = subject.post "a_container"
109
+ end
110
+
111
+ it "should accept a block to change the HTTP request" do
112
+ expect { |b| subject.post "a_container", &b }.to yield_control
113
+ end
114
+
115
+ end
116
+
117
+ describe "put" do
118
+ it "should PUT content to the subject at the HTTP endpoint" do
119
+ resp = subject.put "a_resource", "some-payload"
120
+ expect(resp.status).to eq(204)
121
+ end
57
122
 
123
+ it "should accept a block to change the HTTP request" do
124
+ expect { |b| subject.put "a_resource", "some-payload", &b }.to yield_control
58
125
  end
59
126
  end
60
127
 
128
+
61
129
  describe "find_or_initialize" do
62
130
  it "should be a resource" do
63
131
  resource = subject.find_or_initialize "a_resource"
@@ -71,4 +139,4 @@ describe "Ldp::Client" do
71
139
  end
72
140
 
73
141
  end
74
- end
142
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ldp::Orm do
4
+ subject { Ldp::Orm.new test_resource }
5
+
6
+ let(:simple_graph) do
7
+ graph = RDF::Graph.new << [RDF::URI.new(""), RDF::DC.title, "Hello, world!"]
8
+ graph.dump(:ttl)
9
+ end
10
+
11
+ let(:conn_stubs) do
12
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
13
+ stub.get('/a_resource') {[ 200, {"Link" => "http://www.w3.org/ns/ldp#Resource;rel=\"type\""}, simple_graph ]}
14
+ stub.put("/a_resource") { [204]}
15
+ end
16
+ end
17
+
18
+ let(:mock_conn) do
19
+ test = Faraday.new do |builder|
20
+ builder.adapter :test, conn_stubs do |stub|
21
+ end
22
+ end
23
+ end
24
+
25
+ let :mock_client do
26
+ Ldp::Client.new mock_conn
27
+ end
28
+
29
+ let :test_resource do
30
+ Ldp::Resource.new mock_client, "http://example.com/a_resource"
31
+ end
32
+
33
+ describe "#delete" do
34
+ it "should delete the LDP resource" do
35
+ test_resource.should_receive(:delete)
36
+ subject.delete
37
+ end
38
+ end
39
+
40
+ describe "#create" do
41
+
42
+ end
43
+
44
+ describe "#save" do
45
+ it "should update the resource from the graph" do
46
+ expect(subject.save).to be_true
47
+ end
48
+
49
+ it "should provide a graph of differences if the post-save graph doesn't match our graph" do
50
+ subject.graph << RDF::Statement.new(:subject => subject.resource.subject_uri, :predicate => RDF::URI.new("info:some-predicate"), :object => RDF::Literal.new("xyz"))
51
+ result = subject.save
52
+ expect(result).to_not be_empty
53
+ end
54
+
55
+ it "should return false if the response was not successful" do
56
+ conn_stubs.instance_variable_get(:@stack)[:put] = [] # erases the stubs for :put
57
+ conn_stubs.put('/a_resource') {[412]}
58
+ expect(subject.save).to be_false
59
+ end
60
+ end
61
+
62
+ describe "#save!" do
63
+ it "should raise an exception if there are differences after saving the graph" do
64
+ subject.graph << RDF::Statement.new(:subject => subject.resource.subject_uri, :predicate => RDF::URI.new("info:some-predicate"), :object => RDF::Literal.new("xyz"))
65
+ expect { subject.save! }.to raise_exception(Ldp::GraphDifferenceException)
66
+ end
67
+
68
+ it "should raise an exception if the ETag didn't match" do
69
+ conn_stubs.instance_variable_get(:@stack)[:put] = [] # erases the stubs for :put
70
+ conn_stubs.put('/a_resource') {[412, {}, "Bad If-Match header value: 'ae43aa934dc4f4e15ea1b4dd1ca7a56791972836'"]}
71
+ expect { subject.save! }.to raise_exception(Ldp::SaveException)
72
+ end
73
+ end
74
+
75
+ describe "#value" do
76
+ it "should provide a convenience method for retrieving values" do
77
+ expect(subject.value(RDF::DC.title).first.to_s).to eq "Hello, world!"
78
+ end
79
+ end
80
+
81
+ describe "#reload" do
82
+ before do
83
+ updated_graph = RDF::Graph.new << [RDF::URI.new(""), RDF::DC.title, "Hello again, world!"]
84
+ conn_stubs.get('/a_resource') {[200,
85
+ {"Link" => "http://www.w3.org/ns/ldp#Resource;rel=\"type\"",
86
+ "ETag" => "new-tag"},
87
+ updated_graph.dump(:ttl)]}
88
+ end
89
+
90
+ it "loads the new values" do
91
+ old_value = subject.value(RDF::DC.title).first.to_s
92
+ reloaded = subject.reload
93
+ expect(reloaded.value(RDF::DC.title).first.to_s).not_to eq old_value
94
+ end
95
+
96
+ it "uses the new ETag" do
97
+ old_tag = subject.resource.get.etag
98
+ reloaded = subject.reload
99
+ expect(reloaded.resource.get.etag).not_to eq old_tag
100
+ end
101
+ end
102
+ end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ldp::Resource do
4
+ subject { Ldp::Resource.new(mock_client, path) }
5
+
6
+ let(:conn_stubs) do
7
+ stubs = Faraday::Adapter::Test::Stubs.new do |stub|
8
+ stub.get('/not_found_resource') { [404] }
9
+ stub.get('/a_resource') { [200] }
10
+ end
11
+ end
12
+
13
+ let(:mock_conn) do
14
+ test = Faraday.new do |builder|
15
+ builder.adapter :test, conn_stubs do |stub|
16
+ end
17
+ end
18
+ end
19
+
20
+ let :mock_client do
21
+ Ldp::Client.new mock_conn
22
+ end
23
+
24
+ describe "#get" do
25
+ context "when the resource is not in repository" do
26
+ let(:path) { '/not_found_resource' }
27
+ it "should raise an error" do
28
+ expect{ subject.get }.to raise_error Ldp::NotFound
29
+ end
30
+ end
31
+
32
+ context "when the resource is in the repository" do
33
+ let(:path) { '/a_resource' }
34
+ it "should get the response" do
35
+ expect(subject.get).to be_kind_of Faraday::Response
36
+ expect(subject.get.status).to eq 200
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ describe Ldp::Response do
4
+ LDP_RESOURCE_HEADERS = { "Link" => Ldp.resource.to_s + ";rel=\"type\""}
5
+
6
+ let(:mock_response) { double() }
7
+ let(:mock_client) { double(Ldp::Client) }
8
+
9
+ subject do
10
+ Ldp::Response.wrap mock_client, mock_response
11
+ end
12
+
13
+ describe ".wrap" do
14
+ it "should mixin Ldp::Response into the raw response" do
15
+ Ldp::Response.wrap(mock_client, mock_response)
16
+ expect(mock_response).to be_a_kind_of(Ldp::Response)
17
+ expect(mock_response.ldp_client).to eq(mock_client)
18
+ end
19
+ end
20
+
21
+ describe ".links" do
22
+ it "should extract link headers with relations as a hash" do
23
+ mock_response.stub(:headers => {
24
+ "Link" => [
25
+ "xyz;rel=\"some-rel\"",
26
+ "abc;rel=\"some-multi-rel\"",
27
+ "123;rel=\"some-multi-rel\"",
28
+ "vanilla-link"
29
+ ]
30
+ })
31
+ h = Ldp::Response.links mock_response
32
+
33
+ expect(h['some-rel']).to include("xyz")
34
+ expect(h['some-multi-rel']).to include("abc", "123")
35
+ expect(h['doesnt-exist']).to be_empty
36
+ end
37
+
38
+ it "should return an empty hash if no link headers are availabe" do
39
+ mock_response.stub(:headers => {})
40
+ h = Ldp::Response.links mock_response
41
+
42
+ expect(h).to be_empty
43
+ end
44
+
45
+ end
46
+
47
+ describe ".resource?" do
48
+ it "should be a resource if a Link[rel=type] header asserts it is an ldp:resource" do
49
+ mock_response.stub(:headers => {
50
+ "Link" => [
51
+ "#{Ldp.resource};rel=\"type\""
52
+ ]
53
+ })
54
+ expect(Ldp::Response.resource? mock_response).to be_true
55
+ end
56
+ end
57
+
58
+ describe "#graph" do
59
+ it "should parse the response body for an RDF graph" do
60
+ mock_response.stub :body => "<> <info:b> <info:c> .", :headers => LDP_RESOURCE_HEADERS
61
+ subject.stub :page_subject => RDF::URI.new('info:a')
62
+ graph = subject.graph
63
+
64
+ expect(graph).to have_subject(RDF::URI.new("info:a"))
65
+ expect(graph).to have_statement RDF::Statement.new(RDF::URI.new("info:a"), RDF::URI.new("info:b"), RDF::URI.new("info:c"))
66
+
67
+ end
68
+ end
69
+
70
+ describe "#etag" do
71
+ it "should pass through the response's ETag" do
72
+ mock_response.stub :headers => { 'ETag' => 'xyz'}
73
+
74
+ expect(subject.etag).to eq('xyz')
75
+ end
76
+ end
77
+
78
+ describe "#last_modified" do
79
+ it "should pass through the response's Last-Modified" do
80
+ mock_response.stub :headers => { 'Last-Modified' => 'some-date'}
81
+ expect(subject.last_modified).to eq('some-date')
82
+ end
83
+ end
84
+
85
+ describe "#has_page" do
86
+ it "should see if the response has an ldp:Page statement" do
87
+ graph = RDF::Graph.new
88
+
89
+ subject.stub :page_subject => RDF::URI.new('info:a')
90
+
91
+ graph << [RDF::URI.new('info:a'), RDF.type, Ldp.page]
92
+
93
+ mock_response.stub :body => graph.dump(:ttl), :headers => LDP_RESOURCE_HEADERS
94
+
95
+ expect(subject).to have_page
96
+ end
97
+
98
+ it "should be false otherwise" do
99
+ subject.stub :page_subject => RDF::URI.new('info:a')
100
+ mock_response.stub :body => '', :headers => LDP_RESOURCE_HEADERS
101
+ expect(subject).not_to have_page
102
+ end
103
+ end
104
+
105
+ describe "#page" do
106
+ it "should get the ldp:Page data from the query" do
107
+ graph = RDF::Graph.new
108
+
109
+ subject.stub :page_subject => RDF::URI.new('info:a')
110
+
111
+ graph << [RDF::URI.new('info:a'), RDF.type, Ldp.page]
112
+ graph << [RDF::URI.new('info:b'), RDF.type, Ldp.page]
113
+
114
+ mock_response.stub :body => graph.dump(:ttl), :headers => LDP_RESOURCE_HEADERS
115
+
116
+ expect(subject.page.count).to eq(1)
117
+
118
+ end
119
+ end
120
+
121
+ describe "#subject" do
122
+ it "should extract the HTTP request URI as an RDF URI" do
123
+ mock_response.stub :body => '', :headers => LDP_RESOURCE_HEADERS
124
+ mock_response.stub :env => { :url => 'http://xyz/a'}
125
+ expect(subject.subject).to eq(RDF::URI.new("http://xyz/a"))
126
+ end
127
+ end
128
+ end
data/spec/spec_helper.rb CHANGED
@@ -5,7 +5,6 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
5
  require 'rspec/autorun'
6
6
  require 'ldp'
7
7
  require 'faraday'
8
- require "byebug"
9
8
 
10
9
  RSpec.configure do |config|
11
10
 
metadata CHANGED
@@ -1,83 +1,83 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ldp
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Chris Beer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-07-31 00:00:00.000000000 Z
11
+ date: 2014-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: faraday
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: linkeddata
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - '>='
31
+ - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: '0'
33
+ version: '1.1'
34
34
  type: :runtime
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - '>='
38
+ - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: '0'
40
+ version: '1.1'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: bundler
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - ~>
45
+ - - "~>"
46
46
  - !ruby/object:Gem::Version
47
47
  version: '1.3'
48
48
  type: :development
49
49
  prerelease: false
50
50
  version_requirements: !ruby/object:Gem::Requirement
51
51
  requirements:
52
- - - ~>
52
+ - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '1.3'
55
55
  - !ruby/object:Gem::Dependency
56
56
  name: rake
57
57
  requirement: !ruby/object:Gem::Requirement
58
58
  requirements:
59
- - - '>='
59
+ - - ">="
60
60
  - !ruby/object:Gem::Version
61
61
  version: '0'
62
62
  type: :development
63
63
  prerelease: false
64
64
  version_requirements: !ruby/object:Gem::Requirement
65
65
  requirements:
66
- - - '>='
66
+ - - ">="
67
67
  - !ruby/object:Gem::Version
68
68
  version: '0'
69
69
  - !ruby/object:Gem::Dependency
70
70
  name: rspec
71
71
  requirement: !ruby/object:Gem::Requirement
72
72
  requirements:
73
- - - '>='
73
+ - - ">="
74
74
  - !ruby/object:Gem::Version
75
75
  version: '0'
76
76
  type: :development
77
77
  prerelease: false
78
78
  version_requirements: !ruby/object:Gem::Requirement
79
79
  requirements:
80
- - - '>='
80
+ - - ">="
81
81
  - !ruby/object:Gem::Version
82
82
  version: '0'
83
83
  description: Linked Data Platform client library
@@ -87,7 +87,8 @@ executables: []
87
87
  extensions: []
88
88
  extra_rdoc_files: []
89
89
  files:
90
- - .gitignore
90
+ - ".gitignore"
91
+ - ".travis.yml"
91
92
  - Gemfile
92
93
  - LICENSE.txt
93
94
  - README.md
@@ -95,11 +96,18 @@ files:
95
96
  - ldp.gemspec
96
97
  - lib/ldp.rb
97
98
  - lib/ldp/client.rb
99
+ - lib/ldp/client/methods.rb
98
100
  - lib/ldp/container.rb
101
+ - lib/ldp/orm.rb
99
102
  - lib/ldp/resource.rb
100
103
  - lib/ldp/response.rb
104
+ - lib/ldp/uri.rb
101
105
  - lib/ldp/version.rb
106
+ - spec/lib/integration/integration_spec.rb
102
107
  - spec/lib/ldp/client_spec.rb
108
+ - spec/lib/ldp/orm/orm_spec.rb
109
+ - spec/lib/ldp/resource_spec.rb
110
+ - spec/lib/ldp/response_spec.rb
103
111
  - spec/spec_helper.rb
104
112
  homepage: ''
105
113
  licenses:
@@ -111,20 +119,25 @@ require_paths:
111
119
  - lib
112
120
  required_ruby_version: !ruby/object:Gem::Requirement
113
121
  requirements:
114
- - - '>='
122
+ - - ">="
115
123
  - !ruby/object:Gem::Version
116
124
  version: '0'
117
125
  required_rubygems_version: !ruby/object:Gem::Requirement
118
126
  requirements:
119
- - - '>='
127
+ - - ">="
120
128
  - !ruby/object:Gem::Version
121
129
  version: '0'
122
130
  requirements: []
123
131
  rubyforge_project:
124
- rubygems_version: 2.0.3
132
+ rubygems_version: 2.2.2
125
133
  signing_key:
126
134
  specification_version: 4
127
135
  summary: Linked Data Platform client library
128
136
  test_files:
137
+ - spec/lib/integration/integration_spec.rb
129
138
  - spec/lib/ldp/client_spec.rb
139
+ - spec/lib/ldp/orm/orm_spec.rb
140
+ - spec/lib/ldp/resource_spec.rb
141
+ - spec/lib/ldp/response_spec.rb
130
142
  - spec/spec_helper.rb
143
+ has_rdoc: