active-fedora 9.0.2 → 9.0.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/History.txt +85 -0
- data/README.md +2 -4
- data/active-fedora.gemspec +1 -0
- data/lib/active_fedora.rb +5 -0
- data/lib/active_fedora/associations/builder/has_many.rb +1 -1
- data/lib/active_fedora/associations/collection_association.rb +1 -18
- data/lib/active_fedora/associations/contains_association.rb +3 -1
- data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +12 -10
- data/lib/active_fedora/attached_files.rb +6 -3
- data/lib/active_fedora/change_set.rb +2 -2
- data/lib/active_fedora/core.rb +26 -38
- data/lib/active_fedora/core/fedora_id_translator.rb +12 -0
- data/lib/active_fedora/core/fedora_uri_translator.rb +9 -0
- data/lib/active_fedora/errors.rb +4 -0
- data/lib/active_fedora/fedora_attributes.rb +25 -1
- data/lib/active_fedora/file.rb +2 -15
- data/lib/active_fedora/inheritable_accessors.rb +26 -0
- data/lib/active_fedora/nom_datastream.rb +6 -4
- data/lib/active_fedora/rdf/ntriples_rdf_datastream.rb +0 -4
- data/lib/active_fedora/reflection.rb +3 -1
- data/lib/active_fedora/relation/finder_methods.rb +36 -5
- data/lib/active_fedora/version.rb +1 -1
- data/lib/active_fedora/versions_graph.rb +7 -8
- data/spec/integration/associations_spec.rb +64 -21
- data/spec/integration/belongs_to_association_spec.rb +118 -47
- data/spec/integration/collection_association_spec.rb +46 -0
- data/spec/integration/has_and_belongs_to_many_associations_spec.rb +178 -139
- data/spec/integration/query_result_builder_spec.rb +2 -2
- data/spec/integration/versionable_spec.rb +38 -1
- data/spec/samples/samples.rb +0 -1
- data/spec/spec_helper.rb +1 -0
- data/spec/unit/base_spec.rb +98 -0
- data/spec/unit/change_set_spec.rb +4 -2
- data/spec/unit/core/fedora_id_translator_spec.rb +20 -0
- data/spec/unit/core/fedora_uri_translator_spec.rb +19 -0
- data/spec/unit/core_spec.rb +50 -0
- data/spec/unit/has_many_association_spec.rb +27 -2
- data/spec/unit/qualified_dublin_core_datastream_spec.rb +0 -6
- data/spec/unit/reflection_spec.rb +44 -0
- data/spec/unit/simple_datastream_spec.rb +32 -0
- metadata +23 -13
- data/spec/samples/marpa-dc_datastream.rb +0 -102
- data/spec/samples/models/audio_record.rb +0 -29
- data/spec/samples/models/image.rb +0 -5
- data/spec/samples/models/oral_history.rb +0 -36
- data/spec/samples/models/seminar.rb +0 -29
- data/spec/samples/models/seminar_audio_file.rb +0 -32
- data/spec/samples/oral_history_sample_model.rb +0 -30
- data/spec/samples/special_thing.rb +0 -44
@@ -71,4 +71,50 @@ describe ActiveFedora::Base do
|
|
71
71
|
end
|
72
72
|
end
|
73
73
|
|
74
|
+
describe "finding the inverse" do
|
75
|
+
context "when no inverse exists" do
|
76
|
+
before do
|
77
|
+
class Item < ActiveFedora::Base
|
78
|
+
end
|
79
|
+
class Container < ActiveFedora::Base
|
80
|
+
has_many :items
|
81
|
+
end
|
82
|
+
end
|
83
|
+
after do
|
84
|
+
Object.send(:remove_const, :Item)
|
85
|
+
Object.send(:remove_const, :Container)
|
86
|
+
end
|
87
|
+
|
88
|
+
let(:instance) { Container.new }
|
89
|
+
subject { instance.items }
|
90
|
+
|
91
|
+
it "raises an error" do
|
92
|
+
expect { subject }.to raise_error "No :inverse_of or :predicate attribute was set or could be inferred for has_many :items on Container"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
context "when classes are namespaced" do
|
97
|
+
before do
|
98
|
+
class Item < ActiveFedora::Base
|
99
|
+
has_and_belongs_to_many :container, predicate: ::RDF::DC.extent, class_name: 'Foo::Container'
|
100
|
+
end
|
101
|
+
module Foo
|
102
|
+
class Container < ActiveFedora::Base
|
103
|
+
has_many :items
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
after do
|
108
|
+
Object.send(:remove_const, :Item)
|
109
|
+
Object.send(:remove_const, :Foo)
|
110
|
+
end
|
111
|
+
|
112
|
+
let(:instance) { Foo::Container.new }
|
113
|
+
subject { instance.items }
|
114
|
+
|
115
|
+
it "finds the association" do
|
116
|
+
expect(subject).to eq []
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
74
120
|
end
|
@@ -2,109 +2,131 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
describe ActiveFedora::Base do
|
4
4
|
describe "with inverse" do
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
context "that is also a HABTM" do
|
6
|
+
before do
|
7
|
+
class Book < ActiveFedora::Base
|
8
|
+
has_and_belongs_to_many :topics, predicate: ::RDF::FOAF.primaryTopic, inverse_of: :books
|
9
|
+
end
|
10
|
+
|
11
|
+
class Topic < ActiveFedora::Base
|
12
|
+
has_and_belongs_to_many :books, predicate: ::RDF::FOAF.isPrimaryTopicOf
|
13
|
+
end
|
9
14
|
end
|
10
15
|
|
11
|
-
|
16
|
+
after do
|
17
|
+
Object.send(:remove_const, :Book)
|
18
|
+
Object.send(:remove_const, :Topic)
|
12
19
|
end
|
13
20
|
|
21
|
+
describe "an unsaved instance" do
|
22
|
+
let(:topic1) { Topic.create }
|
23
|
+
let(:book) { Book.create }
|
14
24
|
|
15
|
-
|
16
|
-
|
25
|
+
it "habtm should set and remove relationships bidirectionally" do
|
26
|
+
book.topics << topic1
|
27
|
+
expect(book.topics).to eq [topic1]
|
28
|
+
expect(topic1.books).to eq [book]
|
29
|
+
expect(topic1.reload.books).to eq [book]
|
17
30
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
31
|
+
book.topics.delete(topic1)
|
32
|
+
expect(book.topics).to be_empty
|
33
|
+
expect(topic1.books).to be_empty
|
34
|
+
end
|
22
35
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
36
|
+
it "Should allow for more than 10 items" do
|
37
|
+
(1..12).each do
|
38
|
+
book.topics << Topic.create
|
39
|
+
end
|
40
|
+
book.save
|
41
|
+
expect(book.topics.count).to eq 12
|
42
|
+
book2 = Book.find(book.id)
|
43
|
+
expect(book2.topics.count).to eq 12
|
44
|
+
end
|
29
45
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
46
|
+
context "with subclassed objects" do
|
47
|
+
before do
|
48
|
+
class SpecialInheritedBook < Book
|
49
|
+
end
|
50
|
+
end
|
35
51
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
expect(topic1.books).to eq [@book]
|
40
|
-
expect(topic1.reload.books).to eq [@book]
|
52
|
+
after do
|
53
|
+
Object.send(:remove_const, :SpecialInheritedBook)
|
54
|
+
end
|
41
55
|
|
42
|
-
|
43
|
-
|
44
|
-
|
56
|
+
let!(:special_book) { SpecialInheritedBook.create }
|
57
|
+
it "Should find inherited objects along with base objects" do
|
58
|
+
book.topics << topic1
|
59
|
+
special_book.topics << topic1
|
60
|
+
expect(topic1.books).to match_array [book, special_book]
|
61
|
+
expect(topic1.reload.books).to match_array [book, special_book]
|
62
|
+
end
|
63
|
+
end
|
45
64
|
end
|
46
65
|
|
47
|
-
|
48
|
-
(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
let!(:special_book) { SpecialInheritedBook.create }
|
59
|
-
it "Should find inherited objects along with base objects" do
|
60
|
-
@book.topics << topic1
|
61
|
-
special_book.topics << topic1
|
62
|
-
expect(topic1.books).to eq [@book, special_book]
|
63
|
-
expect(topic1.reload.books).to eq [@book, special_book]
|
66
|
+
describe "a saved instance" do
|
67
|
+
let!(:book) { Book.create }
|
68
|
+
let!(:topic1) { Topic.create }
|
69
|
+
let!(:topic2) { Topic.create }
|
70
|
+
|
71
|
+
it "should set relationships bidirectionally" do
|
72
|
+
book.topics << topic1
|
73
|
+
expect(book.topics).to eq [topic1]
|
74
|
+
expect(book['topic_ids']).to eq [topic1.id]
|
75
|
+
expect(topic1['book_ids']).to eq [book.id]
|
76
|
+
expect(Topic.find(topic1.id).books).to eq [book] #Can't have saved it because book isn't saved yet.
|
64
77
|
end
|
65
|
-
end
|
66
78
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
79
|
+
it "should save new child objects" do
|
80
|
+
book.topics << Topic.new
|
81
|
+
expect(book.topics.first.id).to_not be_nil
|
82
|
+
end
|
71
83
|
|
72
|
-
|
84
|
+
it "should clear out the old associtions" do
|
85
|
+
book.topics = [topic1]
|
86
|
+
book.topics = [topic2]
|
87
|
+
expect(book.topic_ids).to eq [topic2.id]
|
88
|
+
end
|
73
89
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
90
|
+
context "with members" do
|
91
|
+
before do
|
92
|
+
book.topics = [topic1, topic2]
|
93
|
+
book.save
|
94
|
+
end
|
78
95
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
96
|
+
context "destroy" do
|
97
|
+
it "should remove the associations" do
|
98
|
+
book.destroy
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
85
102
|
end
|
103
|
+
end
|
86
104
|
|
87
|
-
|
88
|
-
|
89
|
-
|
105
|
+
context "that is a has_many" do
|
106
|
+
before do
|
107
|
+
class Book < ActiveFedora::Base
|
108
|
+
has_many :collections
|
109
|
+
end
|
110
|
+
|
111
|
+
class Collection < ActiveFedora::Base
|
112
|
+
has_and_belongs_to_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
|
113
|
+
end
|
90
114
|
end
|
91
115
|
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
expect(book.topic_ids).to eq [topic2.id]
|
116
|
+
after do
|
117
|
+
Object.send(:remove_const, :Book)
|
118
|
+
Object.send(:remove_const, :Collection)
|
96
119
|
end
|
97
120
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
book.save
|
102
|
-
end
|
121
|
+
describe "add and remove members" do
|
122
|
+
let(:collection) { Collection.create }
|
123
|
+
let(:book) { Book.create }
|
103
124
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
125
|
+
it "is successful" do
|
126
|
+
collection.books << book
|
127
|
+
expect {
|
128
|
+
collection.books.delete(book)
|
129
|
+
}.to change { collection.books.size }.from(1).to(0)
|
108
130
|
end
|
109
131
|
end
|
110
132
|
end
|
@@ -297,87 +319,104 @@ describe ActiveFedora::Base do
|
|
297
319
|
end
|
298
320
|
end
|
299
321
|
end
|
300
|
-
end
|
301
322
|
|
302
|
-
describe "create" do
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
323
|
+
describe "create" do
|
324
|
+
before do
|
325
|
+
class Book < ActiveFedora::Base
|
326
|
+
has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
|
327
|
+
end
|
307
328
|
|
308
|
-
|
309
|
-
|
329
|
+
class Collection < ActiveFedora::Base
|
330
|
+
property :title, predicate: ::RDF::DC.title
|
331
|
+
end
|
310
332
|
end
|
311
|
-
end
|
312
333
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
334
|
+
after do
|
335
|
+
Object.send(:remove_const, :Book)
|
336
|
+
Object.send(:remove_const, :Collection)
|
337
|
+
end
|
317
338
|
|
318
|
-
|
339
|
+
let(:book) { Book.create }
|
319
340
|
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
341
|
+
it "should create" do
|
342
|
+
collection = book.collections.create(title: ["Permanent"])
|
343
|
+
expect(collection).to be_kind_of Collection
|
344
|
+
expect(book.collections).to include collection
|
345
|
+
book.save
|
346
|
+
expect(book.reload.collections.first.title).to eq ['Permanent']
|
347
|
+
end
|
326
348
|
end
|
327
|
-
end
|
328
349
|
|
329
350
|
|
330
|
-
describe "Autosave" do
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
|
351
|
+
describe "Autosave" do
|
352
|
+
before do
|
353
|
+
class Item < ActiveFedora::Base
|
354
|
+
has_many :components
|
355
|
+
has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
|
356
|
+
m.field "title", :string
|
357
|
+
end
|
358
|
+
has_attributes :title, datastream: 'foo'
|
359
|
+
end
|
360
|
+
|
361
|
+
class Component < ActiveFedora::Base
|
362
|
+
has_and_belongs_to_many :items, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
|
363
|
+
has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
|
364
|
+
m.field "description", :string
|
365
|
+
end
|
366
|
+
has_attributes :description, datastream: 'foo'
|
336
367
|
end
|
337
|
-
has_attributes :title, datastream: 'foo'
|
338
|
-
end
|
339
368
|
|
340
|
-
|
341
|
-
|
342
|
-
|
343
|
-
m.field "description", :string
|
369
|
+
after do
|
370
|
+
Object.send(:remove_const, :Item)
|
371
|
+
Object.send(:remove_const, :Component)
|
344
372
|
end
|
345
|
-
has_attributes :description, datastream: 'foo'
|
346
|
-
end
|
347
|
-
end
|
348
373
|
|
349
|
-
|
350
|
-
|
351
|
-
|
352
|
-
|
374
|
+
describe "From the has_and_belongs_to_many side" do
|
375
|
+
describe "dependent records" do
|
376
|
+
let(:component) { Component.create(items: [Item.new(title: 'my title')]) }
|
377
|
+
|
378
|
+
it "should be saved" do
|
379
|
+
component.reload
|
380
|
+
expect(component.items.first.title).to eq 'my title'
|
381
|
+
end
|
382
|
+
end
|
353
383
|
|
354
|
-
|
355
|
-
|
356
|
-
|
384
|
+
describe "shifting" do
|
385
|
+
let(:component) { Component.new }
|
386
|
+
let(:item) { Item.create }
|
357
387
|
|
358
|
-
|
359
|
-
|
360
|
-
|
388
|
+
it "should set item_ids" do
|
389
|
+
component.items << item
|
390
|
+
expect(component.item_ids).to eq [item.id]
|
391
|
+
end
|
392
|
+
end
|
361
393
|
end
|
362
|
-
end
|
363
394
|
|
364
|
-
|
365
|
-
|
366
|
-
|
395
|
+
context "when the has_and_belongs_to_many provides an inverse_of" do
|
396
|
+
let(:reflection) { Component.reflect_on_association(:items) }
|
397
|
+
before do
|
398
|
+
reflection.options[:inverse_of] = :components
|
399
|
+
end
|
400
|
+
|
401
|
+
describe "shifting" do
|
402
|
+
let(:component) { Component.create }
|
403
|
+
let(:item) { Item.new }
|
367
404
|
|
368
|
-
|
369
|
-
|
370
|
-
|
405
|
+
it "should set item_ids" do
|
406
|
+
component.items << item
|
407
|
+
expect(component.item_ids).to eq [item.id]
|
408
|
+
end
|
409
|
+
end
|
371
410
|
end
|
372
|
-
end
|
373
|
-
end
|
374
411
|
|
375
|
-
|
376
|
-
|
412
|
+
describe "From the has_many side" do
|
413
|
+
let(:item) { Item.create(components: [Component.new(description: 'my description')]) }
|
377
414
|
|
378
|
-
|
379
|
-
|
380
|
-
|
415
|
+
it "should save dependent records" do
|
416
|
+
item.reload
|
417
|
+
expect(item.components.first.description).to eq 'my description'
|
418
|
+
end
|
419
|
+
end
|
381
420
|
end
|
382
421
|
end
|
383
422
|
end
|
@@ -30,7 +30,7 @@ describe ActiveFedora::QueryResultBuilder do
|
|
30
30
|
Object.send(:remove_const, :FooObject)
|
31
31
|
end
|
32
32
|
it "should return an array of objects that are of the class stored in active_fedora_model_s" do
|
33
|
-
query =
|
33
|
+
query = ActiveFedora::SolrQueryBuilder.construct_query_for_ids([@test_object.id, @foo_object.id])
|
34
34
|
solr_result = ActiveFedora::SolrService.query(query)
|
35
35
|
result = ActiveFedora::QueryResultBuilder.reify_solr_results(solr_result)
|
36
36
|
expect(result.length).to eq 2
|
@@ -40,7 +40,7 @@ describe ActiveFedora::QueryResultBuilder do
|
|
40
40
|
end
|
41
41
|
|
42
42
|
it 'should #reify a lightweight object as a new instance' do
|
43
|
-
query =
|
43
|
+
query = ActiveFedora::SolrQueryBuilder.construct_query_for_ids([@foo_object.id])
|
44
44
|
solr_result = ActiveFedora::SolrService.query(query)
|
45
45
|
result = ActiveFedora::QueryResultBuilder.reify_solr_results(solr_result,{:load_from_solr=>true})
|
46
46
|
expect(result.first).to be_instance_of FooObject
|
@@ -18,6 +18,43 @@ describe "a versionable class" do
|
|
18
18
|
|
19
19
|
it { is_expected.to be_versionable }
|
20
20
|
|
21
|
+
describe 'sorting versions' do
|
22
|
+
before do
|
23
|
+
allow(subject).to receive(:fedora_versions) { versions }
|
24
|
+
end
|
25
|
+
|
26
|
+
let(:version1) { double('version1', uri: 'http://localhost:8983/fedora/rest/test/84/61/63/98/84616398-f63a-4572-ba01-0689339e4fcb/fcr:versions/87a0a8c317f1e711aa993d-e1d2-4a65-93ee-3a12fc9541ab', label: 'version1', created: '2015-04-02T19:54:45.962Z') }
|
27
|
+
let(:version2) { double('version2', uri: 'http://localhost:8983/fedora/rest/test/84/61/63/98/84616398-f63a-4572-ba01-0689339e4fcb/fcr:versions/87a0a8c317f1e790373a67-c9ee-447d-b740-4faa882b1a1f', label: 'version2', created: '2015-04-02T19:54:45.96Z') }
|
28
|
+
let(:versions) { [version1, version2] }
|
29
|
+
|
30
|
+
subject { ActiveFedora::VersionsGraph.new }
|
31
|
+
|
32
|
+
it 'sorts by DateTime' do
|
33
|
+
expect(subject.first).to eq version2
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'with an unparseable created date' do
|
37
|
+
let(:version2) { double('version2', uri: 'http://localhost:8983/fedora/rest/test/84/61/63/98/84616398-f63a-4572-ba01-0689339e4fcb/fcr:versions/87a0a8c317f1e790373a67-c9ee-447d-b740-4faa882b1a1f', label: 'version2', created: '') }
|
38
|
+
|
39
|
+
it 'raises an exception' do
|
40
|
+
expect { subject.first }.to raise_error(ActiveFedora::VersionLacksCreateDate)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'with a missing created date' do
|
45
|
+
before do
|
46
|
+
# Because mocks raise RSpec::Mocks::MockExpectationError instead
|
47
|
+
allow(version2).to receive(:created) { raise NoMethodError }
|
48
|
+
end
|
49
|
+
|
50
|
+
let(:version2) { double('version2', uri: 'http://localhost:8983/fedora/rest/test/84/61/63/98/84616398-f63a-4572-ba01-0689339e4fcb/fcr:versions/87a0a8c317f1e790373a67-c9ee-447d-b740-4faa882b1a1f', label: 'version2') }
|
51
|
+
|
52
|
+
it 'raises an exception' do
|
53
|
+
expect { subject.first }.to raise_error(ActiveFedora::VersionLacksCreateDate)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
21
58
|
context "after saving" do
|
22
59
|
before do
|
23
60
|
subject.title = ["Greetings Earthlings"]
|
@@ -175,7 +212,7 @@ describe "a versionable rdf datastream" do
|
|
175
212
|
end
|
176
213
|
|
177
214
|
it "should have two unique versions" do
|
178
|
-
expect(subject.versions.all.size).to eq 2
|
215
|
+
expect(subject.versions.all.size).to eq 2
|
179
216
|
end
|
180
217
|
|
181
218
|
it "should load the restored datastream's content" do
|