active-fedora 3.2.0.pre5 → 3.2.0.pre6
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/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
|