active-fedora 9.1.2 → 9.2.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
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