active-fedora 9.1.2 → 9.2.0.rc1

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +1 -1
  3. data/Gemfile +1 -0
  4. data/History.txt +90 -0
  5. data/active-fedora.gemspec +2 -2
  6. data/lib/active_fedora.rb +17 -3
  7. data/lib/active_fedora/associations.rb +77 -0
  8. data/lib/active_fedora/associations/association.rb +2 -2
  9. data/lib/active_fedora/associations/basic_contains_association.rb +52 -0
  10. data/lib/active_fedora/associations/builder/directly_contains.rb +23 -0
  11. data/lib/active_fedora/associations/builder/directly_contains_one.rb +44 -0
  12. data/lib/active_fedora/associations/builder/has_and_belongs_to_many.rb +2 -23
  13. data/lib/active_fedora/associations/builder/indirectly_contains.rb +26 -0
  14. data/lib/active_fedora/associations/builder/property.rb +10 -0
  15. data/lib/active_fedora/associations/collection_association.rb +42 -45
  16. data/lib/active_fedora/associations/collection_proxy.rb +6 -0
  17. data/lib/active_fedora/associations/contained_finder.rb +41 -0
  18. data/lib/active_fedora/associations/container_proxy.rb +9 -0
  19. data/lib/active_fedora/associations/contains_association.rb +20 -38
  20. data/lib/active_fedora/associations/delete_proxy.rb +28 -0
  21. data/lib/active_fedora/associations/directly_contains_association.rb +56 -0
  22. data/lib/active_fedora/associations/directly_contains_one_association.rb +113 -0
  23. data/lib/active_fedora/associations/has_and_belongs_to_many_association.rb +6 -14
  24. data/lib/active_fedora/associations/has_many_association.rb +0 -3
  25. data/lib/active_fedora/associations/id_composite.rb +30 -0
  26. data/lib/active_fedora/associations/indirectly_contains_association.rb +90 -0
  27. data/lib/active_fedora/associations/rdf.rb +8 -4
  28. data/lib/active_fedora/associations/record_composite.rb +39 -0
  29. data/lib/active_fedora/attached_files.rb +1 -1
  30. data/lib/active_fedora/attributes.rb +28 -10
  31. data/lib/active_fedora/attributes/active_triple_attribute.rb +17 -0
  32. data/lib/active_fedora/attributes/om_attribute.rb +29 -0
  33. data/lib/active_fedora/attributes/rdf_datastream_attribute.rb +47 -0
  34. data/lib/active_fedora/attributes/stream_attribute.rb +46 -0
  35. data/lib/active_fedora/autosave_association.rb +2 -2
  36. data/lib/active_fedora/base.rb +3 -0
  37. data/lib/active_fedora/containers/container.rb +38 -0
  38. data/lib/active_fedora/containers/direct_container.rb +5 -0
  39. data/lib/active_fedora/containers/indirect_container.rb +7 -0
  40. data/lib/active_fedora/core.rb +4 -48
  41. data/lib/active_fedora/delegated_attribute.rb +5 -98
  42. data/lib/active_fedora/fedora.rb +1 -1
  43. data/lib/active_fedora/fedora_attributes.rb +4 -26
  44. data/lib/active_fedora/file.rb +87 -159
  45. data/lib/active_fedora/file/attributes.rb +63 -0
  46. data/lib/active_fedora/file/streaming.rb +46 -0
  47. data/lib/active_fedora/file_relation.rb +7 -0
  48. data/lib/active_fedora/identifiable.rb +87 -0
  49. data/lib/active_fedora/inbound_relation_connection.rb +21 -0
  50. data/lib/active_fedora/indexers.rb +10 -0
  51. data/lib/active_fedora/indexers/global_indexer.rb +30 -0
  52. data/lib/active_fedora/indexers/null_indexer.rb +12 -0
  53. data/lib/active_fedora/indexing/map.rb +4 -5
  54. data/lib/active_fedora/indexing_service.rb +3 -22
  55. data/lib/active_fedora/loadable_from_json.rb +8 -0
  56. data/lib/active_fedora/pathing.rb +24 -0
  57. data/lib/active_fedora/persistence.rb +15 -8
  58. data/lib/active_fedora/rdf.rb +2 -0
  59. data/lib/active_fedora/rdf/fcrepo4.rb +1 -0
  60. data/lib/active_fedora/rdf/field_map.rb +90 -0
  61. data/lib/active_fedora/rdf/field_map_entry.rb +28 -0
  62. data/lib/active_fedora/rdf/indexing_service.rb +9 -23
  63. data/lib/active_fedora/rdf/rdf_datastream.rb +1 -2
  64. data/lib/active_fedora/reflection.rb +16 -15
  65. data/lib/active_fedora/relation/delegation.rb +15 -4
  66. data/lib/active_fedora/relation/finder_methods.rb +4 -4
  67. data/lib/active_fedora/schema.rb +26 -0
  68. data/lib/active_fedora/schema_indexing_strategy.rb +25 -0
  69. data/lib/active_fedora/simple_datastream.rb +2 -2
  70. data/lib/active_fedora/solr_query_builder.rb +3 -2
  71. data/lib/active_fedora/version.rb +1 -1
  72. data/lib/active_fedora/with_metadata.rb +1 -1
  73. data/spec/integration/associations/rdf_spec.rb +49 -0
  74. data/spec/integration/base_spec.rb +19 -0
  75. data/spec/integration/belongs_to_association_spec.rb +6 -6
  76. data/spec/integration/collection_association_spec.rb +4 -4
  77. data/spec/integration/complex_rdf_datastream_spec.rb +12 -12
  78. data/spec/integration/datastream_rdf_nested_attributes_spec.rb +1 -1
  79. data/spec/integration/direct_container_spec.rb +254 -0
  80. data/spec/integration/directly_contains_one_association_spec.rb +102 -0
  81. data/spec/integration/file_spec.rb +16 -5
  82. data/spec/integration/has_many_associations_spec.rb +93 -58
  83. data/spec/integration/indirect_container_spec.rb +251 -0
  84. data/spec/integration/rdf_nested_attributes_spec.rb +1 -1
  85. data/spec/integration/relation_spec.rb +43 -27
  86. data/spec/spec_helper.rb +1 -1
  87. data/spec/unit/attributes_spec.rb +6 -6
  88. data/spec/unit/collection_proxy_spec.rb +28 -0
  89. data/spec/unit/file_spec.rb +1 -1
  90. data/spec/unit/files_hash_spec.rb +4 -4
  91. data/spec/unit/has_and_belongs_to_many_association_spec.rb +11 -9
  92. data/spec/unit/indexers/global_indexer_spec.rb +41 -0
  93. data/spec/unit/indexing_service_spec.rb +0 -21
  94. data/spec/unit/loadable_from_json_spec.rb +31 -0
  95. data/spec/unit/pathing_spec.rb +37 -0
  96. data/spec/unit/rdf/indexing_service_spec.rb +3 -3
  97. data/spec/unit/rdf_resource_datastream_spec.rb +26 -7
  98. data/spec/unit/schema_indexing_strategy_spec.rb +68 -0
  99. data/spec/unit/solr_query_builder_spec.rb +1 -1
  100. data/spec/unit/solr_service_spec.rb +1 -1
  101. metadata +49 -8
@@ -5,12 +5,23 @@ require "rexml/document"
5
5
 
6
6
  describe ActiveFedora::File do
7
7
  describe "#save" do
8
- context "with a string" do
9
- it "should save" do
10
- subject.content = "some stuff"
11
- subject.save
12
- expect(subject).not_to be_new_record
8
+
9
+ context "with new files" do
10
+
11
+ context "with a string" do
12
+ before { subject.content = "hello" }
13
+ it "saves" do
14
+ expect(subject.save).to be true
15
+ end
13
16
  end
17
+
18
+ context "with no content" do
19
+ before { subject.content = nil }
20
+ it "does not save" do
21
+ expect(subject.save).to be false
22
+ end
23
+ end
24
+
14
25
  end
15
26
 
16
27
  context "with UploadedFile" do
@@ -280,85 +280,120 @@ describe "Deleting a dependent relationship" do
280
280
  end
281
281
 
282
282
  describe "Autosave" do
283
- context "a has_many - belongs_to relationship" do
284
- before do
285
- class Item < ActiveFedora::Base
286
- has_many :components
287
- has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
288
- m.field "title", :string
289
- end
290
- Deprecation.silence(ActiveFedora::Attributes) do
291
- has_attributes :title, datastream: 'foo'
292
- end
293
- end
294
- class Component < ActiveFedora::Base
295
- belongs_to :item, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
296
- has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
297
- m.field "description", :string
283
+ context "with new objects" do
284
+ context "a has_many - belongs_to relationship" do
285
+ before do
286
+ class Item < ActiveFedora::Base
287
+ has_many :components
288
+ has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
289
+ m.field "title", :string
290
+ end
291
+ Deprecation.silence(ActiveFedora::Attributes) do
292
+ has_attributes :title, datastream: 'foo'
293
+ end
298
294
  end
299
- Deprecation.silence(ActiveFedora::Attributes) do
300
- has_attributes :description, datastream: 'foo'
295
+ class Component < ActiveFedora::Base
296
+ belongs_to :item, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf
297
+ has_metadata "foo", type: ActiveFedora::SimpleDatastream do |m|
298
+ m.field "description", :string
299
+ end
300
+ Deprecation.silence(ActiveFedora::Attributes) do
301
+ has_attributes :description, datastream: 'foo'
302
+ end
301
303
  end
302
304
  end
303
- end
304
305
 
305
- after do
306
- Object.send(:remove_const, :Item)
307
- Object.send(:remove_const, :Component)
308
- end
306
+ after do
307
+ Object.send(:remove_const, :Item)
308
+ Object.send(:remove_const, :Component)
309
+ end
309
310
 
310
- context "From the belongs_to side" do
311
- let(:component) { Component.create(item: Item.new(title: 'my title')) }
311
+ context "From the belongs_to side" do
312
+ let(:component) { Component.create(item: Item.new(title: 'my title')) }
312
313
 
313
- it "should save dependent records" do
314
- component.reload
315
- expect(component.item.title).to eq 'my title'
314
+ it "should save dependent records" do
315
+ component.reload
316
+ expect(component.item.title).to eq 'my title'
317
+ end
316
318
  end
317
- end
318
319
 
319
- context "From the has_many side" do
320
- let(:item) { Item.create(components: [Component.new(description: 'my description')]) }
320
+ context "From the has_many side" do
321
+ let(:item) { Item.create(components: [Component.new(description: 'my description')]) }
321
322
 
322
- it "should save dependent records" do
323
- item.reload
324
- expect(item.components.first.description).to eq 'my description'
323
+ it "should save dependent records" do
324
+ item.reload
325
+ expect(item.components.first.description).to eq 'my description'
326
+ end
325
327
  end
326
328
  end
327
- end
328
329
 
329
- context "a has_many - has_and_belongs_to_many relationship" do
330
- context "with ActiveFedora::Base as classes" do
331
- before do
332
- class Novel < ActiveFedora::Base
333
- has_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
334
- has_and_belongs_to_many :contents, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
330
+ context "a has_many - has_and_belongs_to_many relationship" do
331
+ context "with ActiveFedora::Base as classes" do
332
+ before do
333
+ class Novel < ActiveFedora::Base
334
+ has_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
335
+ has_and_belongs_to_many :contents, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
336
+ end
337
+ class Text < ActiveFedora::Base
338
+ has_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
339
+ end
335
340
  end
336
- class Text < ActiveFedora::Base
337
- has_many :books, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.isPartOf, class_name: 'ActiveFedora::Base'
341
+ let(:text) { Text.create}
342
+ let(:novel) { Novel.create}
343
+
344
+ after do
345
+ Object.send(:remove_const, :Novel)
346
+ Object.send(:remove_const, :Text)
347
+ end
348
+
349
+ it "should work when added via the has_many" do
350
+ text.books << novel
351
+ novel.save
352
+ expect(novel.reload.contents).to eq [text]
353
+ expect(text.reload.books).to eq [novel]
354
+ end
355
+
356
+ it "should work when added via the has_and_belongs_to_many" do
357
+ novel.contents << text
358
+ novel.save!
359
+ text.reload
360
+ expect(text.books).to eq [novel]
338
361
  end
339
- end
340
- let(:text) { Text.create}
341
- let(:novel) { Novel.create}
342
362
 
343
- after do
344
- Object.send(:remove_const, :Novel)
345
- Object.send(:remove_const, :Text)
346
363
  end
364
+ end
365
+ end
347
366
 
348
- it "should work when added via the has_many" do
349
- text.books << novel
350
- novel.save
351
- expect(novel.reload.contents).to eq [text]
352
- expect(text.reload.books).to eq [novel]
367
+ context "with updated objects" do
368
+
369
+ before :all do
370
+ class Library < ActiveFedora::Base
371
+ has_many :books, autosave: true
353
372
  end
354
373
 
355
- it "should work when added via the has_and_belongs_to_many" do
356
- novel.contents << text
357
- novel.save!
358
- text.reload
359
- expect(text.books).to eq [novel]
374
+ class Book < ActiveFedora::Base
375
+ belongs_to :library, predicate: ActiveFedora::RDF::Fcrepo::RelsExt.hasConstituent
376
+ property :title, predicate: ::RDF::DC.title
360
377
  end
378
+ end
379
+ after :all do
380
+ Object.send(:remove_const, :Book)
381
+ Object.send(:remove_const, :Library)
382
+ end
383
+
384
+ let(:library) { Library.create }
385
+
386
+ before do
387
+ library.books.create(title: ["Great Book"])
388
+ library.books.first.title = ["Better book"]
389
+ library.save
390
+ end
361
391
 
392
+ subject { library.books(true) }
393
+
394
+ it "saves the new title" do
395
+ expect(subject.first.title).to eql ["Better book"]
362
396
  end
397
+
363
398
  end
364
399
  end
@@ -0,0 +1,251 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Indirect containers" do
4
+ before do
5
+ class RelatedObject < ActiveFedora::Base
6
+ property :title, predicate: ::RDF::DC.title, multiple: false
7
+ end
8
+ class Proxy < ActiveFedora::Base
9
+ belongs_to :proxy_for, predicate: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'), class_name: 'ActiveFedora::Base'
10
+ end
11
+ end
12
+
13
+ after do
14
+ Object.send(:remove_const, :RelatedObject)
15
+ Object.send(:remove_const, :Proxy)
16
+ end
17
+
18
+ describe "#include?" do
19
+ before do
20
+ class FooHistory < ActiveFedora::Base
21
+ indirectly_contains :related_objects,
22
+ has_member_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/aggregates'),
23
+ inserted_content_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'),
24
+ through: 'Proxy', foreign_key: :proxy_for
25
+ end
26
+ end
27
+
28
+ after do
29
+ Object.send(:remove_const, :FooHistory)
30
+ end
31
+
32
+ let(:foo) { FooHistory.new }
33
+
34
+ let(:file1) { RelatedObject.create }
35
+
36
+ before do
37
+ foo.related_objects << file1
38
+ foo.save
39
+ end
40
+
41
+ context "when it is not loaded" do
42
+ context "and it contains the file" do
43
+ subject { foo.reload.related_objects.include? file1 }
44
+ it { is_expected.to be true }
45
+ end
46
+
47
+ context "and it doesn't contain the file" do
48
+ let!(:file2) { RelatedObject.create }
49
+ subject { foo.reload.related_objects.include? file2 }
50
+ it { is_expected.to be false }
51
+ end
52
+ end
53
+
54
+ context "when it is loaded" do
55
+ before { foo.related_objects.to_a } # initial load of the association
56
+
57
+ context "and it contains the file" do
58
+ subject { foo.related_objects.include? file1 }
59
+ it { is_expected.to be true }
60
+ end
61
+
62
+ context "and it doesn't contain the file" do
63
+ let!(:file2) { RelatedObject.create }
64
+ subject { foo.related_objects.include? file2 }
65
+ it { is_expected.to be false }
66
+ end
67
+ end
68
+ end
69
+
70
+ describe "delete" do
71
+ before do
72
+ class FooHistory < ActiveFedora::Base
73
+ indirectly_contains :related_objects,
74
+ has_member_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/aggregates'), inserted_content_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'),
75
+ through: 'Proxy',
76
+ foreign_key: :proxy_for
77
+ end
78
+ end
79
+
80
+ after do
81
+ Object.send(:remove_const, :FooHistory)
82
+ end
83
+
84
+ it "should delete only one object" do
85
+ foo = FooHistory.new
86
+ foo.related_objects.build
87
+ file2 = foo.related_objects.build
88
+ foo.save
89
+ expect(foo.related_objects.each.count).to eq(2)
90
+ foo.related_objects.delete(file2)
91
+ expect(foo.related_objects.each.count).to eq 1
92
+ foo = FooHistory.find(foo.id)
93
+ expect(foo.related_objects.each.count).to eq(1)
94
+ end
95
+ end
96
+
97
+ describe "#indirectly_contains" do
98
+ context "when the class is implied" do
99
+ before do
100
+ class FooHistory < ActiveFedora::Base
101
+ # TODO inserted_content_relation can look up the predicate at options[:through].constantize.reflect_on_association(options[:foreign_key]).predicate
102
+ indirectly_contains :related_objects, has_member_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/aggregates'), inserted_content_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'), through: 'Proxy', foreign_key: :proxy_for
103
+ end
104
+ end
105
+ after do
106
+ Object.send(:remove_const, :FooHistory)
107
+ end
108
+
109
+ let(:file) { o.related_objects.build }
110
+ let(:reloaded) { FooHistory.find(o.id) }
111
+
112
+ context "with no related_objects" do
113
+ let(:o) { FooHistory.new }
114
+ subject { o.related_objects }
115
+
116
+ it { is_expected.to be_empty }
117
+ it { is_expected.to eq [] }
118
+ end
119
+
120
+ context "when the object exists" do
121
+ let(:o) { FooHistory.create }
122
+
123
+ before do
124
+ file.title = "HMMM"
125
+ o.save
126
+ end
127
+
128
+ describe "#first" do
129
+ subject { reloaded.related_objects.first }
130
+ it "has the content" do
131
+ expect(subject.title).to eq 'HMMM'
132
+ end
133
+ end
134
+
135
+ describe "#==" do
136
+ subject { reloaded.related_objects }
137
+
138
+ it "delegates to to_a" do
139
+ expect(subject).to eq [file]
140
+ end
141
+ end
142
+
143
+ describe "#append" do
144
+ let(:file2) { o.related_objects.build }
145
+ it "has two related_objects" do
146
+ expect(o.related_objects).to eq [file, file2]
147
+ end
148
+
149
+ context "and then saved/reloaded" do
150
+ before do
151
+ file2.title = "Derp"
152
+ o.save!
153
+ end
154
+ it "has two related_objects" do
155
+ expect(reloaded.related_objects).to eq [file, file2]
156
+ end
157
+ it "has inbound triples" do
158
+ statement = file.reload.resource.query(predicate: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor')).to_a.first
159
+
160
+ expect(statement.object).to eq file.resource.rdf_subject
161
+ end
162
+ end
163
+ end
164
+ describe "remove" do
165
+ it "should be able to remove" do
166
+ o.related_objects = []
167
+ o.save!
168
+
169
+ expect(reloaded.related_objects).to eq []
170
+ end
171
+ end
172
+ end
173
+ end
174
+
175
+ context "when the class is provided" do
176
+ before do
177
+ class Different < ActiveFedora::Base
178
+ property :title, predicate: ::RDF::DC.title, multiple: false
179
+ end
180
+ class FooHistory < ActiveFedora::Base
181
+ indirectly_contains :related_objects, has_member_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/aggregates'), inserted_content_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'), class_name: 'Different', through: 'Proxy', foreign_key: :proxy_for
182
+ end
183
+ end
184
+ after do
185
+ Object.send(:remove_const, :FooHistory)
186
+ Object.send(:remove_const, :Different)
187
+ end
188
+
189
+ let(:o) { FooHistory.create }
190
+ let(:file) { o.related_objects.build }
191
+ let(:reloaded) { FooHistory.find(o.id) }
192
+
193
+ describe "#build" do
194
+ subject { file }
195
+ it { is_expected.to be_kind_of Different }
196
+ end
197
+
198
+ context "when the object exists" do
199
+ before do
200
+ file.title = "HMMM"
201
+ o.save
202
+ end
203
+
204
+ describe "#first" do
205
+ subject { reloaded.related_objects.first }
206
+ it "has the content" do
207
+ expect(subject.title).to eq 'HMMM'
208
+ end
209
+ end
210
+ end
211
+ end
212
+
213
+ context "when using is_member_of_relation" do #, skip: "As far as I can tell, FC4 doesn't support IndirectContainer with isMemberOfRelation" do
214
+ before do
215
+ class FooHistory < ActiveFedora::Base
216
+ indirectly_contains :related_objects, is_member_of_relation: ::RDF::URI.new("http://example.com/isWithin"), inserted_content_relation: ::RDF::URI.new('http://www.openarchives.org/ore/terms/proxyFor'), through: 'Proxy', foreign_key: :proxy_for
217
+ end
218
+ end
219
+ after do
220
+ Object.send(:remove_const, :FooHistory)
221
+ end
222
+
223
+ let(:file) { o.related_objects.build }
224
+ let(:reloaded) { FooHistory.find(o.id) }
225
+
226
+ context "with no related_objects" do
227
+ let(:o) { FooHistory.new }
228
+ subject { o.related_objects }
229
+
230
+ it { is_expected.to be_empty }
231
+ it { is_expected.to eq [] }
232
+ end
233
+
234
+ context "when the object exists" do
235
+ let(:o) { FooHistory.create }
236
+
237
+ before do
238
+ file.title = "HMMM"
239
+ o.save
240
+ end
241
+
242
+ describe "#first" do
243
+ subject { reloaded.related_objects.first }
244
+ it "has the content" do
245
+ expect(subject.title).to eq 'HMMM'
246
+ end
247
+ end
248
+ end
249
+ end
250
+ end
251
+ end