rubydora 0.3.1 → 0.4.0pre1
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.
- data/VERSION +1 -1
- data/lib/rubydora/datastream.rb +93 -18
- data/lib/rubydora/digital_object.rb +51 -6
- data/lib/rubydora/rest_api_client.rb +3 -1
- data/lib/rubydora.rb +2 -0
- data/spec/lib/datastream_spec.rb +213 -0
- data/spec/lib/digital_object_spec.rb +97 -0
- data/spec/lib/integration_test_spec.rb +76 -0
- data/spec/lib/rest_api_client_spec.rb +5 -1
- metadata +31 -34
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.4.0pre1
|
data/lib/rubydora/datastream.rb
CHANGED
@@ -15,11 +15,11 @@ module Rubydora
|
|
15
15
|
attr_reader :digital_object, :dsid
|
16
16
|
|
17
17
|
# mapping datastream attributes (and api parameters) to datastream profile names
|
18
|
-
DS_ATTRIBUTES = {:controlGroup => :dsControlGroup, :dsLocation => :dsLocation, :altIDs => nil, :dsLabel => :dsLabel, :versionable => :dsVersionable, :dsState => :dsState, :formatURI => :dsFormatURI, :checksumType => :dsChecksumType, :checksum => :dsChecksum, :mimeType => :dsMIME, :logMessage => nil, :ignoreContent => nil, :lastModifiedDate => nil, :content => nil}
|
18
|
+
DS_ATTRIBUTES = {:controlGroup => :dsControlGroup, :dsLocation => :dsLocation, :altIDs => nil, :dsLabel => :dsLabel, :versionable => :dsVersionable, :dsState => :dsState, :formatURI => :dsFormatURI, :checksumType => :dsChecksumType, :checksum => :dsChecksum, :mimeType => :dsMIME, :logMessage => nil, :ignoreContent => nil, :lastModifiedDate => nil, :content => nil, :asOfDateTime => nil}
|
19
19
|
DS_DEFAULT_ATTRIBUTES = { :controlGroup => 'M', :dsState => 'A', :checksumType => 'DISABLED', :versionable => true }
|
20
20
|
|
21
21
|
define_attribute_methods DS_ATTRIBUTES.keys
|
22
|
-
|
22
|
+
|
23
23
|
# accessors for datastream attributes
|
24
24
|
DS_ATTRIBUTES.each do |attribute, profile_name|
|
25
25
|
class_eval %Q{
|
@@ -34,6 +34,37 @@ module Rubydora
|
|
34
34
|
}
|
35
35
|
end
|
36
36
|
|
37
|
+
DS_READONLY_ATTRIBUTES = [ :dsCreateDate , :dsSize, :dsVersionID ]
|
38
|
+
DS_READONLY_ATTRIBUTES.each do |attribute|
|
39
|
+
class_eval %Q{
|
40
|
+
def #{attribute.to_s}
|
41
|
+
@#{attribute} || profile['#{attribute.to_s}'] || DS_DEFAULT_ATTRIBUTES[:#{attribute}]
|
42
|
+
end
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
|
47
|
+
# Create humanized accessors for the DS attribute (dsState -> state, dsCreateDate -> createDate)
|
48
|
+
(DS_ATTRIBUTES.keys + DS_READONLY_ATTRIBUTES).select { |k| k.to_s =~ /^ds/ }.each do |attribute|
|
49
|
+
simple_attribute = attribute.to_s.sub(/^ds/, '')
|
50
|
+
simple_attribute = simple_attribute[0].chr.downcase + simple_attribute[1..-1]
|
51
|
+
|
52
|
+
alias_method simple_attribute, attribute
|
53
|
+
|
54
|
+
if self.respond_to? "#{attribute}="
|
55
|
+
alias_method "#{simple_attribute}=", "#{attribute}="
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
def asOfDateTime asOfDateTime = nil
|
61
|
+
if asOfDateTime == nil
|
62
|
+
return @asOfDateTime
|
63
|
+
end
|
64
|
+
|
65
|
+
return self.class.new(@digital_object, @dsid, @options.merge(:asOfDateTime => asOfDateTime))
|
66
|
+
end
|
67
|
+
|
37
68
|
##
|
38
69
|
# Initialize a Rubydora::Datastream object, which may or
|
39
70
|
# may not already exist in the datastore.
|
@@ -47,6 +78,7 @@ module Rubydora
|
|
47
78
|
_run_initialize_callbacks do
|
48
79
|
@digital_object = digital_object
|
49
80
|
@dsid = dsid
|
81
|
+
@options = options
|
50
82
|
options.each do |key, value|
|
51
83
|
self.send(:"#{key}=", value)
|
52
84
|
end
|
@@ -68,7 +100,10 @@ module Rubydora
|
|
68
100
|
# @return [String]
|
69
101
|
def content
|
70
102
|
begin
|
71
|
-
|
103
|
+
options = { :pid => pid, :dsid => dsid }
|
104
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
105
|
+
|
106
|
+
@content ||= repository.datastream_dissemination options
|
72
107
|
rescue RestClient::ResourceNotFound
|
73
108
|
end
|
74
109
|
|
@@ -80,7 +115,9 @@ module Rubydora
|
|
80
115
|
# Get the URL for the datastream content
|
81
116
|
# @return [String]
|
82
117
|
def url
|
83
|
-
|
118
|
+
options = { }
|
119
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
120
|
+
repository.datastream_url(pid, dsid, options) + "/content"
|
84
121
|
end
|
85
122
|
|
86
123
|
# Set the content of the datastream
|
@@ -94,34 +131,56 @@ module Rubydora
|
|
94
131
|
# Content_will_change! would be dynamically created by ActiveModel::Dirty, but it would eagerly load the content.
|
95
132
|
# We don't want to do that.
|
96
133
|
def content_will_change!
|
134
|
+
raise "Can't change values on older versions" if @asOfDateTime
|
97
135
|
changed_attributes[:content] = nil
|
98
136
|
end
|
99
137
|
|
100
138
|
# Retrieve the datastream profile as a hash (and cache it)
|
101
139
|
# @return [Hash] see Fedora #getDatastream documentation for keys
|
102
|
-
def profile
|
140
|
+
def profile profile_xml = nil
|
103
141
|
@profile ||= begin
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
sum[node.name] << node.text
|
110
|
-
sum
|
111
|
-
end
|
112
|
-
h.select { |key, value| value.length == 1 }.each do |key, value|
|
113
|
-
h[key] = value.first
|
114
|
-
end
|
115
|
-
|
116
|
-
h
|
142
|
+
options = { :pid => pid, :dsid => dsid }
|
143
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
144
|
+
profile_xml ||= repository.datastream(options)
|
145
|
+
self.profile_xml_to_hash(profile_xml)
|
146
|
+
|
117
147
|
rescue
|
118
148
|
{}
|
119
149
|
end
|
120
150
|
end
|
151
|
+
alias_method :profile=, :profile
|
152
|
+
|
153
|
+
def profile_xml_to_hash profile_xml
|
154
|
+
profile_xml.gsub! '<datastreamProfile', '<datastreamProfile xmlns="http://www.fedora.info/definitions/1/0/management/"' unless profile_xml =~ /xmlns=/
|
155
|
+
doc = Nokogiri::XML(profile_xml)
|
156
|
+
h = doc.xpath('/management:datastreamProfile/*', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).inject({}) do |sum, node|
|
157
|
+
sum[node.name] ||= []
|
158
|
+
sum[node.name] << node.text
|
159
|
+
sum
|
160
|
+
end
|
161
|
+
h.select { |key, value| value.length == 1 }.each do |key, value|
|
162
|
+
h[key] = value.first
|
163
|
+
end
|
164
|
+
|
165
|
+
h['dsSize'] &&= h['dsSize'].to_i rescue h['dsSize']
|
166
|
+
h['dsCreateDate'] &&= Time.parse(h['dsCreateDate']) rescue h['dsCreateDate']
|
167
|
+
|
168
|
+
h
|
169
|
+
end
|
170
|
+
|
171
|
+
def versions
|
172
|
+
versions_xml = repository.datastream_versions(:pid => pid, :dsid => dsid)
|
173
|
+
versions_xml.gsub! '<datastreamProfile', '<datastreamProfile xmlns="http://www.fedora.info/definitions/1/0/management/"' unless versions_xml =~ /xmlns=/
|
174
|
+
doc = Nokogiri::XML(versions_xml)
|
175
|
+
doc.xpath('//management:datastreamProfile', {'management' => "http://www.fedora.info/definitions/1/0/management/"} ).map do |ds|
|
176
|
+
self.class.new @digital_object, @dsid, :profile => ds.to_s, :asOfDateTime => ds.xpath('management:dsCreateDate', 'management' => "http://www.fedora.info/definitions/1/0/management/").text
|
177
|
+
end
|
178
|
+
end
|
121
179
|
|
122
180
|
# Add datastream to Fedora
|
123
181
|
# @return [Rubydora::Datastream]
|
124
182
|
def create
|
183
|
+
check_if_read_only
|
125
184
|
run_callbacks :create do
|
126
185
|
repository.add_datastream to_api_params.merge({ :pid => pid, :dsid => dsid })
|
127
186
|
reset_profile_attributes
|
@@ -132,6 +191,7 @@ module Rubydora
|
|
132
191
|
# Modify or save the datastream
|
133
192
|
# @return [Rubydora::Datastream]
|
134
193
|
def save
|
194
|
+
check_if_read_only
|
135
195
|
run_callbacks :save do
|
136
196
|
return create if new?
|
137
197
|
repository.modify_datastream to_api_params.merge({ :pid => pid, :dsid => dsid })
|
@@ -143,6 +203,7 @@ module Rubydora
|
|
143
203
|
# Purge the datastream from Fedora
|
144
204
|
# @return [Rubydora::Datastream] `self`
|
145
205
|
def delete
|
206
|
+
check_if_read_only
|
146
207
|
run_callbacks :destroy do
|
147
208
|
repository.purge_datastream(:pid => pid, :dsid => dsid) unless self.new?
|
148
209
|
digital_object.datastreams.delete(dsid)
|
@@ -184,5 +245,19 @@ module Rubydora
|
|
184
245
|
def repository
|
185
246
|
digital_object.repository
|
186
247
|
end
|
248
|
+
|
249
|
+
def asOfDateTime= val
|
250
|
+
@asOfDateTime = val
|
251
|
+
end
|
252
|
+
|
253
|
+
def check_if_read_only
|
254
|
+
raise "Can't change values on older versions" if @asOfDateTime
|
255
|
+
end
|
256
|
+
|
257
|
+
private
|
258
|
+
def attribute_will_change! *args
|
259
|
+
check_if_read_only
|
260
|
+
super
|
261
|
+
end
|
187
262
|
end
|
188
263
|
end
|
@@ -43,8 +43,8 @@ module Rubydora
|
|
43
43
|
# TODO: raise an error if the object does not yet exist
|
44
44
|
# @param [String] pid
|
45
45
|
# @param [Rubydora::Repository] context
|
46
|
-
def self.find pid, repository = nil
|
47
|
-
self.new pid, repository
|
46
|
+
def self.find pid, repository = nil, options = {}
|
47
|
+
self.new pid, repository, options
|
48
48
|
end
|
49
49
|
|
50
50
|
# create a new fedora object (see also DigitalObject#save)
|
@@ -72,6 +72,7 @@ module Rubydora
|
|
72
72
|
self.pid = pid
|
73
73
|
@repository = repository
|
74
74
|
@new = true
|
75
|
+
@options = options
|
75
76
|
|
76
77
|
options.each do |key, value|
|
77
78
|
self.send(:"#{key}=", value)
|
@@ -94,11 +95,25 @@ module Rubydora
|
|
94
95
|
@new
|
95
96
|
end
|
96
97
|
|
98
|
+
def asOfDateTime asOfDateTime = nil
|
99
|
+
if asOfDateTime == nil
|
100
|
+
return @asOfDateTime
|
101
|
+
end
|
102
|
+
|
103
|
+
return self.class.new(pid, @repository, @options.merge(:asOfDateTime => asOfDateTime))
|
104
|
+
end
|
105
|
+
|
106
|
+
def asOfDateTime= val
|
107
|
+
@asOfDateTime = val
|
108
|
+
end
|
109
|
+
|
97
110
|
# Retrieve the object profile as a hash (and cache it)
|
98
111
|
# @return [Hash] see Fedora #getObject documentation for keys
|
99
112
|
def profile
|
100
113
|
@profile ||= begin
|
101
|
-
|
114
|
+
options = { :pid => pid }
|
115
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
116
|
+
profile_xml = repository.object(options)
|
102
117
|
profile_xml.gsub! '<objectProfile', '<objectProfile xmlns="http://www.fedora.info/definitions/1/0/access/"' unless profile_xml =~ /xmlns=/
|
103
118
|
doc = Nokogiri::XML(profile_xml)
|
104
119
|
h = doc.xpath('/access:objectProfile/*', {'access' => "http://www.fedora.info/definitions/1/0/access/"} ).inject({}) do |sum, node|
|
@@ -123,6 +138,16 @@ module Rubydora
|
|
123
138
|
end.freeze
|
124
139
|
end
|
125
140
|
|
141
|
+
def versions
|
142
|
+
versions_xml = repository.object_versions(:pid => pid)
|
143
|
+
versions_xml.gsub! '<fedoraObjectHistory', '<fedoraObjectHistory xmlns="http://www.fedora.info/definitions/1/0/access/"' unless versions_xml =~ /xmlns=/
|
144
|
+
doc = Nokogiri::XML(versions_xml)
|
145
|
+
doc.xpath('//access:objectChangeDate', {'access' => 'http://www.fedora.info/definitions/1/0/access/' } ).map do |changeDate|
|
146
|
+
self.class.new pid, repository, :asOfDateTime => changeDate.text
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
|
126
151
|
# List of datastreams
|
127
152
|
# @return [Array<Rubydora::Datastream>]
|
128
153
|
def datastreams
|
@@ -130,7 +155,9 @@ module Rubydora
|
|
130
155
|
h = Hash.new { |h,k| h[k] = datastream_object_for(k) }
|
131
156
|
|
132
157
|
begin
|
133
|
-
|
158
|
+
options = { :pid => pid }
|
159
|
+
options[:asOfDateTime] = asOfDateTime if asOfDateTime
|
160
|
+
datastreams_xml = repository.datastreams(options)
|
134
161
|
datastreams_xml.gsub! '<objectDatastreams', '<objectDatastreams xmlns="http://www.fedora.info/definitions/1/0/access/"' unless datastreams_xml =~ /xmlns=/
|
135
162
|
doc = Nokogiri::XML(datastreams_xml)
|
136
163
|
doc.xpath('//access:datastream', {'access' => "http://www.fedora.info/definitions/1/0/access/"}).each do |ds|
|
@@ -158,6 +185,7 @@ module Rubydora
|
|
158
185
|
#
|
159
186
|
# @return [Rubydora::DigitalObject] a new copy of this object
|
160
187
|
def save
|
188
|
+
check_if_read_only
|
161
189
|
run_callbacks :save do
|
162
190
|
if self.new?
|
163
191
|
self.pid = repository.ingest to_api_params.merge(:pid => pid)
|
@@ -175,6 +203,7 @@ module Rubydora
|
|
175
203
|
# Purge the object from Fedora
|
176
204
|
# @return [Rubydora::DigitalObject] `self`
|
177
205
|
def delete
|
206
|
+
check_if_read_only
|
178
207
|
my_pid = pid
|
179
208
|
run_callbacks :destroy do
|
180
209
|
@datastreams = nil
|
@@ -219,8 +248,24 @@ module Rubydora
|
|
219
248
|
# instantiate a datastream object for a dsid
|
220
249
|
# @param [String] dsid
|
221
250
|
# @return [Datastream]
|
222
|
-
def datastream_object_for dsid
|
223
|
-
|
251
|
+
def datastream_object_for dsid, options = {}
|
252
|
+
options[:asOfDateTime] ||= asOfDateTime if asOfDateTime
|
253
|
+
Datastream.new self, dsid, options
|
254
|
+
end
|
255
|
+
|
256
|
+
def check_if_read_only
|
257
|
+
raise "Can't change values on older versions" if @asOfDateTime
|
258
|
+
end
|
259
|
+
|
260
|
+
def check_if_read_only
|
261
|
+
raise "Can't change values on older versions" if @asOfDateTime
|
262
|
+
end
|
263
|
+
|
264
|
+
private
|
265
|
+
def attribute_will_change! *args
|
266
|
+
check_if_read_only
|
267
|
+
super
|
224
268
|
end
|
269
|
+
|
225
270
|
end
|
226
271
|
end
|
@@ -198,13 +198,15 @@ module Rubydora
|
|
198
198
|
raise ArgumentError, "Must supply dsid" unless dsid
|
199
199
|
options[:format] ||= 'xml'
|
200
200
|
begin
|
201
|
-
return client[url_for(datastream_url(pid, dsid) + "/
|
201
|
+
return client[url_for(datastream_url(pid, dsid) + "/history", options)].get
|
202
202
|
rescue => e
|
203
203
|
logger.error e.response
|
204
204
|
raise "Error getting versions for datastream #{dsid} for object #{pid}. See logger for details"
|
205
205
|
end
|
206
206
|
end
|
207
207
|
|
208
|
+
alias_method :datastream_history, :datastream_versions
|
209
|
+
|
208
210
|
# {include:RestApiClient::API_DOCUMENTATION}
|
209
211
|
# @param [Hash] options
|
210
212
|
# @option options [String] :pid
|
data/lib/rubydora.rb
CHANGED
data/spec/lib/datastream_spec.rb
CHANGED
@@ -7,6 +7,7 @@ describe Rubydora::Datastream do
|
|
7
7
|
@mock_object.stub(:repository => @mock_repository, :pid => 'pid')
|
8
8
|
end
|
9
9
|
|
10
|
+
|
10
11
|
describe "create" do
|
11
12
|
before(:each) do
|
12
13
|
@mock_repository.stub(:datastream) { raise("") }
|
@@ -118,6 +119,218 @@ describe Rubydora::Datastream do
|
|
118
119
|
|
119
120
|
end
|
120
121
|
|
122
|
+
describe "should check if an object is read-only" do
|
123
|
+
before(:each) do
|
124
|
+
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
125
|
+
@mock_repository.should_receive(:datastream).any_number_of_times.and_return <<-XML
|
126
|
+
<datastreamProfile>
|
127
|
+
<dsLocation>some:uri</dsLocation>
|
128
|
+
<dsLabel>label</dsLabel>
|
129
|
+
</datastreamProfile>
|
130
|
+
XML
|
131
|
+
end
|
132
|
+
|
133
|
+
it "before updating attributes" do
|
134
|
+
@datastream.should_receive(:check_if_read_only)
|
135
|
+
@datastream.dsLabel = 'New Label'
|
136
|
+
end
|
137
|
+
|
138
|
+
it "before saving an object" do
|
139
|
+
@mock_repository.should_receive(:modify_datastream)
|
140
|
+
@datastream.should_receive(:check_if_read_only)
|
141
|
+
@datastream.save
|
142
|
+
end
|
143
|
+
|
144
|
+
it "before deleting an object" do
|
145
|
+
@mock_repository.should_receive(:purge_datastream)
|
146
|
+
@mock_object.should_receive(:datastreams).and_return([])
|
147
|
+
@datastream.should_receive(:check_if_read_only)
|
148
|
+
@datastream.delete
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
describe "versions" do
|
153
|
+
before(:each) do
|
154
|
+
@datastream = Rubydora::Datastream.new @mock_object, 'dsid'
|
155
|
+
@mock_repository.should_receive(:datastream_versions).any_number_of_times.and_return <<-XML
|
156
|
+
<datastreamHistory>
|
157
|
+
<datastreamProfile>
|
158
|
+
<dsVersionID>dsid.1</dsVersionID>
|
159
|
+
<dsCreateDate>2010-01-02T00:00:00.012Z</dsCreateDate>
|
160
|
+
</datastreamProfile>
|
161
|
+
<datastreamProfile>
|
162
|
+
<dsVersionID>dsid.0</dsVersionID>
|
163
|
+
<dsCreateDate>2008-08-05T01:30:05.012Z</dsCreateDate>
|
164
|
+
</datastreamProfile>
|
165
|
+
</datastreamHistory>
|
166
|
+
XML
|
167
|
+
end
|
168
|
+
|
169
|
+
it "should have a list of previous versions" do
|
170
|
+
@datastream.versions.should have(2).items
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should access versions as read-only copies" do
|
174
|
+
expect { @datastream.versions.first.label = "asdf" }.to raise_error
|
175
|
+
end
|
176
|
+
|
177
|
+
it "should lookup content of datastream using the asOfDateTime parameter" do
|
178
|
+
@mock_repository.should_receive(:datastream_dissemination).with(hash_including(:asOfDateTime => '2008-08-05T01:30:05.012Z'))
|
179
|
+
@datastream.versions.last.content
|
180
|
+
end
|
181
|
+
|
182
|
+
end
|
183
|
+
|
184
|
+
describe "datastream attributes" do
|
185
|
+
before do
|
186
|
+
@mock_repository.stub(:datastream => <<-XML
|
187
|
+
<datastreamProfile>
|
188
|
+
<anyProfileValue />
|
189
|
+
</datastreamProfile>
|
190
|
+
XML
|
191
|
+
)
|
192
|
+
end
|
193
|
+
|
194
|
+
shared_examples "a datastream attribute" do
|
195
|
+
subject { Rubydora::Datastream.new @mock_object, 'dsid' }
|
196
|
+
|
197
|
+
describe "getter" do
|
198
|
+
it "should return the value" do
|
199
|
+
subject.instance_variable_set("@#{method}", 'asdf')
|
200
|
+
subject.send(method).should == 'asdf'
|
201
|
+
end
|
202
|
+
|
203
|
+
it "should look in the object profile" do
|
204
|
+
subject.should_receive(:profile) { { Rubydora::Datastream::DS_ATTRIBUTES[method.to_sym].to_s => 'qwerty' } }
|
205
|
+
subject.send(method).should == 'qwerty'
|
206
|
+
end
|
207
|
+
|
208
|
+
it "should fall-back to the set of default attributes" do
|
209
|
+
Rubydora::Datastream::DS_DEFAULT_ATTRIBUTES.should_receive(:[]).with(method.to_sym) { 'zxcv'}
|
210
|
+
subject.send(method).should == 'zxcv'
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
describe "setter" do
|
215
|
+
before do
|
216
|
+
subject.stub(:datastreams => [])
|
217
|
+
end
|
218
|
+
it "should mark the object as changed after setting" do
|
219
|
+
subject.send("#{method}=", 'new_value')
|
220
|
+
subject.should be_changed
|
221
|
+
end
|
222
|
+
|
223
|
+
it "should appear in the save request" do
|
224
|
+
@mock_repository.should_receive(:modify_datastream).with(hash_including(method.to_sym => 'new_value'))
|
225
|
+
subject.send("#{method}=", 'new_value')
|
226
|
+
subject.save
|
227
|
+
end
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
shared_examples "a read-only datastream attribute" do
|
232
|
+
subject { Rubydora::Datastream.new @mock_object, 'dsid' }
|
233
|
+
|
234
|
+
describe "getter" do
|
235
|
+
it "should return the value" do
|
236
|
+
subject.instance_variable_set("@#{method}", 'asdf')
|
237
|
+
subject.send(method).should == 'asdf'
|
238
|
+
end
|
239
|
+
|
240
|
+
it "should look in the object profile" do
|
241
|
+
subject.should_receive(:profile) { { method => 'qwerty' } }
|
242
|
+
subject.send(method).should == 'qwerty'
|
243
|
+
end
|
244
|
+
|
245
|
+
it "should fall-back to the set of default attributes" do
|
246
|
+
Rubydora::Datastream::DS_DEFAULT_ATTRIBUTES.should_receive(:[]).with(method.to_sym) { 'zxcv'}
|
247
|
+
subject.send(method).should == 'zxcv'
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
describe "#controlGroup" do
|
254
|
+
it_behaves_like "a datastream attribute"
|
255
|
+
let(:method) { 'controlGroup' }
|
256
|
+
end
|
257
|
+
|
258
|
+
describe "#dsLocation" do
|
259
|
+
it_behaves_like "a datastream attribute"
|
260
|
+
let(:method) { 'dsLocation' }
|
261
|
+
end
|
262
|
+
|
263
|
+
describe "#altIDs" do
|
264
|
+
it_behaves_like "a datastream attribute"
|
265
|
+
let(:method) { 'altIDs' }
|
266
|
+
end
|
267
|
+
|
268
|
+
describe "#dsLabel" do
|
269
|
+
it_behaves_like "a datastream attribute"
|
270
|
+
let(:method) { 'dsLabel' }
|
271
|
+
end
|
272
|
+
|
273
|
+
describe "#versionable" do
|
274
|
+
it_behaves_like "a datastream attribute"
|
275
|
+
let(:method) { 'versionable' }
|
276
|
+
end
|
277
|
+
|
278
|
+
describe "#dsState" do
|
279
|
+
it_behaves_like "a datastream attribute"
|
280
|
+
let(:method) { 'dsState' }
|
281
|
+
end
|
282
|
+
|
283
|
+
describe "#formatURI" do
|
284
|
+
it_behaves_like "a datastream attribute"
|
285
|
+
let(:method) { 'formatURI' }
|
286
|
+
end
|
287
|
+
|
288
|
+
describe "#checksumType" do
|
289
|
+
it_behaves_like "a datastream attribute"
|
290
|
+
let(:method) { 'checksumType' }
|
291
|
+
end
|
292
|
+
|
293
|
+
describe "#checksum" do
|
294
|
+
it_behaves_like "a datastream attribute"
|
295
|
+
let(:method) { 'checksum' }
|
296
|
+
end
|
297
|
+
|
298
|
+
describe "#mimeType" do
|
299
|
+
it_behaves_like "a datastream attribute"
|
300
|
+
let(:method) { 'mimeType' }
|
301
|
+
end
|
302
|
+
|
303
|
+
describe "#logMessage" do
|
304
|
+
it_behaves_like "a datastream attribute"
|
305
|
+
let(:method) { 'logMessage' }
|
306
|
+
end
|
307
|
+
|
308
|
+
describe "#ignoreContent" do
|
309
|
+
it_behaves_like "a datastream attribute"
|
310
|
+
let(:method) { 'ignoreContent' }
|
311
|
+
end
|
312
|
+
|
313
|
+
describe "#lastModifiedDate" do
|
314
|
+
it_behaves_like "a datastream attribute"
|
315
|
+
let(:method) { 'lastModifiedDate' }
|
316
|
+
end
|
317
|
+
|
318
|
+
describe "#dsCreateDate" do
|
319
|
+
it_behaves_like "a read-only datastream attribute"
|
320
|
+
let(:method) { 'dsCreateDate' }
|
321
|
+
end
|
322
|
+
|
323
|
+
describe "#dsSize" do
|
324
|
+
it_behaves_like "a read-only datastream attribute"
|
325
|
+
let(:method) { 'dsSize' }
|
326
|
+
end
|
327
|
+
|
328
|
+
describe "#dsVersionID" do
|
329
|
+
it_behaves_like "a read-only datastream attribute"
|
330
|
+
let(:method) { 'dsVersionID' }
|
331
|
+
end
|
332
|
+
end
|
333
|
+
|
121
334
|
describe "to_api_params" do
|
122
335
|
|
123
336
|
describe "with existing properties" do
|
@@ -292,6 +292,41 @@ describe Rubydora::DigitalObject do
|
|
292
292
|
end
|
293
293
|
end
|
294
294
|
|
295
|
+
describe "versions" do
|
296
|
+
before(:each) do
|
297
|
+
@mock_repository.stub(:object) { <<-XML
|
298
|
+
<objectProfile>
|
299
|
+
</objectProfile>
|
300
|
+
XML
|
301
|
+
}
|
302
|
+
|
303
|
+
@mock_repository.stub(:object_versions) { <<-XML
|
304
|
+
<fedoraObjectHistory>
|
305
|
+
<objectChangeDate>2011-09-26T20:41:02.450Z</objectChangeDate>
|
306
|
+
<objectChangeDate>2011-10-11T21:17:48.124Z</objectChangeDate>
|
307
|
+
</fedoraObjectHistory>
|
308
|
+
XML
|
309
|
+
}
|
310
|
+
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
|
311
|
+
end
|
312
|
+
|
313
|
+
it "should have a list of previous versions" do
|
314
|
+
@object.versions.should have(2).items
|
315
|
+
@object.versions.first.asOfDateTime.should == '2011-09-26T20:41:02.450Z'
|
316
|
+
end
|
317
|
+
|
318
|
+
it "should access versions as read-only copies" do
|
319
|
+
expect { @object.versions.first.label = "asdf" }.to raise_error
|
320
|
+
end
|
321
|
+
|
322
|
+
it "should lookup content of datastream using the asOfDateTime parameter" do
|
323
|
+
@mock_repository.should_receive(:datastreams).with(hash_including(:asOfDateTime => '2011-09-26T20:41:02.450Z')).and_return('')
|
324
|
+
Rubydora::Datastream.should_receive(:new).with(anything, 'my_ds', hash_including(:asOfDateTime => '2011-09-26T20:41:02.450Z'))
|
325
|
+
ds = @object.versions.first['my_ds']
|
326
|
+
end
|
327
|
+
|
328
|
+
end
|
329
|
+
|
295
330
|
describe "to_api_params" do
|
296
331
|
before(:each) do
|
297
332
|
@object = Rubydora::DigitalObject.new 'pid', @mock_repository
|
@@ -300,4 +335,66 @@ describe Rubydora::DigitalObject do
|
|
300
335
|
@object.send(:to_api_params).should == {}
|
301
336
|
end
|
302
337
|
end
|
338
|
+
|
339
|
+
shared_examples "an object attribute" do
|
340
|
+
subject { Rubydora::DigitalObject.new 'pid', @mock_repository }
|
341
|
+
|
342
|
+
describe "getter" do
|
343
|
+
it "should return the value" do
|
344
|
+
subject.instance_variable_set("@#{method}", 'asdf')
|
345
|
+
subject.send(method).should == 'asdf'
|
346
|
+
end
|
347
|
+
|
348
|
+
it "should look in the object profile" do
|
349
|
+
subject.should_receive(:profile) { { Rubydora::DigitalObject::OBJ_ATTRIBUTES[method.to_sym].to_s => 'qwerty' } }
|
350
|
+
subject.send(method).should == 'qwerty'
|
351
|
+
end
|
352
|
+
|
353
|
+
it "should fall-back to the set of default attributes" do
|
354
|
+
Rubydora::DigitalObject::OBJ_DEFAULT_ATTRIBUTES.should_receive(:[]).with(method.to_sym) { 'zxcv'}
|
355
|
+
subject.send(method).should == 'zxcv'
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
describe "setter" do
|
360
|
+
before do
|
361
|
+
subject.stub(:datastreams => [])
|
362
|
+
end
|
363
|
+
it "should mark the object as changed after setting" do
|
364
|
+
subject.send("#{method}=", 'new_value')
|
365
|
+
subject.should be_changed
|
366
|
+
end
|
367
|
+
|
368
|
+
it "should appear in the save request" do
|
369
|
+
@mock_repository.should_receive(:ingest).with(hash_including(method.to_sym => 'new_value'))
|
370
|
+
subject.send("#{method}=", 'new_value')
|
371
|
+
subject.save
|
372
|
+
end
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe "#state" do
|
377
|
+
it_behaves_like "an object attribute"
|
378
|
+
let(:method) { 'state' }
|
379
|
+
end
|
380
|
+
|
381
|
+
describe "#ownerId" do
|
382
|
+
it_behaves_like "an object attribute"
|
383
|
+
let(:method) { 'ownerId' }
|
384
|
+
end
|
385
|
+
|
386
|
+
describe "#label" do
|
387
|
+
it_behaves_like "an object attribute"
|
388
|
+
let(:method) { 'label' }
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "#logMessage" do
|
392
|
+
it_behaves_like "an object attribute"
|
393
|
+
let(:method) { 'logMessage' }
|
394
|
+
end
|
395
|
+
|
396
|
+
describe "#lastModifiedDate" do
|
397
|
+
it_behaves_like "an object attribute"
|
398
|
+
let(:method) { 'lastModifiedDate' }
|
399
|
+
end
|
303
400
|
end
|
@@ -93,6 +93,18 @@ describe "Integration testing against a live Fedora repository", :integration =>
|
|
93
93
|
obj.datastreams["Test"].content.should match( "Integration testing against a live Fedora repository")
|
94
94
|
end
|
95
95
|
|
96
|
+
it "should have profile attributes" do
|
97
|
+
obj = @repository.find('test:1')
|
98
|
+
ds = obj.datastreams["Test"]
|
99
|
+
|
100
|
+
ds.versionID.should == "Test.0"
|
101
|
+
|
102
|
+
(Time.now - ds.createDate).should be < 60*60 # 1 hour
|
103
|
+
ds.state.should == "A"
|
104
|
+
ds.controlGroup.should == "M"
|
105
|
+
ds.size.should be > 100
|
106
|
+
end
|
107
|
+
|
96
108
|
it "should delete datastreams" do
|
97
109
|
obj = @repository.find('test:1')
|
98
110
|
ds = obj.datastreams["Test"].delete
|
@@ -125,6 +137,70 @@ describe "Integration testing against a live Fedora repository", :integration =>
|
|
125
137
|
obj.datastreams["my_ds"].mimeType.should == "application/x-text"
|
126
138
|
end
|
127
139
|
|
140
|
+
|
141
|
+
describe "object versions" do
|
142
|
+
it "should have versions" do
|
143
|
+
obj = @repository.find('test:1')
|
144
|
+
obj.versions.should_not be_empty
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should have read-only versions" do
|
148
|
+
obj = @repository.find('test:1')
|
149
|
+
expect { obj.versions.first.label = "asdf" }.to raise_error
|
150
|
+
end
|
151
|
+
|
152
|
+
## This isn't how Fedora object profiles actually work??
|
153
|
+
#it "should access profile data using asOfDateTime" do
|
154
|
+
# obj = @repository.find('test:3')
|
155
|
+
# obj.label = "asdf"
|
156
|
+
# obj.save
|
157
|
+
#
|
158
|
+
# obj = @repository.find('test:3')
|
159
|
+
# obj.label = "qwerty"
|
160
|
+
# obj.save
|
161
|
+
#
|
162
|
+
# obj = @repository.find('test:3')
|
163
|
+
# obj.versions.map { |x| x.label }.should include('adsf', 'qwerty')
|
164
|
+
#end
|
165
|
+
|
166
|
+
it "should access datastreams list using asOfDateTime (and pass the asOfDateTime through to the datastreams)" do
|
167
|
+
obj = @repository.find('test:1')
|
168
|
+
oldest = obj.versions.first.datastreams.keys
|
169
|
+
newest = obj.versions.last.datastreams.keys
|
170
|
+
(newest - oldest).should_not be_empty
|
171
|
+
|
172
|
+
obj.versions.first.datastreams.values.first.asOfDateTime.should == obj.versions.first.asOfDateTime
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe "datastream versions" do
|
177
|
+
|
178
|
+
it "should have versions" do
|
179
|
+
obj = @repository.find('test:1')
|
180
|
+
versions = obj.datastreams["my_ds"].versions
|
181
|
+
versions.should_not be_empty
|
182
|
+
versions.map { |x| x.versionID }.should include('my_ds.1', 'my_ds.0')
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should have read-only versions" do
|
186
|
+
obj = @repository.find('test:1')
|
187
|
+
ds = obj.datastreams["my_ds"].asOfDateTime(Time.now)
|
188
|
+
expect { ds.dsLabel = 'asdf' }.to raise_error
|
189
|
+
expect { ds.content = 'asdf' }.to raise_error
|
190
|
+
end
|
191
|
+
|
192
|
+
it "should access the content of older datastreams" do
|
193
|
+
obj = @repository.find('test:1')
|
194
|
+
|
195
|
+
ds = obj.datastreams["my_ds"]
|
196
|
+
ds.content = "YYY"
|
197
|
+
ds.save
|
198
|
+
|
199
|
+
versions = obj.datastreams["my_ds"].versions
|
200
|
+
versions.map { |x| x.content }.should include("XXX", "YYY")
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
128
204
|
context "mime types" do
|
129
205
|
before(:each) do
|
130
206
|
obj = @repository.find('test:1')
|
@@ -163,9 +163,13 @@ describe Rubydora::RestApiClient do
|
|
163
163
|
end
|
164
164
|
|
165
165
|
it "datastream_versions" do
|
166
|
-
RestClient::Request.should_receive(:execute).with(hash_including(:url => "http://example.org/objects/mypid/datastreams/aaa/
|
166
|
+
RestClient::Request.should_receive(:execute).with(hash_including(:url => "http://example.org/objects/mypid/datastreams/aaa/history?format=xml"))
|
167
167
|
@mock_repository.datastream_versions :pid => 'mypid', :dsid => 'aaa'
|
168
|
+
end
|
168
169
|
|
170
|
+
it "datastream_history" do
|
171
|
+
RestClient::Request.should_receive(:execute).with(hash_including(:url => "http://example.org/objects/mypid/datastreams/aaa/history?format=xml"))
|
172
|
+
@mock_repository.datastream_history :pid => 'mypid', :dsid => 'aaa'
|
169
173
|
end
|
170
174
|
|
171
175
|
it "relationships" do
|
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rubydora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
5
|
-
prerelease:
|
4
|
+
version: 0.4.0pre1
|
5
|
+
prerelease: 5
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Chris Beer
|
@@ -13,7 +13,7 @@ date: 2011-12-29 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: fastercsv
|
16
|
-
requirement: &
|
16
|
+
requirement: &70158854103660 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70158854103660
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rest-client
|
27
|
-
requirement: &
|
27
|
+
requirement: &70158854103200 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70158854103200
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: nokogiri
|
38
|
-
requirement: &
|
38
|
+
requirement: &70158854102700 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70158854102700
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mime-types
|
49
|
-
requirement: &
|
49
|
+
requirement: &70158854102180 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70158854102180
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: activesupport
|
60
|
-
requirement: &
|
60
|
+
requirement: &70158854101740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70158854101740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: activemodel
|
71
|
-
requirement: &
|
71
|
+
requirement: &70158854101320 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,10 +76,10 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70158854101320
|
80
80
|
- !ruby/object:Gem::Dependency
|
81
81
|
name: savon
|
82
|
-
requirement: &
|
82
|
+
requirement: &70158854117240 !ruby/object:Gem::Requirement
|
83
83
|
none: false
|
84
84
|
requirements:
|
85
85
|
- - ! '>='
|
@@ -87,10 +87,10 @@ dependencies:
|
|
87
87
|
version: '0'
|
88
88
|
type: :runtime
|
89
89
|
prerelease: false
|
90
|
-
version_requirements: *
|
90
|
+
version_requirements: *70158854117240
|
91
91
|
- !ruby/object:Gem::Dependency
|
92
92
|
name: rake
|
93
|
-
requirement: &
|
93
|
+
requirement: &70158854116180 !ruby/object:Gem::Requirement
|
94
94
|
none: false
|
95
95
|
requirements:
|
96
96
|
- - ! '>='
|
@@ -98,10 +98,10 @@ dependencies:
|
|
98
98
|
version: '0'
|
99
99
|
type: :development
|
100
100
|
prerelease: false
|
101
|
-
version_requirements: *
|
101
|
+
version_requirements: *70158854116180
|
102
102
|
- !ruby/object:Gem::Dependency
|
103
103
|
name: shoulda
|
104
|
-
requirement: &
|
104
|
+
requirement: &70158854115100 !ruby/object:Gem::Requirement
|
105
105
|
none: false
|
106
106
|
requirements:
|
107
107
|
- - ! '>='
|
@@ -109,10 +109,10 @@ dependencies:
|
|
109
109
|
version: '0'
|
110
110
|
type: :development
|
111
111
|
prerelease: false
|
112
|
-
version_requirements: *
|
112
|
+
version_requirements: *70158854115100
|
113
113
|
- !ruby/object:Gem::Dependency
|
114
114
|
name: bundler
|
115
|
-
requirement: &
|
115
|
+
requirement: &70158854112280 !ruby/object:Gem::Requirement
|
116
116
|
none: false
|
117
117
|
requirements:
|
118
118
|
- - ! '>='
|
@@ -120,10 +120,10 @@ dependencies:
|
|
120
120
|
version: 1.0.14
|
121
121
|
type: :development
|
122
122
|
prerelease: false
|
123
|
-
version_requirements: *
|
123
|
+
version_requirements: *70158854112280
|
124
124
|
- !ruby/object:Gem::Dependency
|
125
125
|
name: rspec
|
126
|
-
requirement: &
|
126
|
+
requirement: &70158854111780 !ruby/object:Gem::Requirement
|
127
127
|
none: false
|
128
128
|
requirements:
|
129
129
|
- - ! '>='
|
@@ -131,10 +131,10 @@ dependencies:
|
|
131
131
|
version: '0'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
|
-
version_requirements: *
|
134
|
+
version_requirements: *70158854111780
|
135
135
|
- !ruby/object:Gem::Dependency
|
136
136
|
name: yard
|
137
|
-
requirement: &
|
137
|
+
requirement: &70158854111220 !ruby/object:Gem::Requirement
|
138
138
|
none: false
|
139
139
|
requirements:
|
140
140
|
- - ! '>='
|
@@ -142,10 +142,10 @@ dependencies:
|
|
142
142
|
version: '0'
|
143
143
|
type: :development
|
144
144
|
prerelease: false
|
145
|
-
version_requirements: *
|
145
|
+
version_requirements: *70158854111220
|
146
146
|
- !ruby/object:Gem::Dependency
|
147
147
|
name: jettywrapper
|
148
|
-
requirement: &
|
148
|
+
requirement: &70158854110800 !ruby/object:Gem::Requirement
|
149
149
|
none: false
|
150
150
|
requirements:
|
151
151
|
- - ! '>='
|
@@ -153,7 +153,7 @@ dependencies:
|
|
153
153
|
version: '0'
|
154
154
|
type: :development
|
155
155
|
prerelease: false
|
156
|
-
version_requirements: *
|
156
|
+
version_requirements: *70158854110800
|
157
157
|
description: ! 'Fedora Commons REST API ruby library : REQUIRES FCREPO 3.4+'
|
158
158
|
email:
|
159
159
|
- chris@cbeer.info
|
@@ -211,16 +211,13 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
211
211
|
version: '0'
|
212
212
|
segments:
|
213
213
|
- 0
|
214
|
-
hash:
|
214
|
+
hash: 142486579625571647
|
215
215
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
216
216
|
none: false
|
217
217
|
requirements:
|
218
|
-
- - ! '
|
218
|
+
- - ! '>'
|
219
219
|
- !ruby/object:Gem::Version
|
220
|
-
version:
|
221
|
-
segments:
|
222
|
-
- 0
|
223
|
-
hash: 4478861482245070325
|
220
|
+
version: 1.3.1
|
224
221
|
requirements: []
|
225
222
|
rubyforge_project:
|
226
223
|
rubygems_version: 1.8.10
|