wf4ever-rosrs-client 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/.rvmrc ADDED
@@ -0,0 +1 @@
1
+ rvm --create use 1.9.3@rosrs_client
data/Gemfile ADDED
@@ -0,0 +1,13 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "json"
4
+ gem "rdf"
5
+ gem "rdf-raptor"
6
+
7
+ # Add dependencies to develop your gem here.
8
+ # Include everything needed to run rake, tests, features, etc.
9
+ group :development do
10
+ gem "rdoc", "~> 3.12"
11
+ gem "bundler", "~> 1.2.1"
12
+ gem "jeweler", "~> 1.8.4"
13
+ end
data/LICENSE.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Finn Bacall
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,180 @@
1
+ ROSRSClient
2
+ =================
3
+
4
+ Partial port of Python ROSRS_Session code to Ruby.
5
+
6
+ [This project [8]][ref8] is intended to provide a Ruby-callable API for [myExperiment [9]][ref9] to access [Research Objects [1]][ref1], [[2]][ref2] stored in RODL, using the [ROSRS API [3]][ref3]. The functions provided closely follow the ROSRS API specification. The code is based on an implementation in Python used by the RO_Manager utility; a full implementat ROSRS test suite can be found in the [GitHub `wf4ever/ro-manager` project [7]][ref7].
7
+
8
+ [ref1]: http://www.wf4ever-project.org/wiki/pages/viewpage.action?pageId=2065079 "What is an RO?"
9
+
10
+ [ref2]: http://wf4ever.github.com/ro/ "Wf4Ever Research Object Model"
11
+
12
+ [ref3]: http://www.wf4ever-project.org/wiki/display/docs/RO+SRS+interface+6 "ROSRS interface (v6)"
13
+
14
+ [ref7]: https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/ROSRS_Session.py "Python ROSRS_Session in RO Manager. See also test suite: https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/test/TestROSRS_Session.py"
15
+
16
+ [ref8]: https://github.com/gklyne/ruby-http-session "ruby-http-session project, or successor"
17
+
18
+ [ref9]: http://www.myexperiment.org/ "De Roure, D., Goble, C. and Stevens, R. (2009) The Design and Realisation of the myExperiment Virtual Research Environment for Social Sharing of Workflows. Future Generation Computer Systems 25, pp. 561-567. doi:10.1016/j.future.2008.06.010"
19
+
20
+
21
+ ## Contents
22
+
23
+ * Contents
24
+ * Package structure
25
+ * API calling conventions
26
+ * A simple example
27
+ * Development setup
28
+ * URIs
29
+ * Further work
30
+ * References
31
+
32
+
33
+ ## Package structure
34
+
35
+ Key functions are currently contained in four files:
36
+
37
+ * `lib/wf4ever/rosrs_session.rb`
38
+ * `lib/wf4ever/rdf_graph.rb`
39
+ * `lib/wf4ever/namespaces.rb`
40
+ * `lib/wf4ever/folders.rb`
41
+ * `test/test_rosrs_session`
42
+
43
+ The main functions provided by this package are in `rosrs_session`. This module provides a class whose instances manage a session with a specified ROSRS service endpoint. A service URI is provided when an instance is created, and is used as a base URI for accessing ROs and other resources using relative URI references. Any attempt to access a resource on a different host or post is rejected.
44
+
45
+ `rdf_graph` implements a simplified interface to the [Ruby RDF library [4]][ref4], handling parsing of RDF from strings, serialization to strings and simplified search and access to individual triples. Most of the functions provided are quite trivial; the module is intended to provide (a) a distillation of knowledge about how to perform desired functions using the RDF and associated libraries, and (b) a shim layer for adapting between different conventions used by the RDF libraries and the `rosrs_session` library. The [Raptor library [5]][ref5] and its [Ruby RDF interface[6]][ref6] are used for RDF/XML parsing and serialization.
46
+
47
+ [ref4]: http://rdf.rubyforge.org/ "RDF.rb: Linked Data for Ruby"
48
+
49
+ [ref5]: http://librdf.org/raptor/ "Raptor RDF Syntax Library"
50
+
51
+ [ref6]: http://rdf.rubyforge.org/raptor/ "Raptor RDF Parser Plugin for RDF.rb"
52
+
53
+ `namespaces` provides definitions of URIs for namespaces and namespace terms used in RDF graphs. These are in similar form to the namespaces provided by the RDF library.
54
+
55
+ `folders` contains objects to represent and traverse RO's folder structure.
56
+
57
+ `test_rosrs_session` is a test suite for all the above. It serves to provide regression testing for implemented functions, and also to provide examples of how the various ROSRS API functions provided can be accessed.
58
+
59
+
60
+ ## API calling conventions
61
+
62
+ Many API functions have a small number of mandatory parameters which are provided as normal positional parameters, and a (possibly larger) number of optional keyword parameters that are provided as a Ruby hash. The Ruby calling convention of collecting multiple `key => value` parameter expressions into a single has is used.
63
+
64
+ Return values are generally in the form of an array, which can be used with parallel assignment for easy access to the return values.
65
+
66
+ Example:
67
+
68
+ code, reason, headers, body = rosrs.do_request("POST", rouri,
69
+ :body => data
70
+ :ctype => "text/plain"
71
+ :accept => "application/rdf+xml"
72
+ :headers => reqheaders)
73
+
74
+
75
+ ## A simple example
76
+
77
+ Here is a flavour of how the `rosrs_session` module may be used:
78
+
79
+ # Create an ROSRS session
80
+ rosrs = ROSRSSession.new(
81
+ "http://sandbox.wf4ever-project.org/rodl/ROs/",
82
+ "47d5423c-b507-4e1c-8")
83
+
84
+ # Create a new RO
85
+ code, reason, rouri, manifest = @rosrs.create_research_object("Test-RO-name")
86
+ if code != 201
87
+ raise "Failed to create new RO: "+reason
88
+ end
89
+
90
+ # Aggregate a resource into the new RO
91
+ res_body = %q(
92
+ New resource body
93
+ )
94
+ options = { :body => res_body, :ctype => "text/plain" }
95
+
96
+ # Create and aggregate "internal" resource in new RO
97
+ code, reason, proxyuri, resourceuri = rosrs.aggregate_internal_resource(
98
+ rouri, "data/test_resource",
99
+ :body => res_body,
100
+ :ctype => "text/plain")
101
+ if code != 201
102
+ raise "Failed to create new resource: "+reason
103
+
104
+ # Create a new folder
105
+ folder_contents = [{:name => 'test_data.txt', :uri => 'http://www.example.com/ro/file1.txt'},
106
+ {:uri => 'http://www.myexperiment.org/workflows/7'}]
107
+ folder_uri = rosrs.create_folder(rouri, "Input Data", folder_contents).uri
108
+
109
+ # Examine a folder
110
+ folder = rosrs.get_folder(folder_uri)
111
+ puts folder.name
112
+ puts folder.contents.inspect
113
+
114
+
115
+
116
+
117
+ # When finished, close session
118
+ rosrs.close
119
+
120
+
121
+ ## Development setup
122
+
123
+ Development has been performed using Ruby 1.8.7 on Ubuntu Linux 10.04 and 12.04. The code uses `rubygems`, `json`, `rdf` and `rdf-raptor` libraries beyond the standard Ruby libraries.
124
+
125
+ The `rdf-raptor` Ruby library uses the Ubuntu `raptor-util` and `libraptor-dev` packages. NOTE: the Ruby RDF documentation does not mention `libraptor-dev`, but I found that without this the RDF libraries would not work for parsing and serializing RDF/XML.
126
+
127
+ Once the environment is set up, I find the following statements are sufficient include the required libraries:
128
+
129
+ require "wf4ever/rosrs_client"
130
+
131
+ ## URIs
132
+
133
+ Be aware that the standard Ruby library provides a URI class, and that the RDF library provides a different, incompatible URI class:
134
+
135
+ # Standard Ruby library URI:
136
+ uri1 = URI("http://example.com/")
137
+
138
+ # URI class used by RDF library:
139
+ uri2 = RDF::URI("http://example.com")
140
+
141
+ These URIs are not equivalent, and are not even directly comparable.
142
+
143
+ Currently, the HTTP handling code uses the standard Ruby library URIs, and the RDF handling code uses URIs provided by the RDF library. The `namespaces` module returns `RDF::URI` values.
144
+
145
+ I'm not currently sure if this will prove to cause problems. Take care when dereferencing URIs obtained from RDF.
146
+
147
+ ## Further work
148
+
149
+ At the time of writing this, the code is very much a work in progress. Some of the things possibly yet to-do include:
150
+
151
+ * Fork project into the wf4ever organization. Rename to rosrs_session.
152
+ * Complete the APi functions
153
+ * Work out strategy for dealing with different URI classes.
154
+ * When creating an RO, use the supplied RO information to create some initial annotations (similar to RO Manager)?
155
+ * Refactor `rosrs_session.rb` to separate out `http_session`
156
+ * May want to investigate "streaming" RDF data between HTTP and RDF libraries, or using RDF reader/writer classes, rather than transferring via strings. Currently, I assume the RDF is small enough that this doesn't matter.
157
+ * Refactor test suite per tested module (may require simple HTTP server setup if HTTP factored out as above)
158
+
159
+
160
+ ## References
161
+
162
+ [[1] _What is an RO?_][ref1]; Wf4Ever Research Object description and notes.
163
+
164
+ [[2] _Wf4Ever Research Object Model_][ref2]; Specification of RO model.
165
+
166
+ [[3] _Wf4ever ROSRS interface (v6)_][ref3]; Description of the HTTP/REST interface for accessing and updating Research Objects, implemented by Wf4Ever RODL.
167
+
168
+ [[4] `RDF.rb`][ref4]; Linked Data for Ruby
169
+
170
+ [[5] _Raptor_][ref5]; Raptor RDF Syntax Library
171
+
172
+ [[6] `rdf_raptor`][ref6]; Raptor RDF Parser Plugin for RDF.rb
173
+
174
+ [[7] _Python ROSRS\_Session in RO Manager_][ref7]; See also the test suite: [TestROSRS_Session.py ](https://github.com/wf4ever/ro-manager/blob/master/src/rocommand/test/TestROSRS_Session.py).
175
+
176
+ [[8] `ruby-http-session` project, or successor][ref8]
177
+
178
+ [[9] _myExperiment_][ref9]; "De Roure, D., Goble, C. and Stevens, R. (2009) The Design and Realisation of the myExperiment Virtual Research Environment for Social Sharing of Workflows. Future Generation Computer Systems 25, pp. 561-567. doi:10.1016/j.future.2008.06.010"
179
+
180
+
data/Rakefile ADDED
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ # gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
17
+ gem.name = "wf4ever-rosrs-client"
18
+ gem.homepage = "http://github.com/fbacall/rosrs_client"
19
+ gem.summary = %Q{A client to interact with the ROSRS API.}
20
+ gem.description = %Q{A port of the ROSRS API Python client into Ruby.}
21
+ gem.email = "finn.bacall@cs.man.ac.uk"
22
+ gem.authors = ["Graham Klyne","Finn Bacall"]
23
+ # dependencies defined in Gemfile
24
+ end
25
+ Jeweler::RubygemsDotOrgTasks.new
26
+
27
+ require 'rake/testtask'
28
+ Rake::TestTask.new(:test) do |test|
29
+ test.libs << 'lib' << 'test'
30
+ test.pattern = 'test/**/test_*.rb'
31
+ test.verbose = true
32
+ end
33
+
34
+ task :default => :test
35
+
36
+ require 'rdoc/task'
37
+ Rake::RDocTask.new do |rdoc|
38
+ version = File.exist?('VERSION') ? File.read('VERSION') : ""
39
+
40
+ rdoc.rdoc_dir = 'rdoc'
41
+ rdoc.title = "rosrs_client #{version}"
42
+ rdoc.rdoc_files.include('README*')
43
+ rdoc.rdoc_files.include('lib/**/*.rb')
44
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.1.1
@@ -0,0 +1,76 @@
1
+ module ROSRS
2
+ class Annotation
3
+
4
+ attr_reader :uri, :body_uri, :resource_uri, :created_at, :created_by, :research_object
5
+
6
+ def initialize(research_object, uri, body_uri, resource_uri, options = {})
7
+ @research_object = research_object
8
+ @session = @research_object.session
9
+ @uri = uri
10
+ @body_uri = body_uri
11
+ @resource_uri = resource_uri
12
+ @created_at = options[:created_at]
13
+ @created_by = options[:created_by]
14
+ @loaded = false
15
+ if options[:body]
16
+ @body = options[:body]
17
+ @loaded = true
18
+ end
19
+ load if options[:load]
20
+ end
21
+
22
+ ##
23
+ # The resource which this annotation relates to
24
+ def resource
25
+ @resource ||= @research_object.resources(@resource_uri) ||
26
+ @research_object.folders(@resource_uri) ||
27
+ ROSRS::Resource.new(@research_object, @resource_uri)
28
+ end
29
+
30
+ def loaded?
31
+ @loaded
32
+ end
33
+
34
+ def load
35
+ c,r,u,@body = @session.get_annotation(body_uri)
36
+ @loaded = true
37
+ end
38
+
39
+ def body
40
+ load unless loaded?
41
+ @body
42
+ end
43
+
44
+ def delete
45
+ code = @session.remove_annotation(uri)
46
+ @loaded = false
47
+ @research_object.remove_annotation(self)
48
+ code == 204
49
+ end
50
+
51
+ def self.create(ro, resource_uri, annotation)
52
+ if ROSRS::Helper.is_uri?(annotation)
53
+ code, reason, annotation_uri = ro.session.create_annotation_stub(ro.uri, resource_uri, annotation)
54
+ self.new(ro, annotation_uri, annotation, resource_uri)
55
+ else
56
+ code, reason, annotation_uri, body_uri = ro.session.create_internal_annotation(ro.uri, resource_uri, annotation)
57
+ self.new(ro, annotation_uri, body_uri, resource_uri, :body => annotation)
58
+ end
59
+ end
60
+
61
+ def update(resource_uri, annotation)
62
+ if ROSRS::Helper.is_uri?(annotation)
63
+ code, reason = @session.update_annotation_stub(@research_object.uri, @uri, resource_uri, body_uri)
64
+ @loaded = false
65
+ else
66
+ code, reason, body_uri = @session.update_internal_annotation(@research_object.uri, @uri, resource_uri, annotation)
67
+ @loaded = true
68
+ @body = annotation
69
+ end
70
+ @resource_uri = resource_uri
71
+ @body_uri = body_uri
72
+ self
73
+ end
74
+
75
+ end
76
+ end
@@ -0,0 +1,19 @@
1
+ # Exception class used to signal HTTP Session errors
2
+ module ROSRS
3
+
4
+ class Exception < Exception
5
+ end
6
+
7
+ class NotFoundException < Exception
8
+ end
9
+
10
+ class ForbiddenException < Exception
11
+ end
12
+
13
+ class UnauthorizedException < Exception
14
+ end
15
+
16
+ class ConflictException < Exception
17
+ end
18
+
19
+ end
@@ -0,0 +1,127 @@
1
+ module ROSRS
2
+
3
+ # A representation of a folder in a Research Object.
4
+ class Folder < Resource
5
+
6
+ attr_reader :name
7
+
8
+ ##
9
+ # +research_object+:: The Wf4Ever::ResearchObject that aggregates this folder.
10
+ # +uri+:: The URI for the resource referred to by the Folder.
11
+ # +options+:: A hash of options:
12
+ # [:contents_graph] An RDFGraph of the folder contents, if on hand (to save having to make a request).
13
+ # [:root_folder] A boolean flag to say if this folder is the root folder of the RO.
14
+ def initialize(research_object, uri, proxy_uri = nil, options = {})
15
+ super(research_object, uri, proxy_uri)
16
+ @name = uri.to_s.split('/').last
17
+ @session = research_object.session
18
+ @loaded = false
19
+ if options[:contents_graph]
20
+ @contents = parse_folder_description(options[:contents_graph])
21
+ @loaded = true
22
+ end
23
+ @root_folder = options[:root_folder]
24
+ end
25
+
26
+ ##
27
+ # Fetch the entry with name +child_name+ from the Folder's contents
28
+ def child(child_name)
29
+ contents.select {|child| child.name == child_name}.first
30
+ end
31
+
32
+ ##
33
+ # Returns boolean stating whether or not a description of this Folder's contents has been fetched and loaded.
34
+ def loaded?
35
+ @loaded
36
+ end
37
+
38
+ ##
39
+ # Returns whether or not this folder is the root folder of the RO
40
+ def root?
41
+ @root_folder
42
+ end
43
+
44
+ ##
45
+ # Returns an array of FolderEntry objects
46
+ def contents
47
+ load unless loaded?
48
+ @contents
49
+ end
50
+
51
+ ##
52
+ # Fetch and parse the Folder's description to get the Folder's contents.
53
+ def load
54
+ @contents = fetch_folder_contents
55
+ @loaded = true
56
+ end
57
+
58
+ ##
59
+ # Delete this folder from the RO. Contents will be preserved.
60
+ # Also deletes any entries in other folders pointing to this one.
61
+ def delete
62
+ code = @session.delete_folder(@uri)[0]
63
+ @loaded = false
64
+ @research_object.remove_folder(self)
65
+ code == 204
66
+ end
67
+
68
+ ##
69
+ # Add an entry to the folder. +resource+ can be a ROSRS::Resource object or a URI
70
+ def add(resource, entry_name = nil)
71
+ if resource.instance_of?(ROSRS::Resource)
72
+ contents << ROSRS::FolderEntry.create(self, entry_name, resource.uri)
73
+ else
74
+ contents << ROSRS::FolderEntry.create(self, entry_name, resource)
75
+ end
76
+
77
+ end
78
+
79
+ ##
80
+ # Remove an entry from the folder.
81
+ def remove(entry)
82
+ entry.delete
83
+ contents.delete(entry)
84
+ end
85
+
86
+ ##
87
+ # Create a folder in the RO and add it to this folder as a subfolder
88
+ def create_folder(name)
89
+ # Makes folder name parent/child instead of just child
90
+ folder_name = (URI(uri) + URI(name) - URI(@research_object.uri)).to_s
91
+ folder = @research_object.create_folder(folder_name)
92
+ add(folder.uri, name)
93
+ folder
94
+ end
95
+
96
+ def self.create(ro, name, contents = [])
97
+ code, reason, uri, proxy_uri, folder_description = ro.session.create_folder(ro.uri, name, contents)
98
+ self.new(ro, uri, proxy_uri, :contents_graph => folder_description)
99
+ end
100
+
101
+ private
102
+
103
+ # Get folder contents from remote resource map file
104
+ def fetch_folder_contents
105
+ code, reason, headers, uripath, graph = @session.get_folder(uri)
106
+ parse_folder_description(graph)
107
+ end
108
+
109
+ def parse_folder_description(graph)
110
+ contents = []
111
+
112
+ query = RDF::Query.new do
113
+ pattern [:folder_entry, RDF.type, RDF::RO.FolderEntry]
114
+ pattern [:folder_entry, RDF::RO.entryName, :name]
115
+ pattern [:folder_entry, RDF::ORE.proxyFor, :target]
116
+ end
117
+
118
+ # Create instances for each item.
119
+ graph.query(query).each do |result|
120
+ contents << ROSRS::FolderEntry.new(self, result.name.to_s, result.folder_entry.to_s, result.target.to_s)
121
+ end
122
+
123
+ contents
124
+ end
125
+
126
+ end
127
+ end
@@ -0,0 +1,44 @@
1
+ module ROSRS
2
+
3
+ # An item within a folder.
4
+
5
+ class FolderEntry
6
+
7
+ attr_reader :parent_folder, :name, :uri
8
+
9
+ ##
10
+ # +parent_folder+:: The ROSRS::Folder object in which this entry resides..
11
+ # +name+:: The display name of the ROSRS::FolderEntry.
12
+ # +uri+:: The URI of this ROSRS::FolderEntry
13
+ # +resource_uri+:: The URI for the resource referred to by this ROSRS::FolderEntry.
14
+ def initialize(parent_folder, name, uri, resource_uri)
15
+ @uri = uri
16
+ @name = name
17
+ @resource_uri = resource_uri
18
+ @parent_folder = parent_folder
19
+ @session = @parent_folder.research_object.session
20
+ end
21
+
22
+ # The resource that this entry points to. Lazily loaded.
23
+ def resource
24
+ @resource ||= @parent_folder.research_object.resources(@resource_uri) ||
25
+ @parent_folder.research_object.folders(@resource_uri) ||
26
+ ROSRS::Resource.new(@parent_folder.research_object, @resource_uri)
27
+ end
28
+
29
+ ##
30
+ # Removes this folder entry from the folder. Does not delete the resource.
31
+ def delete
32
+ code = @session.delete_resource(@uri)[0]
33
+ @loaded = false
34
+ code == 204
35
+ end
36
+
37
+ def self.create(parent_folder, name, resource_uri)
38
+ code, reason, uri = parent_folder.research_object.session.add_folder_entry(parent_folder.uri, resource_uri, name)
39
+ self.new(parent_folder, name, uri, resource_uri)
40
+ end
41
+
42
+ end
43
+
44
+ end
@@ -0,0 +1,12 @@
1
+ module ROSRS
2
+ module Helper
3
+ def self.is_uri?(object)
4
+ if object.is_a?(URI) ||
5
+ object.is_a?(String) && (object.start_with?("/") || object.start_with?("http"))
6
+ true
7
+ else
8
+ false
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,42 @@
1
+ #:nodoc: all
2
+
3
+ module RDF
4
+
5
+ class AO < Vocabulary("http://purl.org/ao/")
6
+ # Declaring these might not be necessary
7
+ property :Annotation
8
+ property :body
9
+ property :annotatesResource
10
+ end
11
+
12
+ class ORE < Vocabulary("http://www.openarchives.org/ore/terms/")
13
+ property :Aggregation
14
+ property :AggregatedResource
15
+ property :Proxy
16
+ property :aggregates
17
+ property :proxyFor
18
+ property :proxyIn
19
+ property :isDescribedBy
20
+ end
21
+
22
+ class RO < Vocabulary("http://purl.org/wf4ever/ro#")
23
+ property :ResearchObject
24
+ property :AggregatedAnnotation
25
+ property :annotatesAggregatedResource
26
+ property :FolderEntry
27
+ property :Folder
28
+ property :Resource
29
+ property :entryName
30
+ end
31
+
32
+ class ROEVO < Vocabulary("http://purl.org/wf4ever/roevo#")
33
+ property :LiveRO
34
+ end
35
+
36
+ class ROTERMS < Vocabulary("http://ro.example.org/ro/terms/")
37
+ property :note
38
+ property :resource
39
+ property :defaultBase
40
+ end
41
+
42
+ end
@@ -0,0 +1,72 @@
1
+ # Shim class for RDF graph parsing, serialization, access
2
+ module ROSRS
3
+ class RDFGraph
4
+
5
+ def initialize(options={})
6
+ # options: :uri => (URI to load),
7
+ # :data => (string to load)
8
+ # :format => (format of data)
9
+ @format = :rdfxml
10
+ @graph = RDF::Graph.new
11
+ if options[:uri]
12
+ load_resource(options[:uri], options[:format])
13
+ end
14
+ if options[:data]
15
+ load_data(options[:data], options[:format])
16
+ end
17
+ end
18
+
19
+ def load_data(data, format=nil)
20
+ @graph << RDF::Reader.for(map_format(format)).new(data)
21
+ end
22
+
23
+ def load_resource(uri, format=nil)
24
+ raise NotImplementedError.new("Attempt to initialize RDFGraph from web resource: #{uri}")
25
+ end
26
+
27
+ def serialize(format=nil)
28
+ return RDF::Writer.for(map_format(format)).buffer { |w| w << @graph }
29
+ end
30
+
31
+ # other methods here
32
+
33
+ def has_statement?(stmt)
34
+ return @graph.has_statement?(stmt)
35
+ end
36
+
37
+ def each_statement(&block)
38
+ @graph.each_statement(&block)
39
+ end
40
+
41
+ def query(pattern, &block)
42
+ @graph.query(pattern, &block)
43
+ end
44
+
45
+ def match?(pattern)
46
+ pattern_found = false
47
+ @graph.query(pattern) { |s| pattern_found = true }
48
+ return pattern_found
49
+ end
50
+
51
+ # Private helpers
52
+
53
+ private
54
+
55
+ def map_format(format=nil)
56
+ rdf_format = :rdfxml # default
57
+ if format
58
+ if format == :xml
59
+ rdf_format = :rdfxml
60
+ elsif format == :ntriples
61
+ rdf_format = :ntriples
62
+ elsif format == :turtle
63
+ rdf_format = :turtle
64
+ else
65
+ raise ArgumentError.new("Unrecognized RDF format: #{format}")
66
+ end
67
+ end
68
+ return rdf_format
69
+ end
70
+
71
+ end
72
+ end