active-fedora 3.2.0.pre5 → 3.2.0.pre6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +1 -1
- data/lib/active_fedora.rb +1 -0
- data/lib/active_fedora/base.rb +11 -253
- data/lib/active_fedora/callbacks.rb +3 -4
- data/lib/active_fedora/datastream.rb +6 -1
- data/lib/active_fedora/datastreams.rb +264 -0
- data/lib/active_fedora/nokogiri_datastream.rb +3 -1
- data/lib/active_fedora/persistence.rb +9 -4
- data/lib/active_fedora/unsaved_digital_object.rb +2 -1
- data/lib/active_fedora/version.rb +1 -1
- data/spec/unit/base_spec.rb +1 -0
- data/spec/unit/nokogiri_datastream_spec.rb +15 -11
- data/spec/unit/unsaved_digital_object_spec.rb +20 -0
- metadata +7 -4
data/Gemfile.lock
CHANGED
data/lib/active_fedora.rb
CHANGED
data/lib/active_fedora/base.rb
CHANGED
@@ -32,6 +32,7 @@ module ActiveFedora
|
|
32
32
|
class Base
|
33
33
|
include SemanticNode
|
34
34
|
|
35
|
+
|
35
36
|
def self.method_missing (name, *args)
|
36
37
|
if [:has_relationship, :has_bidirectional_relationship, :register_relationship_desc].include? name
|
37
38
|
ActiveSupport::Deprecation.warn("Deprecation: Relationships will not be included by default in the next version. To use #{name} add 'include ActiveFedora::Relationships' to your model")
|
@@ -67,15 +68,15 @@ module ActiveFedora
|
|
67
68
|
end
|
68
69
|
|
69
70
|
|
70
|
-
class_attribute :ds_specs
|
71
|
-
|
72
|
-
def self.inherited(p)
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
end
|
77
|
-
|
78
|
-
self.ds_specs = {'RELS-EXT'=> {:type=> ActiveFedora::RelsExtDatastream, :label=>"", :label=>"Fedora Object-to-Object Relationship Metadata", :control_group=>'X', :block=>nil}}
|
71
|
+
# class_attribute :ds_specs
|
72
|
+
#
|
73
|
+
# def self.inherited(p)
|
74
|
+
# # each subclass should get a copy of the parent's datastream definitions, it should not add to the parent's definition table.
|
75
|
+
# p.ds_specs = p.ds_specs.dup
|
76
|
+
# super
|
77
|
+
# end
|
78
|
+
#
|
79
|
+
# self.ds_specs = {'RELS-EXT'=> {:type=> ActiveFedora::RelsExtDatastream, :label=>"", :label=>"Fedora Object-to-Object Relationship Metadata", :control_group=>'X', :block=>nil}}
|
79
80
|
|
80
81
|
# Has this object been saved?
|
81
82
|
def new_object?
|
@@ -162,207 +163,6 @@ module ActiveFedora
|
|
162
163
|
obj
|
163
164
|
end
|
164
165
|
|
165
|
-
## Given a method name, return the best-guess dsid
|
166
|
-
def corresponding_datastream_name(method_name)
|
167
|
-
dsid = method_name.to_s
|
168
|
-
return dsid if datastreams.has_key? dsid
|
169
|
-
unescaped_name = method_name.to_s.gsub('_', '-')
|
170
|
-
return unescaped_name if datastreams.has_key? unescaped_name
|
171
|
-
nil
|
172
|
-
end
|
173
|
-
|
174
|
-
|
175
|
-
#
|
176
|
-
# Datastream Management
|
177
|
-
#
|
178
|
-
|
179
|
-
# Returns all known datastreams for the object. If the object has been
|
180
|
-
# saved to fedora, the persisted datastreams will be included.
|
181
|
-
# Datastreams that have been modified in memory are given preference over
|
182
|
-
# the copy in Fedora.
|
183
|
-
def datastreams
|
184
|
-
@datastreams ||= DatastreamHash.new(self)
|
185
|
-
end
|
186
|
-
|
187
|
-
def datastreams_in_memory
|
188
|
-
ActiveSupport::Deprecation.warn("ActiveFedora::Base.datastreams_in_memory has been deprecated. Use #datastreams instead")
|
189
|
-
datastreams
|
190
|
-
end
|
191
|
-
|
192
|
-
def configure_datastream(ds, ds_spec=nil)
|
193
|
-
ds_spec ||= self.class.ds_specs[ds.instance_variable_get(:@dsid)]
|
194
|
-
if ds_spec
|
195
|
-
ds.model = self if ds_spec[:type] == RelsExtDatastream
|
196
|
-
# If you called has_metadata with a block, pass the block into the Datastream class
|
197
|
-
if ds_spec[:block].class == Proc
|
198
|
-
ds_spec[:block].call(ds)
|
199
|
-
end
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
|
-
def datastream_from_spec(ds_spec, name)
|
204
|
-
ds = ds_spec[:type].new(inner_object, name)
|
205
|
-
ds.dsLabel = ds_spec[:label] if ds_spec[:label].present?
|
206
|
-
ds.controlGroup = ds_spec[:control_group]
|
207
|
-
additional_attributes_for_external_and_redirect_control_groups(ds, ds_spec)
|
208
|
-
ds
|
209
|
-
end
|
210
|
-
|
211
|
-
def load_datastreams
|
212
|
-
ds_specs = self.class.ds_specs.dup
|
213
|
-
inner_object.datastreams.each do |dsid, ds|
|
214
|
-
self.add_datastream(ds)
|
215
|
-
configure_datastream(datastreams[dsid])
|
216
|
-
ds_specs.delete(dsid)
|
217
|
-
end
|
218
|
-
ds_specs.each do |name,ds_spec|
|
219
|
-
ds = datastream_from_spec(ds_spec, name)
|
220
|
-
self.add_datastream(ds)
|
221
|
-
configure_datastream(ds, ds_spec)
|
222
|
-
end
|
223
|
-
end
|
224
|
-
|
225
|
-
# Adds datastream to the object. Saves the datastream to fedora upon adding.
|
226
|
-
# If datastream does not have a DSID, a unique DSID is generated
|
227
|
-
# :prefix option will set the prefix on auto-generated DSID
|
228
|
-
# @return [String] dsid of the added datastream
|
229
|
-
def add_datastream(datastream, opts={})
|
230
|
-
if datastream.dsid == nil || datastream.dsid.empty?
|
231
|
-
prefix = opts.has_key?(:prefix) ? opts[:prefix] : "DS"
|
232
|
-
datastream.instance_variable_set :@dsid, generate_dsid(prefix)
|
233
|
-
end
|
234
|
-
datastreams[datastream.dsid] = datastream
|
235
|
-
return datastream.dsid
|
236
|
-
end
|
237
|
-
|
238
|
-
def add(datastream) # :nodoc:
|
239
|
-
warn "Warning: ActiveFedora::Base.add has been deprecated. Use add_datastream"
|
240
|
-
add_datastream(datastream)
|
241
|
-
end
|
242
|
-
|
243
|
-
#return all datastreams of type ActiveFedora::MetadataDatastream
|
244
|
-
def metadata_streams
|
245
|
-
results = []
|
246
|
-
datastreams.each_value do |ds|
|
247
|
-
if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.kind_of?(ActiveFedora::NokogiriDatastream)
|
248
|
-
results << ds
|
249
|
-
end
|
250
|
-
end
|
251
|
-
return results
|
252
|
-
end
|
253
|
-
|
254
|
-
#return all datastreams not of type ActiveFedora::MetadataDatastream
|
255
|
-
#(that aren't Dublin Core or RELS-EXT streams either)
|
256
|
-
def file_streams
|
257
|
-
results = []
|
258
|
-
datastreams.each_value do |ds|
|
259
|
-
if !ds.kind_of?(ActiveFedora::MetadataDatastream)
|
260
|
-
dsid = ds.dsid
|
261
|
-
if dsid != "DC" && dsid != "RELS-EXT"
|
262
|
-
results << ds
|
263
|
-
end
|
264
|
-
end
|
265
|
-
end
|
266
|
-
return results
|
267
|
-
end
|
268
|
-
|
269
|
-
# return a valid dsid that is not currently in use. Uses a prefix (default "DS") and an auto-incrementing integer
|
270
|
-
# Example: if there are already datastreams with IDs DS1 and DS2, this method will return DS3. If you specify FOO as the prefix, it will return FOO1.
|
271
|
-
def generate_dsid(prefix="DS")
|
272
|
-
matches = datastreams.keys.map {|d| data = /^#{prefix}(\d+)$/.match(d); data && data[1].to_i}.compact
|
273
|
-
val = matches.empty? ? 1 : matches.max + 1
|
274
|
-
format_dsid(prefix, val)
|
275
|
-
end
|
276
|
-
|
277
|
-
### Provided so that an application can override how generated pids are formatted (e.g DS01 instead of DS1)
|
278
|
-
def format_dsid(prefix, suffix)
|
279
|
-
sprintf("%s%i", prefix,suffix)
|
280
|
-
end
|
281
|
-
|
282
|
-
# Return the Dublin Core (DC) Datastream. You can also get at this via
|
283
|
-
# the +datastreams["DC"]+.
|
284
|
-
def dc
|
285
|
-
#dc = REXML::Document.new(datastreams["DC"].content)
|
286
|
-
return datastreams["DC"]
|
287
|
-
end
|
288
|
-
|
289
|
-
# Returns the RELS-EXT Datastream
|
290
|
-
# Tries to grab from in-memory datastreams first
|
291
|
-
# Failing that, attempts to load from Fedora and addst to in-memory datastreams
|
292
|
-
# Failing that, creates a new RelsExtDatastream and adds it to the object
|
293
|
-
def rels_ext
|
294
|
-
if !datastreams.has_key?("RELS-EXT")
|
295
|
-
ds = ActiveFedora::RelsExtDatastream.new(@inner_object,'RELS-EXT')
|
296
|
-
ds.model = self
|
297
|
-
add_datastream(ds)
|
298
|
-
end
|
299
|
-
return datastreams["RELS-EXT"]
|
300
|
-
end
|
301
|
-
|
302
|
-
#
|
303
|
-
# File Management
|
304
|
-
#
|
305
|
-
|
306
|
-
# Add the given file as a datastream in the object
|
307
|
-
#
|
308
|
-
# @param [File] file the file to add
|
309
|
-
# @param [Hash] opts options: :dsid, :label, :mimeType, :prefix
|
310
|
-
def add_file_datastream(file, opts={})
|
311
|
-
label = opts.has_key?(:label) ? opts[:label] : ""
|
312
|
-
attrs = {:dsLabel => label, :controlGroup => 'M', :blob => file, :prefix=>opts[:prefix]}
|
313
|
-
if opts.has_key?(:mime_type)
|
314
|
-
attrs.merge!({:mimeType=>opts[:mime_type]})
|
315
|
-
elsif opts.has_key?(:mimeType)
|
316
|
-
attrs.merge!({:mimeType=>opts[:mimeType]})
|
317
|
-
elsif opts.has_key?(:content_type)
|
318
|
-
attrs.merge!({:mimeType=>opts[:content_type]})
|
319
|
-
end
|
320
|
-
ds = create_datastream(ActiveFedora::Datastream, opts[:dsid], attrs)
|
321
|
-
add_datastream(ds)
|
322
|
-
end
|
323
|
-
|
324
|
-
|
325
|
-
def create_datastream(type, dsid, opts={})
|
326
|
-
dsid = generate_dsid(opts[:prefix] || "DS") if dsid == nil
|
327
|
-
klass = type.kind_of?(Class) ? type : type.constantize
|
328
|
-
raise ArgumentError, "Argument dsid must be of type string" unless dsid.kind_of?(String) || dsid.kind_of?(NilClass)
|
329
|
-
ds = klass.new(inner_object, dsid)
|
330
|
-
ds.mimeType = opts[:mimeType]
|
331
|
-
ds.controlGroup = opts[:controlGroup]
|
332
|
-
ds.dsLabel = opts[:dsLabel]
|
333
|
-
ds.dsLocation = opts[:dsLocation]
|
334
|
-
blob = opts[:blob]
|
335
|
-
if blob
|
336
|
-
if !ds.mimeType.present?
|
337
|
-
##TODO, this is all done by rubydora -- remove
|
338
|
-
ds.mimeType = blob.respond_to?(:content_type) ? blob.content_type : "application/octet-stream"
|
339
|
-
end
|
340
|
-
if !ds.dsLabel.present? && blob.respond_to?(:path)
|
341
|
-
ds.dsLabel = File.basename(blob.path)
|
342
|
-
# ds.dsLabel = blob.original_filename
|
343
|
-
end
|
344
|
-
end
|
345
|
-
|
346
|
-
# blob = blob.read if blob.respond_to? :read
|
347
|
-
ds.content = blob || ""
|
348
|
-
ds
|
349
|
-
end
|
350
|
-
|
351
|
-
|
352
|
-
#
|
353
|
-
# Relationships Management
|
354
|
-
#
|
355
|
-
|
356
|
-
# @return [Hash] relationships hash, as defined by SemanticNode
|
357
|
-
# Rely on rels_ext datastream to track relationships array
|
358
|
-
# Overrides accessor for relationships array used by SemanticNode.
|
359
|
-
# If outbound_only is false, inbound relationships will be included.
|
360
|
-
# def relationships(outbound_only=true)
|
361
|
-
# outbound_only ? rels_ext.relationships : rels_ext.relationships.merge(:inbound=>inbound_relationships)
|
362
|
-
# end
|
363
|
-
|
364
|
-
|
365
|
-
|
366
166
|
def inner_object # :nodoc
|
367
167
|
@inner_object
|
368
168
|
end
|
@@ -372,7 +172,6 @@ module ActiveFedora
|
|
372
172
|
# TODO make inner_object a proxy that can hold the pid
|
373
173
|
def pid
|
374
174
|
@inner_object.pid
|
375
|
-
# @inner_object ? @inner_object.pid : @pid
|
376
175
|
end
|
377
176
|
|
378
177
|
|
@@ -624,48 +423,6 @@ module ActiveFedora
|
|
624
423
|
end
|
625
424
|
end
|
626
425
|
|
627
|
-
|
628
|
-
private
|
629
|
-
def configure_defined_datastreams
|
630
|
-
if self.class.ds_specs
|
631
|
-
self.class.ds_specs.each do |name,ds_config|
|
632
|
-
if self.datastreams.has_key?(name)
|
633
|
-
#attributes = self.datastreams[name].attributes
|
634
|
-
else
|
635
|
-
ds = ds_config[:type].new(inner_object, name)
|
636
|
-
ds.model = self if ds_config[:type] == RelsExtDatastream
|
637
|
-
ds.dsLabel = ds_config[:label] if ds_config[:label].present?
|
638
|
-
ds.controlGroup = ds_config[:control_group]
|
639
|
-
# If you called has_metadata with a block, pass the block into the Datastream class
|
640
|
-
if ds_config[:block].class == Proc
|
641
|
-
ds_config[:block].call(ds)
|
642
|
-
end
|
643
|
-
additional_attributes_for_external_and_redirect_control_groups(ds, ds_config)
|
644
|
-
self.add_datastream(ds)
|
645
|
-
end
|
646
|
-
end
|
647
|
-
end
|
648
|
-
end
|
649
|
-
|
650
|
-
|
651
|
-
# This method provides validation of proper options for control_group 'E' and 'R' and builds an attribute hash to be merged back into ds.attributes prior to saving
|
652
|
-
#
|
653
|
-
# @param [Object] ds The datastream
|
654
|
-
# @param [Object] ds_config hash of options which may contain :disseminator and :url
|
655
|
-
def additional_attributes_for_external_and_redirect_control_groups(ds,ds_config)
|
656
|
-
if ds.controlGroup=='E'
|
657
|
-
raise "Must supply either :disseminator or :url if you specify :control_group => 'E'" if (ds_config[:disseminator].empty? && ds_config[:url].empty?)
|
658
|
-
if !ds_config[:disseminator].empty?
|
659
|
-
ds.dsLocation= "#{RubydoraConnection.instance.options[:url]}/objects/#{pid}/methods/#{ds_config[:disseminator]}"
|
660
|
-
elsif !ds_config[:url].empty?
|
661
|
-
ds.dsLocation= ds_config[:url]
|
662
|
-
end
|
663
|
-
elsif ds.controlGroup=='R'
|
664
|
-
raise "Must supply a :url if you specify :control_group => 'R'" if (ds_config[:url].empty?)
|
665
|
-
ds.dsLocation= ds_config[:url]
|
666
|
-
end
|
667
|
-
end
|
668
|
-
|
669
426
|
end
|
670
427
|
|
671
428
|
Base.class_eval do
|
@@ -676,6 +433,7 @@ module ActiveFedora
|
|
676
433
|
include ActiveModel::Conversion
|
677
434
|
include Validations
|
678
435
|
include Callbacks
|
436
|
+
include Datastreams
|
679
437
|
extend ActiveModel::Naming
|
680
438
|
include Delegating
|
681
439
|
include Associations
|
@@ -19,7 +19,6 @@ module ActiveFedora
|
|
19
19
|
# * (-) <tt>create</tt>
|
20
20
|
# * (5) <tt>after_create</tt>
|
21
21
|
# * (6) <tt>after_save</tt>
|
22
|
-
# * (7) <tt>after_commit</tt>
|
23
22
|
#
|
24
23
|
# Lastly an <tt>after_find</tt> and <tt>after_initialize</tt> callback is triggered for each object that
|
25
24
|
# is found and instantiated by a finder, with <tt>after_initialize</tt> being triggered after new objects
|
@@ -233,12 +232,12 @@ module ActiveFedora
|
|
233
232
|
run_callbacks(:destroy) { super }
|
234
233
|
end
|
235
234
|
|
236
|
-
def save #:nodoc:
|
237
|
-
run_callbacks(:save) { super }
|
238
|
-
end
|
239
235
|
|
240
236
|
private
|
241
237
|
|
238
|
+
def persist #:nodoc:
|
239
|
+
run_callbacks(:save) { super }
|
240
|
+
end
|
242
241
|
|
243
242
|
def create #:nodoc:
|
244
243
|
run_callbacks(:create) { super }
|
@@ -5,7 +5,7 @@ module ActiveFedora
|
|
5
5
|
|
6
6
|
attr_writer :digital_object
|
7
7
|
attr_accessor :dirty, :last_modified, :fields
|
8
|
-
before_create :add_mime_type
|
8
|
+
before_create :add_mime_type, :add_ds_location
|
9
9
|
|
10
10
|
def initialize(digital_object, dsid)
|
11
11
|
@fields={}
|
@@ -21,6 +21,11 @@ module ActiveFedora
|
|
21
21
|
self.mimeType = 'text/xml' unless self.mimeType
|
22
22
|
end
|
23
23
|
|
24
|
+
def add_ds_location
|
25
|
+
if self.controlGroup == 'E'
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
24
29
|
#compatibility method for rails' url generators. This method will
|
25
30
|
#urlescape escape dots, which are apparently
|
26
31
|
#invalid characters in a dsid.
|
@@ -0,0 +1,264 @@
|
|
1
|
+
module ActiveFedora
|
2
|
+
module Datastreams
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
included do
|
6
|
+
class_attribute :ds_specs
|
7
|
+
self.ds_specs = {'RELS-EXT'=> {:type=> ActiveFedora::RelsExtDatastream, :label=>"", :label=>"Fedora Object-to-Object Relationship Metadata", :control_group=>'X', :block=>nil}}
|
8
|
+
class << self
|
9
|
+
def inherited_with_datastreams(kls) #:nodoc:
|
10
|
+
## Do some inheritance logic that doesn't override Base.inherited
|
11
|
+
inherited_without_datastreams kls
|
12
|
+
# each subclass should get a copy of the parent's datastream definitions, it should not add to the parent's definition table.
|
13
|
+
kls.ds_specs = kls.ds_specs.dup
|
14
|
+
end
|
15
|
+
alias_method_chain :inherited, :datastreams
|
16
|
+
end
|
17
|
+
|
18
|
+
before_save :add_disseminator_location_to_datastreams
|
19
|
+
before_save :serialize_datastreams
|
20
|
+
end
|
21
|
+
|
22
|
+
def serialize_datastreams
|
23
|
+
datastreams.each {|k, ds| ds.serialize! }
|
24
|
+
self.metadata_is_dirty = datastreams.any? {|k,ds| ds.changed? && (ds.class.included_modules.include?(ActiveFedora::MetadataDatastreamHelper) || ds.instance_of?(ActiveFedora::RelsExtDatastream))}
|
25
|
+
true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Adds the disseminator location to the datastream after the pid has been established
|
29
|
+
def add_disseminator_location_to_datastreams
|
30
|
+
self.class.ds_specs.each do |name,ds_config|
|
31
|
+
ds = datastreams[name]
|
32
|
+
if ds && ds.controlGroup == 'E' && ds_config[:disseminator].present?
|
33
|
+
ds.dsLocation= "#{RubydoraConnection.instance.options[:url]}/objects/#{pid}/methods/#{ds_config[:disseminator]}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
true
|
37
|
+
end
|
38
|
+
|
39
|
+
## Given a method name, return the best-guess dsid
|
40
|
+
def corresponding_datastream_name(method_name)
|
41
|
+
dsid = method_name.to_s
|
42
|
+
return dsid if datastreams.has_key? dsid
|
43
|
+
unescaped_name = method_name.to_s.gsub('_', '-')
|
44
|
+
return unescaped_name if datastreams.has_key? unescaped_name
|
45
|
+
nil
|
46
|
+
end
|
47
|
+
|
48
|
+
|
49
|
+
#
|
50
|
+
# Datastream Management
|
51
|
+
#
|
52
|
+
|
53
|
+
# Returns all known datastreams for the object. If the object has been
|
54
|
+
# saved to fedora, the persisted datastreams will be included.
|
55
|
+
# Datastreams that have been modified in memory are given preference over
|
56
|
+
# the copy in Fedora.
|
57
|
+
def datastreams
|
58
|
+
@datastreams ||= DatastreamHash.new(self)
|
59
|
+
end
|
60
|
+
|
61
|
+
def datastreams_in_memory
|
62
|
+
ActiveSupport::Deprecation.warn("ActiveFedora::Base.datastreams_in_memory has been deprecated. Use #datastreams instead")
|
63
|
+
datastreams
|
64
|
+
end
|
65
|
+
|
66
|
+
def configure_datastream(ds, ds_spec=nil)
|
67
|
+
ds_spec ||= self.class.ds_specs[ds.instance_variable_get(:@dsid)]
|
68
|
+
if ds_spec
|
69
|
+
ds.model = self if ds_spec[:type] == RelsExtDatastream
|
70
|
+
# If you called has_metadata with a block, pass the block into the Datastream class
|
71
|
+
if ds_spec[:block].class == Proc
|
72
|
+
ds_spec[:block].call(ds)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def datastream_from_spec(ds_spec, name)
|
78
|
+
ds = ds_spec[:type].new(inner_object, name)
|
79
|
+
ds.dsLabel = ds_spec[:label] if ds_spec[:label].present?
|
80
|
+
ds.controlGroup = ds_spec[:control_group]
|
81
|
+
additional_attributes_for_external_and_redirect_control_groups(ds, ds_spec)
|
82
|
+
ds
|
83
|
+
end
|
84
|
+
|
85
|
+
def load_datastreams
|
86
|
+
ds_specs = self.class.ds_specs.dup
|
87
|
+
inner_object.datastreams.each do |dsid, ds|
|
88
|
+
self.add_datastream(ds)
|
89
|
+
configure_datastream(datastreams[dsid])
|
90
|
+
ds_specs.delete(dsid)
|
91
|
+
end
|
92
|
+
ds_specs.each do |name,ds_spec|
|
93
|
+
ds = datastream_from_spec(ds_spec, name)
|
94
|
+
self.add_datastream(ds)
|
95
|
+
configure_datastream(ds, ds_spec)
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
# Adds datastream to the object. Saves the datastream to fedora upon adding.
|
100
|
+
# If datastream does not have a DSID, a unique DSID is generated
|
101
|
+
# :prefix option will set the prefix on auto-generated DSID
|
102
|
+
# @return [String] dsid of the added datastream
|
103
|
+
def add_datastream(datastream, opts={})
|
104
|
+
if datastream.dsid == nil || datastream.dsid.empty?
|
105
|
+
prefix = opts.has_key?(:prefix) ? opts[:prefix] : "DS"
|
106
|
+
datastream.instance_variable_set :@dsid, generate_dsid(prefix)
|
107
|
+
end
|
108
|
+
datastreams[datastream.dsid] = datastream
|
109
|
+
return datastream.dsid
|
110
|
+
end
|
111
|
+
|
112
|
+
def add(datastream) # :nodoc:
|
113
|
+
warn "Warning: ActiveFedora::Base.add has been deprecated. Use add_datastream"
|
114
|
+
add_datastream(datastream)
|
115
|
+
end
|
116
|
+
|
117
|
+
#return all datastreams of type ActiveFedora::MetadataDatastream
|
118
|
+
def metadata_streams
|
119
|
+
results = []
|
120
|
+
datastreams.each_value do |ds|
|
121
|
+
if ds.kind_of?(ActiveFedora::MetadataDatastream) || ds.kind_of?(ActiveFedora::NokogiriDatastream)
|
122
|
+
results << ds
|
123
|
+
end
|
124
|
+
end
|
125
|
+
return results
|
126
|
+
end
|
127
|
+
|
128
|
+
#return all datastreams not of type ActiveFedora::MetadataDatastream
|
129
|
+
#(that aren't Dublin Core or RELS-EXT streams either)
|
130
|
+
def file_streams
|
131
|
+
results = []
|
132
|
+
datastreams.each_value do |ds|
|
133
|
+
if !ds.kind_of?(ActiveFedora::MetadataDatastream)
|
134
|
+
dsid = ds.dsid
|
135
|
+
if dsid != "DC" && dsid != "RELS-EXT"
|
136
|
+
results << ds
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
return results
|
141
|
+
end
|
142
|
+
|
143
|
+
# return a valid dsid that is not currently in use. Uses a prefix (default "DS") and an auto-incrementing integer
|
144
|
+
# Example: if there are already datastreams with IDs DS1 and DS2, this method will return DS3. If you specify FOO as the prefix, it will return FOO1.
|
145
|
+
def generate_dsid(prefix="DS")
|
146
|
+
matches = datastreams.keys.map {|d| data = /^#{prefix}(\d+)$/.match(d); data && data[1].to_i}.compact
|
147
|
+
val = matches.empty? ? 1 : matches.max + 1
|
148
|
+
format_dsid(prefix, val)
|
149
|
+
end
|
150
|
+
|
151
|
+
### Provided so that an application can override how generated pids are formatted (e.g DS01 instead of DS1)
|
152
|
+
def format_dsid(prefix, suffix)
|
153
|
+
sprintf("%s%i", prefix,suffix)
|
154
|
+
end
|
155
|
+
|
156
|
+
# Return the Dublin Core (DC) Datastream. You can also get at this via
|
157
|
+
# the +datastreams["DC"]+.
|
158
|
+
def dc
|
159
|
+
#dc = REXML::Document.new(datastreams["DC"].content)
|
160
|
+
return datastreams["DC"]
|
161
|
+
end
|
162
|
+
|
163
|
+
# Returns the RELS-EXT Datastream
|
164
|
+
# Tries to grab from in-memory datastreams first
|
165
|
+
# Failing that, attempts to load from Fedora and addst to in-memory datastreams
|
166
|
+
# Failing that, creates a new RelsExtDatastream and adds it to the object
|
167
|
+
def rels_ext
|
168
|
+
if !datastreams.has_key?("RELS-EXT")
|
169
|
+
ds = ActiveFedora::RelsExtDatastream.new(@inner_object,'RELS-EXT')
|
170
|
+
ds.model = self
|
171
|
+
add_datastream(ds)
|
172
|
+
end
|
173
|
+
return datastreams["RELS-EXT"]
|
174
|
+
end
|
175
|
+
|
176
|
+
#
|
177
|
+
# File Management
|
178
|
+
#
|
179
|
+
|
180
|
+
# Add the given file as a datastream in the object
|
181
|
+
#
|
182
|
+
# @param [File] file the file to add
|
183
|
+
# @param [Hash] opts options: :dsid, :label, :mimeType, :prefix
|
184
|
+
def add_file_datastream(file, opts={})
|
185
|
+
label = opts.has_key?(:label) ? opts[:label] : ""
|
186
|
+
attrs = {:dsLabel => label, :controlGroup => 'M', :blob => file, :prefix=>opts[:prefix]}
|
187
|
+
if opts.has_key?(:mime_type)
|
188
|
+
attrs.merge!({:mimeType=>opts[:mime_type]})
|
189
|
+
elsif opts.has_key?(:mimeType)
|
190
|
+
attrs.merge!({:mimeType=>opts[:mimeType]})
|
191
|
+
elsif opts.has_key?(:content_type)
|
192
|
+
attrs.merge!({:mimeType=>opts[:content_type]})
|
193
|
+
end
|
194
|
+
ds = create_datastream(ActiveFedora::Datastream, opts[:dsid], attrs)
|
195
|
+
add_datastream(ds)
|
196
|
+
end
|
197
|
+
|
198
|
+
|
199
|
+
def create_datastream(type, dsid, opts={})
|
200
|
+
dsid = generate_dsid(opts[:prefix] || "DS") if dsid == nil
|
201
|
+
klass = type.kind_of?(Class) ? type : type.constantize
|
202
|
+
raise ArgumentError, "Argument dsid must be of type string" unless dsid.kind_of?(String) || dsid.kind_of?(NilClass)
|
203
|
+
ds = klass.new(inner_object, dsid)
|
204
|
+
ds.mimeType = opts[:mimeType]
|
205
|
+
ds.controlGroup = opts[:controlGroup]
|
206
|
+
ds.dsLabel = opts[:dsLabel]
|
207
|
+
ds.dsLocation = opts[:dsLocation]
|
208
|
+
blob = opts[:blob]
|
209
|
+
if blob
|
210
|
+
if !ds.mimeType.present?
|
211
|
+
##TODO, this is all done by rubydora -- remove
|
212
|
+
ds.mimeType = blob.respond_to?(:content_type) ? blob.content_type : "application/octet-stream"
|
213
|
+
end
|
214
|
+
if !ds.dsLabel.present? && blob.respond_to?(:path)
|
215
|
+
ds.dsLabel = File.basename(blob.path)
|
216
|
+
# ds.dsLabel = blob.original_filename
|
217
|
+
end
|
218
|
+
end
|
219
|
+
|
220
|
+
# blob = blob.read if blob.respond_to? :read
|
221
|
+
ds.content = blob || ""
|
222
|
+
ds
|
223
|
+
end
|
224
|
+
|
225
|
+
# def configure_defined_datastreams
|
226
|
+
# if self.class.ds_specs
|
227
|
+
# self.class.ds_specs.each do |name,ds_config|
|
228
|
+
# if self.datastreams.has_key?(name)
|
229
|
+
# #attributes = self.datastreams[name].attributes
|
230
|
+
# else
|
231
|
+
# ds = ds_config[:type].new(inner_object, name)
|
232
|
+
# ds.model = self if ds_config[:type] == RelsExtDatastream
|
233
|
+
# ds.dsLabel = ds_config[:label] if ds_config[:label].present?
|
234
|
+
# ds.controlGroup = ds_config[:control_group]
|
235
|
+
# # If you called has_metadata with a block, pass the block into the Datastream class
|
236
|
+
# if ds_config[:block].class == Proc
|
237
|
+
# ds_config[:block].call(ds)
|
238
|
+
# end
|
239
|
+
# additional_attributes_for_external_and_redirect_control_groups(ds, ds_config)
|
240
|
+
# self.add_datastream(ds)
|
241
|
+
# end
|
242
|
+
# end
|
243
|
+
# end
|
244
|
+
# end
|
245
|
+
|
246
|
+
|
247
|
+
# This method provides validation of proper options for control_group 'E' and 'R' and builds an attribute hash to be merged back into ds.attributes prior to saving
|
248
|
+
#
|
249
|
+
# @param [Object] ds The datastream
|
250
|
+
# @param [Object] ds_config hash of options which may contain :disseminator and :url
|
251
|
+
def additional_attributes_for_external_and_redirect_control_groups(ds,ds_config)
|
252
|
+
if ds.controlGroup=='E'
|
253
|
+
raise "Must supply either :disseminator or :url if you specify :control_group => 'E'" if (ds_config[:disseminator].empty? && ds_config[:url].empty?)
|
254
|
+
if !ds_config[:disseminator] && ds_config[:url].present?
|
255
|
+
ds.dsLocation= ds_config[:url]
|
256
|
+
end
|
257
|
+
elsif ds.controlGroup=='R'
|
258
|
+
raise "Must supply a :url if you specify :control_group => 'R'" if (ds_config[:url].empty?)
|
259
|
+
ds.dsLocation= ds_config[:url]
|
260
|
+
end
|
261
|
+
end
|
262
|
+
|
263
|
+
end
|
264
|
+
end
|
@@ -46,6 +46,7 @@ module ActiveFedora
|
|
46
46
|
|
47
47
|
def ng_xml=(new_xml)
|
48
48
|
self.xml_loaded=true
|
49
|
+
self.dirty = true
|
49
50
|
case new_xml
|
50
51
|
when Nokogiri::XML::Document, Nokogiri::XML::Element, Nokogiri::XML::Node
|
51
52
|
@ng_xml = new_xml
|
@@ -58,7 +59,8 @@ module ActiveFedora
|
|
58
59
|
|
59
60
|
def content=(content)
|
60
61
|
super
|
61
|
-
self.
|
62
|
+
self.xml_loaded=true
|
63
|
+
@ng_xml = Nokogiri::XML::Document.parse(content)
|
62
64
|
end
|
63
65
|
|
64
66
|
|
@@ -85,21 +85,26 @@ module ActiveFedora
|
|
85
85
|
|
86
86
|
# Deals with preparing new object to be saved to Fedora, then pushes it and its datastreams into Fedora.
|
87
87
|
def create
|
88
|
-
|
88
|
+
assign_pid
|
89
89
|
assert_content_model
|
90
90
|
@metadata_is_dirty = true
|
91
91
|
persist
|
92
92
|
end
|
93
|
+
|
94
|
+
def assign_pid
|
95
|
+
@inner_object = @inner_object.save #replace the unsaved digital object with a saved digital object
|
96
|
+
end
|
93
97
|
|
94
98
|
# Pushes the object and all of its new or dirty datastreams into Fedora
|
95
99
|
def update
|
96
100
|
persist
|
97
101
|
end
|
98
102
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
103
|
+
def metadata_is_dirty=(bool)
|
104
|
+
@metadata_is_dirty = bool
|
105
|
+
end
|
102
106
|
|
107
|
+
def persist
|
103
108
|
result = @inner_object.save
|
104
109
|
|
105
110
|
### Rubydora re-inits the datastreams after a save, so ensure our copy stays in synch
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveFedora
|
2
2
|
# Helps Rubydora create datastreams of the type defined by the ActiveFedora::Base#datastream_class_for_name
|
3
3
|
class UnsavedDigitalObject
|
4
|
-
attr_accessor :original_class, :datastreams, :label, :namespace
|
4
|
+
attr_accessor :original_class, :ownerId, :datastreams, :label, :namespace
|
5
5
|
|
6
6
|
def initialize(original_class, namespace, pid=nil)
|
7
7
|
@pid = pid
|
@@ -25,6 +25,7 @@ module ActiveFedora
|
|
25
25
|
v.digital_object = obj
|
26
26
|
obj.datastreams[k] = v
|
27
27
|
end
|
28
|
+
obj.ownerId = ownerId if ownerId
|
28
29
|
obj
|
29
30
|
end
|
30
31
|
|
data/spec/unit/base_spec.rb
CHANGED
@@ -157,6 +157,7 @@ describe ActiveFedora::Base do
|
|
157
157
|
@n.datastreams["properties"].controlGroup.should eql("X")
|
158
158
|
@n.datastreams["descMetadata"].controlGroup.should eql("M")
|
159
159
|
@n.datastreams["UKETD_DC"].controlGroup.should eql("E")
|
160
|
+
@n.datastreams["UKETD_DC"].dsLocation.should == "urlsub_url/objects/#{@this_pid}/methods/hull-sDef:uketdObject/getUKETDMetadata"
|
160
161
|
end
|
161
162
|
|
162
163
|
context ":control_group => 'E'" do
|
@@ -14,12 +14,12 @@ describe ActiveFedora::NokogiriDatastream do
|
|
14
14
|
end
|
15
15
|
|
16
16
|
before(:each) do
|
17
|
-
mock_inner = mock('inner object')
|
17
|
+
@mock_inner = mock('inner object')
|
18
18
|
@mock_repo = mock('repository')
|
19
19
|
@mock_repo.stubs(:datastream_dissemination=>'My Content')
|
20
|
-
mock_inner.stubs(:repository).returns(@mock_repo)
|
21
|
-
mock_inner.stubs(:pid)
|
22
|
-
@test_ds = ActiveFedora::NokogiriDatastream.new(mock_inner, "descMetadata")
|
20
|
+
@mock_inner.stubs(:repository).returns(@mock_repo)
|
21
|
+
@mock_inner.stubs(:pid)
|
22
|
+
@test_ds = ActiveFedora::NokogiriDatastream.new(@mock_inner, "descMetadata")
|
23
23
|
@test_ds.content="<test_xml/>"
|
24
24
|
end
|
25
25
|
|
@@ -78,6 +78,7 @@ describe ActiveFedora::NokogiriDatastream do
|
|
78
78
|
end
|
79
79
|
it "should do nothing if field key is a string (must be an array or symbol). Will not accept xpath queries!" do
|
80
80
|
xml_before = @mods_ds.to_xml
|
81
|
+
logger.expects(:warn).with "WARNING: descMetadata ignoring {\"fubar\" => \"the role\"} because \"fubar\" is a String (only valid OM Term Pointers will be used). Make sure your html has the correct field_selector tags in it."
|
81
82
|
@mods_ds.update_indexed_attributes( { "fubar"=>"the role" } ).should == {}
|
82
83
|
@mods_ds.to_xml.should == xml_before
|
83
84
|
end
|
@@ -192,16 +193,19 @@ describe ActiveFedora::NokogiriDatastream do
|
|
192
193
|
end
|
193
194
|
|
194
195
|
describe 'ng_xml=' do
|
196
|
+
before do
|
197
|
+
@test_ds2 = ActiveFedora::NokogiriDatastream.new(@mock_inner, "descMetadata")
|
198
|
+
end
|
195
199
|
it "should parse raw xml for you" do
|
196
|
-
@
|
197
|
-
@
|
198
|
-
@
|
199
|
-
@test_ds.ng_xml.to_xml.should be_equivalent_to(@sample_raw_xml)
|
200
|
+
@test_ds2.ng_xml = @sample_raw_xml
|
201
|
+
@test_ds2.ng_xml.class.should == Nokogiri::XML::Document
|
202
|
+
@test_ds2.ng_xml.to_xml.should be_equivalent_to(@sample_raw_xml)
|
200
203
|
end
|
201
204
|
it "should mark the datastream as dirty" do
|
202
|
-
@
|
203
|
-
@
|
204
|
-
@
|
205
|
+
@test_ds2.dirty.should be_false
|
206
|
+
@test_ds2.ng_xml = @sample_raw_xml
|
207
|
+
@test_ds2.dirty.should be_true #not the same as be_dirty
|
208
|
+
@test_ds2.should be_dirty
|
205
209
|
end
|
206
210
|
end
|
207
211
|
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe ActiveFedora::UnsavedDigitalObject do
|
4
|
+
it "should have ownerId property" do
|
5
|
+
@obj = ActiveFedora::UnsavedDigitalObject.new(String, 'bar')
|
6
|
+
@obj.ownerId = 'fooo'
|
7
|
+
@obj.ownerId.should == 'fooo'
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#save" do
|
11
|
+
it "should set the ownerId property" do
|
12
|
+
@obj = ActiveFedora::UnsavedDigitalObject.new(String, 'bar')
|
13
|
+
@obj.ownerId = 'fooo'
|
14
|
+
saved_obj = @obj.save
|
15
|
+
saved_obj.should be_kind_of ActiveFedora::DigitalObject
|
16
|
+
saved_obj.ownerId.should == 'fooo'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
metadata
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active-fedora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 1923832037
|
5
5
|
prerelease: 6
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 2
|
9
9
|
- 0
|
10
10
|
- pre
|
11
|
-
-
|
12
|
-
version: 3.2.0.
|
11
|
+
- 6
|
12
|
+
version: 3.2.0.pre6
|
13
13
|
platform: ruby
|
14
14
|
authors:
|
15
15
|
- Matt Zumwalt
|
@@ -19,7 +19,7 @@ autorequire:
|
|
19
19
|
bindir: bin
|
20
20
|
cert_chain: []
|
21
21
|
|
22
|
-
date: 2012-01-
|
22
|
+
date: 2012-01-02 00:00:00 -06:00
|
23
23
|
default_executable:
|
24
24
|
dependencies:
|
25
25
|
- !ruby/object:Gem::Dependency
|
@@ -568,6 +568,7 @@ files:
|
|
568
568
|
- lib/active_fedora/datastream.rb
|
569
569
|
- lib/active_fedora/datastream_collections.rb
|
570
570
|
- lib/active_fedora/datastream_hash.rb
|
571
|
+
- lib/active_fedora/datastreams.rb
|
571
572
|
- lib/active_fedora/delegating.rb
|
572
573
|
- lib/active_fedora/digital_object.rb
|
573
574
|
- lib/active_fedora/fedora_object.rb
|
@@ -721,6 +722,7 @@ files:
|
|
721
722
|
- spec/unit/service_definitions_spec.rb
|
722
723
|
- spec/unit/solr_config_options_spec.rb
|
723
724
|
- spec/unit/solr_service_spec.rb
|
725
|
+
- spec/unit/unsaved_digital_object_spec.rb
|
724
726
|
- spec/unit/validations_spec.rb
|
725
727
|
has_rdoc: true
|
726
728
|
homepage: http://yourmediashelf.com/activefedora
|
@@ -866,4 +868,5 @@ test_files:
|
|
866
868
|
- spec/unit/service_definitions_spec.rb
|
867
869
|
- spec/unit/solr_config_options_spec.rb
|
868
870
|
- spec/unit/solr_service_spec.rb
|
871
|
+
- spec/unit/unsaved_digital_object_spec.rb
|
869
872
|
- spec/unit/validations_spec.rb
|