rubydora 0.5.10 → 0.5.11
Sign up to get free protection for your applications and to get access to all the features.
- data/History.textile +20 -0
- data/VERSION +1 -1
- data/lib/rubydora/digital_object.rb +21 -5
- data/lib/rubydora/rest_api_client.rb +135 -173
- data/lib/rubydora/transactions.rb +159 -0
- data/lib/rubydora.rb +2 -0
- data/rubydora.gemspec +2 -0
- data/spec/lib/integration_test_spec.rb +112 -0
- data/spec/lib/rest_api_client_spec.rb +39 -2
- data/spec/lib/transactions_spec.rb +126 -0
- data/spec/spec_helper.rb +1 -0
- metadata +37 -2
data/History.textile
CHANGED
@@ -1,3 +1,23 @@
|
|
1
|
+
h3. 0.5.11
|
2
|
+
* Ensure that the base rest resource is insulated from blocks passed to dissemination and datastream_dissemination.
|
3
|
+
* Deprecated a behavior for DigitalObject.find that allowed one to call DigitalObject.find for a non-existent object. This will raise an exception in a future rubydora release. Instead, you should use the new DigitalObject.find_or_initialize for that behavior.
|
4
|
+
* Use ActiveSupport::Rescuable for the REST API calls.
|
5
|
+
* Implement a basic form of "transactions" in Rubydora, intended to be used during testing. It uses the new REST API hooks and knows how to roll-back the different data-changing operations. In some cases, this involves deleting and re-ingesting the previous version of the object (purge, modify datastream, purge datastream), which make it unsuitable for production use, especially with large content datastreams.
|
6
|
+
|
7
|
+
At Stanford, we've hooked it into our rspec tests as an around filter:
|
8
|
+
bc. RSpec.configure do |config|
|
9
|
+
…
|
10
|
+
config.around(:each) do |example|
|
11
|
+
ActiveFedora::Base.connection_for_pid(0).transaction do |t|
|
12
|
+
example.call
|
13
|
+
t.rollback
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
h3. 0.5.10
|
19
|
+
* Support for content_changed? and content_will_change!
|
20
|
+
|
1
21
|
h3. 0.5.9
|
2
22
|
* Raise exception if it's not 404
|
3
23
|
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.5.
|
1
|
+
0.5.11
|
@@ -16,6 +16,10 @@ module Rubydora
|
|
16
16
|
include Rubydora::ModelsMixin
|
17
17
|
include Rubydora::RelationshipsMixin
|
18
18
|
|
19
|
+
extend Deprecation
|
20
|
+
|
21
|
+
self.deprecation_horizon = 'rubydora 0.6'
|
22
|
+
|
19
23
|
|
20
24
|
attr_reader :pid
|
21
25
|
|
@@ -44,7 +48,23 @@ module Rubydora
|
|
44
48
|
# @param [String] pid
|
45
49
|
# @param [Rubydora::Repository] context
|
46
50
|
def self.find pid, repository = nil, options = {}
|
47
|
-
self.new pid, repository, options
|
51
|
+
obj = self.new pid, repository, options
|
52
|
+
if obj.new?
|
53
|
+
Deprecation.warn(Rubydora::DigitalObject, "DigitalObject.find called
|
54
|
+
for an object that doesn't exist. In #{Rubydora::DigitalObject.deprecation_horizon},
|
55
|
+
this behavior will raise an exception. Use
|
56
|
+
DigitalObject.new or DigitalObject.find_or_initialize instead.")
|
57
|
+
end
|
58
|
+
|
59
|
+
obj
|
60
|
+
end
|
61
|
+
|
62
|
+
# find or initialize a Fedora object
|
63
|
+
# @param [String] pid
|
64
|
+
# @param [Rubydora::Repository] repository context
|
65
|
+
# @param [Hash] options default attribute values (used esp. for creating new datastreams
|
66
|
+
def self.find_or_initialize *args
|
67
|
+
self.new *args
|
48
68
|
end
|
49
69
|
|
50
70
|
# create a new fedora object (see also DigitalObject#save)
|
@@ -258,10 +278,6 @@ module Rubydora
|
|
258
278
|
raise "Can't change values on older versions" if @asOfDateTime
|
259
279
|
end
|
260
280
|
|
261
|
-
def check_if_read_only
|
262
|
-
raise "Can't change values on older versions" if @asOfDateTime
|
263
|
-
end
|
264
|
-
|
265
281
|
private
|
266
282
|
def attribute_will_change! *args
|
267
283
|
check_if_read_only
|
@@ -1,4 +1,7 @@
|
|
1
1
|
require 'active_support/core_ext/hash/indifferent_access'
|
2
|
+
require 'active_support/core_ext/class'
|
3
|
+
require 'active_support/core_ext/module'
|
4
|
+
require 'hooks'
|
2
5
|
|
3
6
|
module Rubydora
|
4
7
|
|
@@ -6,17 +9,42 @@ module Rubydora
|
|
6
9
|
module RestApiClient
|
7
10
|
|
8
11
|
include Rubydora::FedoraUrlHelpers
|
12
|
+
extend ActiveSupport::Concern
|
9
13
|
include ActiveSupport::Benchmarkable
|
10
14
|
|
15
|
+
|
11
16
|
VALID_CLIENT_OPTIONS = [:user, :password, :timeout, :open_timeout, :ssl_client_cert, :ssl_client_key]
|
17
|
+
|
18
|
+
included do
|
19
|
+
include ActiveSupport::Rescuable
|
20
|
+
|
21
|
+
|
22
|
+
rescue_from RestClient::InternalServerError do |e|
|
23
|
+
logger.error e.response
|
24
|
+
logger.flush if logger.respond_to? :flush
|
25
|
+
raise FedoraInvalidRequest, "See logger for details"
|
26
|
+
end
|
27
|
+
|
28
|
+
rescue_from Errno::ECONNREFUSED, Errno::EHOSTUNREACH do |exception|
|
29
|
+
logger.error "Unable to connect to Fedora at #{@client.url}"
|
30
|
+
raise exception
|
31
|
+
end
|
32
|
+
|
33
|
+
include Hooks
|
34
|
+
[:ingest, :modify_object, :purge_object, :set_datastream_options, :add_datastream, :modify_datastream, :purge_datastream, :add_relationship, :purge_relationship].each do |h|
|
35
|
+
define_hook "before_#{h}"
|
36
|
+
end
|
37
|
+
|
38
|
+
define_hook "after_ingest"
|
39
|
+
include Transactions
|
40
|
+
end
|
41
|
+
|
12
42
|
# Create an authorized HTTP client for the Fedora REST API
|
13
43
|
# @param [Hash] config
|
14
44
|
# @option config [String] :url
|
15
45
|
# @option config [String] :user
|
16
46
|
# @option config [String] :password
|
17
47
|
# @return [RestClient::Resource]
|
18
|
-
|
19
|
-
|
20
48
|
#TODO trap for these errors specifically: RestClient::Request::Unauthorized, Errno::ECONNREFUSED
|
21
49
|
def client config = {}
|
22
50
|
client_config = self.config.merge(config)
|
@@ -37,13 +65,9 @@ module Rubydora
|
|
37
65
|
# @return [String]
|
38
66
|
def next_pid options = {}
|
39
67
|
options[:format] ||= 'xml'
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
logger.error e.response
|
44
|
-
logger.flush if logger.respond_to? :flush
|
45
|
-
raise FedoraInvalidRequest, "Error getting nextPID. See logger for details"
|
46
|
-
end
|
68
|
+
client[next_pid_url(options)].post nil
|
69
|
+
rescue Exception => exception
|
70
|
+
rescue_with_handler(exception) || raise
|
47
71
|
end
|
48
72
|
|
49
73
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -53,17 +77,13 @@ module Rubydora
|
|
53
77
|
raise ArgumentError,"Cannot have both :terms and :query parameters" if options[:terms] and options[:query]
|
54
78
|
options[:resultFormat] ||= 'xml'
|
55
79
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
logger.error e.response
|
64
|
-
logger.flush if logger.respond_to? :flush
|
65
|
-
raise FedoraInvalidRequest, "Error finding objects. See logger for details"
|
66
|
-
end
|
80
|
+
resource = client[find_objects_url(options)]
|
81
|
+
if block_given?
|
82
|
+
resource.options[:block_response] = block_response
|
83
|
+
end
|
84
|
+
return resource.get
|
85
|
+
rescue Exception => exception
|
86
|
+
rescue_with_handler(exception) || raise
|
67
87
|
end
|
68
88
|
|
69
89
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -73,15 +93,9 @@ module Rubydora
|
|
73
93
|
def object options = {}
|
74
94
|
pid = options.delete(:pid)
|
75
95
|
options[:format] ||= 'xml'
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
raise e
|
80
|
-
rescue RestClient::InternalServerError => e
|
81
|
-
logger.error e.response
|
82
|
-
logger.flush if logger.respond_to? :flush
|
83
|
-
raise FedoraInvalidRequest, "Error getting object #{pid}. See logger for details"
|
84
|
-
end
|
96
|
+
client[object_url(pid, options)].get
|
97
|
+
rescue Exception => exception
|
98
|
+
rescue_with_handler(exception) || raise
|
85
99
|
end
|
86
100
|
|
87
101
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -91,16 +105,11 @@ module Rubydora
|
|
91
105
|
def ingest options = {}
|
92
106
|
pid = options.delete(:pid) || 'new'
|
93
107
|
file = options.delete(:file)
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
raise
|
99
|
-
rescue RestClient::InternalServerError => e
|
100
|
-
logger.error e.response
|
101
|
-
logger.flush if logger.respond_to? :flush
|
102
|
-
raise FedoraInvalidRequest, "Error ingesting object #{pid}. See logger for details"
|
103
|
-
end
|
108
|
+
assigned_pid = client[object_url(pid, options)].post file, :content_type => 'text/xml'
|
109
|
+
run_hook :after_ingest, :pid => assigned_pid, :file => file, :options => options
|
110
|
+
assigned_pid
|
111
|
+
rescue Exception => exception
|
112
|
+
rescue_with_handler(exception) || raise
|
104
113
|
end
|
105
114
|
|
106
115
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -109,12 +118,9 @@ module Rubydora
|
|
109
118
|
# @return [String]
|
110
119
|
def export options = {}
|
111
120
|
pid = options.delete(:pid)
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
logger.error e.response
|
116
|
-
raise FedoraInvalidRequest, "Error exporting object #{pid}. See logger for details"
|
117
|
-
end
|
121
|
+
client[export_object_url(pid, options)].get
|
122
|
+
rescue Exception => exception
|
123
|
+
rescue_with_handler(exception) || raise
|
118
124
|
end
|
119
125
|
|
120
126
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -123,13 +129,10 @@ module Rubydora
|
|
123
129
|
# @return [String]
|
124
130
|
def modify_object options = {}
|
125
131
|
pid = options.delete(:pid)
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
logger.flush if logger.respond_to? :flush
|
131
|
-
raise FedoraInvalidRequest, "Error modifying object #{pid}. See logger for details"
|
132
|
-
end
|
132
|
+
run_hook :before_modify_object, :pid => pid, :options => options
|
133
|
+
client[object_url(pid, options)].put nil
|
134
|
+
rescue Exception => exception
|
135
|
+
rescue_with_handler(exception) || raise
|
133
136
|
end
|
134
137
|
|
135
138
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -138,15 +141,10 @@ module Rubydora
|
|
138
141
|
# @return [String]
|
139
142
|
def purge_object options = {}
|
140
143
|
pid = options.delete(:pid)
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
raise
|
145
|
-
rescue RestClient::InternalServerError => e
|
146
|
-
logger.error e.response
|
147
|
-
logger.flush if logger.respond_to? :flush
|
148
|
-
raise FedoraInvalidRequest, "Error purging object #{pid}. See logger for details"
|
149
|
-
end
|
144
|
+
run_hook :before_purge_object, :pid => pid, :options => options
|
145
|
+
client[object_url(pid, options)].delete
|
146
|
+
rescue Exception => exception
|
147
|
+
rescue_with_handler(exception) || raise
|
150
148
|
end
|
151
149
|
|
152
150
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -157,13 +155,9 @@ module Rubydora
|
|
157
155
|
pid = options.delete(:pid)
|
158
156
|
options[:format] ||= 'xml'
|
159
157
|
raise ArgumentError, "Must have a pid" unless pid
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
logger.error e.response
|
164
|
-
logger.flush if logger.respond_to? :flush
|
165
|
-
raise FedoraInvalidRequest, "Error getting versions for object #{pid}. See logger for details"
|
166
|
-
end
|
158
|
+
client[object_versions_url(pid, options)].get
|
159
|
+
rescue Exception => exception
|
160
|
+
rescue_with_handler(exception) || raise
|
167
161
|
end
|
168
162
|
|
169
163
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -174,13 +168,9 @@ module Rubydora
|
|
174
168
|
pid = options.delete(:pid)
|
175
169
|
raise ArgumentError, "Missing required parameter :pid" unless pid
|
176
170
|
options[:format] ||= 'xml'
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
logger.error e.response
|
181
|
-
logger.flush if logger.respond_to? :flush
|
182
|
-
raise FedoraInvalidRequest, "Error getting objectXML for object #{pid}. See logger for details"
|
183
|
-
end
|
171
|
+
client[object_xml_url(pid, options)].get
|
172
|
+
rescue Exception => exception
|
173
|
+
rescue_with_handler(exception) || raise
|
184
174
|
end
|
185
175
|
|
186
176
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -194,26 +184,18 @@ module Rubydora
|
|
194
184
|
pid = options.delete(:pid)
|
195
185
|
dsid = options.delete(:dsid)
|
196
186
|
options[:format] ||= 'xml'
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
val = client[datastream_url(pid, dsid, options)].get
|
202
|
-
end
|
203
|
-
return val
|
204
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH => e
|
205
|
-
logger.error "Unable to connect to Fedora at #{@client.url}"
|
206
|
-
raise e
|
207
|
-
rescue RestClient::ResourceNotFound => e
|
208
|
-
raise e
|
209
|
-
rescue RestClient::Unauthorized => e
|
210
|
-
logger.error "Unauthorized at #{client.url}/#{datastream_url(pid, dsid, options)}"
|
211
|
-
raise e
|
212
|
-
rescue RestClient::InternalServerError => e
|
213
|
-
logger.error e.response
|
214
|
-
logger.flush if logger.respond_to? :flush
|
215
|
-
raise FedoraInvalidRequest, "Error getting datastream '#{dsid}' for object #{pid}. See logger for details"
|
187
|
+
val = nil
|
188
|
+
message = dsid.nil? ? "Loaded datastream list for #{pid}" : "Loaded datastream #{pid}/#{dsid}"
|
189
|
+
benchmark message, :level=>:debug do
|
190
|
+
val = client[datastream_url(pid, dsid, options)].get
|
216
191
|
end
|
192
|
+
|
193
|
+
val
|
194
|
+
rescue RestClient::Unauthorized => e
|
195
|
+
logger.error "Unauthorized at #{client.url}/#{datastream_url(pid, dsid, options)}"
|
196
|
+
raise e
|
197
|
+
rescue Exception => exception
|
198
|
+
rescue_with_handler(exception) || raise
|
217
199
|
end
|
218
200
|
|
219
201
|
alias_method :datastreams, :datastream
|
@@ -226,13 +208,10 @@ module Rubydora
|
|
226
208
|
def set_datastream_options options = {}
|
227
209
|
pid = options.delete(:pid)
|
228
210
|
dsid = options.delete(:dsid)
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
logger.flush if logger.respond_to? :flush
|
234
|
-
raise FedoraInvalidRequest, "Error setting datastream options on #{dsid} for object #{pid}. See logger for details"
|
235
|
-
end
|
211
|
+
run_hook :before_set_datastream_options, :pid => pid, :dsid => dsid, :options => options
|
212
|
+
client[datastream_url(pid, dsid, options)].put nil
|
213
|
+
rescue Exception => exception
|
214
|
+
rescue_with_handler(exception) || raise
|
236
215
|
end
|
237
216
|
|
238
217
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -245,16 +224,12 @@ module Rubydora
|
|
245
224
|
dsid = options.delete(:dsid)
|
246
225
|
raise ArgumentError, "Must supply dsid" unless dsid
|
247
226
|
options[:format] ||= 'xml'
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
logger.error e.response
|
255
|
-
logger.flush if logger.respond_to? :flush
|
256
|
-
raise FedoraInvalidRequest, "Error getting versions for datastream #{dsid} for object #{pid}. See logger for details"
|
257
|
-
end
|
227
|
+
client[datastream_history_url(pid, dsid, options)].get
|
228
|
+
rescue RestClient::ResourceNotFound => e
|
229
|
+
#404 Resource Not Found: No datastream history could be found. There is no datastream history for the digital object "changeme:1" with datastream ID of "descMetadata
|
230
|
+
return nil
|
231
|
+
rescue Exception => exception
|
232
|
+
rescue_with_handler(exception) || raise
|
258
233
|
end
|
259
234
|
|
260
235
|
alias_method :datastream_history, :datastream_versions
|
@@ -270,19 +245,14 @@ module Rubydora
|
|
270
245
|
method = options.delete(:method)
|
271
246
|
method ||= :get
|
272
247
|
raise self.class.name + "#datastream_dissemination requires a DSID" unless dsid
|
273
|
-
|
248
|
+
if block_given?
|
249
|
+
resource = safe_subresource(datastream_content_url(pid, dsid, options), :block_response => block_response)
|
250
|
+
else
|
274
251
|
resource = client[datastream_content_url(pid, dsid, options)]
|
275
|
-
if block_given?
|
276
|
-
resource.options[:block_response] = block_response
|
277
|
-
end
|
278
|
-
return resource.send(method)
|
279
|
-
rescue RestClient::ResourceNotFound => e
|
280
|
-
raise e
|
281
|
-
rescue RestClient::InternalServerError => e
|
282
|
-
logger.error e.response
|
283
|
-
logger.flush if logger.respond_to? :flush
|
284
|
-
raise FedoraInvalidRequest, "Error getting dissemination for datastream #{dsid} for object #{pid}. See logger for details"
|
285
252
|
end
|
253
|
+
resource.send(method)
|
254
|
+
rescue Exception => exception
|
255
|
+
rescue_with_handler(exception) || raise
|
286
256
|
end
|
287
257
|
|
288
258
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -295,13 +265,10 @@ module Rubydora
|
|
295
265
|
dsid = options.delete(:dsid)
|
296
266
|
file = options.delete(:content)
|
297
267
|
content_type = options.delete(:content_type) || options[:mimeType] || (MIME::Types.type_for(file.path).first if file.respond_to? :path) || 'application/octet-stream'
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
logger.flush if logger.respond_to? :flush
|
303
|
-
raise FedoraInvalidRequest, "Error adding datastream #{dsid} for object #{pid}. See logger for details"
|
304
|
-
end
|
268
|
+
run_hook :before_add_datastream, :pid => pid, :dsid => dsid, :file => file, :options => options
|
269
|
+
client[datastream_url(pid, dsid, options)].post file, :content_type => content_type.to_s, :multipart => true
|
270
|
+
rescue Exception => exception
|
271
|
+
rescue_with_handler(exception) || raise
|
305
272
|
end
|
306
273
|
|
307
274
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -321,13 +288,11 @@ module Rubydora
|
|
321
288
|
rest_client_options[:content_type] = content_type
|
322
289
|
end
|
323
290
|
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
raise FedoraInvalidRequest, "Error modifying datastream #{dsid} for #{pid}. See logger for details"
|
330
|
-
end
|
291
|
+
run_hook :before_modify_datastream, :pid => pid, :dsid => dsid, :file => file, :content_type => content_type, :options => options
|
292
|
+
client[datastream_url(pid, dsid, options)].put(file, rest_client_options)
|
293
|
+
|
294
|
+
rescue Exception => exception
|
295
|
+
rescue_with_handler(exception) || raise
|
331
296
|
end
|
332
297
|
|
333
298
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -338,13 +303,10 @@ module Rubydora
|
|
338
303
|
def purge_datastream options = {}
|
339
304
|
pid = options.delete(:pid)
|
340
305
|
dsid = options.delete(:dsid)
|
341
|
-
|
342
|
-
|
343
|
-
|
344
|
-
|
345
|
-
logger.flush if logger.respond_to? :flush
|
346
|
-
raise FedoraInvalidRequest, "Error purging datastream #{dsid} for #{pid}. See logger for details"
|
347
|
-
end
|
306
|
+
run_hook :before_purge_datastream, :pid => pid, :dsid => dsid
|
307
|
+
client[datastream_url(pid, dsid, options)].delete
|
308
|
+
rescue Exception => exception
|
309
|
+
rescue_with_handler(exception) || raise
|
348
310
|
end
|
349
311
|
|
350
312
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -355,13 +317,9 @@ module Rubydora
|
|
355
317
|
pid = options.delete(:pid) || options[:subject]
|
356
318
|
raise ArgumentError, "Missing required parameter :pid" unless pid
|
357
319
|
options[:format] ||= 'xml'
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
logger.error e.response
|
362
|
-
logger.flush if logger.respond_to? :flush
|
363
|
-
raise FedoraInvalidRequest, "Error getting relationships for #{pid}. See logger for details"
|
364
|
-
end
|
320
|
+
client[object_relationship_url(pid, options)].get
|
321
|
+
rescue Exception => exception
|
322
|
+
rescue_with_handler(exception) || raise
|
365
323
|
end
|
366
324
|
|
367
325
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -370,13 +328,10 @@ module Rubydora
|
|
370
328
|
# @return [String]
|
371
329
|
def add_relationship options = {}
|
372
330
|
pid = options.delete(:pid) || options[:subject]
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
logger.flush if logger.respond_to? :flush
|
378
|
-
raise FedoraInvalidRequest, "Error adding relationship for #{pid}. See logger for details"
|
379
|
-
end
|
331
|
+
run_hook :before_add_relationship, :pid => pid, :options => options
|
332
|
+
client[new_object_relationship_url(pid, options)].post nil
|
333
|
+
rescue Exception => exception
|
334
|
+
rescue_with_handler(exception) || raise
|
380
335
|
end
|
381
336
|
|
382
337
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -385,13 +340,10 @@ module Rubydora
|
|
385
340
|
# @return [String]
|
386
341
|
def purge_relationship options = {}
|
387
342
|
pid = options.delete(:pid) || options[:subject]
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
392
|
-
logger.flush if logger.respond_to? :flush
|
393
|
-
raise FedoraInvalidRequest, "Error purging relationships for #{pid}. See logger for details"
|
394
|
-
end
|
343
|
+
run_hook :before_purge_relationship, :pid => pid, :options => options
|
344
|
+
client[object_relationship_url(pid, options)].delete
|
345
|
+
rescue Exception => exception
|
346
|
+
rescue_with_handler(exception) || raise
|
395
347
|
end
|
396
348
|
|
397
349
|
# {include:RestApiClient::API_DOCUMENTATION}
|
@@ -405,16 +357,26 @@ module Rubydora
|
|
405
357
|
sdef = options.delete(:sdef)
|
406
358
|
method = options.delete(:method)
|
407
359
|
options[:format] ||= 'xml' unless pid and sdef and method
|
408
|
-
|
360
|
+
if block_given?
|
361
|
+
resource = safe_subresource(dissemination_url(pid,sdef,method,options), :block_response => block_response)
|
362
|
+
else
|
409
363
|
resource = client[dissemination_url(pid,sdef,method,options)]
|
410
|
-
|
411
|
-
|
412
|
-
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
364
|
+
end
|
365
|
+
resource.get
|
366
|
+
|
367
|
+
rescue Exception => exception
|
368
|
+
rescue_with_handler(exception) || raise
|
369
|
+
|
370
|
+
end
|
371
|
+
|
372
|
+
def safe_subresource(subresource, options=Hash.new)
|
373
|
+
url = client.concat_urls(client.url, subresource)
|
374
|
+
options = client.options.dup.merge! options
|
375
|
+
block = client.block
|
376
|
+
if block
|
377
|
+
client.class.new(url, options, &block)
|
378
|
+
else
|
379
|
+
client.class.new(url, options)
|
418
380
|
end
|
419
381
|
end
|
420
382
|
end
|
@@ -0,0 +1,159 @@
|
|
1
|
+
module Rubydora
|
2
|
+
# Extremely basic (and naive) 'transaction' support for Rubydora. This isn't
|
3
|
+
# really intended to be used in a production-like situation -- more for
|
4
|
+
# rolling back (small) changes during testing.
|
5
|
+
module Transactions
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
class << self
|
9
|
+
attr_accessor :use_transactions
|
10
|
+
end
|
11
|
+
|
12
|
+
included do
|
13
|
+
after_ingest do |options|
|
14
|
+
append_to_transactions_log :ingest, options if Rubydora::Transactions.use_transactions
|
15
|
+
end
|
16
|
+
|
17
|
+
before_purge_object do |options|
|
18
|
+
append_to_transactions_log :purge_object, :pid => options[:pid], :foxml => export(:pid => options[:pid], :context => :archive) if Rubydora::Transactions.use_transactions
|
19
|
+
end
|
20
|
+
|
21
|
+
before_modify_datastream do |options|
|
22
|
+
append_to_transactions_log :modify_datastream, :pid => options[:pid], :foxml => export(:pid => options[:pid], :context => :archive) if Rubydora::Transactions.use_transactions
|
23
|
+
end
|
24
|
+
|
25
|
+
before_purge_datastream do |options|
|
26
|
+
append_to_transactions_log :purge_datastream, :pid => options[:pid], :foxml => export(:pid => options[:pid], :context => :archive) if Rubydora::Transactions.use_transactions
|
27
|
+
end
|
28
|
+
|
29
|
+
before_add_datastream do |options|
|
30
|
+
append_to_transactions_log :add_datastream, options if Rubydora::Transactions.use_transactions
|
31
|
+
end
|
32
|
+
|
33
|
+
before_add_relationship do |options|
|
34
|
+
append_to_transactions_log :add_relationship, options if Rubydora::Transactions.use_transactions
|
35
|
+
end
|
36
|
+
|
37
|
+
before_purge_relationship do |options|
|
38
|
+
append_to_transactions_log :purge_relationship, options if Rubydora::Transactions.use_transactions
|
39
|
+
end
|
40
|
+
|
41
|
+
before_modify_object do |options|
|
42
|
+
if Rubydora::Transactions.use_transactions
|
43
|
+
obj = find(options[:pid])
|
44
|
+
append_to_transactions_log :modify_object, :pid => options[:pid], :state => obj.state, :ownerId => obj.ownerId, :logMessage => 'reverting'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
before_set_datastream_options do |options|
|
49
|
+
if Rubydora::Transactions.use_transactions
|
50
|
+
obj = find(options[:pid])
|
51
|
+
ds = obj.datastreams[options[:dsid]]
|
52
|
+
|
53
|
+
if options[:options][:versionable]
|
54
|
+
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :versionable => ds.versionable
|
55
|
+
end
|
56
|
+
|
57
|
+
if options[:options][:state]
|
58
|
+
append_to_transactions_log :set_datastream_options, :pid => options[:pid], :dsid => options[:dsid], :state => ds.state
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
|
66
|
+
# Start a transaction
|
67
|
+
def transaction &block
|
68
|
+
Transaction.new self, &block
|
69
|
+
self.transactions_log.clear
|
70
|
+
end
|
71
|
+
|
72
|
+
# Unshift a transaction entry onto the transaction logs.
|
73
|
+
# We want these entries in reverse-chronological order
|
74
|
+
# for ease of undoing..
|
75
|
+
def append_to_transactions_log *args
|
76
|
+
return unless Rubydora::Transactions.use_transactions
|
77
|
+
transactions_log.unshift(args)
|
78
|
+
end
|
79
|
+
|
80
|
+
# The repository transaction log.
|
81
|
+
def transactions_log
|
82
|
+
@log ||= []
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class Transaction
|
87
|
+
attr_reader :repository
|
88
|
+
def initialize repository, &block
|
89
|
+
@repository = repository
|
90
|
+
with_transactions(&block)
|
91
|
+
end
|
92
|
+
|
93
|
+
def with_transactions &block
|
94
|
+
old_state = Rubydora::Transactions.use_transactions
|
95
|
+
Rubydora::Transactions.use_transactions = true
|
96
|
+
|
97
|
+
yield(self)
|
98
|
+
|
99
|
+
Rubydora::Transactions.use_transactions = old_state
|
100
|
+
end
|
101
|
+
|
102
|
+
def without_transactions &block
|
103
|
+
old_state = Rubydora::Transactions.use_transactions
|
104
|
+
Rubydora::Transactions.use_transactions = false
|
105
|
+
|
106
|
+
yield(self)
|
107
|
+
|
108
|
+
Rubydora::Transactions.use_transactions = old_state
|
109
|
+
end
|
110
|
+
|
111
|
+
# Roll-back transactions by reversing their outcomes
|
112
|
+
# (or, in some cases, re-ingesting the object at the
|
113
|
+
# previous state.
|
114
|
+
def rollback
|
115
|
+
without_transactions do
|
116
|
+
repository.transactions_log.delete_if do |(method, options)|
|
117
|
+
|
118
|
+
begin
|
119
|
+
case method
|
120
|
+
when :ingest
|
121
|
+
repository.purge_object :pid => options[:pid]
|
122
|
+
|
123
|
+
when :modify_object
|
124
|
+
repository.modify_object options
|
125
|
+
|
126
|
+
when :add_datastream
|
127
|
+
repository.purge_datastream :pid => options[:pid], :dsid => options[:dsid]
|
128
|
+
|
129
|
+
when :add_relationship
|
130
|
+
repository.purge_relationship options[:options].merge(:pid => options[:pid])
|
131
|
+
|
132
|
+
when :purge_relationship
|
133
|
+
repository.add_relationship options[:options].merge(:pid => options[:pid])
|
134
|
+
|
135
|
+
when :purge_object
|
136
|
+
repository.ingest :pid => options[:pid], :file => options[:foxml]
|
137
|
+
|
138
|
+
when :set_datastream_options
|
139
|
+
repository.set_datastream_options options
|
140
|
+
|
141
|
+
when :modify_datastream
|
142
|
+
repository.purge_object :pid => options[:pid] rescue nil
|
143
|
+
repository.ingest :pid => options[:pid], :file => options[:foxml]
|
144
|
+
|
145
|
+
when :purge_datastream
|
146
|
+
repository.purge_object :pid => options[:pid] rescue nil
|
147
|
+
repository.ingest :pid => options[:pid], :file => options[:foxml]
|
148
|
+
end
|
149
|
+
rescue
|
150
|
+
# no-op
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
end
|
155
|
+
true
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
end
|
data/lib/rubydora.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
1
|
# Fedora Commons REST API module
|
2
2
|
require 'active_model'
|
3
|
+
require 'deprecation'
|
3
4
|
|
4
5
|
module Rubydora
|
5
6
|
autoload :Datastream, "rubydora/datastream"
|
@@ -15,6 +16,7 @@ module Rubydora
|
|
15
16
|
autoload :ExtensionParameters, "rubydora/extension_parameters"
|
16
17
|
autoload :Callbacks, "rubydora/callbacks"
|
17
18
|
autoload :ArrayWithCallback, "rubydora/array_with_callback"
|
19
|
+
autoload :Transactions, "rubydora/transactions"
|
18
20
|
|
19
21
|
|
20
22
|
require 'csv'
|
data/rubydora.gemspec
CHANGED
@@ -23,6 +23,8 @@ Gem::Specification.new do |s|
|
|
23
23
|
s.add_dependency "activesupport"
|
24
24
|
s.add_dependency "activemodel"
|
25
25
|
s.add_dependency "savon"
|
26
|
+
s.add_dependency "hooks"
|
27
|
+
s.add_dependency "deprecation"
|
26
28
|
|
27
29
|
s.add_development_dependency("rake")
|
28
30
|
s.add_development_dependency("shoulda")
|
@@ -15,6 +15,23 @@ describe "Integration testing against a live Fedora repository", :integration =>
|
|
15
15
|
@repository.ping.should == true
|
16
16
|
end
|
17
17
|
|
18
|
+
it "should ingest from foxml" do
|
19
|
+
@repository.find('changeme:n').delete rescue nil
|
20
|
+
pid = @repository.ingest :pid => 'changeme:n'
|
21
|
+
|
22
|
+
pid.should == 'changeme:n'
|
23
|
+
|
24
|
+
obj = @repository.find(pid)
|
25
|
+
obj.should_not be_new
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should ingest from foxml" do
|
29
|
+
pid = @repository.ingest :pid => 'new'
|
30
|
+
|
31
|
+
obj = @repository.find(pid)
|
32
|
+
obj.should_not be_new
|
33
|
+
@repository.find(pid).delete rescue nil
|
34
|
+
end
|
18
35
|
|
19
36
|
it "should create an object" do
|
20
37
|
obj = @repository.find('test:1')
|
@@ -138,6 +155,101 @@ describe "Integration testing against a live Fedora repository", :integration =>
|
|
138
155
|
obj.datastreams["my_ds"].mimeType.should == "application/x-text"
|
139
156
|
end
|
140
157
|
|
158
|
+
describe "with transactions" do
|
159
|
+
it "should work on ingest" do
|
160
|
+
@repository.find('transactions:1').delete rescue nil
|
161
|
+
|
162
|
+
@repository.transaction do |t|
|
163
|
+
obj = @repository.find('transactions:1')
|
164
|
+
obj.save
|
165
|
+
|
166
|
+
t.rollback
|
167
|
+
end
|
168
|
+
|
169
|
+
obj = @repository.find('transactions:1')
|
170
|
+
obj.should be_new
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should work on purge" do
|
174
|
+
@repository.find('transactions:1').delete rescue nil
|
175
|
+
|
176
|
+
obj = @repository.find('transactions:1')
|
177
|
+
obj.save
|
178
|
+
|
179
|
+
@repository.transaction do |t|
|
180
|
+
obj.delete
|
181
|
+
|
182
|
+
t.rollback
|
183
|
+
end
|
184
|
+
|
185
|
+
obj = @repository.find('transactions:1')
|
186
|
+
obj.should_not be_new
|
187
|
+
end
|
188
|
+
|
189
|
+
it "should work on datastreams" do
|
190
|
+
@repository.find('transactions:1').delete rescue nil
|
191
|
+
|
192
|
+
obj = @repository.find('transactions:1')
|
193
|
+
obj.save
|
194
|
+
|
195
|
+
ds = obj.datastreams['datastream_to_delete']
|
196
|
+
ds.content = 'asdf'
|
197
|
+
ds.save
|
198
|
+
|
199
|
+
ds2 = obj.datastreams['datastream_to_change']
|
200
|
+
ds2.content = 'asdf'
|
201
|
+
ds2.save
|
202
|
+
|
203
|
+
ds3 = obj.datastreams['datastream_to_change_properties']
|
204
|
+
ds3.content = 'asdf'
|
205
|
+
ds3.versionable = true
|
206
|
+
ds3.dsState = 'I'
|
207
|
+
ds3.save
|
208
|
+
|
209
|
+
@repository.transaction do |t|
|
210
|
+
ds.delete
|
211
|
+
|
212
|
+
ds2.content = '1234'
|
213
|
+
ds2.save
|
214
|
+
|
215
|
+
@repository.set_datastream_options :pid => obj.pid, :dsid => 'datastream_to_change_properties', :state => 'A'
|
216
|
+
@repository.set_datastream_options :pid => obj.pid, :dsid => 'datastream_to_change_properties', :versionable => false
|
217
|
+
|
218
|
+
ds4 = obj.datastreams['datastream_to_create']
|
219
|
+
ds4.content = 'asdf'
|
220
|
+
ds4.save
|
221
|
+
|
222
|
+
t.rollback
|
223
|
+
end
|
224
|
+
|
225
|
+
obj = @repository.find('transactions:1')
|
226
|
+
obj.datastreams.keys.should_not include('datsatream_to_create')
|
227
|
+
obj.datastreams.keys.should include('datastream_to_delete')
|
228
|
+
obj.datastreams['datastream_to_change'].content.should == 'asdf'
|
229
|
+
obj.datastreams['datastream_to_change_properties'].versionable.should == true
|
230
|
+
obj.datastreams['datastream_to_change_properties'].dsState.should == 'I'
|
231
|
+
end
|
232
|
+
|
233
|
+
it "should work on relationships" do
|
234
|
+
@repository.find('transactions:1').delete rescue nil
|
235
|
+
|
236
|
+
obj = @repository.find('transactions:1')
|
237
|
+
obj.save
|
238
|
+
@repository.add_relationship :subject => obj.pid, :predicate => 'uri:asdf', :object => 'fedora:object'
|
239
|
+
|
240
|
+
ds = obj.datastreams['RELS-EXT'].content
|
241
|
+
|
242
|
+
@repository.transaction do |t|
|
243
|
+
@repository.purge_relationship :subject => obj.pid, :predicate => 'uri:asdf', :object => 'fedora:object'
|
244
|
+
@repository.add_relationship :subject => obj.pid, :predicate => 'uri:qwerty', :object => 'fedora:object'
|
245
|
+
|
246
|
+
t.rollback
|
247
|
+
|
248
|
+
end
|
249
|
+
obj = @repository.find('transactions:1')
|
250
|
+
obj.datastreams['RELS-EXT'].content.should == ds
|
251
|
+
end
|
252
|
+
end
|
141
253
|
|
142
254
|
describe "object versions" do
|
143
255
|
it "should have versions" do
|
@@ -1,15 +1,52 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'loggable'
|
3
2
|
|
4
3
|
describe Rubydora::RestApiClient do
|
4
|
+
class FakeException < Exception
|
5
|
+
|
6
|
+
end
|
5
7
|
class MockRepository
|
6
8
|
include Rubydora::RestApiClient
|
7
9
|
include Loggable
|
8
10
|
|
9
|
-
|
10
11
|
attr_accessor :config
|
11
12
|
end
|
12
13
|
|
14
|
+
|
15
|
+
|
16
|
+
describe "exception handling" do
|
17
|
+
|
18
|
+
shared_examples "RestClient error handling" do
|
19
|
+
subject {
|
20
|
+
mock_repository = MockRepository.new
|
21
|
+
mock_repository.config = { :url => 'http://example.org' }
|
22
|
+
|
23
|
+
mock_repository
|
24
|
+
}
|
25
|
+
|
26
|
+
it "should replace a RestClient exception with a Rubydora one" do
|
27
|
+
subject.stub_chain(:client, :[], :get).and_raise RestClient::InternalServerError.new
|
28
|
+
subject.stub_chain(:client, :[], :put).and_raise RestClient::InternalServerError.new
|
29
|
+
subject.stub_chain(:client, :[], :delete).and_raise RestClient::InternalServerError.new
|
30
|
+
subject.stub_chain(:client, :[], :post).and_raise RestClient::InternalServerError.new
|
31
|
+
expect { subject.send(method, :pid => 'fake:pid', :dsid => 'my_dsid') }.to raise_error Rubydora::FedoraInvalidRequest
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
[:next_pid, :find_objects, :object, :ingest, :export, :modify_object, :purge_object, :object_versions, :object_xml, :datastream, :datastreams, :set_datastream_options, :datastream_versions, :datastream_history, :datastream_dissemination, :add_datastream, :modify_datastream, :purge_datastream, :relationships, :add_relationship, :purge_relationship, :dissemination].each do |method|
|
36
|
+
|
37
|
+
class_eval %Q{
|
38
|
+
describe "##{method}" do
|
39
|
+
it_behaves_like "RestClient error handling"
|
40
|
+
let(:method) { '#{method}' }
|
41
|
+
end
|
42
|
+
}
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
|
49
|
+
|
13
50
|
before(:each) do
|
14
51
|
@fedora_user = 'fedoraAdmin'
|
15
52
|
@fedora_password = 'fedoraAdmin'
|
@@ -0,0 +1,126 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Rubydora::Transactions do
|
4
|
+
|
5
|
+
|
6
|
+
subject {
|
7
|
+
Rubydora::Repository.any_instance.stub(:version).and_return(100)
|
8
|
+
repository = Rubydora::Repository.new :url => 'http://example.org'
|
9
|
+
}
|
10
|
+
|
11
|
+
|
12
|
+
describe "#rollback" do
|
13
|
+
it "ingest" do
|
14
|
+
subject.client.stub_chain(:[], :post).and_return 'asdf'
|
15
|
+
subject.should_receive(:purge_object).with(hash_including(:pid => 'asdf'))
|
16
|
+
|
17
|
+
subject.transaction do |t|
|
18
|
+
|
19
|
+
subject.ingest :pid => 'asdf', :file => '<a />'
|
20
|
+
|
21
|
+
t.rollback
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it "modify_object" do
|
26
|
+
subject.client.stub_chain(:[], :put).and_return 'asdf'
|
27
|
+
|
28
|
+
mock_object = double('Rubydora::DigitalObject', :state => 'A', :ownerId => '567', :logMessage => 'dfghj')
|
29
|
+
subject.should_receive(:find).with('asdf').and_return mock_object
|
30
|
+
|
31
|
+
|
32
|
+
subject.transaction do |t|
|
33
|
+
subject.modify_object :pid => 'asdf', :state => 'I', :ownerId => '123', :logMessage => 'changing asdf'
|
34
|
+
|
35
|
+
subject.should_receive(:modify_object).with(hash_including(:pid => 'asdf', :state => 'A', :ownerId => '567', :logMessage => 'reverting'))
|
36
|
+
t.rollback
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "purge_object" do
|
41
|
+
subject.client.stub_chain(:[], :delete)
|
42
|
+
|
43
|
+
subject.should_receive(:export).with(hash_including(:pid => 'asdf', :context => :archive)).and_return '<xml />'
|
44
|
+
subject.should_receive(:ingest).with(hash_including(:pid => 'asdf', :file => '<xml />'))
|
45
|
+
|
46
|
+
subject.transaction do |t|
|
47
|
+
subject.purge_object :pid => 'asdf'
|
48
|
+
|
49
|
+
t.rollback
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
it "add_datastream" do
|
54
|
+
subject.client.stub_chain(:[], :post)
|
55
|
+
subject.should_receive(:purge_datastream).with(hash_including(:pid => 'asdf', :dsid => 'mydsid'))
|
56
|
+
|
57
|
+
subject.transaction do |t|
|
58
|
+
subject.add_datastream :pid => 'asdf', :dsid => 'mydsid'
|
59
|
+
|
60
|
+
t.rollback
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
it "modify_datastream" do
|
65
|
+
subject.client.stub_chain(:[], :put)
|
66
|
+
|
67
|
+
subject.should_receive(:export).with(hash_including(:pid => 'asdf', :context => :archive)).and_return '<xml />'
|
68
|
+
subject.should_receive(:ingest).with(hash_including(:pid => 'asdf', :file => '<xml />'))
|
69
|
+
|
70
|
+
subject.transaction do |t|
|
71
|
+
subject.modify_datastream :pid => 'asdf', :dsid => 'mydsid'
|
72
|
+
|
73
|
+
t.rollback
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "set_datastream_options" do
|
78
|
+
subject.client.stub_chain(:[], :put)
|
79
|
+
|
80
|
+
mock_object = double('Rubydora::DigitalObject')
|
81
|
+
mock_object.stub_chain(:datastreams, :[], :versionable).and_return(false)
|
82
|
+
subject.should_receive(:find).with('asdf').and_return mock_object
|
83
|
+
|
84
|
+
subject.transaction do |t|
|
85
|
+
subject.set_datastream_options :pid => 'asdf', :dsid => 'mydsid', :versionable => true
|
86
|
+
|
87
|
+
subject.should_receive(:set_datastream_options).with(hash_including(:pid => 'asdf', :versionable => false, :dsid => 'mydsid'))
|
88
|
+
|
89
|
+
t.rollback
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
it "purge_datastream" do
|
94
|
+
subject.client.stub_chain(:[], :delete)
|
95
|
+
|
96
|
+
subject.should_receive(:export).with(hash_including(:pid => 'asdf', :context => :archive)).and_return '<xml />'
|
97
|
+
subject.should_receive(:ingest).with(hash_including(:pid => 'asdf', :file => '<xml />'))
|
98
|
+
|
99
|
+
subject.transaction do |t|
|
100
|
+
subject.purge_datastream :pid => 'asdf', :dsid => 'mydsid'
|
101
|
+
|
102
|
+
t.rollback
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it "add_relationship" do
|
107
|
+
subject.client.stub_chain(:[], :post)
|
108
|
+
subject.should_receive(:purge_relationship).with(hash_including(:subject => 'subject', :predicate => 'predicate', :object => 'object'))
|
109
|
+
|
110
|
+
subject.transaction do |t|
|
111
|
+
subject.add_relationship :subject => 'subject', :predicate => 'predicate', :object => 'object'
|
112
|
+
t.rollback
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
116
|
+
it "purge_relationship" do
|
117
|
+
subject.client.stub_chain(:[], :delete)
|
118
|
+
subject.should_receive(:add_relationship).with(hash_including(:subject => 'subject', :predicate => 'predicate', :object => 'object'))
|
119
|
+
|
120
|
+
subject.transaction do |t|
|
121
|
+
subject.purge_relationship :subject => 'subject', :predicate => 'predicate', :object => 'object'
|
122
|
+
t.rollback
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubydora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.11
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-07-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fastercsv
|
@@ -123,6 +123,38 @@ dependencies:
|
|
123
123
|
- - ! '>='
|
124
124
|
- !ruby/object:Gem::Version
|
125
125
|
version: '0'
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: hooks
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
none: false
|
130
|
+
requirements:
|
131
|
+
- - ! '>='
|
132
|
+
- !ruby/object:Gem::Version
|
133
|
+
version: '0'
|
134
|
+
type: :runtime
|
135
|
+
prerelease: false
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - ! '>='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: '0'
|
142
|
+
- !ruby/object:Gem::Dependency
|
143
|
+
name: deprecation
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
145
|
+
none: false
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
type: :runtime
|
151
|
+
prerelease: false
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - ! '>='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: '0'
|
126
158
|
- !ruby/object:Gem::Dependency
|
127
159
|
name: rake
|
128
160
|
requirement: !ruby/object:Gem::Requirement
|
@@ -251,6 +283,7 @@ files:
|
|
251
283
|
- lib/rubydora/rest_api_client.rb
|
252
284
|
- lib/rubydora/rest_api_client/v33.rb
|
253
285
|
- lib/rubydora/soap.rb
|
286
|
+
- lib/rubydora/transactions.rb
|
254
287
|
- lib/rubydora/version.rb
|
255
288
|
- rubydora.gemspec
|
256
289
|
- spec/lib/datastream_spec.rb
|
@@ -263,6 +296,7 @@ files:
|
|
263
296
|
- spec/lib/resource_index_spec.rb
|
264
297
|
- spec/lib/rest_api_client_spec.rb
|
265
298
|
- spec/lib/soap_spec.rb
|
299
|
+
- spec/lib/transactions_spec.rb
|
266
300
|
- spec/spec_helper.rb
|
267
301
|
homepage: http://github.com/cbeer/rubydora
|
268
302
|
licenses: []
|
@@ -299,5 +333,6 @@ test_files:
|
|
299
333
|
- spec/lib/resource_index_spec.rb
|
300
334
|
- spec/lib/rest_api_client_spec.rb
|
301
335
|
- spec/lib/soap_spec.rb
|
336
|
+
- spec/lib/transactions_spec.rb
|
302
337
|
- spec/spec_helper.rb
|
303
338
|
has_rdoc:
|