active-fedora 4.1.0 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +1 -1
- data/Gemfile +10 -2
- data/Gemfile.lock +53 -27
- data/History.txt +22 -1
- data/README.textile +2 -2
- data/active-fedora.gemspec +3 -3
- data/config/predicate_mappings.yml +2 -0
- data/lib/active_fedora/associations/belongs_to_association.rb +2 -6
- data/lib/active_fedora/base.rb +44 -7
- data/lib/active_fedora/datastreams.rb +15 -13
- data/lib/active_fedora/model.rb +76 -51
- data/lib/active_fedora/rdf_datastream.rb +56 -26
- data/lib/active_fedora/semantic_node.rb +9 -0
- data/lib/active_fedora/unsaved_digital_object.rb +6 -0
- data/lib/active_fedora/version.rb +1 -1
- data/lib/tasks/active_fedora_dev.rake +11 -2
- data/spec/integration/associations_spec.rb +17 -0
- data/spec/integration/base_spec.rb +87 -36
- data/spec/integration/datastream_spec.rb +29 -0
- data/spec/integration/ntriples_datastream_spec.rb +7 -0
- data/spec/spec_helper.rb +9 -0
- data/spec/support/mock_fedora.rb +6 -2
- data/spec/unit/base_spec.rb +55 -40
- data/spec/unit/datastreams_spec.rb +6 -2
- data/spec/unit/model_spec.rb +106 -60
- data/spec/unit/ntriples_datastream_spec.rb +85 -7
- data/spec/unit/semantic_node_spec.rb +17 -3
- data/spec/unit/unsaved_digital_object_spec.rb +9 -0
- metadata +272 -173
@@ -87,8 +87,8 @@ module ActiveFedora
|
|
87
87
|
config[:predicate_mapping][vocab] = { name => predicate }
|
88
88
|
end
|
89
89
|
# stuff data_type and behaviors in there for to_solr support
|
90
|
-
config[:predicate_mapping][vocab]["#{name}
|
91
|
-
config[:predicate_mapping][vocab]["#{name}
|
90
|
+
config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
|
91
|
+
config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
|
92
92
|
else
|
93
93
|
config = {
|
94
94
|
:default_namespace => vocab,
|
@@ -97,8 +97,8 @@ module ActiveFedora
|
|
97
97
|
}
|
98
98
|
}
|
99
99
|
# stuff data_type and behaviors in there for to_solr support
|
100
|
-
config[:predicate_mapping][vocab]["#{name}
|
101
|
-
config[:predicate_mapping][vocab]["#{name}
|
100
|
+
config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
|
101
|
+
config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
|
102
102
|
end
|
103
103
|
end
|
104
104
|
end
|
@@ -145,20 +145,40 @@ module ActiveFedora
|
|
145
145
|
end
|
146
146
|
|
147
147
|
include ModelMethods
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
148
|
+
attr_accessor :loaded
|
149
|
+
|
150
|
+
def ensure_loaded
|
151
|
+
return if loaded
|
152
|
+
self.loaded = true
|
153
|
+
unless new?
|
154
|
+
deserialize content
|
152
155
|
end
|
153
156
|
end
|
154
157
|
|
155
|
-
def
|
156
|
-
|
158
|
+
def dirty?
|
159
|
+
graph.dirty
|
160
|
+
end
|
161
|
+
|
162
|
+
def save
|
157
163
|
super
|
164
|
+
graph.dirty = false
|
165
|
+
end
|
166
|
+
|
167
|
+
def serialize! # :nodoc:
|
168
|
+
return unless dirty?
|
169
|
+
return unless loaded
|
170
|
+
self.content = serialize
|
171
|
+
end
|
172
|
+
|
173
|
+
def content=(content)
|
174
|
+
super
|
175
|
+
@graph = RelationshipGraph.new
|
176
|
+
deserialize(content)
|
158
177
|
end
|
159
178
|
|
160
179
|
# returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
|
161
180
|
def fields
|
181
|
+
ensure_loaded
|
162
182
|
field_map = {}
|
163
183
|
graph.relationships.each do |predicate, values|
|
164
184
|
vocab_sym, name = predicate.qname
|
@@ -168,15 +188,16 @@ module ActiveFedora
|
|
168
188
|
config = self.class.config[:predicate_mapping][vocab.to_s]
|
169
189
|
|
170
190
|
name, indexed_as = config.select { |k, v| name.to_s == v.to_s && k.to_s.split("__")[0] == self.class.prefix(name).to_s.split("__")[0]}.first
|
171
|
-
next unless name and config.has_key?("#{name}
|
172
|
-
type = config["#{name}
|
173
|
-
behaviors = config["#{name}
|
191
|
+
next unless name and config.has_key?("#{name}__type".to_sym) and config.has_key?("#{name}__behaviors".to_sym)
|
192
|
+
type = config["#{name}__type".to_sym]
|
193
|
+
behaviors = config["#{name}__behaviors".to_sym]
|
174
194
|
field_map[name.to_sym] = {:values => values.map {|v| v.to_s}, :type => type, :behaviors => behaviors}
|
175
195
|
end
|
176
196
|
field_map
|
177
197
|
end
|
178
198
|
|
179
199
|
def to_solr(solr_doc = Hash.new) # :nodoc:
|
200
|
+
ensure_loaded
|
180
201
|
fields.each do |field_key, field_info|
|
181
202
|
values = field_info.fetch(:values, false)
|
182
203
|
if values
|
@@ -199,25 +220,33 @@ module ActiveFedora
|
|
199
220
|
RDF::URI(result.reverse.join)
|
200
221
|
end
|
201
222
|
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
223
|
+
# Populate a RDFDatastream object based on the "datastream" content
|
224
|
+
# Assumes that the datastream contains RDF content
|
225
|
+
# @param [String] data the "rdf" node
|
226
|
+
def deserialize(data)
|
227
|
+
unless data.nil?
|
228
|
+
RDF::Reader.for(serialization_format).new(data) do |reader|
|
229
|
+
reader.each_statement do |statement|
|
230
|
+
begin
|
208
231
|
next unless statement.subject == rdf_subject
|
209
|
-
|
210
|
-
object = literal ? statement.object.value : statement.object.to_s
|
211
|
-
graph.add(statement.predicate, object, literal)
|
232
|
+
rescue
|
212
233
|
end
|
234
|
+
literal = statement.object.kind_of?(RDF::Literal)
|
235
|
+
object = literal ? statement.object.value : statement.object.to_s
|
236
|
+
graph.add(statement.predicate, object, literal)
|
213
237
|
end
|
214
238
|
end
|
215
|
-
graph
|
216
239
|
end
|
240
|
+
graph
|
241
|
+
end
|
242
|
+
|
243
|
+
def graph
|
244
|
+
@graph ||= RelationshipGraph.new
|
217
245
|
end
|
218
246
|
|
219
247
|
# @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
|
220
248
|
def get_values(predicate)
|
249
|
+
ensure_loaded
|
221
250
|
predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
|
222
251
|
results = graph[predicate]
|
223
252
|
return if results.nil?
|
@@ -231,6 +260,7 @@ module ActiveFedora
|
|
231
260
|
# if there are any existing statements with this predicate, replace them
|
232
261
|
# @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
|
233
262
|
def set_value(predicate, args)
|
263
|
+
ensure_loaded
|
234
264
|
predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
|
235
265
|
graph.delete(predicate)
|
236
266
|
args = [args] unless args.respond_to? :each
|
@@ -244,6 +274,7 @@ module ActiveFedora
|
|
244
274
|
# append a value
|
245
275
|
# @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
|
246
276
|
def append(predicate, args)
|
277
|
+
ensure_loaded
|
247
278
|
predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
|
248
279
|
graph.add(predicate, args, true)
|
249
280
|
graph.dirty = true
|
@@ -268,9 +299,7 @@ module ActiveFedora
|
|
268
299
|
# Get the subject for this rdf/xml datastream
|
269
300
|
def rdf_subject
|
270
301
|
@subject ||= self.class.rdf_subject.call(self)
|
271
|
-
end
|
272
|
-
|
273
|
-
|
302
|
+
end
|
274
303
|
|
275
304
|
# Creates a RDF datastream for insertion into a Fedora Object
|
276
305
|
# Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
|
@@ -280,6 +309,7 @@ module ActiveFedora
|
|
280
309
|
writer << statement
|
281
310
|
end
|
282
311
|
end
|
312
|
+
graph.dirty = false
|
283
313
|
out
|
284
314
|
end
|
285
315
|
end
|
@@ -33,6 +33,15 @@ module ActiveFedora
|
|
33
33
|
rels_ext.dirty = true
|
34
34
|
end
|
35
35
|
|
36
|
+
# Clears all relationships with the specified predicate
|
37
|
+
# @param predicate
|
38
|
+
def clear_relationship(predicate)
|
39
|
+
relationships(predicate).each do |target|
|
40
|
+
object_relations.delete(predicate, target)
|
41
|
+
end
|
42
|
+
rels_ext.dirty = true
|
43
|
+
end
|
44
|
+
|
36
45
|
# Checks that this object is matches the model class passed in.
|
37
46
|
# It requires two steps to pass to return true
|
38
47
|
# 1. It has a hasModel relationship of the same model
|
@@ -69,14 +69,23 @@ task :hudson do
|
|
69
69
|
jetty_params = Jettywrapper.load_config
|
70
70
|
jetty_params[:startup_wait]= 30
|
71
71
|
error = Jettywrapper.wrap(jetty_params) do
|
72
|
-
Rake::Task[
|
73
|
-
Rake::Task["active_fedora:rspec"].invoke
|
72
|
+
Rake::Task['active_fedora:coverage'].invoke
|
74
73
|
end
|
75
74
|
raise "test failures: #{error}" if error
|
76
75
|
# Only create documentation if the tests have passed
|
77
76
|
Rake::Task["active_fedora:doc"].invoke
|
78
77
|
end
|
79
78
|
|
79
|
+
desc "Execute specs with coverage"
|
80
|
+
task :coverage do
|
81
|
+
# Put spec opts in a file named .rspec in root
|
82
|
+
ruby_engine = defined?(RUBY_ENGINE) ? RUBY_ENGINE : "ruby"
|
83
|
+
ENV['COVERAGE'] = 'true' unless ruby_engine == 'jruby'
|
84
|
+
|
85
|
+
Rake::Task["active_fedora:load_fixtures"].invoke
|
86
|
+
Rake::Task["active_fedora:rspec"].invoke
|
87
|
+
end
|
88
|
+
|
80
89
|
# Provides an :environment task for use while working within a working copy of active-fedora
|
81
90
|
# You should never load this rake file into any other application
|
82
91
|
desc 'Set up ActiveFedora environment. !! Only for use while working within a working copy of active-fedora'
|
@@ -190,6 +190,23 @@ describe ActiveFedora::Base do
|
|
190
190
|
Book.find(@book.id).author.send(:find_target).should be_kind_of Person
|
191
191
|
end
|
192
192
|
|
193
|
+
describe "when changing the belonger" do
|
194
|
+
before do
|
195
|
+
@book.library = @library
|
196
|
+
@book.save
|
197
|
+
@library2 = Library.create
|
198
|
+
end
|
199
|
+
it "should replace an existing instance" do
|
200
|
+
@book.library_id.should == @library.id
|
201
|
+
@book.library = @library2
|
202
|
+
@book.save
|
203
|
+
Book.find(@book.id).library_id.should == @library2.id
|
204
|
+
end
|
205
|
+
after do
|
206
|
+
@library2.delete
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
193
210
|
after do
|
194
211
|
@library.delete
|
195
212
|
@book.delete
|
@@ -1,31 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
describe "Datastreams synched together" do
|
5
|
-
before do
|
6
|
-
class DSTest < ActiveFedora::Base
|
7
|
-
def load_datastreams
|
8
|
-
super
|
9
|
-
unless self.datastreams.keys.include? 'test_ds'
|
10
|
-
add_file_datastream("XXX",:dsid=>'test_ds', :mimeType=>'text/html')
|
11
|
-
end
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
15
|
-
it "Should update datastream" do
|
16
|
-
@nc = DSTest.new
|
17
|
-
@nc.save
|
18
|
-
@nc.test_ds.content.should == 'XXX'
|
19
|
-
ds = @nc.datastreams['test_ds']
|
20
|
-
ds.content = "Foobar"
|
21
|
-
@nc.save
|
22
|
-
DSTest.find(@nc.pid).datastreams['test_ds'].content.should == 'Foobar'
|
23
|
-
DSTest.find(@nc.pid).test_ds.content.should == 'Foobar'
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
27
|
-
|
28
|
-
describe "has_metadata" do
|
3
|
+
describe "A base object with metadata" do
|
29
4
|
before :all do
|
30
5
|
class MockAFBaseRelationship < ActiveFedora::Base
|
31
6
|
has_metadata :name=>'foo', :type=>Hydra::ModsArticleDatastream
|
@@ -46,24 +21,100 @@ describe "has_metadata" do
|
|
46
21
|
end
|
47
22
|
end
|
48
23
|
|
49
|
-
|
50
|
-
describe "a changed document" do
|
24
|
+
describe "that already exists in the repo" do
|
51
25
|
before do
|
52
|
-
@
|
53
|
-
@
|
54
|
-
@
|
55
|
-
@
|
56
|
-
@
|
26
|
+
@release = MockAFBaseRelationship.create()
|
27
|
+
@release.add_relationship(:is_governed_by, 'info:fedora/narmdemo:catalog-fixture')
|
28
|
+
@release.add_relationship(:is_part_of, 'info:fedora/narmdemo:777')
|
29
|
+
@release.foo.person = "test foo content"
|
30
|
+
@release.save
|
31
|
+
end
|
32
|
+
describe "and has been changed" do
|
33
|
+
before do
|
34
|
+
@release.foo.person = 'frank'
|
35
|
+
@release.save
|
36
|
+
end
|
37
|
+
it "should save the datastream." do
|
38
|
+
MockAFBaseRelationship.find(@release.pid).foo.person.should == ['frank']
|
39
|
+
ActiveFedora::SolrService.query("id:#{@release.pid.gsub(":", "\\:")}", :fl=>'id person_t').first.should == {"id"=>@release.pid, 'person_t'=>['frank']}
|
40
|
+
end
|
57
41
|
end
|
58
|
-
|
59
|
-
|
60
|
-
|
42
|
+
describe "clone_into a new object" do
|
43
|
+
before do
|
44
|
+
begin
|
45
|
+
new_object = MockAFBaseRelationship.find('narm:999')
|
46
|
+
new_object.delete
|
47
|
+
rescue ActiveFedora::ObjectNotFoundError
|
48
|
+
end
|
49
|
+
|
50
|
+
new_object = MockAFBaseRelationship.create(:pid => 'narm:999')
|
51
|
+
@release.clone_into(new_object)
|
52
|
+
@new_object = MockAFBaseRelationship.find('narm:999')
|
53
|
+
end
|
54
|
+
it "should have all the assertions" do
|
55
|
+
@new_object.rels_ext.content.should be_equivalent_to '<rdf:RDF xmlns:ns1="info:fedora/fedora-system:def/model#" xmlns:ns2="info:fedora/fedora-system:def/relations-external#" xmlns:ns0="http://projecthydra.org/ns/relations#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
56
|
+
<rdf:Description rdf:about="info:fedora/narm:999">
|
57
|
+
<ns0:isGovernedBy rdf:resource="info:fedora/narmdemo:catalog-fixture"/>
|
58
|
+
<ns1:hasModel rdf:resource="info:fedora/afmodel:MockAFBaseRelationship"/>
|
59
|
+
<ns2:isPartOf rdf:resource="info:fedora/narmdemo:777"/>
|
60
|
+
|
61
|
+
</rdf:Description>
|
62
|
+
</rdf:RDF>'
|
63
|
+
end
|
64
|
+
it "should have the other datastreams too" do
|
65
|
+
@new_object.datastreams.keys.should include "foo"
|
66
|
+
@new_object.foo.content.should be_equivalent_to @release.foo.content
|
67
|
+
end
|
68
|
+
end
|
69
|
+
describe "clone" do
|
70
|
+
before do
|
71
|
+
@new_object = @release.clone
|
72
|
+
end
|
73
|
+
it "should have all the assertions" do
|
74
|
+
@new_object.rels_ext.content.should be_equivalent_to '<rdf:RDF xmlns:ns1="info:fedora/fedora-system:def/model#" xmlns:ns2="info:fedora/fedora-system:def/relations-external#" xmlns:ns0="http://projecthydra.org/ns/relations#" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
|
75
|
+
<rdf:Description rdf:about="info:fedora/'+ @new_object.pid+'">
|
76
|
+
<ns0:isGovernedBy rdf:resource="info:fedora/narmdemo:catalog-fixture"/>
|
77
|
+
<ns1:hasModel rdf:resource="info:fedora/afmodel:MockAFBaseRelationship"/>
|
78
|
+
<ns2:isPartOf rdf:resource="info:fedora/narmdemo:777"/>
|
79
|
+
|
80
|
+
</rdf:Description>
|
81
|
+
</rdf:RDF>'
|
82
|
+
end
|
83
|
+
it "should have the other datastreams too" do
|
84
|
+
@new_object.datastreams.keys.should include "foo"
|
85
|
+
@new_object.foo.content.should be_equivalent_to @release.foo.content
|
86
|
+
end
|
61
87
|
end
|
62
88
|
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "Datastreams synched together" do
|
92
|
+
before do
|
93
|
+
class DSTest < ActiveFedora::Base
|
94
|
+
def load_datastreams
|
95
|
+
super
|
96
|
+
unless self.datastreams.keys.include? 'test_ds'
|
97
|
+
add_file_datastream("XXX",:dsid=>'test_ds', :mimeType=>'text/html')
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
it "Should update datastream" do
|
103
|
+
@nc = DSTest.new
|
104
|
+
@nc.save
|
105
|
+
@nc.test_ds.content.should == 'XXX'
|
106
|
+
ds = @nc.datastreams['test_ds']
|
107
|
+
ds.content = "Foobar"
|
108
|
+
@nc.save
|
109
|
+
DSTest.find(@nc.pid).datastreams['test_ds'].content.should == 'Foobar'
|
110
|
+
DSTest.find(@nc.pid).test_ds.content.should == 'Foobar'
|
111
|
+
end
|
63
112
|
|
64
113
|
end
|
65
114
|
|
66
115
|
|
116
|
+
|
117
|
+
|
67
118
|
describe ActiveFedora::Base do
|
68
119
|
before :all do
|
69
120
|
class MockAFBaseRelationship < ActiveFedora::Base
|
@@ -55,4 +55,33 @@ describe ActiveFedora::Datastream do
|
|
55
55
|
|
56
56
|
end
|
57
57
|
|
58
|
+
it "should be able to set the versionable attribute" do
|
59
|
+
dsid = "ds#{Time.now.to_i}"
|
60
|
+
v1 = "<version1>data</version1>"
|
61
|
+
v2 = "<version2>data</version2>"
|
62
|
+
ds = ActiveFedora::Datastream.new(@test_object.inner_object, dsid)
|
63
|
+
ds.content = v1
|
64
|
+
ds.versionable = false
|
65
|
+
@test_object.add_datastream(ds).should be_true
|
66
|
+
@test_object.save
|
67
|
+
to = ActiveFedora::Base.find(@test_object.pid)
|
68
|
+
ds = to.datastreams[dsid]
|
69
|
+
ds.versionable.should be_false
|
70
|
+
ds.versionable = true
|
71
|
+
to.save
|
72
|
+
ds.content = v2
|
73
|
+
to.save
|
74
|
+
versions = ds.versions
|
75
|
+
versions.length.should == 2
|
76
|
+
# order of versions not guaranteed
|
77
|
+
if versions[0].content == v2
|
78
|
+
versions[1].content.should == v1
|
79
|
+
versions[0].asOfDateTime.should be >= versions[1].asOfDateTime
|
80
|
+
else
|
81
|
+
versions[0].content.should == v1
|
82
|
+
versions[1].content.should == v2
|
83
|
+
versions[1].asOfDateTime.should be >= versions[0].asOfDateTime
|
84
|
+
end
|
85
|
+
ds.content.should == v2
|
86
|
+
end
|
58
87
|
end
|
@@ -64,6 +64,13 @@ describe ActiveFedora::NtriplesRDFDatastream do
|
|
64
64
|
@subject.part << "thing 2"
|
65
65
|
@subject.part.should == ["thing 1", "thing 2"]
|
66
66
|
end
|
67
|
+
it "should delete a value" do
|
68
|
+
@subject.title = "Hamlet"
|
69
|
+
@subject.save
|
70
|
+
@subject.title = ""
|
71
|
+
@subject.save
|
72
|
+
@subject.title.should be_nil
|
73
|
+
end
|
67
74
|
it "should delete values" do
|
68
75
|
@subject.title = "Hamlet"
|
69
76
|
@subject.related_url = "http://psu.edu/"
|
data/spec/spec_helper.rb
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
ENV["environment"] ||= 'test'
|
2
2
|
require "bundler/setup"
|
3
|
+
|
4
|
+
if ENV['COVERAGE'] and RUBY_VERSION =~ /^1.9/
|
5
|
+
require 'simplecov'
|
6
|
+
require 'simplecov-rcov'
|
7
|
+
|
8
|
+
SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
|
9
|
+
SimpleCov.start
|
10
|
+
end
|
11
|
+
|
3
12
|
require 'active-fedora'
|
4
13
|
require 'rspec'
|
5
14
|
require 'equivalent-xml/rspec_matchers'
|