rdf-ldp 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 76067ed8fd6b28e3c35eb9bcb65d14585cd4e0fe
4
- data.tar.gz: 098810c5faf3aca4dd7bc0992797eb1d4d309c67
3
+ metadata.gz: 96681a7e685f8af473a2bfe9a2b25ffdb147a057
4
+ data.tar.gz: 80a4b2e3efa3ec7aa7c41a0c6f252d67431babc0
5
5
  SHA512:
6
- metadata.gz: 0fcb758fa163d0c6e229af2286f7332fd1561df33f56f23786e36de7a524dcfe6cb7457f0c26e06faf9cf6d7519f56df58a9b82958ff9e8e7e0398365cba6fe1
7
- data.tar.gz: 465af32bf8ca54109cf01b555d626cc6e229ef83ffabc30d69eebd5ad1142697f3624cfbc38e618e1acf03b3b684d0e070a4bb36a157aba97ff802c10940d1f3
6
+ metadata.gz: fd5442ef53e136c2dc83bc6fc5cb2d4c35b66d6e2be7669abd1c7d6eb5888d4fa5ecae8ccdfeb888d6e702675dbe1e2cab6f98ff01cd142c03f8baf826b86c30
7
+ data.tar.gz: 1acbe59831cd7219ffb933957c96d67cbc16b21c4cd949d81b60f60201cba4c88490a4c2ab1897bae69a249858e2db77f4febe6c99a293da621de2e9b08a62d6
data/AUTHORS ADDED
@@ -0,0 +1 @@
1
+ * Tom Johnson <tom@dp.la>
data/CREDITS ADDED
File without changes
data/README.md CHANGED
@@ -1,37 +1,59 @@
1
- # DEPRECATED - use rdf-vocab
1
+ RDF::LDP
2
+ ========
2
3
 
3
- This gem is deprecated; rdf-vocab gem (https://github.com/ruby-rdf/rdf-vocab, included in the linkeddata gem) now contains RDF::Vocab::LDP. You can find the helper method to strip LDP triples from an RDF::Graph object in the triannon gem in lib/oa_graph_helper.rb.
4
+ [![Build Status](https://travis-ci.org/ruby-rdf/rdf-ldp.svg?branch=develop)](https://travis-ci.org/ruby-rdf/rdf-ldp)
4
5
 
5
- # rdf-ldp
6
+ This software ships with the following libraries:
6
7
 
7
- [![Build Status](https://travis-ci.org/sul-dlss/rdf-ldp.svg)](https://travis-ci.org/sul-dlss/rdf-ldp) [![Dependency Status](https://gemnasium.com/sul-dlss/rdf-ldp.svg)](https://gemnasium.com/sul-dlss/rdf-ldp) [![Gem Version](https://badge.fury.io/rb/rdf-ldp.svg)](http://badge.fury.io/rb/rdf-ldp)
8
+ - `RDF::LDP` --- contains the domain model for LDP Resources.
9
+ - `Rack::LDP` --- a suite of Rack middleware for creating LDP servers based on
10
+ `RDF::LDP`.
11
+ - Lamprey --- a basic LDP server implemented with `Rack::LDP`.
8
12
 
9
- Contains vocabularies to be used by RDF ruby gem https://github.com/ruby-rdf/rdf/ to simplify coding when using LDP data.
13
+ Lamprey
14
+ =======
10
15
 
11
- Also contains helper method to strip LDP triples from an RDF::Graph object.
16
+ Lamprey is a basic LDP server. To start it, use:
12
17
 
13
- ## Installation
14
-
15
- Add this line to your application's Gemfile:
16
-
17
- ```ruby
18
- gem 'rdf-vocab' # (was rdf-ldp)
18
+ ```
19
+ bundle exec ruby app/lamprey.rb
19
20
  ```
20
21
 
21
- And then execute:
22
+ An `ldp:BasicContainer` will be created at the address of your first
23
+ `GET` request. Note that if that request is made to the server root,
24
+ Sinatra will assume a trailing slash.
25
+
26
+ ```bash
27
+ $ curl -i http://localhost:4567
28
+
29
+ HTTP/1.1 200 OK
30
+ Content-Type: text/turtle
31
+ Link: <http://www.w3.org/ns/ldp#Resource>;rel="type",<http://www.w3.org/ns/ldp#RDFSource>;rel="type",<http://www.w3.org/ns/ldp#BasicContainer>;rel="type"
32
+ Allow: GET, POST, PUT, DELETE, OPTIONS, HEAD
33
+ Accept-Post: application/n-triples, text/plain, application/n-quads, text/x-nquads, application/ld+json, application/x-ld+json, application/rdf+json, text/html, text/n3, text/rdf+n3, application/rdf+n3, application/rdf+xml, text/csv, text/tab-separated-values, application/csvm+json, text/turtle, text/rdf+turtle, application/turtle, application/x-turtle, application/trig, application/x-trig, application/trix
34
+ Etag: "1B2M2Y8AsgTpgAmY7PhCfg==0"
35
+ Vary: Accept
36
+ X-Content-Type-Options: nosniff
37
+ Server: WEBrick/1.3.1 (Ruby/2.1.0/2013-12-25)
38
+ Date: Mon, 27 Jul 2015 23:19:06 GMT
39
+ Content-Length: 0
40
+ Connection: Keep-Alive
41
+ ```
22
42
 
23
- $ bundle
43
+ Compliance
44
+ ----------
24
45
 
25
- Or install it yourself as:
46
+ Current compliance reports for Lamprey are located in [/reports](reports/).
47
+ Reports are generated by the LDP test suite. To duplicate the results,
48
+ use the `testsuite` branch, which contains a work-around for
49
+ [w3c/ldp-testsuite#224](https://github.com/w3c/ldp-testsuite/issues/224).
26
50
 
27
- $ gem install rdf-vocab # (was rdf-ldp)
51
+ License
52
+ ========
28
53
 
29
- ## Usage
54
+ This software is released under a public domain waiver (Unlicense).
30
55
 
31
- require 'rdf/vocab'
56
+
32
57
 
33
- RDF::Vocab::LDP.member #=> RDF::URI("http://www.w3.org/ns/ldp#member")
34
58
 
35
- # DEPRECATED - use rdf-vocab
36
59
 
37
- This gem is deprecated; rdf-vocab gem (https://github.com/ruby-rdf/rdf-vocab, included in the linkeddata gem) now contains RDF::Vocab::LDP. You can find the helper method to strip LDP triples from an RDF::Graph object in the triannon gem in lib/oa_graph_helper.rb.
data/UNLICENSE ADDED
@@ -0,0 +1,24 @@
1
+ This is free and unencumbered software released into the public domain.
2
+
3
+ Anyone is free to copy, modify, publish, use, compile, sell, or
4
+ distribute this software, either in source code form or as a compiled
5
+ binary, for any purpose, commercial or non-commercial, and by any
6
+ means.
7
+
8
+ In jurisdictions that recognize copyright laws, the author or authors
9
+ of this software dedicate any and all copyright interest in the
10
+ software to the public domain. We make this dedication for the benefit
11
+ of the public at large and to the detriment of our heirs and
12
+ successors. We intend this dedication to be an overt act of
13
+ relinquishment in perpetuity of all present and future rights to this
14
+ software under copyright law.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
+ IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
20
+ OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
21
+ ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
23
+
24
+ For more information, please refer to <http://unlicense.org/>
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.2.0
data/lib/rack/ldp.rb ADDED
@@ -0,0 +1,121 @@
1
+ require 'rack'
2
+ begin
3
+ require 'linkeddata'
4
+ rescue LoadError => e
5
+ require 'rdf/turtle'
6
+ require 'json/ld'
7
+ end
8
+
9
+ require 'rack/linkeddata'
10
+ require 'rdf/ldp'
11
+
12
+ module Rack
13
+ ##
14
+ # Provides Rack middleware for handling Linked Data Platform requirements
15
+ # when passed {RDF::LDP::Resource} and its subclasses as response objects.
16
+ #
17
+ # Response objects that are not an {RDF::LDP::Resource} are passed over
18
+ # without alteration, allowing server implementers to mix LDP interaction
19
+ # patterns with others on the same server.
20
+ #
21
+ # The suite can be mix-and-matched as needed. This allows easy swap in of
22
+ # custom handlers for parts of the behavior. It is recommended that you use
23
+ # {Rack::LDP::ContentNegotiation}, {Rack::LDP::Errors}, and
24
+ # {Rack::LDP::Responses} as the outer three services. With these in place,
25
+ # you can handle requests as needed in your application, giving responses
26
+ # conforming to the core {RDF::LDP::Resource} interface.
27
+ #
28
+ # @example
29
+ # run Rack:;Builder.new do
30
+ # use Rack::LDP::ContentNegotiation
31
+ # use Rack::LDP::Errors
32
+ # use Rack::LDP::Responses
33
+ # # ...
34
+ # end
35
+ #
36
+ # @see http://www.w3.org/TR/ldp/ the LDP specification
37
+ module LDP
38
+ ##
39
+ # Catches and handles RequestErrors thrown by RDF::LDP
40
+ class Errors
41
+ ##
42
+ # @param [#call] app
43
+ def initialize(app)
44
+ @app = app
45
+ end
46
+
47
+ ##
48
+ # Catches {RDF::LDP::RequestError} and its various subclasses, building an
49
+ # appropriate response
50
+ #
51
+ # @param [Array] env a rack env array
52
+ # @return [Array] a rack env array with added headers
53
+ def call(env)
54
+ begin
55
+ @app.call(env)
56
+ rescue RDF::LDP::RequestError => err
57
+ return [err.status, err.headers, [err.message]]
58
+ end
59
+ end
60
+ end
61
+
62
+ ##
63
+ # Converts RDF::LDP::Resource} into appropriate responses
64
+ class Responses
65
+ ##
66
+ # @param [#call] app
67
+ def initialize(app)
68
+ @app = app
69
+ end
70
+
71
+ ##
72
+ # Converts the response body from {RDF::LDP::Resource} form to a Graph
73
+ def call(env)
74
+ status, headers, response = @app.call(env)
75
+
76
+ if response.is_a? RDF::LDP::Resource
77
+ new_response = response.to_response
78
+ response.close if response.respond_to? :close
79
+ response = new_response
80
+ end
81
+
82
+ [status, headers, response]
83
+ end
84
+ end
85
+
86
+ ##
87
+ #
88
+ class Requests
89
+ ##
90
+ # @param [#call] app
91
+ def initialize(app)
92
+ @app = app
93
+ end
94
+
95
+ ##
96
+ # Handles a Rack protocol request. Sends appropriate request to the
97
+ # object, alters response accordingly.
98
+ #
99
+ # @param [Array] env a rack env array
100
+ # @return [Array] a rack env array with added headers
101
+ def call(env)
102
+ status, headers, response = @app.call(env)
103
+ return [status, headers, response] unless
104
+ response.is_a? RDF::LDP::Resource
105
+
106
+ response
107
+ .send(:request, env['REQUEST_METHOD'].to_sym, status, headers, env)
108
+ end
109
+ end
110
+
111
+ ##
112
+ # Specializes {Rack::LinkedData::ContentNegotiation}, making the default
113
+ # return type 'text/turtle'
114
+ class ContentNegotiation < Rack::LinkedData::ContentNegotiation
115
+ def initialize(app, options = {})
116
+ options[:default] ||= 'text/turtle'
117
+ super
118
+ end
119
+ end
120
+ end
121
+ end
@@ -0,0 +1,143 @@
1
+ module RDF::LDP
2
+ class Container < RDFSource
3
+ ##
4
+ # @return [RDF::URI] uri with lexical representation
5
+ # 'http://www.w3.org/ns/ldp#Container'
6
+ def self.to_uri
7
+ RDF::Vocab::LDP.Container
8
+ end
9
+
10
+ ##
11
+ # @return [Boolean] whether this is an ldp:Container
12
+ def container?
13
+ true
14
+ end
15
+
16
+ ##
17
+ # @return [RDF::URI] a URI representing the container type
18
+ def container_class
19
+ CONTAINER_CLASSES[:basic]
20
+ end
21
+
22
+ ##
23
+ # @see RDFSource#create
24
+ def create(input, content_type)
25
+ super { |statements| validate_triples!(statements) }
26
+ end
27
+
28
+ ##
29
+ # @see RDFSource#update
30
+ def update(input, content_type)
31
+ super { |statements| validate_triples!(statements) }
32
+ end
33
+
34
+ ##
35
+ # Adds a member `resource` to the container. Handles containment and
36
+ # membership triples as appropriate for the container type.
37
+ #
38
+ # @param [RDF::Term] a new member for this container
39
+ # @return [Container] self
40
+ def add(resource)
41
+ add_containment_triple(resource.to_uri)
42
+ end
43
+
44
+ ##
45
+ # Removes a member `resource` from the container. Handles containment and
46
+ # membership triples as appropriate for the container type.
47
+ #
48
+ # @param [RDF::Term] a new member for this container
49
+ # @return [Container] self
50
+ def remove(resource)
51
+ remove_containment_triple(resource.to_uri)
52
+ end
53
+
54
+ ##
55
+ # @return [RDF::Query::Enumerator] the containment triples
56
+ def containment_triples
57
+ graph.query([subject_uri,
58
+ RDF::Vocab::LDP.contains,
59
+ nil]).statements
60
+ end
61
+
62
+ ##
63
+ # @param [RDF::Statement] statement
64
+ #
65
+ # @return [Boolean] true if the containment triple exists
66
+ #
67
+ # @todo for some reason `#include?` doesn't work! figure out why, this is
68
+ # clumsy.
69
+ def has_containment_triple?(statement)
70
+ !(containment_triples.select { |t| statement == t }.empty?)
71
+ end
72
+
73
+ ##
74
+ # Adds a containment triple for `resource` to the container's `#graph`.
75
+ #
76
+ # @param [RDF::Term] a new member for this container
77
+ # @return [Container] self
78
+ def add_containment_triple(resource)
79
+ graph << make_containment_triple(resource)
80
+ self
81
+ end
82
+
83
+ ##
84
+ # Remove a containment triple for `resource` to the container's `#graph`.
85
+ #
86
+ # @param [RDF::Term] a member to remove from this container
87
+ # @return [Container] self
88
+ def remove_containment_triple(resource)
89
+ graph.delete(make_containment_triple(resource))
90
+ self
91
+ end
92
+
93
+ ##
94
+ # @param [RDF::Term] a member for this container
95
+ #
96
+ # @return [RDF::URI] the containment triple
97
+ def make_containment_triple(resource)
98
+ RDF::Statement(subject_uri, RDF::Vocab::LDP.contains, resource)
99
+ end
100
+
101
+ private
102
+
103
+ ##
104
+ # Handles a POST request. Parses a graph in the body of `env` and treats all
105
+ # statements in that graph (irrespective of any graph names) as constituting
106
+ # the initial state of the created source.
107
+ #
108
+ # @raise [RDF::LDP::RequestError] when creation fails
109
+ #
110
+ # @return [Array<Fixnum, Hash<String, String>, #each] a new Rack response
111
+ # array.
112
+ def post(status, headers, env)
113
+ klass = self.class.interaction_model(env.fetch('HTTP_LINK', ''))
114
+ slug = env['HTTP_SLUG']
115
+ slug = klass.gen_id if slug.nil? || slug.empty?
116
+ raise NotAcceptable.new('Refusing to create resource with `#` in Slug') if
117
+ slug.include? '#'
118
+
119
+ id = (subject_uri / slug).canonicalize
120
+
121
+ created = klass.new(id, @data)
122
+ .create(env['rack.input'], env['CONTENT_TYPE'])
123
+
124
+ add(created)
125
+ headers['Location'] = created.subject_uri.to_s
126
+ [201, created.send(:update_headers, headers), created]
127
+ end
128
+
129
+ def validate_triples!(statements)
130
+ existing_triples = containment_triples.to_a
131
+ statements.query(subject: subject_uri,
132
+ predicate: RDF::Vocab::LDP.contains) do |statement|
133
+ existing_triples.delete(statement) do
134
+ raise Conflict.new('Attempted to write unacceptable LDP ' \
135
+ "containment-triple: #{statement}")
136
+ end
137
+ end
138
+ raise Conflict.new('Cannot remove containment triples in updates. ' \
139
+ "Attepted to remove #{existing_triples}") unless
140
+ existing_triples.empty?
141
+ end
142
+ end
143
+ end
@@ -0,0 +1,112 @@
1
+ module RDF::LDP
2
+ class DirectContainer < Container
3
+ def self.to_uri
4
+ RDF::Vocab::LDP.DirectContainer
5
+ end
6
+
7
+ RELATION_TERMS = [RDF::Vocab::LDP.hasMemberRelation,
8
+ RDF::Vocab::LDP.isMemberOfRelation]
9
+
10
+ ##
11
+ # @return [RDF::URI] a URI representing the container type
12
+ def container_class
13
+ CONTAINER_CLASSES[:direct]
14
+ end
15
+
16
+ def add(resource)
17
+ process_membership_resource(resource.to_uri) do |membership, triple|
18
+ super
19
+ membership.graph << triple
20
+ end
21
+ end
22
+
23
+ def remove(resource)
24
+ process_membership_resource(resource.to_uri) do |membership, triple|
25
+ super
26
+ membership.graph.delete(triple)
27
+ end
28
+ end
29
+
30
+ ##
31
+ # Aliases #subject_uri
32
+ # @return [RDF::URI] #subject_uri
33
+ def membership_constant_uri
34
+ case membership_resource_statements.count
35
+ when 0
36
+ graph << RDF::Statement(subject_uri,
37
+ RDF::Vocab::LDP.membershipResource,
38
+ subject_uri)
39
+ subject_uri
40
+ when 1
41
+ membership_resource_statements.first.object
42
+ else
43
+ raise NotAcceptable.new('An LDP-DC MUST have exactly ' \
44
+ 'one membership resource; found ' \
45
+ "#{membership_resource_statements.count}.")
46
+ end
47
+ end
48
+
49
+ ##
50
+ # @return [RDF::URI] the membership predicate
51
+ # @see http://www.w3.org/TR/ldp/#dfn-membership-predicate
52
+ def membership_predicate
53
+ case member_relation_statements.count
54
+ when 0
55
+ graph << RDF::Statement(subject_uri,
56
+ RELATION_TERMS.first,
57
+ RDF::Vocab::LDP.member)
58
+ RDF::Vocab::LDP.member
59
+ when 1
60
+ member_relation_statements.first.object
61
+ else
62
+ raise NotAcceptable.new('An LDP-DC MUST have exactly ' \
63
+ 'one member relation triple; found ' \
64
+ "#{member_relation_statements.count}.")
65
+ end
66
+ end
67
+
68
+ ##
69
+ # @param [RDF::Term] a member for this container
70
+ #
71
+ # @return [RDF::URI] the membership triple to be added to the
72
+ def make_membership_triple(resource)
73
+ predicate = membership_predicate
74
+ return RDF::Statement(membership_constant_uri, predicate, resource) if
75
+ member_relation_statements.first.predicate == RELATION_TERMS.first
76
+ RDF::Statement(resource, predicate, membership_constant_uri)
77
+ end
78
+
79
+ private
80
+
81
+ def membership_resource_statements
82
+ graph.query([subject_uri, RDF::Vocab::LDP.membershipResource, :o])
83
+ end
84
+
85
+ def member_relation_statements
86
+ graph.statements.select do |st|
87
+ st.subject == subject_uri && RELATION_TERMS.include?(st.predicate)
88
+ end
89
+ end
90
+
91
+ def membership_resource
92
+ uri = membership_constant_uri
93
+ uri = uri.fragment ? (uri.root / uri.request_uri) : uri
94
+ RDF::LDP::Resource.find(uri, @data)
95
+ end
96
+
97
+ def process_membership_resource(resource, &block)
98
+ triple = make_membership_triple(resource)
99
+
100
+ begin
101
+ membership_rs = membership_resource
102
+ rescue NotFound => e
103
+ raise NotAcceptable.new('Membership resource ' \
104
+ "#{membership_constant_uri} does not exist")
105
+ end
106
+
107
+ yield(membership_resource, triple, resource) if block_given?
108
+
109
+ self
110
+ end
111
+ end
112
+ end
@@ -0,0 +1,13 @@
1
+ module RDF::LDP
2
+ class IndirectContainer < DirectContainer
3
+ def self.to_uri
4
+ RDF::Vocab::LDP.IndirectContainer
5
+ end
6
+
7
+ ##
8
+ # @return [RDF::URI] a URI representing the container type
9
+ def container_class
10
+ CONTAINER_CLASSES[:indirect]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ module RDF::LDP
2
+ class NonRDFSource < Resource
3
+ ##
4
+ # @return [RDF::URI] uri with lexical representation
5
+ # 'http://www.w3.org/ns/ldp#NonRDFSource'
6
+ #
7
+ # @see http://www.w3.org/TR/ldp/#dfn-linked-data-platform-non-rdf-source
8
+ def self.to_uri
9
+ RDF::Vocab::LDP.NonRDFSource
10
+ end
11
+
12
+ ##
13
+ # @return [Boolean] whether this is an ldp:NonRDFSource
14
+ def non_rdf_source?
15
+ true
16
+ end
17
+ end
18
+ end