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.
Files changed (50) hide show
  1. checksums.yaml +5 -5
  2. data/History.txt +85 -0
  3. data/README.md +2 -4
  4. data/active-fedora.gemspec +1 -0
  5. data/lib/active_fedora.rb +5 -0
  6. data/lib/active_fedora/associations/builder/has_many.rb +1 -1
  7. data/lib/active_fedora/associations/collection_association.rb +1 -18
  8. data/lib/active_fedora/associations/contains_association.rb +3 -1
  9. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +12 -10
  10. data/lib/active_fedora/attached_files.rb +6 -3
  11. data/lib/active_fedora/change_set.rb +2 -2
  12. data/lib/active_fedora/core.rb +26 -38
  13. data/lib/active_fedora/core/fedora_id_translator.rb +12 -0
  14. data/lib/active_fedora/core/fedora_uri_translator.rb +9 -0
  15. data/lib/active_fedora/errors.rb +4 -0
  16. data/lib/active_fedora/fedora_attributes.rb +25 -1
  17. data/lib/active_fedora/file.rb +2 -15
  18. data/lib/active_fedora/inheritable_accessors.rb +26 -0
  19. data/lib/active_fedora/nom_datastream.rb +6 -4
  20. data/lib/active_fedora/rdf/ntriples_rdf_datastream.rb +0 -4
  21. data/lib/active_fedora/reflection.rb +3 -1
  22. data/lib/active_fedora/relation/finder_methods.rb +36 -5
  23. data/lib/active_fedora/version.rb +1 -1
  24. data/lib/active_fedora/versions_graph.rb +7 -8
  25. data/spec/integration/associations_spec.rb +64 -21
  26. data/spec/integration/belongs_to_association_spec.rb +118 -47
  27. data/spec/integration/collection_association_spec.rb +46 -0
  28. data/spec/integration/has_and_belongs_to_many_associations_spec.rb +178 -139
  29. data/spec/integration/query_result_builder_spec.rb +2 -2
  30. data/spec/integration/versionable_spec.rb +38 -1
  31. data/spec/samples/samples.rb +0 -1
  32. data/spec/spec_helper.rb +1 -0
  33. data/spec/unit/base_spec.rb +98 -0
  34. data/spec/unit/change_set_spec.rb +4 -2
  35. data/spec/unit/core/fedora_id_translator_spec.rb +20 -0
  36. data/spec/unit/core/fedora_uri_translator_spec.rb +19 -0
  37. data/spec/unit/core_spec.rb +50 -0
  38. data/spec/unit/has_many_association_spec.rb +27 -2
  39. data/spec/unit/qualified_dublin_core_datastream_spec.rb +0 -6
  40. data/spec/unit/reflection_spec.rb +44 -0
  41. data/spec/unit/simple_datastream_spec.rb +32 -0
  42. metadata +23 -13
  43. data/spec/samples/marpa-dc_datastream.rb +0 -102
  44. data/spec/samples/models/audio_record.rb +0 -29
  45. data/spec/samples/models/image.rb +0 -5
  46. data/spec/samples/models/oral_history.rb +0 -36
  47. data/spec/samples/models/seminar.rb +0 -29
  48. data/spec/samples/models/seminar_audio_file.rb +0 -32
  49. data/spec/samples/oral_history_sample_model.rb +0 -30
  50. 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
- before do
6
- class Book < ActiveFedora::Base
7
- has_and_belongs_to_many :topics, predicate: ::RDF::FOAF.primaryTopic, inverse_of: :books
8
- has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
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
- class SpecialInheritedBook < Book
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
- class Collection < ActiveFedora::Base
16
- end
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
- class Topic < ActiveFedora::Base
19
- has_and_belongs_to_many :books, predicate: ::RDF::FOAF.isPrimaryTopicOf
20
- end
21
- end
31
+ book.topics.delete(topic1)
32
+ expect(book.topics).to be_empty
33
+ expect(topic1.books).to be_empty
34
+ end
22
35
 
23
- after do
24
- Object.send(:remove_const, :SpecialInheritedBook)
25
- Object.send(:remove_const, :Book)
26
- Object.send(:remove_const, :Collection)
27
- Object.send(:remove_const, :Topic)
28
- end
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
- describe "an unsaved instance" do
31
- let(:topic1) { Topic.create }
32
- before do
33
- @book = Book.create
34
- end
46
+ context "with subclassed objects" do
47
+ before do
48
+ class SpecialInheritedBook < Book
49
+ end
50
+ end
35
51
 
36
- it "habtm should set and remove relationships bidirectionally" do
37
- @book.topics << topic1
38
- expect(@book.topics).to eq [topic1]
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
- @book.topics.delete(topic1)
43
- expect(@book.topics).to be_empty
44
- expect(topic1.books).to be_empty
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
- it "Should allow for more than 10 items" do
48
- (1..12).each do
49
- @book.topics << Topic.create
50
- end
51
- @book.save
52
- expect(@book.topics.count).to eq 12
53
- book2 = Book.find(@book.id)
54
- expect(book2.topics.count).to eq 12
55
- end
56
-
57
- context "with subclassed objects" do
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
- it "Should cast found books to the correct cmodel" do
68
- topic1.books[0].class == Book
69
- topic1.books[1].class == SpecialInheritedBook
70
- end
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
- end
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
- describe "a saved instance" do
75
- let!(:book) { Book.create }
76
- let!(:topic1) { Topic.create }
77
- let!(:topic2) { Topic.create }
90
+ context "with members" do
91
+ before do
92
+ book.topics = [topic1, topic2]
93
+ book.save
94
+ end
78
95
 
79
- it "should set relationships bidirectionally" do
80
- book.topics << topic1
81
- expect(book.topics).to eq [topic1]
82
- expect(book['topic_ids']).to eq [topic1.id]
83
- expect(topic1['book_ids']).to eq [book.id]
84
- expect(Topic.find(topic1.id).books).to eq [book] #Can't have saved it because book isn't saved yet.
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
- it "should save new child objects" do
88
- book.topics << Topic.new
89
- expect(book.topics.first.id).to_not be_nil
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
- it "should clear out the old associtions" do
93
- book.topics = [topic1]
94
- book.topics = [topic2]
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
- context "with members" do
99
- before do
100
- book.topics = [topic1, topic2]
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
- context "destroy" do
105
- it "should remove the associations" do
106
- book.destroy
107
- end
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
- before do
304
- class Book < ActiveFedora::Base
305
- has_and_belongs_to_many :collections, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isMemberOfCollection
306
- end
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
- class Collection < ActiveFedora::Base
309
- property :title, predicate: ::RDF::DC.title
329
+ class Collection < ActiveFedora::Base
330
+ property :title, predicate: ::RDF::DC.title
331
+ end
310
332
  end
311
- end
312
333
 
313
- after do
314
- Object.send(:remove_const, :Book)
315
- Object.send(:remove_const, :Collection)
316
- end
334
+ after do
335
+ Object.send(:remove_const, :Book)
336
+ Object.send(:remove_const, :Collection)
337
+ end
317
338
 
318
- let(:book) { Book.create }
339
+ let(:book) { Book.create }
319
340
 
320
- it "should create" do
321
- collection = book.collections.create(title: ["Permanent"])
322
- expect(collection).to be_kind_of Collection
323
- expect(book.collections).to include collection
324
- book.save
325
- expect(book.reload.collections.first.title).to eq ['Permanent']
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
- before do
332
- class Item < ActiveFedora::Base
333
- has_many :components
334
- has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
335
- m.field "title", :string
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
- class Component < ActiveFedora::Base
341
- has_and_belongs_to_many :items, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
342
- has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
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
- after do
350
- Object.send(:remove_const, :Item)
351
- Object.send(:remove_const, :Component)
352
- end
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
- describe "From the has_and_belongs_to_many side" do
355
- describe "dependent records" do
356
- let(:component) { Component.create(items: [Item.new(title: 'my title')]) }
384
+ describe "shifting" do
385
+ let(:component) { Component.new }
386
+ let(:item) { Item.create }
357
387
 
358
- it "should be saved" do
359
- component.reload
360
- expect(component.items.first.title).to eq 'my title'
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
- describe "shifting" do
365
- let(:component) { Component.new }
366
- let(:item) { Item.create }
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
- it "should set item_ids" do
369
- component.items << item
370
- expect(component.item_ids).to eq [item.id]
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
- describe "From the has_many side" do
376
- let(:item) { Item.create(components: [Component.new(description: 'my description')]) }
412
+ describe "From the has_many side" do
413
+ let(:item) { Item.create(components: [Component.new(description: 'my description')]) }
377
414
 
378
- it "should save dependent records" do
379
- item.reload
380
- expect(item.components.first.description).to eq 'my description'
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 = "id\:#{RSolr.escape(@test_object.id)} OR id\:#{RSolr.escape(@foo_object.id)}"
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 = "id\:#{RSolr.escape(@foo_object.id)}"
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