active-fedora 3.1.5 → 3.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +3 -3
- data/History.txt +4 -0
- data/active-fedora.gemspec +1 -1
- data/lib/active_fedora.rb +1 -0
- data/lib/active_fedora/associations.rb +33 -0
- data/lib/active_fedora/base.rb +27 -332
- data/lib/active_fedora/datastream.rb +0 -1
- data/lib/active_fedora/datastream_collections.rb +326 -0
- data/lib/active_fedora/metadata_datastream.rb +24 -2
- data/lib/active_fedora/metadata_datastream_helper.rb +3 -25
- data/lib/active_fedora/version.rb +1 -1
- data/spec/integration/associations_spec.rb +14 -0
- data/spec/integration/full_featured_model_spec.rb +2 -3
- data/spec/unit/base_named_datastream_spec.rb +58 -56
- data/spec/unit/base_spec.rb +17 -0
- data/spec/unit/metadata_datastream_spec.rb +1 -0
- data/spec/unit/qualified_dublin_core_datastream_spec.rb +1 -0
- data/spec/unit/solr_config_options_spec.rb +0 -3
- metadata +8 -7
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
active-fedora (3.1.
|
4
|
+
active-fedora (3.1.6)
|
5
5
|
activeresource (~> 3.0.0)
|
6
6
|
activesupport (~> 3.0.0)
|
7
7
|
equivalent-xml
|
@@ -10,7 +10,7 @@ PATH
|
|
10
10
|
mime-types (>= 1.16)
|
11
11
|
multipart-post (= 1.1.2)
|
12
12
|
nokogiri
|
13
|
-
om (>= 1.4.
|
13
|
+
om (>= 1.4.4)
|
14
14
|
rdf
|
15
15
|
rdf-rdfxml
|
16
16
|
rubydora (~> 0.2.6)
|
@@ -69,7 +69,7 @@ GEM
|
|
69
69
|
multipart-post (1.1.2)
|
70
70
|
nokogiri (1.5.0)
|
71
71
|
nori (1.0.2)
|
72
|
-
om (1.4.
|
72
|
+
om (1.4.4)
|
73
73
|
mediashelf-loggable
|
74
74
|
nokogiri (>= 1.4.2)
|
75
75
|
rack (1.3.5)
|
data/History.txt
CHANGED
data/active-fedora.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |s|
|
|
20
20
|
s.add_dependency('mime-types', '>= 1.16')
|
21
21
|
s.add_dependency('multipart-post', "= 1.1.2")
|
22
22
|
s.add_dependency('nokogiri')
|
23
|
-
s.add_dependency('om', '>= 1.4.
|
23
|
+
s.add_dependency('om', '>= 1.4.4')
|
24
24
|
s.add_dependency('solrizer', '>1.0.0')
|
25
25
|
s.add_dependency("activeresource", '~> 3.0.0')
|
26
26
|
s.add_dependency("activesupport", '~> 3.0.0')
|
data/lib/active_fedora.rb
CHANGED
@@ -40,6 +40,39 @@ module ActiveFedora
|
|
40
40
|
end
|
41
41
|
|
42
42
|
|
43
|
+
# Specifies a one-to-one association with another class. This method should only be used
|
44
|
+
# if this class contains the foreign key.
|
45
|
+
#
|
46
|
+
# Methods will be added for retrieval and query for a single associated object, for which
|
47
|
+
# this object holds an id:
|
48
|
+
#
|
49
|
+
# [association()]
|
50
|
+
# Returns the associated object. +nil+ is returned if none is found.
|
51
|
+
# [association=(associate)]
|
52
|
+
# Assigns the associate object, extracts the primary key, and sets it as the foreign key.
|
53
|
+
#
|
54
|
+
# (+association+ is replaced with the symbol passed as the first argument, so
|
55
|
+
# <tt>belongs_to :author</tt> would add among others <tt>author.nil?</tt>.)
|
56
|
+
#
|
57
|
+
# === Example
|
58
|
+
#
|
59
|
+
# A Post class declares <tt>belongs_to :author</tt>, which will add:
|
60
|
+
# * <tt>Post#author</tt> (similar to <tt>Author.find(author_id)</tt>)
|
61
|
+
# * <tt>Post#author=(author)</tt>
|
62
|
+
# The declaration can also include an options hash to specialize the behavior of the association.
|
63
|
+
#
|
64
|
+
# === Options
|
65
|
+
#
|
66
|
+
# [:property]
|
67
|
+
# the association predicate to use when storing the association +REQUIRED+
|
68
|
+
# [:class_name]
|
69
|
+
# Specify the class name of the association. Use it only if that name can't be inferred
|
70
|
+
# from the association name. So <tt>has_one :author</tt> will by default be linked to the Author class, but
|
71
|
+
# if the real class name is Person, you'll have to specify it with this option.
|
72
|
+
#
|
73
|
+
# Option examples:
|
74
|
+
# belongs_to :firm, :property => :client_of
|
75
|
+
# belongs_to :author, :class_name => "Person", :property => :author_of
|
43
76
|
def belongs_to(association_id, options = {})
|
44
77
|
raise "You must specify a property name for #{name}" if !options[:property]
|
45
78
|
has_relationship association_id.to_s, options[:property]
|
data/lib/active_fedora/base.rb
CHANGED
@@ -32,12 +32,10 @@ module ActiveFedora
|
|
32
32
|
class Base
|
33
33
|
include RelationshipsHelper
|
34
34
|
include SemanticNode
|
35
|
-
class_inheritable_accessor :ds_specs
|
36
|
-
self.class_named_datastreams_desc = {}
|
35
|
+
class_inheritable_accessor :ds_specs
|
37
36
|
|
38
37
|
self.ds_specs = {'RELS-EXT'=> {:type=> ActiveFedora::RelsExtDatastream, :label=>"", :block=>nil}}
|
39
38
|
|
40
|
-
attr_accessor :named_datastreams_desc
|
41
39
|
|
42
40
|
|
43
41
|
has_relationship "collection_members", :has_collection_member
|
@@ -110,21 +108,29 @@ module ActiveFedora
|
|
110
108
|
ds_specs[args[:name]]= {:type => args[:type], :label => args.fetch(:label,""), :control_group => args.fetch(:control_group,"X"), :disseminator => args.fetch(:disseminator,""), :url => args.fetch(:url,""),:block => block}
|
111
109
|
end
|
112
110
|
|
111
|
+
|
113
112
|
def method_missing(name, *args)
|
114
|
-
|
113
|
+
dsid = corresponding_datastream_name(name)
|
114
|
+
if dsid
|
115
115
|
### Create and invoke a proxy method
|
116
|
-
self.class.
|
117
|
-
|
118
|
-
|
119
|
-
end
|
120
|
-
end_eval
|
121
|
-
|
116
|
+
self.class.send :define_method, name do
|
117
|
+
datastreams[dsid]
|
118
|
+
end
|
122
119
|
self.send(name)
|
123
120
|
else
|
124
121
|
super
|
125
122
|
end
|
126
123
|
end
|
127
124
|
|
125
|
+
## Given a method name, return the best-guess dsid
|
126
|
+
def corresponding_datastream_name(method_name)
|
127
|
+
dsid = method_name.to_s
|
128
|
+
return dsid if datastreams.has_key? dsid
|
129
|
+
unescaped_name = method_name.to_s.gsub('_', '-')
|
130
|
+
return unescaped_name if datastreams.has_key? unescaped_name
|
131
|
+
nil
|
132
|
+
end
|
133
|
+
|
128
134
|
#Saves a Base object, and any dirty datastreams, then updates
|
129
135
|
#the Solr index for this object.
|
130
136
|
def save
|
@@ -224,8 +230,9 @@ module ActiveFedora
|
|
224
230
|
datastreams[datastream.dsid] = datastream
|
225
231
|
return datastream.dsid
|
226
232
|
end
|
233
|
+
|
227
234
|
def add(datastream) # :nodoc:
|
228
|
-
warn "Warning: ActiveFedora::Base.add has been
|
235
|
+
warn "Warning: ActiveFedora::Base.add has been deprecated. Use add_datastream"
|
229
236
|
add_datastream(datastream)
|
230
237
|
end
|
231
238
|
|
@@ -258,21 +265,16 @@ module ActiveFedora
|
|
258
265
|
# return a valid dsid that is not currently in use. Uses a prefix (default "DS") and an auto-incrementing integer
|
259
266
|
# 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.
|
260
267
|
def generate_dsid(prefix="DS")
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
while keys.include?(new_dsid)
|
265
|
-
next_index += 1
|
266
|
-
new_dsid = prefix.to_s + next_index.to_s
|
267
|
-
end
|
268
|
-
new_dsid
|
269
|
-
|
270
|
-
# while keys.include?(new_dsid)
|
271
|
-
# next_index += 1
|
272
|
-
# new_dsid = prefix.to_s + rand(range).to_s
|
273
|
-
# end
|
268
|
+
matches = datastreams.keys.map {|d| data = /^#{prefix}(\d+)$/.match(d); data && data[1].to_i}.compact
|
269
|
+
val = matches.empty? ? 1 : matches.max + 1
|
270
|
+
format_dsid(prefix, val)
|
274
271
|
end
|
275
272
|
|
273
|
+
### Provided so that an application can override how generated pids are formatted (e.g DS01 instead of DS1)
|
274
|
+
def format_dsid(prefix, suffix)
|
275
|
+
sprintf("%s%i", prefix,suffix)
|
276
|
+
end
|
277
|
+
|
276
278
|
# Return the Dublin Core (DC) Datastream. You can also get at this via
|
277
279
|
# the +datastreams["DC"]+.
|
278
280
|
def dc
|
@@ -375,192 +377,6 @@ module ActiveFedora
|
|
375
377
|
# will rely on SemanticNode.remove_relationship once it is implemented
|
376
378
|
end
|
377
379
|
|
378
|
-
# ** EXPERIMENTAL **
|
379
|
-
#
|
380
|
-
# Returns array of datastream names defined for this object
|
381
|
-
def datastream_names
|
382
|
-
named_datastreams_desc.keys
|
383
|
-
end
|
384
|
-
|
385
|
-
# ** EXPERIMENTAL **
|
386
|
-
#
|
387
|
-
# Calls add_named_datastream while assuming it will be managed content and sets :blob and :controlGroup values accordingly
|
388
|
-
# ====Parameters
|
389
|
-
# name: Datastream name
|
390
|
-
# file: The file to add for this datastream
|
391
|
-
# opts: Options hash. See +add_named_datastream+ for expected keys and values
|
392
|
-
def add_named_file_datastream(name, file, opts={})
|
393
|
-
opts.merge!({:blob=>file,:controlGroup=>'M'})
|
394
|
-
add_named_datastream(name,opts)
|
395
|
-
end
|
396
|
-
|
397
|
-
# ** EXPERIMENTAL **
|
398
|
-
#
|
399
|
-
# This object is used by [datastream_name]_append helper to add a named datastream
|
400
|
-
# but can also be called directly.
|
401
|
-
# ====Parameters
|
402
|
-
# name: name of datastream to add
|
403
|
-
# opts: hash defining datastream attributes
|
404
|
-
# The following are expected keys in opts hash:
|
405
|
-
# :label => Defaults to the file name
|
406
|
-
# :blob or :file => Required to point to the datastream file being added if managed content
|
407
|
-
# :controlGroup => defaults to 'M' for managed, can also be 'E' external and 'R' for redirected
|
408
|
-
# :content_type => required if the file does not respond to 'content_type' and should match :mimeType in has_datastream definition if defined
|
409
|
-
# :dsLocation => holds uri location of datastream. Required only if :controlGroup is type 'E' or 'R'.
|
410
|
-
# :dsid or :dsId => Optional, and used to update an existing datastream with dsid supplied. Will throw an error if dsid does not exist and does not match prefix pattern for datastream name
|
411
|
-
def add_named_datastream(name,opts={})
|
412
|
-
unless named_datastreams_desc.has_key?(name) && named_datastreams_desc[name].has_key?(:type)
|
413
|
-
raise "Failed to add datastream. Named datastream #{name} not defined for object #{pid}."
|
414
|
-
end
|
415
|
-
|
416
|
-
if opts.has_key?(:mime_type)
|
417
|
-
opts.merge!({:content_type=>opts[:mime_type]})
|
418
|
-
elsif opts.has_key?(:mimeType)
|
419
|
-
opts.merge!({:content_type=>opts[:mimeType]})
|
420
|
-
end
|
421
|
-
opts.merge!(named_datastreams_desc[name])
|
422
|
-
|
423
|
-
label = opts.has_key?(:label) ? opts[:label] : ""
|
424
|
-
|
425
|
-
#only do these steps for managed datastreams
|
426
|
-
unless (opts.has_key?(:controlGroup)&&opts[:controlGroup]!="M")
|
427
|
-
if opts.has_key?(:file)
|
428
|
-
opts.merge!({:blob => opts[:file]})
|
429
|
-
opts.delete(:file)
|
430
|
-
end
|
431
|
-
|
432
|
-
raise "You must define parameter blob for this managed datastream to load for #{pid}" unless opts.has_key?(:blob)
|
433
|
-
|
434
|
-
#if no explicit label and is a file use original file name for label
|
435
|
-
if !opts.has_key?(:label)&&opts[:blob].respond_to?(:original_filename)
|
436
|
-
label = opts[:blob].original_filename
|
437
|
-
end
|
438
|
-
|
439
|
-
if opts[:blob].respond_to?(:content_type)&&!opts[:blob].content_type.nil? && !opts.has_key?(:content_type)
|
440
|
-
opts.merge!({:content_type=>opts[:blob].content_type})
|
441
|
-
end
|
442
|
-
|
443
|
-
raise "The blob must respond to content_type or the hash must have :content_type or :mime_type property set" unless opts.has_key?(:content_type)
|
444
|
-
|
445
|
-
#throw error for mimeType mismatch
|
446
|
-
if named_datastreams_desc[name].has_key?(:mimeType) && !named_datastreams_desc[name][:mimeType].eql?(opts[:content_type])
|
447
|
-
raise "Content type mismatch for add datastream #{name} to #{pid}. Expected: #{named_datastreams_desc[name][:mimeType]}, Actual: #{opts[:content_type]}"
|
448
|
-
end
|
449
|
-
else
|
450
|
-
label = opts[:dsLocation] if (opts.has_key?(:dsLocation))
|
451
|
-
end
|
452
|
-
|
453
|
-
opts.merge!(:dsLabel => label)
|
454
|
-
|
455
|
-
ds = create_datastream(named_datastreams_desc[name][:type], opts[:dsid], opts)
|
456
|
-
#Must be of type datastream
|
457
|
-
assert_kind_of 'datastream', ds, ActiveFedora::Datastream
|
458
|
-
#make sure dsid is nil so that it uses the prefix for mapping purposes
|
459
|
-
#check dsid works for the prefix if it is set
|
460
|
-
if !ds.dsid.nil? && opts.has_key?(:prefix)
|
461
|
-
raise "dsid supplied does not conform to pattern #{opts[:prefix]}[number]" unless ds.dsid =~ /#{opts[:prefix]}[0-9]/
|
462
|
-
end
|
463
|
-
|
464
|
-
add_datastream(ds,opts)
|
465
|
-
end
|
466
|
-
|
467
|
-
# ** EXPERIMENTAL **
|
468
|
-
#
|
469
|
-
# Update an existing named datastream. It has same parameters as add_named_datastream
|
470
|
-
# except the :dsid key is now required.
|
471
|
-
#
|
472
|
-
# ====TODO
|
473
|
-
# Currently requires you to update file if a managed datastream
|
474
|
-
# but could change to allow metadata only updates as well
|
475
|
-
def update_named_datastream(name, opts={})
|
476
|
-
#check that dsid provided matches existing datastream with that name
|
477
|
-
raise "You must define parameter dsid for datastream to update for #{pid}" unless opts.include?(:dsid)
|
478
|
-
raise "Datastream with name #{name} and dsid #{opts[:dsid]} does not exist for #{pid}" unless self.send("#{name}_ids").include?(opts[:dsid])
|
479
|
-
add_named_datastream(name,opts)
|
480
|
-
end
|
481
|
-
|
482
|
-
# ** EXPERIMENTAL **
|
483
|
-
#
|
484
|
-
# Throws an assertion failure unless the object 'o' is kind_of? class 't'
|
485
|
-
# ====Parameters
|
486
|
-
# n: Name of object
|
487
|
-
# o: The object to test
|
488
|
-
# t: The class type to check is kind_of?
|
489
|
-
def assert_kind_of(n, o,t)
|
490
|
-
raise "Assertion failure: #{n}: #{o} is not of type #{t}" unless o.kind_of?(t)
|
491
|
-
end
|
492
|
-
|
493
|
-
# ** EXPERIMENTAL **
|
494
|
-
#
|
495
|
-
# Returns true if the name is a defined named datastream
|
496
|
-
def is_named_datastream?(name)
|
497
|
-
named_datastreams_desc.has_key?(name)
|
498
|
-
end
|
499
|
-
|
500
|
-
# ** EXPERIMENTAL **
|
501
|
-
#
|
502
|
-
# Returns hash of datastream names defined by has_datastream calls mapped to
|
503
|
-
# array of datastream objects that have been added
|
504
|
-
# ====Example
|
505
|
-
# For the following has_datastream entries and a datastream defined for minivan only would be
|
506
|
-
# has_datastream :name=>"minivan", :prefix => "VAN", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'M'
|
507
|
-
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
508
|
-
#
|
509
|
-
# Returns
|
510
|
-
# {"external_images"=>[],"thumbnails"=>{#<ActiveFedora::Datastream:0x7ffd6512daf8 ...}}
|
511
|
-
def named_datastreams
|
512
|
-
ds_values = {}
|
513
|
-
self.class.named_datastreams_desc.keys.each do |name|
|
514
|
-
ds_values.merge!({name=>self.send("#{name}")})
|
515
|
-
end
|
516
|
-
return ds_values
|
517
|
-
end
|
518
|
-
|
519
|
-
# ** EXPERIMENTAL **
|
520
|
-
#
|
521
|
-
# Returns hash of datastream names mapped to an array
|
522
|
-
# of dsid's for named datastream objects
|
523
|
-
# === Example
|
524
|
-
# For the following has_datastream call, assume we have added two datastreams.
|
525
|
-
#
|
526
|
-
# has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
|
527
|
-
#
|
528
|
-
# It would then return
|
529
|
-
# {"thumbnails=>["THUMB1", "THUMB2"]}
|
530
|
-
def named_datastreams_ids
|
531
|
-
dsids = {}
|
532
|
-
self.class.named_datastreams_desc.keys.each do |name|
|
533
|
-
dsid_array = self.send("#{name}_ids")
|
534
|
-
dsids[name] = dsid_array
|
535
|
-
end
|
536
|
-
return dsids
|
537
|
-
end
|
538
|
-
|
539
|
-
# ** EXPERIMENTAL **
|
540
|
-
#
|
541
|
-
# Returns the hash that stores arguments passed to has_datastream calls within an
|
542
|
-
# ActiveFedora::Base child class.
|
543
|
-
#
|
544
|
-
# has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
|
545
|
-
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
546
|
-
#
|
547
|
-
# The above examples result in the following hash
|
548
|
-
# {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
|
549
|
-
# "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
|
550
|
-
#
|
551
|
-
# This hash is later used when adding a named datastream such as an "audio_file" as defined above.
|
552
|
-
def named_datastreams_desc
|
553
|
-
@named_datastreams_desc ||= named_datastreams_desc_from_class
|
554
|
-
end
|
555
|
-
|
556
|
-
# ** EXPERIMENTAL **
|
557
|
-
#
|
558
|
-
# Get class variable hash that stores has_datastream arguments.
|
559
|
-
# It is used to initialize the value returned by public named_datastreams_desc method
|
560
|
-
def named_datastreams_desc_from_class
|
561
|
-
self.class.named_datastreams_desc
|
562
|
-
end
|
563
|
-
|
564
380
|
def create_datastream(type, dsid, opts={})
|
565
381
|
dsid = generate_dsid(opts[:prefix] || "DS") if dsid == nil
|
566
382
|
klass = type.kind_of?(Class) ? type : type.constantize
|
@@ -587,128 +403,6 @@ module ActiveFedora
|
|
587
403
|
ds
|
588
404
|
end
|
589
405
|
|
590
|
-
# ** EXPERIMENTAL **
|
591
|
-
#
|
592
|
-
# Allows for a datastream to be treated like any other attribute of a model class
|
593
|
-
# while enforcing mimeType and/or datastream type (ie. external, managed, etc.) if defined.
|
594
|
-
# ====Examples
|
595
|
-
#
|
596
|
-
# has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
|
597
|
-
# has_datastream :name=>"EADs", :type=>ActiveFedora::Datastream, :mimeType=>"application/xml", :controlGroup=>'M'
|
598
|
-
# has_datastream :name=>"external_images", :type=>ActiveFedora::Datastream, :controlGroup=>'E'
|
599
|
-
#
|
600
|
-
# Required Keys in args
|
601
|
-
# :name - name to give this datastream (must be unique)
|
602
|
-
#
|
603
|
-
# Optional Keys in args
|
604
|
-
# :prefix - used to create the DSID plus an index ie. THUMB1, THUMB2. If :prefix is not specified, defaults to :name value in all uppercase
|
605
|
-
# :type - defaults to ActiveFedora::Datastream if you would like content specific class to be used supply it here
|
606
|
-
# :mimeType - if supplied it will ensure any datastreams added are of this type, if not supplied any mimeType is acceptabl e
|
607
|
-
# :controlGroup - possible values "X", "M", "R", or "E" (InlineXML, Managed Content, Redirect, or External Referenced) If controlGroup is 'E' or 'R' it expects a dsLocation be defined when adding the datastream.
|
608
|
-
#
|
609
|
-
# You use the datastream attribute using helper methods created for each datastream name:
|
610
|
-
#
|
611
|
-
# ====Helper Method Examples
|
612
|
-
# thumbnails_append - Append a thumbnail datastream
|
613
|
-
# thumbnails - Get array of thumbnail datastreams
|
614
|
-
# thumbnails_ids - Get array of dsid's for thumbnail datastreams
|
615
|
-
#
|
616
|
-
# When loading the list of datastreams for a name from Fedora it uses the DSID prefix to find them in Fedora
|
617
|
-
def self.has_datastream(args)
|
618
|
-
unless args.has_key?(:name)
|
619
|
-
return false
|
620
|
-
end
|
621
|
-
unless args.has_key?(:prefix)
|
622
|
-
args.merge!({:prefix=>args[:name].to_s.upcase})
|
623
|
-
end
|
624
|
-
unless named_datastreams_desc.has_key?(args[:name])
|
625
|
-
named_datastreams_desc[args[:name]] = {}
|
626
|
-
end
|
627
|
-
|
628
|
-
args.merge!({:mimeType=>args[:mime_type]}) if args.has_key?(:mime_type)
|
629
|
-
|
630
|
-
unless named_datastreams_desc[args[:name]].has_key?(:type)
|
631
|
-
#default to type ActiveFedora::Datastream
|
632
|
-
args.merge!({:type => "ActiveFedora::Datastream"})
|
633
|
-
end
|
634
|
-
named_datastreams_desc[args[:name]]= args
|
635
|
-
create_named_datastream_finders(args[:name],args[:prefix])
|
636
|
-
create_named_datastream_update_methods(args[:name])
|
637
|
-
end
|
638
|
-
|
639
|
-
# ** EXPERIMENTAL **
|
640
|
-
#
|
641
|
-
# Creates the following helper methods for a datastream name
|
642
|
-
# [datastream_name]_append - Add a named datastream
|
643
|
-
#
|
644
|
-
# ==== Examples for "thumbnails" datastream
|
645
|
-
# thumbnails_append - Append a thumbnail datastream
|
646
|
-
# TODO: Add [datastream_name]_remove
|
647
|
-
def self.create_named_datastream_update_methods(name)
|
648
|
-
append_file_method_name = "#{name.to_s.downcase}_file_append"
|
649
|
-
append_method_name = "#{name.to_s.downcase}_append"
|
650
|
-
#remove_method_name = "#{name.to_s.downcase}_remove"
|
651
|
-
self.send(:define_method,:"#{append_file_method_name}") do |*args|
|
652
|
-
file,opts = *args
|
653
|
-
opts ||= {}
|
654
|
-
add_named_file_datastream(name,file,opts)
|
655
|
-
end
|
656
|
-
|
657
|
-
self.send(:define_method,:"#{append_method_name}") do |*args|
|
658
|
-
#call add_named_datastream instead of add_file_named_datastream in case not managed datastream
|
659
|
-
add_named_datastream(name,*args)
|
660
|
-
end
|
661
|
-
end
|
662
|
-
|
663
|
-
# ** EXPERIMENTAL **
|
664
|
-
#
|
665
|
-
# Creates the following helper methods for a datastream name
|
666
|
-
# [datastream_name] - Returns array of named datastreams
|
667
|
-
# [datastream_name]_ids - Returns array of named datastream dsids
|
668
|
-
#
|
669
|
-
# ==== Examples for "thumbnails" datastream
|
670
|
-
# thumbnails - Get array of thumbnail datastreams
|
671
|
-
# thumbnails_ids - Get array of dsid's for thumbnail datastreams
|
672
|
-
def self.create_named_datastream_finders(name, prefix)
|
673
|
-
class_eval <<-END, __FILE__, __LINE__
|
674
|
-
def #{name}(opts={})
|
675
|
-
id_array = []
|
676
|
-
keys = datastreams.keys
|
677
|
-
id_array = keys.select {|v| v =~ /#{prefix}\d*/}
|
678
|
-
if opts[:response_format] == :id_array
|
679
|
-
return id_array
|
680
|
-
else
|
681
|
-
named_ds = []
|
682
|
-
id_array.each do |name|
|
683
|
-
if datastreams.has_key?(name)
|
684
|
-
named_ds.push(datastreams[name])
|
685
|
-
end
|
686
|
-
end
|
687
|
-
return named_ds
|
688
|
-
end
|
689
|
-
end
|
690
|
-
def #{name}_ids
|
691
|
-
#{name}(:response_format => :id_array)
|
692
|
-
end
|
693
|
-
END
|
694
|
-
end
|
695
|
-
|
696
|
-
# ** EXPERIMENTAL **
|
697
|
-
#
|
698
|
-
# Accessor for class variable for hash that stores arguments passed to has_datastream calls within an
|
699
|
-
# ActiveFedora::Base child class.
|
700
|
-
#
|
701
|
-
# has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
|
702
|
-
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
703
|
-
#
|
704
|
-
# The above examples result in the following hash
|
705
|
-
# {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
|
706
|
-
# "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
|
707
|
-
#
|
708
|
-
# This hash is later used when adding a named datastream such as an "audio_file" as defined above.
|
709
|
-
def self.named_datastreams_desc
|
710
|
-
self.class_named_datastreams_desc ||= {}
|
711
|
-
end
|
712
406
|
|
713
407
|
#
|
714
408
|
# Relationships Management
|
@@ -1073,6 +767,7 @@ module ActiveFedora
|
|
1073
767
|
include Associations
|
1074
768
|
include NestedAttributes
|
1075
769
|
include Reflection
|
770
|
+
include DatastreamCollections
|
1076
771
|
end
|
1077
772
|
|
1078
773
|
end
|
@@ -0,0 +1,326 @@
|
|
1
|
+
module DatastreamCollections
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
class_inheritable_accessor :class_named_datastreams_desc
|
6
|
+
self.class_named_datastreams_desc = {}
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
|
11
|
+
# ** EXPERIMENTAL **
|
12
|
+
#
|
13
|
+
# Allows for a datastream to be treated like any other attribute of a model class
|
14
|
+
# while enforcing mimeType and/or datastream type (ie. external, managed, etc.) if defined.
|
15
|
+
# ====Examples
|
16
|
+
#
|
17
|
+
# has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
|
18
|
+
# has_datastream :name=>"EADs", :type=>ActiveFedora::Datastream, :mimeType=>"application/xml", :controlGroup=>'M'
|
19
|
+
# has_datastream :name=>"external_images", :type=>ActiveFedora::Datastream, :controlGroup=>'E'
|
20
|
+
#
|
21
|
+
# Required Keys in args
|
22
|
+
# :name - name to give this datastream (must be unique)
|
23
|
+
#
|
24
|
+
# Optional Keys in args
|
25
|
+
# :prefix - used to create the DSID plus an index ie. THUMB1, THUMB2. If :prefix is not specified, defaults to :name value in all uppercase
|
26
|
+
# :type - defaults to ActiveFedora::Datastream if you would like content specific class to be used supply it here
|
27
|
+
# :mimeType - if supplied it will ensure any datastreams added are of this type, if not supplied any mimeType is acceptabl e
|
28
|
+
# :controlGroup - possible values "X", "M", "R", or "E" (InlineXML, Managed Content, Redirect, or External Referenced) If controlGroup is 'E' or 'R' it expects a dsLocation be defined when adding the datastream.
|
29
|
+
#
|
30
|
+
# You use the datastream attribute using helper methods created for each datastream name:
|
31
|
+
#
|
32
|
+
# ====Helper Method Examples
|
33
|
+
# thumbnails_append - Append a thumbnail datastream
|
34
|
+
# thumbnails - Get array of thumbnail datastreams
|
35
|
+
# thumbnails_ids - Get array of dsid's for thumbnail datastreams
|
36
|
+
#
|
37
|
+
# When loading the list of datastreams for a name from Fedora it uses the DSID prefix to find them in Fedora
|
38
|
+
def has_datastream(args)
|
39
|
+
unless args.has_key?(:name)
|
40
|
+
return false
|
41
|
+
end
|
42
|
+
unless args.has_key?(:prefix)
|
43
|
+
args.merge!({:prefix=>args[:name].to_s.upcase})
|
44
|
+
end
|
45
|
+
unless class_named_datastreams_desc.has_key?(args[:name])
|
46
|
+
class_named_datastreams_desc[args[:name]] = {}
|
47
|
+
end
|
48
|
+
|
49
|
+
args.merge!({:mimeType=>args[:mime_type]}) if args.has_key?(:mime_type)
|
50
|
+
|
51
|
+
unless class_named_datastreams_desc[args[:name]].has_key?(:type)
|
52
|
+
#default to type ActiveFedora::Datastream
|
53
|
+
args.merge!({:type => "ActiveFedora::Datastream"})
|
54
|
+
end
|
55
|
+
class_named_datastreams_desc[args[:name]]= args
|
56
|
+
create_named_datastream_finders(args[:name],args[:prefix])
|
57
|
+
create_named_datastream_update_methods(args[:name])
|
58
|
+
end
|
59
|
+
|
60
|
+
# ** EXPERIMENTAL **
|
61
|
+
#
|
62
|
+
# Creates the following helper methods for a datastream name
|
63
|
+
# [datastream_name]_append - Add a named datastream
|
64
|
+
#
|
65
|
+
# ==== Examples for "thumbnails" datastream
|
66
|
+
# thumbnails_append - Append a thumbnail datastream
|
67
|
+
# TODO: Add [datastream_name]_remove
|
68
|
+
def create_named_datastream_update_methods(name)
|
69
|
+
append_file_method_name = "#{name.to_s.downcase}_file_append"
|
70
|
+
append_method_name = "#{name.to_s.downcase}_append"
|
71
|
+
#remove_method_name = "#{name.to_s.downcase}_remove"
|
72
|
+
self.send(:define_method,:"#{append_file_method_name}") do |*args|
|
73
|
+
file,opts = *args
|
74
|
+
opts ||= {}
|
75
|
+
add_named_file_datastream(name,file,opts)
|
76
|
+
end
|
77
|
+
|
78
|
+
self.send(:define_method,:"#{append_method_name}") do |*args|
|
79
|
+
#call add_named_datastream instead of add_file_named_datastream in case not managed datastream
|
80
|
+
add_named_datastream(name,*args)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# ** EXPERIMENTAL **
|
85
|
+
#
|
86
|
+
# Creates the following helper methods for a datastream name
|
87
|
+
# [datastream_name] - Returns array of named datastreams
|
88
|
+
# [datastream_name]_ids - Returns array of named datastream dsids
|
89
|
+
#
|
90
|
+
# ==== Examples for "thumbnails" datastream
|
91
|
+
# thumbnails - Get array of thumbnail datastreams
|
92
|
+
# thumbnails_ids - Get array of dsid's for thumbnail datastreams
|
93
|
+
def create_named_datastream_finders(name, prefix)
|
94
|
+
class_eval <<-END, __FILE__, __LINE__
|
95
|
+
def #{name}(opts={})
|
96
|
+
id_array = []
|
97
|
+
keys = datastreams.keys
|
98
|
+
id_array = keys.select {|v| v =~ /#{prefix}\d*/}
|
99
|
+
if opts[:response_format] == :id_array
|
100
|
+
return id_array
|
101
|
+
else
|
102
|
+
named_ds = []
|
103
|
+
id_array.each do |name|
|
104
|
+
if datastreams.has_key?(name)
|
105
|
+
named_ds.push(datastreams[name])
|
106
|
+
end
|
107
|
+
end
|
108
|
+
return named_ds
|
109
|
+
end
|
110
|
+
end
|
111
|
+
def #{name}_ids
|
112
|
+
#{name}(:response_format => :id_array)
|
113
|
+
end
|
114
|
+
END
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
# ** EXPERIMENTAL **
|
122
|
+
#
|
123
|
+
# Accessor for class variable for hash that stores arguments passed to has_datastream calls within an
|
124
|
+
# ActiveFedora::Base child class.
|
125
|
+
#
|
126
|
+
# has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
|
127
|
+
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
128
|
+
#
|
129
|
+
# The above examples result in the following hash
|
130
|
+
# {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
|
131
|
+
# "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
|
132
|
+
#
|
133
|
+
# This hash is later used when adding a named datastream such as an "audio_file" as defined above.
|
134
|
+
def named_datastreams_desc
|
135
|
+
self.class_named_datastreams_desc ||= {}
|
136
|
+
end
|
137
|
+
|
138
|
+
# ** EXPERIMENTAL **
|
139
|
+
#
|
140
|
+
# Returns array of datastream names defined for this object
|
141
|
+
def datastream_names
|
142
|
+
named_datastreams_desc.keys
|
143
|
+
end
|
144
|
+
|
145
|
+
# ** EXPERIMENTAL **
|
146
|
+
#
|
147
|
+
# Calls add_named_datastream while assuming it will be managed content and sets :blob and :controlGroup values accordingly
|
148
|
+
# ====Parameters
|
149
|
+
# name: Datastream name
|
150
|
+
# file: The file to add for this datastream
|
151
|
+
# opts: Options hash. See +add_named_datastream+ for expected keys and values
|
152
|
+
def add_named_file_datastream(name, file, opts={})
|
153
|
+
opts.merge!({:blob=>file,:controlGroup=>'M'})
|
154
|
+
add_named_datastream(name,opts)
|
155
|
+
end
|
156
|
+
|
157
|
+
# ** EXPERIMENTAL **
|
158
|
+
#
|
159
|
+
# This object is used by [datastream_name]_append helper to add a named datastream
|
160
|
+
# but can also be called directly.
|
161
|
+
# ====Parameters
|
162
|
+
# name: name of datastream to add
|
163
|
+
# opts: hash defining datastream attributes
|
164
|
+
# The following are expected keys in opts hash:
|
165
|
+
# :label => Defaults to the file name
|
166
|
+
# :blob or :file => Required to point to the datastream file being added if managed content
|
167
|
+
# :controlGroup => defaults to 'M' for managed, can also be 'E' external and 'R' for redirected
|
168
|
+
# :content_type => required if the file does not respond to 'content_type' and should match :mimeType in has_datastream definition if defined
|
169
|
+
# :dsLocation => holds uri location of datastream. Required only if :controlGroup is type 'E' or 'R'.
|
170
|
+
# :dsid or :dsId => Optional, and used to update an existing datastream with dsid supplied. Will throw an error if dsid does not exist and does not match prefix pattern for datastream name
|
171
|
+
def add_named_datastream(name,opts={})
|
172
|
+
unless named_datastreams_desc.has_key?(name) && named_datastreams_desc[name].has_key?(:type)
|
173
|
+
raise "Failed to add datastream. Named datastream #{name} not defined for object #{pid}."
|
174
|
+
end
|
175
|
+
|
176
|
+
if opts.has_key?(:mime_type)
|
177
|
+
opts.merge!({:content_type=>opts[:mime_type]})
|
178
|
+
elsif opts.has_key?(:mimeType)
|
179
|
+
opts.merge!({:content_type=>opts[:mimeType]})
|
180
|
+
end
|
181
|
+
opts.merge!(named_datastreams_desc[name])
|
182
|
+
|
183
|
+
label = opts.has_key?(:label) ? opts[:label] : ""
|
184
|
+
|
185
|
+
#only do these steps for managed datastreams
|
186
|
+
unless (opts.has_key?(:controlGroup)&&opts[:controlGroup]!="M")
|
187
|
+
if opts.has_key?(:file)
|
188
|
+
opts.merge!({:blob => opts[:file]})
|
189
|
+
opts.delete(:file)
|
190
|
+
end
|
191
|
+
|
192
|
+
raise "You must define parameter blob for this managed datastream to load for #{pid}" unless opts.has_key?(:blob)
|
193
|
+
|
194
|
+
#if no explicit label and is a file use original file name for label
|
195
|
+
if !opts.has_key?(:label)&&opts[:blob].respond_to?(:original_filename)
|
196
|
+
label = opts[:blob].original_filename
|
197
|
+
end
|
198
|
+
|
199
|
+
if opts[:blob].respond_to?(:content_type)&&!opts[:blob].content_type.nil? && !opts.has_key?(:content_type)
|
200
|
+
opts.merge!({:content_type=>opts[:blob].content_type})
|
201
|
+
end
|
202
|
+
|
203
|
+
raise "The blob must respond to content_type or the hash must have :content_type or :mime_type property set" unless opts.has_key?(:content_type)
|
204
|
+
|
205
|
+
#throw error for mimeType mismatch
|
206
|
+
if named_datastreams_desc[name].has_key?(:mimeType) && !named_datastreams_desc[name][:mimeType].eql?(opts[:content_type])
|
207
|
+
raise "Content type mismatch for add datastream #{name} to #{pid}. Expected: #{named_datastreams_desc[name][:mimeType]}, Actual: #{opts[:content_type]}"
|
208
|
+
end
|
209
|
+
else
|
210
|
+
label = opts[:dsLocation] if (opts.has_key?(:dsLocation))
|
211
|
+
end
|
212
|
+
|
213
|
+
opts.merge!(:dsLabel => label)
|
214
|
+
|
215
|
+
ds = create_datastream(named_datastreams_desc[name][:type], opts[:dsid], opts)
|
216
|
+
#Must be of type datastream
|
217
|
+
assert_kind_of 'datastream', ds, ActiveFedora::Datastream
|
218
|
+
#make sure dsid is nil so that it uses the prefix for mapping purposes
|
219
|
+
#check dsid works for the prefix if it is set
|
220
|
+
if !ds.dsid.nil? && opts.has_key?(:prefix)
|
221
|
+
raise "dsid supplied does not conform to pattern #{opts[:prefix]}[number]" unless ds.dsid =~ /#{opts[:prefix]}[0-9]/
|
222
|
+
end
|
223
|
+
|
224
|
+
add_datastream(ds,opts)
|
225
|
+
end
|
226
|
+
|
227
|
+
# ** EXPERIMENTAL **
|
228
|
+
#
|
229
|
+
# Update an existing named datastream. It has same parameters as add_named_datastream
|
230
|
+
# except the :dsid key is now required.
|
231
|
+
#
|
232
|
+
# ====TODO
|
233
|
+
# Currently requires you to update file if a managed datastream
|
234
|
+
# but could change to allow metadata only updates as well
|
235
|
+
def update_named_datastream(name, opts={})
|
236
|
+
#check that dsid provided matches existing datastream with that name
|
237
|
+
raise "You must define parameter dsid for datastream to update for #{pid}" unless opts.include?(:dsid)
|
238
|
+
raise "Datastream with name #{name} and dsid #{opts[:dsid]} does not exist for #{pid}" unless self.send("#{name}_ids").include?(opts[:dsid])
|
239
|
+
add_named_datastream(name,opts)
|
240
|
+
end
|
241
|
+
|
242
|
+
# ** EXPERIMENTAL **
|
243
|
+
#
|
244
|
+
# Throws an assertion failure unless the object 'o' is kind_of? class 't'
|
245
|
+
# ====Parameters
|
246
|
+
# n: Name of object
|
247
|
+
# o: The object to test
|
248
|
+
# t: The class type to check is kind_of?
|
249
|
+
def assert_kind_of(n, o,t)
|
250
|
+
raise "Assertion failure: #{n}: #{o} is not of type #{t}" unless o.kind_of?(t)
|
251
|
+
end
|
252
|
+
|
253
|
+
# ** EXPERIMENTAL **
|
254
|
+
#
|
255
|
+
# Returns true if the name is a defined named datastream
|
256
|
+
def is_named_datastream?(name)
|
257
|
+
named_datastreams_desc.has_key?(name)
|
258
|
+
end
|
259
|
+
|
260
|
+
# ** EXPERIMENTAL **
|
261
|
+
#
|
262
|
+
# Returns hash of datastream names defined by has_datastream calls mapped to
|
263
|
+
# array of datastream objects that have been added
|
264
|
+
# ====Example
|
265
|
+
# For the following has_datastream entries and a datastream defined for minivan only would be
|
266
|
+
# has_datastream :name=>"minivan", :prefix => "VAN", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'M'
|
267
|
+
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
268
|
+
#
|
269
|
+
# Returns
|
270
|
+
# {"external_images"=>[],"thumbnails"=>{#<ActiveFedora::Datastream:0x7ffd6512daf8 ...}}
|
271
|
+
def named_datastreams
|
272
|
+
ds_values = {}
|
273
|
+
self.class.class_named_datastreams_desc.keys.each do |name|
|
274
|
+
ds_values.merge!({name=>self.send("#{name}")})
|
275
|
+
end
|
276
|
+
return ds_values
|
277
|
+
end
|
278
|
+
|
279
|
+
# ** EXPERIMENTAL **
|
280
|
+
#
|
281
|
+
# Returns hash of datastream names mapped to an array
|
282
|
+
# of dsid's for named datastream objects
|
283
|
+
# === Example
|
284
|
+
# For the following has_datastream call, assume we have added two datastreams.
|
285
|
+
#
|
286
|
+
# has_datastream :name=>"thumbnails",:prefix => "THUMB",:type=>ActiveFedora::Datastream, :mimeType=>"image/jpeg", :controlGroup=>'M'
|
287
|
+
#
|
288
|
+
# It would then return
|
289
|
+
# {"thumbnails=>["THUMB1", "THUMB2"]}
|
290
|
+
def named_datastreams_ids
|
291
|
+
dsids = {}
|
292
|
+
self.class.class_named_datastreams_desc.keys.each do |name|
|
293
|
+
dsid_array = self.send("#{name}_ids")
|
294
|
+
dsids[name] = dsid_array
|
295
|
+
end
|
296
|
+
return dsids
|
297
|
+
end
|
298
|
+
|
299
|
+
# ** EXPERIMENTAL **
|
300
|
+
#
|
301
|
+
# Returns the hash that stores arguments passed to has_datastream calls within an
|
302
|
+
# ActiveFedora::Base child class.
|
303
|
+
#
|
304
|
+
# has_datastream :name=>"audio_file", :prefix=>"AUDIO", :type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav"
|
305
|
+
# has_datastream :name=>"external_images", :prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'
|
306
|
+
#
|
307
|
+
# The above examples result in the following hash
|
308
|
+
# {"audio_file"=>{:prefix=>"AUDIO",:type=>ActiveFedora::Datastream, :mimeType=>"audio/x-wav", :controlGroup=>'M'},
|
309
|
+
# "external_images=>{:prefix=>"EXTIMG", :type=>ActiveFedora::Datastream,:mimeType=>"image/jpeg", :controlGroup=>'E'}}
|
310
|
+
#
|
311
|
+
# This hash is later used when adding a named datastream such as an "audio_file" as defined above.
|
312
|
+
def named_datastreams_desc
|
313
|
+
@named_datastreams_desc ||= self.class.class_named_datastreams_desc
|
314
|
+
end
|
315
|
+
|
316
|
+
# ** EXPERIMENTAL **
|
317
|
+
#
|
318
|
+
# Get class variable hash that stores has_datastream arguments.
|
319
|
+
# It is used to initialize the value returned by public named_datastreams_desc method
|
320
|
+
# Deprecated
|
321
|
+
def named_datastreams_desc_from_class
|
322
|
+
logger.warn "named_datastreams_desc_from_class is deprecated and will be removed in the next version"
|
323
|
+
self.class.class_named_datastreams_desc
|
324
|
+
end
|
325
|
+
|
326
|
+
end
|
@@ -8,10 +8,9 @@ module ActiveFedora
|
|
8
8
|
# </fields>
|
9
9
|
class MetadataDatastream < Datastream
|
10
10
|
|
11
|
+
# .to_solr (among other things) is provided by ActiveFedora::MetadataDatastreamHelper
|
11
12
|
include ActiveFedora::MetadataDatastreamHelper
|
12
13
|
|
13
|
-
# .to_solr and .to_xml (among other things) are provided by ActiveFedora::MetadataDatastreamHelper
|
14
|
-
self.xml_model = ActiveFedora::MetadataDatastream
|
15
14
|
|
16
15
|
def update_attributes(params={},opts={})
|
17
16
|
result = params.dup
|
@@ -144,6 +143,29 @@ module ActiveFedora
|
|
144
143
|
tmpl.send(:dirty=, false)
|
145
144
|
tmpl
|
146
145
|
end
|
146
|
+
|
147
|
+
def to_xml(xml = Nokogiri::XML::Document.parse("<fields />")) #:nodoc:
|
148
|
+
if xml.instance_of?(Nokogiri::XML::Builder)
|
149
|
+
xml_insertion_point = xml.doc.root
|
150
|
+
elsif xml.instance_of?(Nokogiri::XML::Document)
|
151
|
+
xml_insertion_point = xml.root
|
152
|
+
else
|
153
|
+
xml_insertion_point = xml
|
154
|
+
end
|
155
|
+
|
156
|
+
builder = Nokogiri::XML::Builder.with(xml_insertion_point) do |xml|
|
157
|
+
fields.each_pair do |field,field_info|
|
158
|
+
element_attrs = field_info[:element_attrs].nil? ? {} : field_info[:element_attrs]
|
159
|
+
values = field_info[:values]
|
160
|
+
values = [values] unless values.respond_to? :each
|
161
|
+
values.each do |val|
|
162
|
+
builder_arg = "xml.#{field}(val, element_attrs)"
|
163
|
+
eval(builder_arg)
|
164
|
+
end
|
165
|
+
end
|
166
|
+
end
|
167
|
+
return builder.to_xml
|
168
|
+
end
|
147
169
|
|
148
170
|
# This method generates the various accessor and mutator methods on self for the datastream metadata attributes.
|
149
171
|
# each field will have the 3 magic methods:
|
@@ -7,8 +7,6 @@ module ActiveFedora::MetadataDatastreamHelper
|
|
7
7
|
|
8
8
|
module ClassMethods
|
9
9
|
|
10
|
-
attr_accessor :xml_model
|
11
|
-
|
12
10
|
#get the Class's field list
|
13
11
|
def fields
|
14
12
|
@@classFields
|
@@ -28,7 +26,9 @@ module ActiveFedora::MetadataDatastreamHelper
|
|
28
26
|
end
|
29
27
|
|
30
28
|
def serialize! # :nodoc:
|
31
|
-
|
29
|
+
if dirty?
|
30
|
+
self.content = self.to_xml
|
31
|
+
end
|
32
32
|
end
|
33
33
|
|
34
34
|
def to_solr(solr_doc = Hash.new) # :nodoc:
|
@@ -70,27 +70,5 @@ module ActiveFedora::MetadataDatastreamHelper
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
def to_xml(xml = Nokogiri::XML::Document.parse("<fields />")) #:nodoc:
|
74
|
-
if xml.instance_of?(Nokogiri::XML::Builder)
|
75
|
-
xml_insertion_point = xml.doc.root
|
76
|
-
elsif xml.instance_of?(Nokogiri::XML::Document)
|
77
|
-
xml_insertion_point = xml.root
|
78
|
-
else
|
79
|
-
xml_insertion_point = xml
|
80
|
-
end
|
81
|
-
|
82
|
-
builder = Nokogiri::XML::Builder.with(xml_insertion_point) do |xml|
|
83
|
-
fields.each_pair do |field,field_info|
|
84
|
-
element_attrs = field_info[:element_attrs].nil? ? {} : field_info[:element_attrs]
|
85
|
-
values = field_info[:values]
|
86
|
-
values = [values] unless values.respond_to? :each
|
87
|
-
values.each do |val|
|
88
|
-
builder_arg = "xml.#{field}(val, element_attrs)"
|
89
|
-
eval(builder_arg)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
end
|
93
|
-
return builder.to_xml
|
94
|
-
end
|
95
73
|
|
96
74
|
end
|
@@ -6,9 +6,13 @@ end
|
|
6
6
|
|
7
7
|
class Book < ActiveFedora::Base
|
8
8
|
belongs_to :library, :property=>:has_constituent
|
9
|
+
belongs_to :author, :property=>:has_member, :class_name=>'Person'
|
9
10
|
has_and_belongs_to_many :topics, :property=>:is_topic_of
|
10
11
|
end
|
11
12
|
|
13
|
+
class Person < ActiveFedora::Base
|
14
|
+
end
|
15
|
+
|
12
16
|
class Topic < ActiveFedora::Base
|
13
17
|
has_and_belongs_to_many :books, :property=>:is_topic_of
|
14
18
|
end
|
@@ -112,6 +116,8 @@ describe ActiveFedora::Base do
|
|
112
116
|
@library.save()
|
113
117
|
@book = Book.new
|
114
118
|
@book.save
|
119
|
+
@person = Person.new
|
120
|
+
@person.save
|
115
121
|
end
|
116
122
|
it "should have many books once it has been saved" do
|
117
123
|
@library.books << @book
|
@@ -124,6 +130,14 @@ describe ActiveFedora::Base do
|
|
124
130
|
@library2 = Library.find(@library.pid)
|
125
131
|
@library2.books.map(&:pid).should == [@book.pid]
|
126
132
|
end
|
133
|
+
|
134
|
+
it "should respect the :class_name parameter" do
|
135
|
+
@book.author = @person
|
136
|
+
@book.save
|
137
|
+
Book.find(@book.id).author_id.should == @person.pid
|
138
|
+
Book.find(@book.id).author.send(:find_target).should be_kind_of Person
|
139
|
+
end
|
140
|
+
|
127
141
|
after do
|
128
142
|
@library.delete
|
129
143
|
@book.delete
|
@@ -1,4 +1,3 @@
|
|
1
|
-
# encoding: WINDOWS-1252
|
2
1
|
require 'spec_helper'
|
3
2
|
require 'rexml/document'
|
4
3
|
require "active_fedora/samples"
|
@@ -69,7 +68,7 @@ describe ActiveFedora::Base do
|
|
69
68
|
|
70
69
|
end
|
71
70
|
sample_location = "Boston, Massachusetts"
|
72
|
-
sample_notes = 'Addelson, Frances. (1973?)
|
71
|
+
sample_notes = 'Addelson, Frances. (1973?) "The Induced Abortion," American Journal of Ortho-Psychiatry, Addelson, Frances. "Abortion: Source of Guilt or Growth," National Journal of Gynecology and Obstetrics., Addelson, Frances. "First Zionist Novel," Jewish Frontier.'
|
73
72
|
sample_other_contributor = 'any other contributors, people or corporate names (eg. Temple Israel)'
|
74
73
|
sample_transcript_editor = 'Siegel, Cheryl'
|
75
74
|
sample_hard_copy_availability = <<-END
|
@@ -77,7 +76,7 @@ describe ActiveFedora::Base do
|
|
77
76
|
END
|
78
77
|
sample_narrator = 'Addelson, Frances'
|
79
78
|
sample_bio = <<-END
|
80
|
-
Rochelle Ruthchild interviewed Frances Addleson on October 18, November 14, and December 10, 1997. The interview thoroughly examined the trajectory of Frances
|
79
|
+
Rochelle Ruthchild interviewed Frances Addleson on October 18, November 14, and December 10, 1997. The interview thoroughly examined the trajectory of Frances\' life from birth until the time of the interview. As a young child, Frances\' father died during the influenza epidemic, and her mother was not equipped to care for her and her siblings. Consequently, they were placed in a Jewish foster home. Although her experience was mostly positive, this experience would leave life-long effects. Frances attended Radcliffe upon the urging of a mentor and later obtained her Master\'s degree in social work from Simmons College in 1954. In the 1940\'s, she returned to work while her children were still young; a rather unusual event for that time period. While working as a social worker at Beth Israel Hospital in the early 1970\'s, she helped counsel countless women who came to the hospital seeking abortions before the procedure was officially legalized during the landmark Roe vs. Wade decision in 1973. Frances would later write two articles that were published in medical journals about her experience during this time. Although not a very religious person, Frances felt connected to the Jewish notion of social justice and remained very active until an accident in the late 1990\'s.
|
81
80
|
END
|
82
81
|
sample_interviewer = "Ruthchild, & Rochelle"
|
83
82
|
|
@@ -59,82 +59,84 @@ describe ActiveFedora::Base do
|
|
59
59
|
has_datastream :name=>"anymime", :type=>ActiveFedora::Datastream, :controlGroup=>'M'
|
60
60
|
has_datastream :name=>"external", :type=>ActiveFedora::Datastream, :controlGroup=>'E'
|
61
61
|
end
|
62
|
-
|
63
|
-
|
62
|
+
|
63
|
+
before do
|
64
64
|
@test_object2 = MockAddNamedDatastream.new
|
65
|
-
f = File.new(File.join( File.dirname(__FILE__), "../fixtures/minivan.jpg"))
|
66
|
-
f2 = File.new(File.join( File.dirname(__FILE__), "../fixtures/dino.jpg" ))
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
had_exception = false
|
71
|
-
begin
|
72
|
-
@test_object2.add_named_datastream("thumb",{:content_type=>"image/jpeg",:blob=>f})
|
73
|
-
rescue
|
74
|
-
had_exception = true
|
75
|
-
end
|
76
|
-
raise "Did not raise exception with datastream name that does not exist" unless had_exception
|
77
|
-
#check that either blob or file opt must be set
|
78
|
-
had_exception = false
|
79
|
-
begin
|
80
|
-
@test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg"})
|
81
|
-
rescue
|
82
|
-
had_exception = true
|
83
|
-
end
|
84
|
-
raise "Did not raise exception with blob not set" unless had_exception
|
65
|
+
@f = File.new(File.join( File.dirname(__FILE__), "../fixtures/minivan.jpg"))
|
66
|
+
@f2 = File.new(File.join( File.dirname(__FILE__), "../fixtures/dino.jpg" ))
|
67
|
+
@f.stubs(:content_type).returns("image/jpeg")
|
68
|
+
@f2.stubs(:original_filename).returns("dino.jpg")
|
69
|
+
end
|
85
70
|
|
86
|
-
|
87
|
-
@test_object2.add_named_datastream("
|
88
|
-
|
89
|
-
|
71
|
+
it 'cannot add a datastream with name that does not exist' do
|
72
|
+
expect { @test_object2.add_named_datastream("thumb",{:content_type=>"image/jpeg",:blob=>f}) }.to raise_error
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should accept a file blob" do
|
76
|
+
@test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg",:blob=>@f})
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should accept a file handle" do
|
80
|
+
@test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg",:file=>@f})
|
81
|
+
end
|
82
|
+
|
83
|
+
it "should raise an error if neither a blob nor file is set" do
|
84
|
+
expect { @test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg"}) }.to raise_error
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should use the given label for the dsLabel" do
|
88
|
+
@test_object2.add_named_datastream("high",{:content_type=>"image/jpeg",:blob=>@f2, :label=>"my_image"})
|
90
89
|
@test_object2.high.first.dsLabel.should == "my_image"
|
91
|
-
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should fallback on using the file name" do
|
93
|
+
@test_object2.add_named_datastream("high",{:content_type=>"image/jpeg",:blob=>@f2})
|
92
94
|
@test_object2.high.first.dsLabel.should == "dino.jpg"
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
rescue
|
109
|
-
had_exception = true
|
110
|
-
end
|
111
|
-
raise "Did not raise exception on content type and mime type mismatch" unless had_exception
|
95
|
+
end
|
96
|
+
|
97
|
+
it "should check the file for a content type" do
|
98
|
+
@f.expects(:content_type).returns("image/jpeg")
|
99
|
+
@test_object2.add_named_datastream("thumbnail",{:file=>@f})
|
100
|
+
end
|
101
|
+
|
102
|
+
it "should raise an error if no content type is avialable" do
|
103
|
+
expect { @test_object2.add_named_datastream("thumbnail",{:file=>@f2}) }.to raise_error
|
104
|
+
end
|
105
|
+
|
106
|
+
it "should encsure mimetype and content type match" do
|
107
|
+
@f.stubs(:content_type).returns("image/tiff")
|
108
|
+
expect { @test_object2.add_named_datastream("thumbnail",{:file=>f}) }.to raise_error
|
109
|
+
end
|
112
110
|
|
111
|
+
it "should allow any mime type" do
|
113
112
|
#check for if any mime type allowed
|
114
|
-
@test_object2.add_named_datastream("anymime",{:file
|
113
|
+
@test_object2.add_named_datastream("anymime",{:file=>@f})
|
115
114
|
#check datastream created is of type ActiveFedora::Datastream
|
116
115
|
@test_object2.anymime.first.class.should == ActiveFedora::Datastream
|
116
|
+
end
|
117
|
+
|
118
|
+
it "should cgecj that a dsid forms to the prefix" do
|
117
119
|
#if dsid supplied check that conforms to prefix
|
118
|
-
f.stubs(:content_type).returns("image/jpeg")
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
end
|
125
|
-
raise "Did not raise exception with dsid that does not conform to prefix" unless had_exception
|
120
|
+
@f.stubs(:content_type).returns("image/jpeg")
|
121
|
+
expect { @test_object2.add_named_datastream("thumbnail",{:file=>@f,:dsid=>"DS1"}) }.to raise_error
|
122
|
+
end
|
123
|
+
|
124
|
+
it "should have the right properties" do
|
125
|
+
@test_object2.add_named_datastream("high",{:content_type=>"image/jpeg",:blob=>@f2})
|
126
126
|
#if prefix not set check uses name in CAPS and dsid uses prefix
|
127
127
|
#@test_object2.high.first.attributes[:prefix].should == "HIGH"
|
128
128
|
@test_object2.high.first.dsid.match(/HIGH[0-9]/)
|
129
129
|
#check datastreams added with other right properties
|
130
130
|
@test_object2.high.first.controlGroup.should == "M"
|
131
|
+
end
|
132
|
+
|
133
|
+
it "should work with external datastreams" do
|
131
134
|
|
132
135
|
#check external datastream
|
133
136
|
@test_object2.add_named_datastream("external",{:dsLocation=>"http://myreasource.com"})
|
134
137
|
#check dslocation goes to dslabel
|
135
138
|
@test_object2.external.first.dsLabel.should == "http://myreasource.com"
|
136
139
|
#check datastreams added to fedora (may want to stub this at first)
|
137
|
-
|
138
140
|
end
|
139
141
|
end
|
140
142
|
|
data/spec/unit/base_spec.rb
CHANGED
@@ -240,6 +240,23 @@ describe ActiveFedora::Base do
|
|
240
240
|
end
|
241
241
|
|
242
242
|
|
243
|
+
describe ".datastreams" do
|
244
|
+
it "should create dynamic accessors" do
|
245
|
+
@test_history.withText.should == @test_history.datastreams['withText']
|
246
|
+
end
|
247
|
+
it "dynamic accessors should convert dashes to underscores" do
|
248
|
+
ds = stub('datastream', :dsid=>'eac-cpf')
|
249
|
+
@test_history.add_datastream(ds)
|
250
|
+
@test_history.eac_cpf.should == ds
|
251
|
+
end
|
252
|
+
it "dynamic accessors should not convert datastreams named with underscore" do
|
253
|
+
ds = stub('datastream', :dsid=>'foo_bar')
|
254
|
+
@test_history.add_datastream(ds)
|
255
|
+
@test_history.foo_bar.should == ds
|
256
|
+
end
|
257
|
+
end
|
258
|
+
|
259
|
+
|
243
260
|
|
244
261
|
describe ".fields" do
|
245
262
|
it "should provide fields" do
|
@@ -44,6 +44,7 @@ describe ActiveFedora::MetadataDatastream do
|
|
44
44
|
@mock_repo.expects(:datastream).with(:pid => nil, :dsid => 'mdDs')
|
45
45
|
@mock_repo.expects(:add_datastream).with(:pid => nil, :dsid => 'mdDs', :checksumType => 'DISABLED', :versionable => true, :content => 'fake xml', :controlGroup => 'M', :dsState => 'A', :mimeType=>'text/xml')
|
46
46
|
@test_ds.expects(:to_xml).returns("fake xml")
|
47
|
+
@test_ds.expects(:dirty?).returns(true)
|
47
48
|
@test_ds.serialize!
|
48
49
|
@test_ds.save
|
49
50
|
@test_ds.mimeType.should == 'text/xml'
|
@@ -135,6 +135,7 @@ describe ActiveFedora::QualifiedDublinCoreDatastream do
|
|
135
135
|
it "should call .content= with to_dc_xml" do
|
136
136
|
result = @test_ds.to_dc_xml
|
137
137
|
@test_ds.expects(:content=).with(result)
|
138
|
+
@test_ds.expects(:dirty?).returns(true)
|
138
139
|
@test_ds.serialize!
|
139
140
|
end
|
140
141
|
end
|
@@ -81,9 +81,6 @@ describe ActiveFedora do
|
|
81
81
|
it "should prevent Base.save from calling update_index if false" do
|
82
82
|
dirty_ds = ActiveFedora::MetadataDatastream.new(@test_object.inner_object, 'ds1')
|
83
83
|
@test_object.datastreams['ds1'] = dirty_ds
|
84
|
-
repo = @test_object.inner_object.repository
|
85
|
-
repo.expects(:add_datastream)
|
86
|
-
repo.expects(:ingest)
|
87
84
|
@test_object.stubs(:datastreams).returns({:ds1 => dirty_ds})
|
88
85
|
@test_object.expects(:update_index).never
|
89
86
|
@test_object.expects(:refresh)
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active-fedora
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 15
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 3
|
8
8
|
- 1
|
9
|
-
-
|
10
|
-
version: 3.1.
|
9
|
+
- 6
|
10
|
+
version: 3.1.6
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Matt Zumwalt
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date:
|
19
|
+
date: 2012-01-05 00:00:00 -06:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -105,12 +105,12 @@ dependencies:
|
|
105
105
|
requirements:
|
106
106
|
- - ">="
|
107
107
|
- !ruby/object:Gem::Version
|
108
|
-
hash:
|
108
|
+
hash: 15
|
109
109
|
segments:
|
110
110
|
- 1
|
111
111
|
- 4
|
112
|
-
-
|
113
|
-
version: 1.4.
|
112
|
+
- 4
|
113
|
+
version: 1.4.4
|
114
114
|
requirement: *id006
|
115
115
|
- !ruby/object:Gem::Dependency
|
116
116
|
name: solrizer
|
@@ -561,6 +561,7 @@ files:
|
|
561
561
|
- lib/active_fedora/base.rb
|
562
562
|
- lib/active_fedora/content_model.rb
|
563
563
|
- lib/active_fedora/datastream.rb
|
564
|
+
- lib/active_fedora/datastream_collections.rb
|
564
565
|
- lib/active_fedora/datastream_hash.rb
|
565
566
|
- lib/active_fedora/delegating.rb
|
566
567
|
- lib/active_fedora/digital_object.rb
|