active-fedora 4.1.0 → 4.2.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.
- 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'
|