pho 0.4 → 0.4.1

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.
Files changed (57) hide show
  1. data/CHANGES +12 -1
  2. data/Rakefile +2 -2
  3. data/doc/index.html +15 -1
  4. data/doc/rdoc/classes/Pho.html +14 -0
  5. data/doc/rdoc/classes/Pho/DatatypeProperty.html +12 -12
  6. data/doc/rdoc/classes/Pho/Etags.html +36 -36
  7. data/doc/rdoc/classes/Pho/Facet/Results.html +19 -19
  8. data/doc/rdoc/classes/Pho/Facet/Term.html +6 -6
  9. data/doc/rdoc/classes/Pho/FieldPredicateMap.html +90 -90
  10. data/doc/rdoc/classes/Pho/FieldWeighting.html +12 -12
  11. data/doc/rdoc/classes/Pho/Job.html +64 -64
  12. data/doc/rdoc/classes/Pho/Jobs.html +61 -61
  13. data/doc/rdoc/classes/Pho/Namespaces.html +6 -1
  14. data/doc/rdoc/classes/Pho/QueryProfile.html +61 -61
  15. data/doc/rdoc/classes/Pho/RDFCollection.html +71 -71
  16. data/doc/rdoc/classes/Pho/RDF_JSON.html +118 -0
  17. data/doc/rdoc/classes/Pho/RDF_JSON/SetAlgebra.html +240 -0
  18. data/doc/rdoc/classes/Pho/Snapshot.html +35 -35
  19. data/doc/rdoc/classes/Pho/Status.html +26 -26
  20. data/doc/rdoc/classes/Pho/Store.html +342 -264
  21. data/doc/rdoc/classes/Pho/Update.html +127 -0
  22. data/doc/rdoc/classes/Pho/Update/Changeset.html +520 -0
  23. data/doc/rdoc/classes/Pho/Update/ChangesetBuilder.html +330 -0
  24. data/doc/rdoc/classes/Pho/Update/Changesets.html +204 -0
  25. data/doc/rdoc/classes/Pho/Update/LiteralStatement.html +248 -0
  26. data/doc/rdoc/classes/Pho/Update/ResourceStatement.html +213 -0
  27. data/doc/rdoc/classes/Pho/Update/Statement.html +302 -0
  28. data/doc/rdoc/classes/String.html +146 -0
  29. data/doc/rdoc/created.rid +1 -1
  30. data/doc/rdoc/files/CHANGES.html +33 -2
  31. data/doc/rdoc/files/lib/pho/changeset_builder_rb.html +108 -0
  32. data/doc/rdoc/files/lib/pho/changeset_rb.html +108 -0
  33. data/doc/rdoc/files/lib/pho/job_rb.html +1 -1
  34. data/doc/rdoc/files/lib/pho/query_profile_rb.html +1 -1
  35. data/doc/rdoc/files/lib/pho/rdf_json_rb.html +101 -0
  36. data/doc/rdoc/files/lib/pho/store_rb.html +1 -1
  37. data/doc/rdoc/files/lib/pho_rb.html +4 -1
  38. data/doc/rdoc/fr_class_index.html +10 -0
  39. data/doc/rdoc/fr_file_index.html +3 -0
  40. data/doc/rdoc/fr_method_index.html +140 -110
  41. data/lib/pho.rb +14 -1
  42. data/lib/pho/changeset.rb +312 -0
  43. data/lib/pho/changeset_builder.rb +118 -0
  44. data/lib/pho/job.rb +1 -1
  45. data/lib/pho/query_profile.rb +1 -1
  46. data/lib/pho/rdf_json.rb +81 -0
  47. data/lib/pho/store.rb +63 -25
  48. data/tests/tc_changeset.rb +273 -0
  49. data/tests/tc_changeset_builder.rb +151 -0
  50. data/tests/tc_changesets.rb +96 -0
  51. data/tests/tc_metabox.rb +20 -2
  52. data/tests/tc_query_profile.rb +4 -2
  53. data/tests/tc_rdf_json.rb +273 -0
  54. data/tests/tc_search.rb +5 -5
  55. data/tests/tc_sparql.rb +12 -0
  56. data/tests/ts_pho.rb +5 -1
  57. metadata +25 -3
@@ -0,0 +1,118 @@
1
+ module Pho
2
+
3
+ require 'uri'
4
+
5
+ #Module organizing classes related to Changeset handling.
6
+ module Update
7
+
8
+ #Utility class providing methods for building Changesets from triple hashes
9
+ class ChangesetBuilder
10
+
11
+ #Build a batch changeset
12
+ #
13
+ #This method is suitable for building an array of changesets that describe changes made to a
14
+ #number of different resources.
15
+ #
16
+ #Returns an array of Changeset objects
17
+ #
18
+ # before:: triple hash describing current state of the resource
19
+ # after:: triple hash describing updated state of the resource
20
+ # creator_name:: name of the creator of the changes
21
+ # change_reason:: description of why the changes are being made
22
+ def ChangesetBuilder.build_batch(before, after, creator_name=nil, change_reason=nil)
23
+
24
+ removals = Pho::RDF_JSON::SetAlgebra.minus(before, after)
25
+ additions = Pho::RDF_JSON::SetAlgebra.minus(after, before)
26
+
27
+ batch = Array.new
28
+
29
+ removals.each do |uri, properties|
30
+ cs = Pho::Update::Changeset.new(uri, creator_name, change_reason) do |cs|
31
+ cs.add_removals( create_statements_for_uri(uri, properties) )
32
+ if additions.has_key?(uri)
33
+ cs.add_additions( create_statements_for_uri(uri, additions[uri] ) )
34
+ additions.delete(uri)
35
+ end
36
+ end
37
+ batch << cs
38
+ end
39
+
40
+ if !additions.empty?
41
+ additions.each do |uri, properties|
42
+ cs = Pho::Update::Changeset.new(uri, creator_name, change_reason) do |cs|
43
+ cs.add_additions( create_statements_for_uri(uri, properties) )
44
+ end
45
+ batch << cs
46
+ end
47
+ end
48
+
49
+ return batch
50
+
51
+ end
52
+
53
+ #Build a single changeset
54
+ #
55
+ #This method is suitable for building changesets that describe changes made to a single resource
56
+ #If the before/after hashes contain data for other subjects, then an error will be thrown.
57
+ #
58
+ #The method will return a single Changeset object.
59
+ #
60
+ # subject_of_change:: uri of the resource being updated
61
+ # before:: triple hash describing current state of the resource
62
+ # after:: triple hash describing updated state of the resource
63
+ # creator_name:: name of the creator of the changes
64
+ # change_reason:: description of why the changes are being made
65
+ def ChangesetBuilder.build(subject_of_change, before, after, creator_name=nil, change_reason=nil)
66
+ removals = Pho::RDF_JSON::SetAlgebra.minus(before, after)
67
+ additions = Pho::RDF_JSON::SetAlgebra.minus(after, before)
68
+
69
+ cs = Pho::Update::Changeset.new(subject_of_change, creator_name, change_reason) do |cs|
70
+ cs.add_removals( create_statements(removals) )
71
+ cs.add_additions( create_statements(additions) )
72
+ end
73
+
74
+ return cs
75
+
76
+ end
77
+
78
+ #Takes an triple hash and serializes it as an array of Pho::Update::Statement objects
79
+ #
80
+ # triples:: a hash of triples, conforming to RDF-in-JSON structure
81
+ def ChangesetBuilder.create_statements(triples)
82
+ statements = Array.new
83
+ triples.each do |uri, properties|
84
+ statements += create_statements_for_uri(uri, properties)
85
+ end
86
+ return statements
87
+ end
88
+
89
+ #Create statements for a specific uri, using predicate-object values in
90
+ #the provided properties hash
91
+ #
92
+ # uri:: subject of change
93
+ # properties:: hash of predicate-object values
94
+ def ChangesetBuilder.create_statements_for_uri(uri, properties)
95
+ statements = Array.new
96
+ properties.each do |predicate, val_array|
97
+ val_array.each do |value|
98
+ s = nil
99
+ if value["type"] == "literal"
100
+ s = Pho::Update::Statement.create_literal(uri, predicate, value["value"], value["lang"], value["datatype"])
101
+ else
102
+ #TODO bnodes?
103
+ s = Pho::Update::Statement.create_resource(uri, predicate, value["value"])
104
+ end
105
+ if s != nil
106
+ statements << s
107
+ end
108
+ end
109
+ end
110
+ return statements
111
+ end
112
+
113
+ end
114
+
115
+ end
116
+
117
+ end
118
+
@@ -21,7 +21,7 @@ module Pho
21
21
  jobs = Array.new
22
22
 
23
23
  doc = REXML::Document.new(resp.content)
24
- REXML::XPath.each(doc.root, "//bf:job", Pho::Namespaces::MAPPING).each do |el|
24
+ REXML::XPath.each(doc.root, "//bf:job", Pho::Namespaces::MAPPING) do |el|
25
25
  jobs << el.attributes["rdf:resource"]
26
26
  end
27
27
  return jobs
@@ -137,7 +137,7 @@ module Pho
137
137
  rdf << " <rdfs:label>#{@label}</rdfs:label> "
138
138
 
139
139
  @field_weights.each do |property|
140
- rdf << " <frm:fieldWeight rdf:resource=\"#{property.uri}\"/> "
140
+ rdf << " <bf:fieldWeight rdf:resource=\"#{property.uri}\"/> "
141
141
  end
142
142
 
143
143
  rdf << " </rdf:Description>"
@@ -0,0 +1,81 @@
1
+ module Pho
2
+
3
+ #TODO
4
+ #blank nodes
5
+
6
+ #Module providing code for manipulating triple hashes structured according
7
+ #to the RDF in JSON spec
8
+ module RDF_JSON
9
+
10
+ #Class providing set algebra methods over triple hashes
11
+ class SetAlgebra
12
+
13
+ #Accepts two triple hashes, expressed as RDF-in-JSON and returns a new
14
+ #Ruby data structure that constitutes the different between the two graphs
15
+ #
16
+ #i.e. the return value will be a hash containing the triples that are in the
17
+ #first graph but which are not present in the second.
18
+ #
19
+ # first:: the first graph
20
+ # second:: the second graph.
21
+ def SetAlgebra.minus(first, second)
22
+
23
+ difference = Hash.new
24
+ first.each do |uri,properties|
25
+ if second.has_key?(uri)
26
+ properties.each do |predicate,value|
27
+ if second[uri].has_key?(predicate)
28
+ #second hash has same uri and predicate, so check value arrays
29
+ second_value = second[uri][predicate]
30
+ value.each do |val|
31
+
32
+ if !object_in_array?(second_value, val)
33
+
34
+ difference[uri] ||= Hash.new
35
+ difference[uri][predicate] ||= Array.new
36
+ difference[uri][predicate] << val
37
+ end
38
+ end
39
+
40
+ else
41
+ #uri is in second, but not this property and value
42
+ difference[uri] ||= Hash.new
43
+ difference[uri][predicate] = value
44
+ end
45
+ end
46
+ else
47
+ #uri not in second, so pass all straight-through
48
+ difference[uri] = properties
49
+ end
50
+
51
+ end
52
+
53
+ return difference
54
+
55
+ end
56
+
57
+ #Is there an object in the specified array, that matches the provided description
58
+ def SetAlgebra.object_in_array?(array, val)
59
+ array.each do |entry|
60
+
61
+ if entry["type"] == val["type"]
62
+ if entry["value"] == val["value"]
63
+
64
+ if entry["type"] == "literal"
65
+ if entry["datatype"] == val["datatype"] &&
66
+ entry["lang"] = val["lang"]
67
+ return true
68
+ end
69
+ end
70
+ return true
71
+ end
72
+
73
+ end
74
+ end
75
+ return false
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -2,14 +2,10 @@ module Pho
2
2
 
3
3
  #TODO:
4
4
  #
5
- # Make it work with Ruby < 1.8.7
6
- # Changesets
7
- # Multisparql
8
- #
9
5
  # Conditional deletions
10
6
  # If-Modified-Since support
11
7
  # Robustness in uri fetching
12
-
8
+ # Etag Testing
13
9
 
14
10
  # The Store class acts as a lightweight client interface to the Talis Platform API
15
11
  # (http://n2.talis.com/wiki/Platform_API). The class provides methods for interacting
@@ -75,10 +71,19 @@ module Pho
75
71
  # METABOX
76
72
  #############
77
73
 
78
- # Store some RDF in the Metabox associated with this store
74
+ # Store some RDF in the Metabox associated with this store. Default is to store the
75
+ # data in the metabox, but a private graph name can also be specified.
76
+
79
77
  # data:: a String containing the data to store
80
- def store_data(data)
81
- u = build_uri("/meta")
78
+ # graph_name:: name of a private graph in which to store the data. E.g. "1" or "private". Resolves to /meta/graphs/graph_name
79
+ def store_data(data, graph_name=nil)
80
+ u = nil
81
+ if graph_name == nil
82
+ u = build_uri("/meta")
83
+ else
84
+ u = build_uri("/meta/graphs/#{graph_name}")
85
+ end
86
+
82
87
  response = @client.post(u, data, RDF_XML )
83
88
  return response
84
89
  end
@@ -97,9 +102,14 @@ module Pho
97
102
  # An Accept header of "application/rdf+xml" will be sent in the request to support retrieval of RDF from
98
103
  # URLs that support Content Negotiation.
99
104
  #
105
+ # NOTE: Currently this method doesn't properly handle base uris of retrieved data. i.e. the data isn't parsed
106
+ # and there is no way to pass a base uri to the Platform. Be warned!
107
+ #
108
+ # The default is to store the data in the Metabox. But a private graph name can also be specified
100
109
  # u:: the url of the data
101
110
  # parameters:: a Hash of url parameters to pass when requesting data from the specified URL
102
- def store_url(u, parameters=nil)
111
+ # graph_name:: name of a private graph in which to store the data. E.g. "1" or "private". Resolves to /meta/graphs/graph_name
112
+ def store_url(u, parameters=nil, graph_name=nil)
103
113
 
104
114
  headers = ACCEPT_RDF.clone()
105
115
  dataresp = @client.get(u, parameters, headers )
@@ -109,7 +119,7 @@ module Pho
109
119
  throw
110
120
  end
111
121
 
112
- return store_data(dataresp.content)
122
+ return store_data(dataresp.content, graph_name)
113
123
 
114
124
  end
115
125
 
@@ -133,7 +143,29 @@ module Pho
133
143
  record_etags("#{u}?about=#{uri}", etags, response)
134
144
  return response
135
145
  end
136
-
146
+
147
+ # Submit a Changeset to the Platform to update the metabox
148
+ #
149
+ # Default behaviour is to update the metabox with an unversioned name
150
+ # However using the optional parameters, changes can be made versioned, and
151
+ # can also be submitted to private graphs.
152
+ #
153
+ # rdf:: the RDF/XML describing the changes
154
+ # versioned:: true or false to indicate this is a versioned change
155
+ # graph_name:: name of private graph to update instead of metabox
156
+ def submit_changeset(rdf, versioned=false, graph_name=nil)
157
+ uri = "/meta"
158
+ if graph_name != nil
159
+ uri = uri + "/graphs/#{graph_name}"
160
+ end
161
+ uri = uri + "/changesets" if versioned
162
+
163
+ u = self.build_uri( uri )
164
+ headers = {"Content-Type" => "application/vnd.talis.changeset+xml"}
165
+ response = @client.post(u, rdf, headers)
166
+ return response
167
+ end
168
+
137
169
  #############
138
170
  # SERVICES
139
171
  #############
@@ -142,40 +174,46 @@ module Pho
142
174
  #
143
175
  # query:: the SPARQL query
144
176
  # format:: the preferred response format
145
- def sparql_describe(query, format="application/rdf+xml")
146
- return sparql(query, format)
177
+ def sparql_describe(query, format="application/rdf+xml", multisparql=false)
178
+ return sparql(query, format, multisparql)
147
179
  end
148
180
 
149
181
  #Perform a SPARQL CONSTRUCT query.
150
182
  #
151
183
  # query:: the SPARQL query
152
184
  # format:: the preferred response format
153
- def sparql_construct(query, format="application/rdf+xml")
154
- return sparql(query, format)
185
+ def sparql_construct(query, format="application/rdf+xml", multisparql=false)
186
+ return sparql(query, format, multisparql)
155
187
  end
156
188
 
157
189
  #Perform a SPARQL ASK query.
158
190
  #
159
191
  # query:: the SPARQL query
160
192
  # format:: the preferred response format
161
- def sparql_ask(query, format="application/sparql-results+xml")
162
- return sparql(query, format)
193
+ def sparql_ask(query, format="application/sparql-results+xml", multisparql=false)
194
+ return sparql(query, format, multisparql)
163
195
  end
164
196
 
165
197
  #Perform a SPARQL SELECT query.
166
198
  #
167
199
  # query:: the SPARQL query
168
200
  # format:: the preferred response format
169
- def sparql_select(query, format="application/sparql-results+xml")
170
- return sparql(query, format)
201
+ def sparql_select(query, format="application/sparql-results+xml", multisparql=false)
202
+ return sparql(query, format, multisparql)
171
203
  end
172
204
 
173
205
  #Perform a SPARQL query
174
206
  #
175
207
  # query:: the SPARQL query
176
- # format:: the preferred response format
177
- def sparql(query, format=nil)
178
- u = self.build_uri("/services/sparql")
208
+ # format:: the preferred response format
209
+ # multisparql:: use default sparql service or multisparql service
210
+ def sparql(query, format=nil, multisparql=false)
211
+ if multisparql
212
+ u = self.build_uri("/services/multisparql")
213
+ else
214
+ u = self.build_uri("/services/sparql")
215
+ end
216
+
179
217
  params = {}
180
218
  params["query"] = query
181
219
  headers = {}
@@ -203,7 +241,7 @@ module Pho
203
241
  def search(query, params=nil)
204
242
  u = self.build_uri("/items")
205
243
  search_params = get_search_params(u, query, params)
206
- response = @client.get(u, search_params, nil)
244
+ response = @client.get(u, search_params)
207
245
  return response
208
246
 
209
247
  end
@@ -225,7 +263,7 @@ module Pho
225
263
  u = self.build_uri("/services/facet")
226
264
  search_params = get_search_params(u, query, params)
227
265
  search_params["fields"] = facets.join(",")
228
- response = @client.get(u, search_params, nil)
266
+ response = @client.get(u, search_params)
229
267
  return response
230
268
  end
231
269
 
@@ -244,7 +282,7 @@ module Pho
244
282
  # uri:: the URL for the RSS 1.0 feed
245
283
  def augment_uri(uri)
246
284
  u = self.build_uri("/services/augment")
247
- response = @client.get(u, {"data-uri" => uri}, nil)
285
+ response = @client.get(u, {"data-uri" => uri})
248
286
  return response
249
287
  end
250
288
 
@@ -0,0 +1,273 @@
1
+ $:.unshift File.join(File.dirname(__FILE__), "..", "lib")
2
+ require 'pho'
3
+ require 'test/unit'
4
+ require 'mocha'
5
+ require 'rexml/document'
6
+ require 'uri'
7
+
8
+ class ChangesetTest < Test::Unit::TestCase
9
+
10
+ def test_equality_resources
11
+ one = Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page1")
12
+ two = Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page2")
13
+ assert_equal(false, one == two)
14
+ assert_equal(true, one != two)
15
+
16
+ two = Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page1")
17
+ assert_are_equal(one, two)
18
+ end
19
+
20
+ def test_equality_literals
21
+ one = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one")
22
+ two = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "two")
23
+ assert_equal(false, one == two)
24
+ assert_equal(true, one != two)
25
+
26
+ two = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one")
27
+ assert_are_equal(one, two)
28
+
29
+ end
30
+
31
+ def test_statement_constructor
32
+ s = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one", "en")
33
+ s = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one", nil, "http://www.example.org/datatype")
34
+ assert_raise RuntimeError do
35
+ s = Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one", "en", "http://www.example.org/datatype")
36
  end
37
+ end
38
+
39
+ def test_statement_constructor_visibility
40
+ assert_raise NoMethodError do
41
+ s = Pho::Update::Statement.new("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "one", "en")
42
+ end
43
+
44
+ end
45
+
46
+ #Test validation code in constructor
47
+ def test_must_pass_uri_to_constructor
48
+
49
+ assert_raise URI::InvalidURIError do
50
+ cs = Pho::Update::Changeset.new(nil)
51
+ end
52
+
53
+ assert_raise URI::InvalidURIError do
54
+ cs = Pho::Update::Changeset.new("literal")
55
+ end
56
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource")
57
+
58
+ end
59
+
60
+ def assert_are_equal(one, two)
61
+ assert_equal(true, one == two)
62
+ assert_equal(false, one != two)
63
+
64
+ assert_equal(true, two == one)
65
+ assert_equal(false, two != one)
66
+ end
67
+
68
+ def test_cannot_add_with_wrong_subject()
69
+ cs = Pho::Update::Changeset.new("http://www.example.org")
70
+ assert_raise RuntimeError do
71
+ cs.add_addition( Pho::Update::Statement.create_literal("http://example.net", "http://example.net/predicate", "foo") )
1
72
  end
73
+ assert_raise RuntimeError do
74
+ cs.add_removal( Pho::Update::Statement.create_literal("http://example.net", "http://example.net/predicate", "foo") )
75
+ end
76
+ end
77
+
78
+ def test_to_rdf_empty_changeset
79
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource")
80
+
81
+ rdf = cs.to_rdf()
82
+ assert_not_nil(rdf)
83
+
84
+ cs_el = get_changeset(rdf)
85
+ soc = REXML::XPath.first(cs_el, "cs:subjectOfChange", Pho::Namespaces::MAPPING)
86
+ assert_equal("http://www.example.org/my-resource", soc.attributes["rdf:resource"] )
87
+
88
+ el = REXML::XPath.first(cs_el, "cs:creatorName", Pho::Namespaces::MAPPING)
89
+ assert_nil(el)
90
+ el = REXML::XPath.first(cs_el, "cs:changeReason", Pho::Namespaces::MAPPING)
91
+ assert_nil(el)
92
+
93
+ end
94
+
95
+ def test_to_rdf_empty_changeset_with_creator_and_reason
96
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource", "creator", "reason")
97
+
98
+ cs_el = get_changeset(cs.to_rdf)
99
+ soc = REXML::XPath.first(cs_el, "cs:subjectOfChange", Pho::Namespaces::MAPPING)
100
+ assert_equal("http://www.example.org/my-resource", soc.attributes["rdf:resource"] )
101
+
102
+ el = REXML::XPath.first(cs_el, "cs:creatorName", Pho::Namespaces::MAPPING)
103
+ assert_equal("creator", el.text)
104
+ el = REXML::XPath.first(cs_el, "cs:changeReason", Pho::Namespaces::MAPPING)
105
+ assert_equal("reason", el.text)
106
+
107
+ end
108
+
109
+ def test_to_rdf_empty_changeset_with_block
110
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |obj|
111
+ obj.creator_name = "creator"
112
+ obj.change_reason = "reason"
113
+ end
114
+
115
+ root = parse(cs.to_rdf)
116
+ cs_el = REXML::XPath.first(root, "cs:ChangeSet", Pho::Namespaces::MAPPING)
117
+ soc = REXML::XPath.first(cs_el, "cs:subjectOfChange", Pho::Namespaces::MAPPING)
118
+ assert_equal("http://www.example.org/my-resource", soc.attributes["rdf:resource"] )
119
+
120
+ el = REXML::XPath.first(cs_el, "cs:creatorName", Pho::Namespaces::MAPPING)
121
+ assert_equal("creator", el.text)
122
+ el = REXML::XPath.first(cs_el, "cs:changeReason", Pho::Namespaces::MAPPING)
123
+ assert_equal("reason", el.text)
124
+
125
+ end
126
+
127
+ def test_to_rdf_with_resource_addition
128
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |c|
129
+ c.add_addition( Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page") )
130
+ end
131
+ assert_equal(1, cs.additions.length)
132
+ assert_equal(0, cs.removals.length)
133
+
134
+ cs_el = get_changeset(cs.to_rdf)
135
+
136
+ addition = REXML::XPath.first(cs_el, "cs:addition", Pho::Namespaces::MAPPING)
137
+ assert_not_nil(addition)
138
+ statement = REXML::XPath.first(addition, "rdf:Statement", Pho::Namespaces::MAPPING)
139
+ assert_not_nil(statement)
140
+ el = REXML::XPath.first(statement, "rdf:subject", Pho::Namespaces::MAPPING)
141
+ assert_equal("http://www.example.org/my-resource", el.attributes["rdf:resource"])
142
+ el = REXML::XPath.first(statement, "rdf:predicate", Pho::Namespaces::MAPPING)
143
+ assert_equal("http://xmlns.com/foaf/0.1/homePage", el.attributes["rdf:resource"])
144
+ el = REXML::XPath.first(statement, "rdf:object", Pho::Namespaces::MAPPING)
145
+ assert_equal("http://www.example.org/page", el.attributes["rdf:resource"])
146
+ assert_equal(nil, el.text)
147
+
148
+ end
149
+
150
+ def test_to_rdf_with_literal_addition
151
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |c|
152
+ c.add_addition( Pho::Update::Statement.create_literal("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "literal") )
153
+ end
154
+ assert_equal(1, cs.additions.length)
155
+
156
+ cs_el = get_changeset(cs.to_rdf)
157
+
158
+ addition = REXML::XPath.first(cs_el, "cs:addition", Pho::Namespaces::MAPPING)
159
+ assert_not_nil(addition)
160
+ statement = REXML::XPath.first(addition, "rdf:Statement", Pho::Namespaces::MAPPING)
161
+ assert_not_nil(statement)
162
+ el = REXML::XPath.first(statement, "rdf:subject", Pho::Namespaces::MAPPING)
163
+ assert_equal("http://www.example.org/my-resource", el.attributes["rdf:resource"])
164
+ el = REXML::XPath.first(statement, "rdf:predicate", Pho::Namespaces::MAPPING)
165
+ assert_equal("http://xmlns.com/foaf/0.1/homePage", el.attributes["rdf:resource"])
166
+ el = REXML::XPath.first(statement, "rdf:object", Pho::Namespaces::MAPPING)
167
+ assert_equal(nil, el.attributes["rdf:resource"])
168
+ assert_equal("literal", el.text)
169
+
170
+ end
171
+
172
+ def test_to_rdf_with_resource_removal
173
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |c|
174
+ c.add_removal( Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page") )
175
+ end
176
+ assert_equal(0, cs.additions.length)
177
+ assert_equal(1, cs.removals.length)
178
+
179
+ cs_el = get_changeset(cs.to_rdf)
180
+
181
+ removal = REXML::XPath.first(cs_el, "cs:removal", Pho::Namespaces::MAPPING)
182
+ assert_not_nil(removal)
183
+
184
+ statement = REXML::XPath.first(removal, "rdf:Statement", Pho::Namespaces::MAPPING)
185
+ assert_not_nil(statement)
186
+ el = REXML::XPath.first(statement, "rdf:subject", Pho::Namespaces::MAPPING)
187
+ assert_equal("http://www.example.org/my-resource", el.attributes["rdf:resource"])
188
+ el = REXML::XPath.first(statement, "rdf:predicate", Pho::Namespaces::MAPPING)
189
+ assert_equal("http://xmlns.com/foaf/0.1/homePage", el.attributes["rdf:resource"])
190
+ el = REXML::XPath.first(statement, "rdf:object", Pho::Namespaces::MAPPING)
191
+ assert_equal("http://www.example.org/page", el.attributes["rdf:resource"])
192
+ assert_equal(nil, el.text)
193
+
194
+ end
195
+
196
+ def test_submit_changeset
197
+ mc = mock()
198
+ mc.expects(:set_auth)
199
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta", "data", {"Content-Type" => "application/vnd.talis.changeset+xml"} )
200
+
201
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
202
+ resp = store.submit_changeset("data")
203
+ end
204
+
205
+ def test_submit_changeset_to_graph
206
+ mc = mock()
207
+ mc.expects(:set_auth)
208
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta/graphs/1", "data", {"Content-Type" => "application/vnd.talis.changeset+xml"} )
209
+
210
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
211
+ resp = store.submit_changeset("data", false, "1")
212
+
213
+ end
214
+
215
+ def test_submit_versioned_changeset
216
+ mc = mock()
217
+ mc.expects(:set_auth)
218
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta/changesets", "data", {"Content-Type" => "application/vnd.talis.changeset+xml"} )
219
+
220
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
221
+ resp = store.submit_changeset("data", true)
222
+ end
223
+
224
+ def test_submit_versioned_changeset_to_graph
225
+ mc = mock()
226
+ mc.expects(:set_auth)
227
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta/graphs/1/changesets", "data", {"Content-Type" => "application/vnd.talis.changeset+xml"} )
228
+
229
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
230
+ resp = store.submit_changeset("data", true, "1")
231
+ end
232
+
233
+
234
+ def test_submit
235
+ mc = mock()
236
+ mc.expects(:set_auth)
237
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta", anything, {"Content-Type" => "application/vnd.talis.changeset+xml"} )
238
+
239
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
240
+
241
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |c|
242
+ c.add_removal( Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page") )
243
+ end
244
+
245
+ resp = cs.submit(store)
246
+
247
+ end
248
+
249
+ def test_submit_versioned
250
+ mc = mock()
251
+ mc.expects(:set_auth)
252
+ mc.expects(:post).with("http://api.talis.com/stores/testing/meta/changesets", anything, {"Content-Type" => "application/vnd.talis.changeset+xml"} )
253
+
254
+ store = Pho::Store.new("http://api.talis.com/stores/testing", "user", "pass", mc)
255
+
256
+ cs = Pho::Update::Changeset.new("http://www.example.org/my-resource") do |c|
257
+ c.add_removal( Pho::Update::Statement.create_resource("http://www.example.org/my-resource", "http://xmlns.com/foaf/0.1/homePage", "http://www.example.org/page") )
258
+ end
259
+
260
+ resp = cs.submit(store, true)
261
+
262
+ end
263
+
264
+ #parse rdf, return root element
265
+ def parse(rdf)
266
+ doc = REXML::Document.new(rdf)
267
+ return doc.root()
268
+ end
269
+
270
+ #parse rdf/xml and retrieve the changeset element
271
+ def get_changeset(rdf)
272
+ root = parse(rdf)
273
+ return REXML::XPath.first(root, "cs:ChangeSet", Pho::Namespaces::MAPPING)
274
+ end
275
+ end