active-fedora 9.0.2 → 9.0.8
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 +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
|