rubydora 1.8.1 → 1.9.0
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.
- checksums.yaml +4 -4
- data/.rspec +1 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +573 -0
- data/.travis.yml +6 -6
- data/Gemfile +2 -3
- data/README.md +86 -0
- data/Rakefile +22 -25
- data/VERSION +1 -1
- data/lib/rubydora.rb +3 -6
- data/lib/rubydora/array_with_callback.rb +4 -4
- data/lib/rubydora/audit_trail.rb +7 -7
- data/lib/rubydora/callbacks.rb +9 -9
- data/lib/rubydora/datastream.rb +43 -39
- data/lib/rubydora/digital_object.rb +31 -33
- data/lib/rubydora/fc3_service.rb +10 -14
- data/lib/rubydora/fedora_url_helpers.rb +21 -22
- data/lib/rubydora/models_mixin.rb +4 -4
- data/lib/rubydora/profile_parser.rb +8 -8
- data/lib/rubydora/relationships_mixin.rb +15 -16
- data/lib/rubydora/repository.rb +11 -11
- data/lib/rubydora/resource_index.rb +10 -14
- data/lib/rubydora/rest_api_client.rb +52 -53
- data/lib/rubydora/transactions.rb +42 -51
- data/rubydora.gemspec +25 -25
- data/spec/audit_trail_spec.rb +1 -1
- data/spec/lib/datastream_spec.rb +34 -32
- data/spec/lib/digital_object_spec.rb +13 -10
- data/spec/lib/integration_test_spec.rb +116 -119
- data/spec/lib/profile_parser_spec.rb +1 -1
- data/spec/lib/repository_spec.rb +5 -5
- data/spec/lib/rest_api_client_spec.rb +60 -66
- data/spec/lib/transactions_spec.rb +4 -6
- data/spec/spec_helper.rb +2 -9
- metadata +30 -31
- data/.gitmodules +0 -0
- data/README.rdoc +0 -79
- data/gemfiles/gemfile.rails3 +0 -11
- data/gemfiles/gemfile.rails4 +0 -10
data/.travis.yml
CHANGED
@@ -1,12 +1,12 @@
|
|
1
|
+
sudo: false
|
1
2
|
language: ruby
|
2
3
|
rvm:
|
3
|
-
- 1.
|
4
|
-
- 2.
|
5
|
-
- 2.1
|
4
|
+
- 2.1.10
|
5
|
+
- 2.2.5
|
6
|
+
- 2.3.1
|
6
7
|
|
7
|
-
|
8
|
-
-
|
9
|
-
- gemfiles/gemfile.rails4
|
8
|
+
jdk:
|
9
|
+
- oraclejdk8
|
10
10
|
|
11
11
|
notifications:
|
12
12
|
irc: "irc.freenode.org#projecthydra"
|
data/Gemfile
CHANGED
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# rubydora
|
2
|
+
[<img src="https://travis-ci.org/projecthydra/rubydora.png?branch=master"
|
3
|
+
alt="Build Status" />](https://travis-ci.org/projecthydra/rubydora) [<img
|
4
|
+
src="https://badge.fury.io/rb/rubydora.png" alt="Gem Version"
|
5
|
+
/>](http://badge.fury.io/rb/rubydora)
|
6
|
+
|
7
|
+
Rubydora is a low-level Fedora Commons REST API consumer, providing direct
|
8
|
+
access to REST API methods, as well as a primitive ruby abstraction.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
```bash
|
13
|
+
gem install rubydora
|
14
|
+
```
|
15
|
+
|
16
|
+
## Examples
|
17
|
+
|
18
|
+
```
|
19
|
+
> repo = Rubydora.connect :url => 'http://localhost:8983/fedora', :user => 'fedoraAdmin', :password => 'fedoraAdmin'
|
20
|
+
=> #<Rubydora::Repository:0x101859538 @config={:url=>"http://localhost:8983/fedora", :user=>"fedoraAdmin", :password=>"fedoraAdmin"}>
|
21
|
+
|
22
|
+
> obj = repo.find('test:1')
|
23
|
+
=> #<Rubydora::DigitalObject:0x101977230 @pid="test:1", @repository=#<Rubydora::Repository:0x1019beef0 @config={:user=>"fedoraAdmin", :url=>"http://localhost:8983/fedora", :password=>"fedora"}>>
|
24
|
+
|
25
|
+
> obj.new?
|
26
|
+
=> true
|
27
|
+
|
28
|
+
> obj = obj.save
|
29
|
+
=> #<Rubydora::DigitalObject:0x1017601b8 @pid="test:1", @repository=#<Rubydora::Repository:0x1018e3058 @config={:url=>"http://localhost:8983/fedora", :user=>"fedoraAdmin", :password=>"fedoraAdmin"}, @client=#<RestClient::Resource:0x101882910 @options={:user=>"fedoraAdmin", :password=>"fedoraAdmin"}, @block=nil, @url="http://localhost:8983/fedora">>>
|
30
|
+
|
31
|
+
> obj.profile
|
32
|
+
=> {"objDissIndexViewURL"=>"http://localhost:8983/fedora/get/test:1/fedora-system:3/viewMethodIndex", "objLabel"=>"", "objModels"=>"info:fedora/fedora-system:FedoraObject-3.0", "objCreateDate"=>"2011-04-18T13:34:11.285Z", "objOwnerId"=>"fedoraAdmin", "objState"=>"A", "objItemIndexViewURL"=>"http://localhost:8983/fedora/get/test:1/fedora-system:3/viewItemIndex", "objLastModDate"=>"2011-04-18T13:47:30.110Z"}
|
33
|
+
|
34
|
+
> obj.models
|
35
|
+
=> ["info:fedora/fedora-system:FedoraObject-3.0"]
|
36
|
+
|
37
|
+
> obj.models << 'info:fedora/test:cmodel'
|
38
|
+
=> ["info:fedora/fedora-system:FedoraObject-3.0", "info:fedora/test:cmodel"]
|
39
|
+
|
40
|
+
> obj2 = repo.find('test:2')
|
41
|
+
=> [...]
|
42
|
+
|
43
|
+
> obj1.parts << obj2
|
44
|
+
=> [...]
|
45
|
+
|
46
|
+
> obj.datastreams
|
47
|
+
=> {"DC"=>#<Rubydora::Datastream:0x101860180 @dsid="DC" ...> }
|
48
|
+
|
49
|
+
> ds = obj.datastreams['File']
|
50
|
+
=> #<Rubydora::Datastream:0x1017f26a8 @dsid="File" ...>
|
51
|
+
> ds.controlGroup = 'R'
|
52
|
+
=> "R"
|
53
|
+
> ds.dsLocation = 'http://example.org/index.html'
|
54
|
+
=> "http://example.org/index.html"
|
55
|
+
> ds.dsLabel = 'Example redirect datastream'
|
56
|
+
=> "Example redirect datastream"
|
57
|
+
> ds.mimeType = 'text/html'
|
58
|
+
=> "text/html"
|
59
|
+
> ds.save
|
60
|
+
=> #<Rubydora::Datastream:0x10177a568 @dsid="File" ...>
|
61
|
+
|
62
|
+
> obj.datastreams
|
63
|
+
=> {"DC"=>#<Rubydora::Datastream:0x101860180 @dsid="DC" ..., "File"=>#<Rubydora::Datastream:0x10177a568 @dsid="File" ...>}
|
64
|
+
|
65
|
+
> obj.datastreams["File"].delete
|
66
|
+
=> true
|
67
|
+
> obj.datastreams["File"].new?
|
68
|
+
=> true
|
69
|
+
```
|
70
|
+
|
71
|
+
## Contributing to rubydora
|
72
|
+
|
73
|
+
* Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
74
|
+
* Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
75
|
+
* Fork the project
|
76
|
+
* Start a feature/bugfix branch
|
77
|
+
* Commit and push until you are happy with your contribution
|
78
|
+
* Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
79
|
+
* Please try not to mess with the Rakefile, version, or history. If you want
|
80
|
+
to have your own version, or is otherwise necessary, that is fine, but
|
81
|
+
please isolate to its own commit so I can cherry-pick around it.
|
82
|
+
|
83
|
+
## Copyright
|
84
|
+
|
85
|
+
Copyright (c) 2011 Chris Beer. See LICENSE.txt for further details.
|
86
|
+
|
data/Rakefile
CHANGED
@@ -1,56 +1,57 @@
|
|
1
1
|
require 'rubygems'
|
2
2
|
require 'bundler'
|
3
3
|
require 'jettywrapper'
|
4
|
+
require 'yard'
|
4
5
|
require 'bundler/gem_tasks'
|
5
6
|
|
7
|
+
ZIP_URL = 'https://github.com/projecthydra/hydra-jetty/archive/v7.2.0.zip'
|
8
|
+
|
6
9
|
begin
|
7
10
|
Bundler.setup(:default, :development)
|
8
11
|
rescue Bundler::BundlerError => e
|
9
12
|
$stderr.puts e.message
|
10
|
-
$stderr.puts
|
13
|
+
$stderr.puts 'Run `bundle install` to install missing gems'
|
11
14
|
exit e.status_code
|
12
15
|
end
|
13
16
|
|
14
17
|
# Get your spec rake tasks working in RSpec 2.0
|
15
|
-
|
16
18
|
require 'rspec/core/rake_task'
|
17
19
|
|
18
20
|
desc 'Default: run ci build.'
|
19
21
|
task :default => :ci
|
20
22
|
|
21
|
-
desc
|
23
|
+
desc 'Run specs'
|
22
24
|
RSpec::Core::RakeTask.new do |t|
|
23
|
-
|
24
|
-
if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.8/
|
25
|
+
if ENV['COVERAGE'] && RUBY_VERSION =~ /^1.8/
|
25
26
|
t.rcov = true
|
26
27
|
t.rcov_opts = %w{--exclude spec\/*,gems\/*,ruby\/* --aggregate coverage.data}
|
27
28
|
end
|
28
29
|
end
|
29
30
|
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
YARD::Rake::YardocTask.new do |yt|
|
32
|
+
yt.files = ['lib/**/*.rb']
|
33
|
+
yt.options = ['--readme', 'README.md']
|
33
34
|
end
|
34
35
|
|
35
|
-
desc
|
36
|
+
desc 'Open an irb session preloaded with this library'
|
36
37
|
task :console do
|
37
|
-
sh
|
38
|
+
sh 'irb -rubygems -I lib -r rubydora.rb'
|
38
39
|
end
|
39
40
|
|
40
|
-
desc
|
41
|
+
desc 'Execute Continuous Integration build'
|
41
42
|
task :ci => 'jetty:clean' do
|
42
43
|
unless ENV['environment'] == 'test'
|
43
|
-
exec(
|
44
|
+
exec('rake ci environment=test')
|
44
45
|
end
|
45
46
|
|
46
47
|
jetty_params = {
|
47
|
-
:jetty_home
|
48
|
-
:quiet
|
49
|
-
:jetty_port
|
50
|
-
:solr_home
|
51
|
-
:fedora_home
|
48
|
+
:jetty_home => File.expand_path(File.dirname(__FILE__) + '/jetty'),
|
49
|
+
:quiet => true,
|
50
|
+
:jetty_port => ENV['TEST_JETTY_PORT'] || 8983,
|
51
|
+
:solr_home => File.expand_path(File.dirname(__FILE__) + '/jetty/solr'),
|
52
|
+
:fedora_home => File.expand_path(File.dirname(__FILE__) + '/jetty/fedora/default'),
|
52
53
|
:startup_wait => 90,
|
53
|
-
:java_opts
|
54
|
+
:java_opts => ['-Xmx256m', '-XX:MaxPermSize=128m']
|
54
55
|
}
|
55
56
|
|
56
57
|
error = Jettywrapper.wrap(jetty_params) do
|
@@ -60,14 +61,10 @@ task :ci => 'jetty:clean' do
|
|
60
61
|
raise "test failures: #{error}" if error
|
61
62
|
end
|
62
63
|
|
63
|
-
|
64
|
-
|
65
|
-
task :coverage do
|
64
|
+
desc 'Execute specs with coverage'
|
65
|
+
task :coverage do
|
66
66
|
# Put spec opts in a file named .rspec in root
|
67
|
-
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE :
|
67
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : 'ruby'
|
68
68
|
ENV['COVERAGE'] = 'true' unless ruby_engine == 'jruby'
|
69
|
-
|
70
|
-
|
71
69
|
Rake::Task['spec'].invoke
|
72
70
|
end
|
73
|
-
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.9.0
|
data/lib/rubydora.rb
CHANGED
@@ -23,9 +23,6 @@ module Rubydora
|
|
23
23
|
require 'time'
|
24
24
|
require 'hooks'
|
25
25
|
|
26
|
-
if CSV.const_defined? :Reader
|
27
|
-
require 'fastercsv'
|
28
|
-
end
|
29
26
|
require 'restclient'
|
30
27
|
require 'nokogiri'
|
31
28
|
|
@@ -35,7 +32,7 @@ module Rubydora
|
|
35
32
|
class << self
|
36
33
|
# Connect to Fedora Repository
|
37
34
|
# @return Rubydora::Repository
|
38
|
-
def connect
|
35
|
+
def connect(*args)
|
39
36
|
Repository.new *args
|
40
37
|
end
|
41
38
|
|
@@ -48,7 +45,7 @@ module Rubydora
|
|
48
45
|
# Set the default Fedora Repository
|
49
46
|
# @param [Rubydora::Repository] repository
|
50
47
|
# @return Rubydora::Repository
|
51
|
-
def repository=
|
48
|
+
def repository=(repository)
|
52
49
|
@repository = repository
|
53
50
|
end
|
54
51
|
|
@@ -64,6 +61,6 @@ module Rubydora
|
|
64
61
|
|
65
62
|
class FedoraInvalidRequest < RubydoraError; end
|
66
63
|
|
67
|
-
class RecordNotFound < RubydoraError; end
|
64
|
+
class RecordNotFound < RubydoraError; end
|
68
65
|
|
69
66
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
module Rubydora
|
2
2
|
##
|
3
|
-
# This is an attempt to implement an Array-like
|
4
|
-
# object that calls a method after data is modified
|
3
|
+
# This is an attempt to implement an Array-like
|
4
|
+
# object that calls a method after data is modified
|
5
5
|
class ArrayWithCallback < Array
|
6
6
|
##
|
7
7
|
# FIXME: It would be nice to use Rubydora::Callbacks here,
|
8
|
-
# however, this method requires instance-level callbacks
|
8
|
+
# however, this method requires instance-level callbacks
|
9
9
|
|
10
10
|
[:<<, :collect!, :map!, :compact!, :concat, :delete, :delete_at, :delete_if, :pop, :push, :reject!, :replace, :select!, :[]=, :slice!, :uniq! ].each do |method|
|
11
11
|
class_eval <<-RUBY
|
@@ -25,7 +25,7 @@ module Rubydora
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# duck-typing Rubydora::Callbacks call_* methods
|
28
|
-
def call_on_change
|
28
|
+
def call_on_change(changes = {})
|
29
29
|
self.on_change.each do |h|
|
30
30
|
h.call(self, changes)
|
31
31
|
end
|
data/lib/rubydora/audit_trail.rb
CHANGED
@@ -5,19 +5,19 @@ module Rubydora::AuditTrail
|
|
5
5
|
end
|
6
6
|
|
7
7
|
private
|
8
|
-
|
8
|
+
|
9
9
|
AT_NS = {'audit' => 'info:fedora/fedora-system:def/audit#'}
|
10
10
|
FOXML_NS = {'foxml' => 'info:fedora/fedora-system:def/foxml#'}
|
11
11
|
AT_XPATH = '/foxml:digitalObject/foxml:datastream[@ID = "AUDIT"]/descendant::audit:auditTrail'
|
12
|
-
|
12
|
+
|
13
13
|
class FedoraAuditTrail
|
14
14
|
def initialize(object_xml)
|
15
|
-
@ng_xml = Nokogiri::XML(object_xml).xpath(AT_XPATH, FOXML_NS.merge(AT_NS))
|
15
|
+
@ng_xml = Nokogiri::XML(object_xml).xpath(AT_XPATH, FOXML_NS.merge(AT_NS))
|
16
16
|
end
|
17
17
|
def records
|
18
|
-
|
18
|
+
unless @records
|
19
19
|
@records = []
|
20
|
-
@ng_xml.xpath('.//audit:record', AT_NS).each do |node|
|
20
|
+
@ng_xml.xpath('.//audit:record', AT_NS).each do |node|
|
21
21
|
@records << FedoraAuditRecord.new(node)
|
22
22
|
end
|
23
23
|
end
|
@@ -27,7 +27,7 @@ module Rubydora::AuditTrail
|
|
27
27
|
@ng_xml.to_xml
|
28
28
|
end
|
29
29
|
end
|
30
|
-
|
30
|
+
|
31
31
|
class FedoraAuditRecord
|
32
32
|
def initialize(node)
|
33
33
|
@record = node
|
@@ -53,6 +53,6 @@ module Rubydora::AuditTrail
|
|
53
53
|
def justification
|
54
54
|
@record.at_xpath('audit:justification', AT_NS).text
|
55
55
|
end
|
56
|
-
end
|
56
|
+
end
|
57
57
|
|
58
58
|
end
|
data/lib/rubydora/callbacks.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Rubydora
|
2
2
|
|
3
|
-
# Provides class level methods for handling
|
4
|
-
# callback methods that alter object instances
|
3
|
+
# Provides class level methods for handling
|
4
|
+
# callback methods that alter object instances
|
5
5
|
module Callbacks
|
6
6
|
# add callback framework to base class
|
7
|
-
# @param [Class] base
|
7
|
+
# @param [Class] base
|
8
8
|
def self.included(base)
|
9
9
|
base.extend ExtendableClassMethods
|
10
10
|
end
|
@@ -19,10 +19,10 @@ module Rubydora
|
|
19
19
|
|
20
20
|
# register callback procs
|
21
21
|
# @param [Array<Symbol>] hook name
|
22
|
-
def register_callback
|
23
|
-
attrs.each do |method_name|
|
22
|
+
def register_callback(*attrs)
|
23
|
+
attrs.each do |method_name|
|
24
24
|
next if methods.include? method_name.to_s
|
25
|
-
instance_eval
|
25
|
+
instance_eval "
|
26
26
|
def #{method_name}(&blk)
|
27
27
|
self.hooks[:#{method_name}] ||= []
|
28
28
|
self.hooks[:#{method_name}] << blk
|
@@ -31,9 +31,9 @@ module Rubydora
|
|
31
31
|
def clear_#{method_name}_blocks!
|
32
32
|
self.hooks[:#{method_name}] = []
|
33
33
|
end
|
34
|
-
|
34
|
+
"
|
35
35
|
|
36
|
-
class_eval
|
36
|
+
class_eval "
|
37
37
|
def call_#{method_name}
|
38
38
|
self.class.hooks[:#{method_name}] ||= []
|
39
39
|
self.class.hooks[:#{method_name}].each do |h|
|
@@ -41,7 +41,7 @@ module Rubydora
|
|
41
41
|
end
|
42
42
|
end
|
43
43
|
|
44
|
-
|
44
|
+
"
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
data/lib/rubydora/datastream.rb
CHANGED
@@ -2,7 +2,7 @@ require 'equivalent-xml'
|
|
2
2
|
module Rubydora
|
3
3
|
# This class represents a Fedora datastream object
|
4
4
|
# and provides helper methods for creating and manipulating
|
5
|
-
# them.
|
5
|
+
# them.
|
6
6
|
class Datastream
|
7
7
|
extend ActiveModel::Callbacks
|
8
8
|
define_model_callbacks :save, :create, :destroy
|
@@ -21,42 +21,41 @@ module Rubydora
|
|
21
21
|
|
22
22
|
define_attribute_methods DS_ATTRIBUTES.keys
|
23
23
|
|
24
|
-
# accessors for datastream attributes
|
24
|
+
# accessors for datastream attributes
|
25
25
|
DS_ATTRIBUTES.each do |attribute, profile_name|
|
26
26
|
define_method attribute.to_s do
|
27
27
|
var = "@#{attribute.to_s}".to_sym
|
28
28
|
if instance_variable_defined?(var)
|
29
29
|
instance_variable_get var
|
30
30
|
elsif profile.has_key? profile_name.to_s
|
31
|
-
|
31
|
+
profile[profile_name.to_s]
|
32
32
|
else
|
33
33
|
default_attributes[attribute.to_sym]
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
class_eval
|
37
|
+
class_eval "
|
38
38
|
def #{attribute.to_s}= val
|
39
39
|
validate_#{attribute.to_s}!(val) if respond_to?(:validate_#{attribute.to_s}!, true)
|
40
40
|
#{attribute.to_s}_will_change! unless val == #{attribute.to_s}
|
41
41
|
@#{attribute.to_s} = val
|
42
42
|
end
|
43
|
-
|
43
|
+
"
|
44
44
|
end
|
45
45
|
|
46
46
|
DS_READONLY_ATTRIBUTES = [ :dsCreateDate , :dsSize, :dsVersionID ]
|
47
47
|
DS_READONLY_ATTRIBUTES.each do |attribute|
|
48
|
-
class_eval
|
48
|
+
class_eval "
|
49
49
|
def #{attribute.to_s}
|
50
50
|
@#{attribute} || profile['#{attribute.to_s}'] || default_attributes[:#{attribute}]
|
51
51
|
end
|
52
|
-
|
52
|
+
"
|
53
53
|
|
54
54
|
def dsChecksumValid
|
55
55
|
profile(:validateChecksum=>true)['dsChecksumValid']
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
-
|
60
59
|
# Create humanized accessors for the DS attribute (dsState -> state, dsCreateDate -> createDate)
|
61
60
|
(DS_ATTRIBUTES.keys + DS_READONLY_ATTRIBUTES).select { |k| k.to_s =~ /^ds/ }.each do |attribute|
|
62
61
|
simple_attribute = attribute.to_s.sub(/^ds/, '')
|
@@ -69,13 +68,12 @@ module Rubydora
|
|
69
68
|
end
|
70
69
|
end
|
71
70
|
|
72
|
-
|
73
|
-
|
74
|
-
if asOfDateTime == nil
|
71
|
+
def asOfDateTime(asOfDateTime = nil)
|
72
|
+
if asOfDateTime.nil?
|
75
73
|
return @asOfDateTime
|
76
74
|
end
|
77
75
|
|
78
|
-
|
76
|
+
self.class.new(@digital_object, dsid, @options.merge(:asOfDateTime => asOfDateTime))
|
79
77
|
end
|
80
78
|
|
81
79
|
def self.default_attributes
|
@@ -86,7 +84,7 @@ module Rubydora
|
|
86
84
|
@default_attributes ||= self.class.default_attributes
|
87
85
|
end
|
88
86
|
|
89
|
-
def default_attributes=
|
87
|
+
def default_attributes=(attributes)
|
90
88
|
@default_attributes = default_attributes.merge attributes
|
91
89
|
end
|
92
90
|
|
@@ -95,11 +93,11 @@ module Rubydora
|
|
95
93
|
# may not already exist in the datastore.
|
96
94
|
#
|
97
95
|
# Provides `after_initialize` callback for extensions
|
98
|
-
#
|
96
|
+
#
|
99
97
|
# @param [Rubydora::DigitalObject]
|
100
98
|
# @param [String] Datastream ID
|
101
99
|
# @param [Hash] default attribute values (used esp. for creating new datastreams)
|
102
|
-
def initialize
|
100
|
+
def initialize(digital_object, dsid, options = {}, default_instance_attributes = {})
|
103
101
|
run_callbacks :initialize do
|
104
102
|
@digital_object = digital_object
|
105
103
|
@dsid = dsid
|
@@ -119,7 +117,10 @@ module Rubydora
|
|
119
117
|
# Does this datastream already exist?
|
120
118
|
# @return [Boolean]
|
121
119
|
def new?
|
122
|
-
digital_object.nil? ||
|
120
|
+
digital_object.nil? ||
|
121
|
+
(digital_object.respond_to?(:new_record?) && digital_object.new_record?) ||
|
122
|
+
(digital_object.respond_to?(:new?) && digital_object.new?) ||
|
123
|
+
profile.empty?
|
123
124
|
end
|
124
125
|
|
125
126
|
# This method is overridden in ActiveFedora, so we didn't
|
@@ -131,7 +132,7 @@ module Rubydora
|
|
131
132
|
# @param [Boolean] ensure_fetch <true> if true, it will grab the content from the repository if is not already loaded
|
132
133
|
# @return [String]
|
133
134
|
def local_or_remote_content(ensure_fetch = true)
|
134
|
-
return @content if new?
|
135
|
+
return @content if new?
|
135
136
|
|
136
137
|
@content ||= ensure_fetch ? datastream_content : @datastream_content
|
137
138
|
|
@@ -169,16 +170,17 @@ module Rubydora
|
|
169
170
|
end
|
170
171
|
|
171
172
|
# Set the content of the datastream
|
172
|
-
# @param [String or IO]
|
173
|
+
# @param [String or IO]
|
173
174
|
# @return [String or IO]
|
174
|
-
def content=
|
175
|
+
def content=(new_content)
|
175
176
|
raise "Can't change values on older versions" if @asOfDateTime
|
176
|
-
|
177
|
+
@content = new_content
|
177
178
|
end
|
178
179
|
|
179
180
|
def content_changed?
|
180
181
|
return false if ['E','R'].include? controlGroup
|
181
|
-
return
|
182
|
+
return false unless content_loaded?
|
183
|
+
return true if new? && !local_or_remote_content(false).blank? # new datastreams must have content
|
182
184
|
|
183
185
|
if controlGroup == "X"
|
184
186
|
if self.eager_load_datastream_content
|
@@ -208,12 +210,16 @@ module Rubydora
|
|
208
210
|
return dsLocation.present? if ['E','R'].include? controlGroup
|
209
211
|
|
210
212
|
# type M has content if dsLocation is not empty
|
211
|
-
return true if controlGroup == 'M'
|
213
|
+
return true if controlGroup == 'M' && dsLocation.present?
|
212
214
|
|
213
215
|
# if we've set content, then we have content
|
214
216
|
behaves_like_io?(@content) || content.present?
|
215
217
|
end
|
216
218
|
|
219
|
+
def content_loaded?
|
220
|
+
!@content.nil?
|
221
|
+
end
|
222
|
+
|
217
223
|
def empty?
|
218
224
|
!has_content?
|
219
225
|
end
|
@@ -222,9 +228,9 @@ module Rubydora
|
|
222
228
|
# it doesn't require holding the entire content in memory. If you specify the from and length
|
223
229
|
# parameters it simulates a range request. Unfortunatly Fedora 3 doesn't have range requests,
|
224
230
|
# so this method needs to download the whole thing and just seek to the part you care about.
|
225
|
-
#
|
226
|
-
# @param [Integer] from (bytes) the starting point you want to return.
|
227
|
-
#
|
231
|
+
#
|
232
|
+
# @param [Integer] from (bytes) the starting point you want to return.
|
233
|
+
#
|
228
234
|
def stream (from = 0, length = nil)
|
229
235
|
counter = 0
|
230
236
|
Enumerator.new do |blk|
|
@@ -246,7 +252,7 @@ module Rubydora
|
|
246
252
|
# At the end of what we beginning of what we need. Write the end of what was read.
|
247
253
|
offset = from - last_counter
|
248
254
|
blk << chunk[offset..-1]
|
249
|
-
else
|
255
|
+
else
|
250
256
|
# In the middle. We need all of this
|
251
257
|
blk << chunk
|
252
258
|
end
|
@@ -259,18 +265,18 @@ module Rubydora
|
|
259
265
|
# Retrieve the datastream profile as a hash (and cache it)
|
260
266
|
# @param opts [Hash] :validateChecksum if you want fedora to validate the checksum
|
261
267
|
# @return [Hash] see Fedora #getDatastream documentation for keys
|
262
|
-
def profile
|
268
|
+
def profile(opts= {})
|
263
269
|
if @profile && !(opts[:validateChecksum] && !@profile.has_key?('dsChecksumValid'))
|
264
270
|
## Force a recheck of the profile if they've passed :validateChecksum and we don't have dsChecksumValid
|
265
271
|
return @profile
|
266
272
|
end
|
267
|
-
|
273
|
+
|
268
274
|
return @profile = {} unless digital_object.respond_to? :repository
|
269
|
-
|
275
|
+
|
270
276
|
@profile = repository.datastream_profile(pid, dsid, opts[:validateChecksum], asOfDateTime)
|
271
277
|
end
|
272
278
|
|
273
|
-
def profile=
|
279
|
+
def profile=(profile_hash)
|
274
280
|
raise ArgumentError, "Must pass a profile, you passed #{profile_hash.class}" unless profile_hash.kind_of? Hash
|
275
281
|
@profile = profile_hash
|
276
282
|
end
|
@@ -285,7 +291,7 @@ module Rubydora
|
|
285
291
|
def current_version?
|
286
292
|
return true if new?
|
287
293
|
vers = versions
|
288
|
-
|
294
|
+
vers.empty? || dsVersionID == vers.first.dsVersionID
|
289
295
|
end
|
290
296
|
|
291
297
|
# Add datastream to Fedora
|
@@ -307,7 +313,7 @@ module Rubydora
|
|
307
313
|
run_callbacks :save do
|
308
314
|
raise RubydoraError.new("Unable to save #{self.inspect} without content") unless has_content?
|
309
315
|
if new?
|
310
|
-
create
|
316
|
+
create
|
311
317
|
else
|
312
318
|
p = repository.modify_datastream(to_api_params.merge({ :pid => pid, :dsid => dsid })) || {}
|
313
319
|
reset_profile_attributes
|
@@ -353,15 +359,13 @@ module Rubydora
|
|
353
359
|
controlGroup == 'X'
|
354
360
|
end
|
355
361
|
|
356
|
-
|
357
|
-
|
358
362
|
protected
|
359
|
-
# datastream parameters
|
363
|
+
# datastream parameters
|
360
364
|
# @return [Hash]
|
361
365
|
def to_api_params
|
362
366
|
h = default_api_params
|
363
367
|
valid_changed_attributes = changes.keys.map { |x| x.to_sym }.select { |x| DS_ATTRIBUTES.key? x }
|
364
|
-
valid_changed_attributes += [:content] if content_changed?
|
368
|
+
valid_changed_attributes += [:content] if content_changed? && !valid_changed_attributes.include?(:content)
|
365
369
|
## if we don't provide a mimeType, application/octet-stream will be used instead
|
366
370
|
(valid_changed_attributes | [:mimeType]).each do |attribute|
|
367
371
|
h[attribute.to_sym] = send(attribute) unless send(attribute).nil?
|
@@ -392,7 +396,7 @@ module Rubydora
|
|
392
396
|
digital_object.repository
|
393
397
|
end
|
394
398
|
|
395
|
-
def asOfDateTime=
|
399
|
+
def asOfDateTime=(val)
|
396
400
|
@asOfDateTime = val
|
397
401
|
end
|
398
402
|
|
@@ -400,7 +404,7 @@ module Rubydora
|
|
400
404
|
raise "Can't change values on older versions" if @asOfDateTime
|
401
405
|
end
|
402
406
|
|
403
|
-
def validate_dsLocation!
|
407
|
+
def validate_dsLocation!(val)
|
404
408
|
URI.parse(val) unless val.nil?
|
405
409
|
end
|
406
410
|
|
@@ -411,7 +415,7 @@ module Rubydora
|
|
411
415
|
obj.is_a?(IO) || (defined?(Rack) && obj.is_a?(Rack::Test::UploadedFile))
|
412
416
|
end
|
413
417
|
|
414
|
-
def attribute_will_change!
|
418
|
+
def attribute_will_change!(*args)
|
415
419
|
check_if_read_only
|
416
420
|
super
|
417
421
|
end
|