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.
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