pho 0.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (80) hide show
  1. data/CHANGES +17 -0
  2. data/Rakefile +10 -2
  3. data/bin/talis_store +37 -92
  4. data/doc/rdoc/classes/Pho.html +11 -0
  5. data/doc/rdoc/classes/Pho/CommandLine.html +508 -0
  6. data/doc/rdoc/classes/Pho/DatatypeProperty.html +15 -15
  7. data/doc/rdoc/classes/Pho/Enrichment.html +1 -1
  8. data/doc/rdoc/classes/Pho/Enrichment/{ResourceEnricher.html → StoreEnricher.html} +158 -58
  9. data/doc/rdoc/classes/Pho/Etags.html +36 -36
  10. data/doc/rdoc/classes/Pho/Facet/Results.html +19 -19
  11. data/doc/rdoc/classes/Pho/Facet/Term.html +6 -6
  12. data/doc/rdoc/classes/Pho/FieldPredicateMap.html +94 -94
  13. data/doc/rdoc/classes/Pho/FieldWeighting.html +14 -14
  14. data/doc/rdoc/classes/Pho/FileManagement/AbstractFileManager.html +126 -91
  15. data/doc/rdoc/classes/Pho/FileManagement/FileManager.html +68 -62
  16. data/doc/rdoc/classes/Pho/FileManagement/RDFManager.html +22 -57
  17. data/doc/rdoc/classes/Pho/Job.html +68 -67
  18. data/doc/rdoc/classes/Pho/Jobs.html +62 -62
  19. data/doc/rdoc/classes/Pho/QueryProfile.html +64 -64
  20. data/doc/rdoc/classes/Pho/RDF.html +120 -0
  21. data/doc/rdoc/classes/Pho/RDF/Parser.html +277 -0
  22. data/doc/rdoc/classes/Pho/ResourceHash.html +1 -1
  23. data/doc/rdoc/classes/Pho/ResourceHash/Converter.html +48 -46
  24. data/doc/rdoc/classes/Pho/ResourceHash/SetAlgebra.html +15 -14
  25. data/doc/rdoc/classes/Pho/Snapshot.html +36 -36
  26. data/doc/rdoc/classes/Pho/Sparql.html +50 -0
  27. data/doc/rdoc/classes/Pho/Sparql/SparqlClient.html +147 -68
  28. data/doc/rdoc/classes/Pho/Sparql/SparqlHelper.html +195 -114
  29. data/doc/rdoc/classes/Pho/Status.html +26 -26
  30. data/doc/rdoc/classes/Pho/Store.html +271 -264
  31. data/doc/rdoc/classes/Pho/StoreSparqlClient.html +183 -0
  32. data/doc/rdoc/classes/Pho/Update.html +1 -0
  33. data/doc/rdoc/classes/Pho/Update/Changeset.html +69 -68
  34. data/doc/rdoc/classes/Pho/Update/ChangesetBuilder.html +24 -24
  35. data/doc/rdoc/classes/Pho/Update/Changesets.html +15 -14
  36. data/doc/rdoc/classes/Pho/Update/LiteralStatement.html +18 -18
  37. data/doc/rdoc/classes/Pho/Update/ResourceStatement.html +24 -24
  38. data/doc/rdoc/classes/Pho/Update/Statement.html +28 -27
  39. data/doc/rdoc/classes/String.html +1 -1
  40. data/doc/rdoc/created.rid +1 -1
  41. data/doc/rdoc/files/CHANGES.html +53 -1
  42. data/doc/rdoc/files/lib/pho/changeset_rb.html +1 -1
  43. data/doc/rdoc/files/lib/pho/command_line_rb.html +101 -0
  44. data/doc/rdoc/files/lib/pho/converter_rb.html +1 -1
  45. data/doc/rdoc/files/lib/pho/enrichment_rb.html +1 -1
  46. data/doc/rdoc/files/lib/pho/file_management_rb.html +1 -1
  47. data/doc/rdoc/files/lib/pho/file_manager_rb.html +1 -1
  48. data/doc/rdoc/files/lib/pho/rdf_collection_rb.html +1 -1
  49. data/doc/rdoc/files/lib/pho/rdf_rb.html +108 -0
  50. data/doc/rdoc/files/lib/pho/sparql_rb.html +1 -1
  51. data/doc/rdoc/files/lib/pho/store_rb.html +8 -1
  52. data/doc/rdoc/files/lib/pho_rb.html +4 -2
  53. data/doc/rdoc/fr_class_index.html +6 -1
  54. data/doc/rdoc/fr_file_index.html +2 -0
  55. data/doc/rdoc/fr_method_index.html +192 -172
  56. data/examples/calais/bio.txt +7 -0
  57. data/examples/calais/dump.rb +17 -0
  58. data/examples/calais/enlighten.rb +23 -0
  59. data/examples/calais/output.rdf +25 -0
  60. data/examples/sinatra/viewer.rb +20 -0
  61. data/lib/pho.rb +4 -1
  62. data/lib/pho/changeset.rb +17 -1
  63. data/lib/pho/command_line.rb +166 -0
  64. data/lib/pho/converter.rb +8 -3
  65. data/lib/pho/enrichment.rb +93 -28
  66. data/lib/pho/file_management.rb +32 -19
  67. data/lib/pho/file_manager.rb +22 -26
  68. data/lib/pho/rdf.rb +74 -0
  69. data/lib/pho/rdf_collection.rb +2 -17
  70. data/lib/pho/sparql.rb +150 -38
  71. data/lib/pho/store.rb +28 -2
  72. data/tests/tc_contentbox.rb +41 -0
  73. data/tests/tc_enrichment.rb +41 -4
  74. data/tests/tc_file_manager.rb +97 -7
  75. data/tests/tc_rdf_collection.rb +25 -13
  76. data/tests/tc_rdf_parser.rb +37 -0
  77. data/tests/tc_sparql.rb +72 -2
  78. data/tests/tc_sparql_helper.rb +16 -0
  79. data/tests/ts_pho.rb +2 -1
  80. metadata +20 -3
@@ -6,44 +6,40 @@ module Pho
6
6
 
7
7
  class FileManager < AbstractFileManager
8
8
 
9
- def initialize(store, dir, ok_suffix=OK, fail_suffix=FAIL, sleep=1)
9
+ attr_reader :base
10
+
11
+ def initialize(store, dir, base = nil, ok_suffix=OK, fail_suffix=FAIL, sleep=1)
10
12
  super(store, dir, ok_suffix, fail_suffix, sleep)
13
+ @base = base
11
14
  end
12
-
15
+
13
16
  #List files being managed, i.e. everything not .ok or .fail
14
- def list()
17
+ def list(recursive=false)
15
18
  files = []
16
- Dir.glob( File.join(@dir, "*") ) do |file|
17
- if File.extname(file) != ".#{@ok_suffix}" && File.extname(file) != ".#{@fail_suffix}"
19
+ if recursive
20
+ pattern = "**/*"
21
+ else
22
+ pattern = "*"
23
+ end
24
+ Dir.glob( File.join(@dir, pattern) ) do |file|
25
+ if File.extname(file) != ".#{@ok_suffix}" && File.extname(file) != ".#{@fail_suffix}" && !File.directory?(file)
18
26
  files << file
19
27
  end
20
28
  end
21
29
  return files
22
30
  end
23
-
24
- #List any new files in the directory
25
- def new_files()
26
- newfiles = Array.new
27
- Dir.glob( File.join(@dir, "*") ) do |file|
28
-
29
- if File.extname(file) != ".#{@ok_suffix}" && File.extname(file) != ".#{@fail_suffix}"
30
- ok_file = get_ok_file_for(file)
31
- fail_file = get_fail_file_for(file)
32
- if !( File.exists?(ok_file) or File.exists?(fail_file) )
33
- newfiles << file
34
- end
35
-
36
- end
37
-
38
- end
39
- return newfiles
40
- end
41
-
42
-
31
+
32
+ def FileManager.name_for_file(dir, file, base=nil)
33
+ uri = file.path.gsub(dir, "")
34
+ uri = "#{base}#{uri}" if base != nil
35
+ return uri
36
+ end
37
+
43
38
  protected
44
39
 
45
40
  def store_file(file, filename)
46
- response = @store.upload_item(file, MIME::Types.type_for(filename)[0].to_s )
41
+ uri = FileManager.name_for_file(@dir, file, @base)
42
+ response = @store.upload_item(file, MIME::Types.type_for(filename)[0].to_s, uri )
47
43
  if (response.status < 300 )
48
44
  File.open(get_ok_file_for(filename), "w") do |file|
49
45
  file.print( "OK" )
@@ -0,0 +1,74 @@
1
+ module Pho
2
+
3
+ #Module containing general RDF utilities and classes
4
+ #
5
+ #Dependent on the redland ruby bindings
6
+ module RDF
7
+
8
+ begin
9
+ require 'rdf/redland'
10
+ rescue LoadError
11
+ $stderr.puts "WARNING: Unable to load redland-ruby bindings. Some RDF utils will be unavailable"
12
+ end
13
+
14
+ #General RDF parsing utilities.
15
+ #
16
+ #Currently a convenience wrapper around the Redland Ruby bindings
17
+ class Parser
18
+
19
+ #Parse a file containing ntriples into RDF/XML. Returns a string
20
+ #
21
+ # file:: File object
22
+ # base_uri:: optional base uri to be used when parsing. If not set, then uris are resolved
23
+ # relative to the File
24
+ def Parser.parse_ntriples(file, base_uri=nil)
25
+ model = Redland::Model.new()
26
+ parser = Redland::Parser.new("ntriples", "")
27
+ uri = "file:#{file.path}"
28
+ base_uri = uri unless base_uri
29
+ parser.parse_into_model(model, uri, base_uri)
30
+ serializer = Redland::Serializer.new( "rdfxml", "application/rdf+xml" )
31
+ data = serializer.model_to_string(Redland::Uri.new(base_uri), model)
32
+ return data
33
+ end
34
+
35
+ #Parse a string containing ntriples into RDF/XML. Returns a string
36
+ #
37
+ # string:: the string containing the data
38
+ # base_uri:: base uri for parsing the data
39
+ def Parser.parse_ntriples_from_string(string, base_uri)
40
+ model = Redland::Model.new()
41
+ parser = Redland::Parser.new("ntriples", "")
42
+ parser.parse_string_into_model(model, string, Redland::Uri.new(base_uri))
43
+ serializer = Redland::Serializer.new( "rdfxml", "application/rdf+xml" )
44
+ data = serializer.model_to_string(Redland::Uri.new(base_uri), model)
45
+ return data
46
+ end
47
+
48
+ #Convenience method to parse an ntriples file and store it a Platform store
49
+ #
50
+ # file:: the file to parse
51
+ # store:: the store to receive the data
52
+ # base_uri:: base uri against which the data is parsed
53
+ # graph_name:: uri of graph in store
54
+ def Parser.store_ntriples(file, store, base_uri=nil, graph_name=nil)
55
+ data = Parser.parse_ntriples(file, base_uri)
56
+ return store.store_data(data, graph_name)
57
+ end
58
+
59
+ #Convenience method to parse an ntriples string and store it a Platform store
60
+ #
61
+ # string:: the data to parse
62
+ # store:: the store to receive the data
63
+ # base_uri:: base uri against which the data is parsed
64
+ # graph_name:: uri of graph in store
65
+ def Parser.store_ntriples_from_string(string, store, base_uri, graph_name=nil)
66
+ data = Parser.parse_ntriples_from_string(string, base_uri)
67
+ return store.store_data(data, graph_name)
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+
74
+ end
@@ -14,26 +14,11 @@ module Pho
14
14
  super(store, dir, ok_suffix, fail_suffix, sleep)
15
15
  @rdf_suffix = rdf_suffix
16
16
  end
17
-
18
-
17
+
19
18
  #List files being managed
20
- def list()
19
+ def list(recursive=false)
21
20
  return Dir.glob( File.join(@dir, "*.#{@rdf_suffix}") )
22
21
  end
23
-
24
- #List any new files in the directory
25
- def new_files()
26
- newfiles = Array.new
27
- Dir.glob( File.join(@dir, "*.#{@rdf_suffix}") ) do |file|
28
- ok_file = get_ok_file_for(file)
29
- fail_file = get_fail_file_for(file)
30
- if !( File.exists?(ok_file) or File.exists?(fail_file) )
31
- newfiles << file
32
- end
33
- end
34
- return newfiles
35
- end
36
-
37
22
 
38
23
  protected
39
24
 
@@ -7,6 +7,90 @@ module Pho
7
7
  SPARQL_RESULTS_XML = "application/sparql-results+xml"
8
8
  SPARQL_RESULTS_JSON = "application/sparql-results+json"
9
9
 
10
+ #Includes all statements along both in-bound and out-bound arc paths
11
+ #
12
+ #See http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF
13
+ SYMMETRIC_BOUNDED_DESCRIPTION = <<-EOL
14
+ CONSTRUCT {?uri ?p ?o . ?s ?p2 ?uri .} WHERE { {?uri ?p ?o .} UNION {?s ?p2 ?uri .} }
15
+ EOL
16
+
17
+ #Similar to Concise Bounded Description but includes labels for referenced resources
18
+ #
19
+ #See http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF
20
+ LABELLED_BOUNDED_DESCRIPTION = <<-EOL
21
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
22
+ CONSTRUCT {
23
+ ?uri ?p ?o .
24
+ ?o rdfs:label ?label .
25
+ ?o rdfs:comment ?comment .
26
+ ?o <http://www.w3.org/2004/02/skos/core#prefLabel> ?plabel .
27
+ ?o rdfs:seeAlso ?seealso.
28
+ } WHERE {
29
+ ?uri ?p ?o .
30
+ OPTIONAL {
31
+ ?o rdfs:label ?label .
32
+ }
33
+ OPTIONAL {
34
+ ?o <http://www.w3.org/2004/02/skos/core#prefLabel> ?plabel .
35
+ }
36
+ OPTIONAL {
37
+ ?o rdfs:comment ?comment .
38
+ }
39
+ OPTIONAL {
40
+ ?o rdfs:seeAlso ?seealso.
41
+ }
42
+ }
43
+ EOL
44
+
45
+ #Derived from both the Symmetric and Labelled Bounded Descriptions. Includes all in-bound
46
+ #and out-bound arc paths, with labels for any referenced resources.
47
+ #
48
+ #See http://n2.talis.com/wiki/Bounded_Descriptions_in_RDF
49
+ SYMMETRIC_LABELLED_BOUNDED_DESCRIPTION = <<-EOL
50
+ PREFIX rdfs: <http://www.w3.org/2000/01/rdf-schema#>
51
+ CONSTRUCT {
52
+ ?uri ?p ?o .
53
+ ?o rdfs:label ?label .
54
+ ?o rdfs:comment ?comment .
55
+ ?o rdfs:seeAlso ?seealso.
56
+ ?s ?p2 ?uri .
57
+ ?s rdfs:label ?label .
58
+ ?s rdfs:comment ?comment .
59
+ ?s rdfs:seeAlso ?seealso.
60
+ } WHERE {
61
+ { ?uri ?p ?o .
62
+ OPTIONAL {
63
+ ?o rdfs:label ?label .
64
+ }
65
+ OPTIONAL {
66
+ ?o rdfs:comment ?comment .
67
+ }
68
+ OPTIONAL {
69
+ ?o rdfs:seeAlso ?seealso.
70
+ }
71
+ }
72
+ UNION {
73
+ ?s ?p2 ?uri .
74
+ OPTIONAL {
75
+ ?s rdfs:label ?label .
76
+ }
77
+ OPTIONAL {
78
+ ?s rdfs:comment ?comment .
79
+ }
80
+ OPTIONAL {
81
+ ?s rdfs:seeAlso ?seealso.
82
+ }
83
+ }
84
+ }
85
+ EOL
86
+
87
+ DESCRIPTIONS = {
88
+ :cbd => "DESCRIBE ?uri",
89
+ :scbd => SYMMETRIC_BOUNDED_DESCRIPTION,
90
+ :lcbd => LABELLED_BOUNDED_DESCRIPTION,
91
+ :slcbd => SYMMETRIC_LABELLED_BOUNDED_DESCRIPTION
92
+ }
93
+
10
94
  #A simple SPARQL client that handles the basic HTTP traffic
11
95
  class SparqlClient
12
96
 
@@ -29,8 +113,8 @@ module Pho
29
113
 
30
114
  #Initialize a client for a specific endpoint
31
115
  #
32
- # endpoint:: uri of the SPARQL endpoint
33
- # client:: optionally, a reference to an existing HTTPClient object instance
116
+ #endpoint:: uri of the SPARQL endpoint
117
+ #client:: optionally, a reference to an existing HTTPClient object instance
34
118
  def initialize(endpoint, client=HTTPClient.new() )
35
119
  @endpoint = endpoint
36
120
  @graphs = nil
@@ -59,10 +143,10 @@ module Pho
59
143
 
60
144
  #Perform a sparql query
61
145
  #
62
- # sparql:: a valid SPARQL query
63
- # format:: specific a request format. Usually a media-type, but may be a name for a type, if not using Conneg
64
- # graphs:: an array of default graphs
65
- # named_graphs:: an array of named graphs
146
+ #sparql:: a valid SPARQL query
147
+ #format:: specific a request format. Usually a media-type, but may be a name for a type, if not using Conneg
148
+ #graphs:: an array of default graphs
149
+ #named_graphs:: an array of named graphs
66
150
  def query(sparql, format=nil, graphs=nil, named_graphs=nil)
67
151
 
68
152
  params = {}
@@ -94,10 +178,24 @@ module Pho
94
178
  return @client.get( @endpoint, params, headers )
95
179
  end
96
180
 
181
+ #Describe a uri, optionally specifying a form of bounded description
182
+ #
183
+ #uri:: the uri to describe
184
+ #format:: mimetype for results
185
+ #type:: symbol indicating type of description, i.e. +:cbd+, +:scbd+, +:lcbd+, or +:slcbd+
186
+ def describe_uri(uri, format="application/rdf+xml", type=:cbd)
187
+ template = Pho::Sparql::DESCRIPTIONS[type]
188
+ if template == nil
189
+ raise "Unknown description type"
190
+ end
191
+ query = Pho::Sparql::SparqlHelper.apply_initial_bindings(template, {"uri" => "<#{uri}>"} )
192
+ return describe(query, format)
193
+ end
194
+
97
195
  #Perform a SPARQL DESCRIBE query.
98
196
  #
99
- # query:: the SPARQL query
100
- # format:: the preferred response format
197
+ #query:: the SPARQL query
198
+ #format:: the preferred response format
101
199
  def describe(query, format="application/rdf+xml")
102
200
  return query(query, format)
103
201
  end
@@ -108,8 +206,8 @@ module Pho
108
206
  #This will generate a query like:
109
207
  # DESCRIBE <http://www.example.org> <http://www.example.com> ...
110
208
  #
111
- # uris:: list of the uris to be described
112
- # format:: the preferred response format. Default is RDF/XML
209
+ #uris:: list of the uris to be described
210
+ #format:: the preferred response format. Default is RDF/XML
113
211
  def multi_describe(uris, format="application/rdf+xml")
114
212
  query = "DESCRIBE " + uris.map {|u| "<#{u}>" }.join(" ")
115
213
  return query(query, format)
@@ -117,24 +215,24 @@ module Pho
117
215
 
118
216
  #Perform a SPARQL CONSTRUCT query.
119
217
  #
120
- # query:: the SPARQL query
121
- # format:: the preferred response format
218
+ #query:: the SPARQL query
219
+ #format:: the preferred response format
122
220
  def construct(query, format="application/rdf+xml")
123
221
  return query(query, format)
124
222
  end
125
223
 
126
224
  #Perform a SPARQL ASK query.
127
225
  #
128
- # query:: the SPARQL query
129
- # format:: the preferred response format
226
+ #query:: the SPARQL query
227
+ #format:: the preferred response format
130
228
  def ask(query, format=Pho::Sparql::SPARQL_RESULTS_XML)
131
229
  return query(query, format)
132
230
  end
133
231
 
134
232
  #Perform a SPARQL SELECT query.
135
233
  #
136
- # query:: the SPARQL query
137
- # format:: the preferred response format
234
+ #query:: the SPARQL query
235
+ #format:: the preferred response format
138
236
  def select(query, format=Pho::Sparql::SPARQL_RESULTS_XML)
139
237
  return query(query, format)
140
238
  end
@@ -154,8 +252,8 @@ module Pho
154
252
  #Any keys in the hash that are not in the query are ignored. Any variables not found
155
253
  #in the hash remain unbound.
156
254
  #
157
- # query:: the query whose initial bindings are to be set
158
- # values:: hash of query name to value
255
+ #query:: the query whose initial bindings are to be set
256
+ #values:: hash of query name to value
159
257
  def SparqlHelper.apply_initial_bindings(query, bindings={})
160
258
  copy = query.clone()
161
259
  copy.gsub!(VARIABLE_MATCHER) do |pattern|
@@ -180,7 +278,7 @@ module Pho
180
278
  #performed to extract some variables that can later be plugged into a subsequent
181
279
  #query
182
280
  #
183
- # result:: hash conforming to structure of a <tt>binding</tt> in the SPARQL JSON format
281
+ #result:: hash conforming to structure of a <tt>binding</tt> in the SPARQL JSON format
184
282
  def SparqlHelper.result_to_query_binding(result)
185
283
  hash = {}
186
284
  result.each_pair do |key, value|
@@ -202,10 +300,10 @@ module Pho
202
300
  #into the results.
203
301
  #
204
302
  #E.g:
205
- # <tt>results = Pho::Sparql::SparqlHelper.select(query, sparql_client)</tt>
206
- # <tt>bindings = Pho::Sparql::SparqlHelper.results_to_query_bindings(results)</tt>
303
+ #<tt>results = Pho::Sparql::SparqlHelper.select(query, sparql_client)</tt>
304
+ #<tt>bindings = Pho::Sparql::SparqlHelper.results_to_query_bindings(results)</tt>
207
305
  #
208
- # results:: hash conforming to SPARQL SELECT structure
306
+ #results:: hash conforming to SPARQL SELECT structure
209
307
  def SparqlHelper.results_to_query_bindings(results)
210
308
  bindings = []
211
309
 
@@ -221,8 +319,8 @@ module Pho
221
319
  #
222
320
  #An error will be raised if the response is HTTP OK.
223
321
  #
224
- # query:: the SPARQL SELECT query
225
- # sparql_client:: a configured SparqlClient object
322
+ #query:: the SPARQL SELECT query
323
+ #sparql_client:: a configured SparqlClient object
226
324
  def SparqlHelper.select(query, sparql_client)
227
325
  #TODO: test whether endpoint supports json, and if not, switch to parsing XML
228
326
  resp = sparql_client.select(query, Pho::Sparql::SPARQL_RESULTS_JSON)
@@ -237,8 +335,8 @@ module Pho
237
335
  #Will request the results using the SPARQL JSON results format, parse the
238
336
  #resulting JSON results, and extract the true/false response.
239
337
  #
240
- # query:: the SPARQL SELECT query
241
- # sparql_client:: a configured SparqlClient object
338
+ #query:: the SPARQL SELECT query
339
+ #sparql_client:: a configured SparqlClient object
242
340
  def SparqlHelper.ask(query, sparql_client)
243
341
  json = SparqlHelper.select(query, sparql_client)
244
342
  return json["boolean"] == "true"
@@ -252,8 +350,8 @@ module Pho
252
350
  #
253
351
  #Note this will lose any type information, only the value of the bindings are returned
254
352
  #
255
- # query:: the SPARQL SELECT query
256
- # sparql_client:: a configured SparqlClient object
353
+ #query:: the SPARQL SELECT query
354
+ #sparql_client:: a configured SparqlClient object
257
355
  def SparqlHelper.select_values(query, sparql_client)
258
356
  results = SparqlHelper.select(query, sparql_client)
259
357
  v = results["head"]["vars"][0];
@@ -272,8 +370,8 @@ module Pho
272
370
  #
273
371
  #Note this will lose any type information, only the value of the binding is returned
274
372
  #
275
- # query:: the SPARQL SELECT query
276
- # sparql_client:: a configured SparqlClient object
373
+ #query:: the SPARQL SELECT query
374
+ #sparql_client:: a configured SparqlClient object
277
375
  def SparqlHelper.select_single_value(query, sparql_client)
278
376
  results = SparqlHelper.select(query, sparql_client)
279
377
  v = results["head"]["vars"][0];
@@ -285,8 +383,8 @@ module Pho
285
383
  #Will request the results as application/json (with the expectation that it returns RDF_JSON),
286
384
  #and parses the resulting JSON document.
287
385
  #
288
- # query:: the SPARQL SELECT query
289
- # sparql_client:: a configured SparqlClient object
386
+ #query:: the SPARQL SELECT query
387
+ #sparql_client:: a configured SparqlClient object
290
388
  def SparqlHelper.construct_to_resource_hash(query, sparql_client)
291
389
  #TODO: test whether endpoint supports json, and if not, switch to parsing XML
292
390
  resp = sparql_client.construct(query, "application/json")
@@ -301,8 +399,8 @@ module Pho
301
399
  #Will request the results as application/json (with the expectation that it returns RDF_JSON),
302
400
  #and parses the resulting JSON document.
303
401
  #
304
- # query:: the SPARQL SELECT query
305
- # sparql_client:: a configured SparqlClient object
402
+ #query:: the SPARQL SELECT query
403
+ #sparql_client:: a configured SparqlClient object
306
404
  def SparqlHelper.describe_to_resource_hash(query, sparql_client)
307
405
  #TODO: test whether endpoint supports json, and if not, switch to parsing XML
308
406
  resp = sparql_client.describe(query, "application/json")
@@ -311,11 +409,11 @@ module Pho
311
409
  end
312
410
  return Pho::ResourceHash::Converter.parse_json( resp.content )
313
411
  end
314
-
412
+
315
413
  #DESCRIBE multiple resources in a single SPARQL request
316
414
  #
317
- # uris:: an array of URIs
318
- # sparql_client:: a configured SparqlClient objec
415
+ #uris:: an array of URIs
416
+ #sparql_client:: a configured SparqlClient objec
319
417
  def SparqlHelper.multi_describe(uris, sparql_client)
320
418
  #TODO: test whether endpoint supports json, and if not, switch to parsing XML
321
419
  resp = sparql_client.multi_describe(uris, "application/json")
@@ -324,7 +422,21 @@ module Pho
324
422
  end
325
423
  return Pho::ResourceHash::Converter.parse_json( resp.content )
326
424
  end
327
-
425
+
426
+ #Describe a single URI using one of several forms of Bounded Description
427
+ #See SparqlClient.describe_uri
428
+ #
429
+ #uri:: resource to describe
430
+ #sparql_client:: configured SPARQL client
431
+ #type:: form of bounded description to generate
432
+ def SparqlHelper.describe_uri(uri, sparql_client, type=:cbd)
433
+ #TODO: test whether endpoint supports json, and if not, switch to parsing XML
434
+ resp = sparql_client.describe_uri(uri, "application/json", type)
435
+ if resp.status != 200
436
+ raise "Error performing sparql query: #{resp.status} #{resp.reason}\n#{resp.content}"
437
+ end
438
+ return Pho::ResourceHash::Converter.parse_json( resp.content )
439
+ end
328
440
  end
329
441
 
330
442
  end