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
@@ -76,20 +76,20 @@ describe ActiveFedora::Base do
76
76
  before do
77
77
  class Item < ActiveFedora::Base
78
78
  end
79
- class Container < ActiveFedora::Base
79
+ class SpecContainer < ActiveFedora::Base
80
80
  has_many :items
81
81
  end
82
82
  end
83
83
  after do
84
84
  Object.send(:remove_const, :Item)
85
- Object.send(:remove_const, :Container)
85
+ Object.send(:remove_const, :SpecContainer)
86
86
  end
87
87
 
88
- let(:instance) { Container.new }
88
+ let(:instance) { SpecContainer.new }
89
89
  subject { instance.items }
90
90
 
91
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"
92
+ expect { subject }.to raise_error "No :inverse_of or :predicate attribute was set or could be inferred for has_many :items on SpecContainer"
93
93
  end
94
94
  end
95
95
 
@@ -36,7 +36,7 @@ describe "Nested Rdf Objects" do
36
36
  end
37
37
 
38
38
  it "should be able to nest a complex object" do
39
- comp = SpecDatastream::Component.new(ds.graph)
39
+ comp = SpecDatastream::Component.new(nil, ds.graph)
40
40
  comp.label = ["Alternator"]
41
41
  ds.parts = comp
42
42
  expect(ds.parts.first.label).to eq ["Alternator"]
@@ -53,16 +53,16 @@ describe "Nested Rdf Objects" do
53
53
  ds.parts.build(label: 'Alternator')
54
54
  ds.parts.build(label: 'Distributor')
55
55
  expect(ds.parts.size).to eq 2
56
- comp = SpecDatastream::Component.new(ds.graph)
56
+ comp = SpecDatastream::Component.new(nil, ds.graph)
57
57
  comp.label = "Injector port"
58
58
  ds.parts = [comp]
59
59
  expect(ds.parts.size).to eq 1
60
60
  end
61
61
 
62
62
  it "should be able to nest many complex objects" do
63
- comp1 = SpecDatastream::Component.new ds.graph
63
+ comp1 = SpecDatastream::Component.new nil, ds.graph
64
64
  comp1.label = ["Alternator"]
65
- comp2 = SpecDatastream::Component.new ds.graph
65
+ comp2 = SpecDatastream::Component.new nil, ds.graph
66
66
  comp2.label = ["Crankshaft"]
67
67
  ds.parts = [comp1, comp2]
68
68
  expect(ds.parts.first.label).to eq ["Alternator"]
@@ -70,9 +70,9 @@ describe "Nested Rdf Objects" do
70
70
  end
71
71
 
72
72
  it "should be able to clear complex objects" do
73
- comp1 = SpecDatastream::Component.new ds.graph
73
+ comp1 = SpecDatastream::Component.new nil, ds.graph
74
74
  comp1.label = ["Alternator"]
75
- comp2 = SpecDatastream::Component.new ds.graph
75
+ comp2 = SpecDatastream::Component.new nil, ds.graph
76
76
  comp2.label = ["Crankshaft"]
77
77
  ds.parts = [comp1, comp2]
78
78
  ds.parts = []
@@ -147,7 +147,7 @@ END
147
147
 
148
148
 
149
149
  it "should store the type of complex objects when type is specified" do
150
- comp = SpecDatastream::MediatorUser.new ds.graph
150
+ comp = SpecDatastream::MediatorUser.new nil, ds.graph
151
151
  comp.title = ["Doctor"]
152
152
  ds.mediator = comp
153
153
  expect(ds.mediator.first.type.first).to be_instance_of ::RDF::URI
@@ -180,7 +180,7 @@ END
180
180
  property :title
181
181
  end
182
182
 
183
- class Container < ActiveFedora::Base
183
+ class SpecContainer < ActiveFedora::Base
184
184
  contains :info, class_name: 'SpecDatastream'
185
185
  end
186
186
 
@@ -203,19 +203,19 @@ END
203
203
 
204
204
  after(:each) do
205
205
  Object.send(:remove_const, :SpecDatastream)
206
- Object.send(:remove_const, :Container)
206
+ Object.send(:remove_const, :SpecContainer)
207
207
  end
208
208
 
209
- let(:parent) { Container.new id: '124' }
209
+ let(:parent) { SpecContainer.new id: '124' }
210
210
  let (:file) { parent.info }
211
211
 
212
212
 
213
213
  it "should store the type of complex objects when type is specified" do
214
- series = SpecDatastream::Series.new file.graph
214
+ series = SpecDatastream::Series.new nil, file.graph
215
215
  series.title = ["renovating bathrooms"]
216
216
  file.series = series
217
217
 
218
- program = SpecDatastream::Program.new file.graph
218
+ program = SpecDatastream::Program.new nil, file.graph
219
219
  program.title = ["This old House"]
220
220
  file.program = program
221
221
 
@@ -99,7 +99,7 @@ describe "Nesting attribute behavior of RDFDatastream" do
99
99
  end
100
100
 
101
101
  describe "on lists" do
102
- subject { ComplexRDFDatastream::PersonalName.new(RDF::Graph.new) }
102
+ subject { ComplexRDFDatastream::PersonalName.new(nil) }
103
103
  it "should accept a hash" do
104
104
  subject.elementList_attributes = [{ topicElement_attributes: {'0' => { elementValue:"Quantum Behavior" }, '1' => { elementValue:"Wave Function" }}}]
105
105
  expect(subject.elementList.first[0].elementValue).to eq ["Quantum Behavior"]
@@ -0,0 +1,254 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Direct containers" do
4
+ describe "#directly_contains" do
5
+ context "when the class is ActiveFedora::File" do
6
+ before do
7
+ class FooHistory < ActiveFedora::Base
8
+ directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles")
9
+ end
10
+ end
11
+ after do
12
+ Object.send(:remove_const, :FooHistory)
13
+ end
14
+
15
+ let(:file) { o.files.build }
16
+ let(:reloaded) { FooHistory.find(o.id) }
17
+
18
+ context "with no files" do
19
+ let(:o) { FooHistory.new }
20
+ subject { o.files }
21
+
22
+ it { is_expected.to be_empty }
23
+ it { is_expected.to eq [] }
24
+ end
25
+
26
+ context "when the object exists" do
27
+ let(:o) { FooHistory.create }
28
+
29
+ before do
30
+ file.content = "HMMM"
31
+ o.save
32
+ end
33
+
34
+ describe "#first" do
35
+ subject { reloaded.files.first }
36
+ it "has the content" do
37
+ expect(subject.content).to eq 'HMMM'
38
+ end
39
+ end
40
+
41
+ describe "#to_a" do
42
+ subject { reloaded.files }
43
+ it "has the content" do
44
+ expect(subject.to_a).to eq [file]
45
+ end
46
+ end
47
+
48
+ describe "#append" do
49
+ let(:file2) { o.files.build }
50
+ it "has two files" do
51
+ expect(o.files).to eq [file, file2]
52
+ end
53
+
54
+ context "and then saved/reloaded" do
55
+ before do
56
+ file2.content = "Derp"
57
+ o.save!
58
+ end
59
+ it "has two files" do
60
+ expect(reloaded.files).to eq [file, file2]
61
+ end
62
+ end
63
+ end
64
+ end
65
+
66
+ context "when the object is new" do
67
+ let(:o) { FooHistory.new }
68
+ let(:file) { o.files.build }
69
+
70
+ it "fails" do
71
+ # This is the expected behavior right now. In the future make the uri get assigned by autosave.
72
+ expect { o.files.build }.to raise_error "Can't get uri. Owner isn't saved"
73
+ end
74
+ end
75
+ end
76
+
77
+ context "when the class is a subclass of ActiveFedora::File" do
78
+ before do
79
+ class SubFile < ActiveFedora::File; end
80
+ class FooHistory < ActiveFedora::Base
81
+ directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles"), class_name: 'SubFile'
82
+ end
83
+ end
84
+ after do
85
+ Object.send(:remove_const, :FooHistory)
86
+ Object.send(:remove_const, :SubFile)
87
+ end
88
+
89
+ let(:o) { FooHistory.create }
90
+ let(:file) { o.files.build }
91
+ let(:reloaded) { FooHistory.find(o.id) }
92
+
93
+ describe "#build" do
94
+ subject { file }
95
+ it { is_expected.to be_kind_of SubFile }
96
+ end
97
+
98
+ context "when the object exists" do
99
+ before do
100
+ file.content = "HMMM"
101
+ o.save
102
+ end
103
+
104
+ describe "#first" do
105
+ subject { reloaded.files.first }
106
+ it "has the content" do
107
+ expect(subject.content).to eq 'HMMM'
108
+ end
109
+ end
110
+ end
111
+ end
112
+
113
+ context "when using is_member_of_relation" do
114
+ before do
115
+ class FooHistory < ActiveFedora::Base
116
+ directly_contains :files, is_member_of_relation: ::RDF::URI.new("http://example.com/isWithin")
117
+ end
118
+ end
119
+ after do
120
+ Object.send(:remove_const, :FooHistory)
121
+ end
122
+
123
+ let(:file) { o.files.build }
124
+ let(:reloaded) { FooHistory.find(o.id) }
125
+
126
+ context "with no files" do
127
+ let(:o) { FooHistory.new }
128
+ subject { o.files }
129
+
130
+ it { is_expected.to be_empty }
131
+ it { is_expected.to eq [] }
132
+ end
133
+
134
+ context "when the object exists" do
135
+ let(:o) { FooHistory.create }
136
+
137
+ before do
138
+ file.content = "HMMM"
139
+ o.save
140
+ end
141
+
142
+ describe "#first" do
143
+ subject { reloaded.files.first }
144
+ it "has the content" do
145
+ expect(subject.content).to eq 'HMMM'
146
+ end
147
+ end
148
+ end
149
+ end
150
+
151
+ context "deleting members" do
152
+ before do
153
+ class FooHistory < ActiveFedora::Base
154
+ directly_contains :files, is_member_of_relation: ::RDF::URI.new("http://example.com/isWithin")
155
+ end
156
+ end
157
+ after do
158
+ Object.send(:remove_const, :FooHistory)
159
+ end
160
+
161
+ describe "#delete the contained object directly" do
162
+ let(:history) { FooHistory.create }
163
+ let(:file1) { history.files.build }
164
+ let(:file2) { history.files.build }
165
+
166
+ before do
167
+ file1.content = "hello"
168
+ file2.content = "hola"
169
+ history.save
170
+ history.reload
171
+ end
172
+
173
+ it "deletes the contained resource directly" do
174
+ expect(history.files).to eq [file1, file2]
175
+ file1.delete
176
+ history.reload
177
+ expect(history.files).to eq [file2]
178
+ end
179
+ end
180
+
181
+ describe "#delete via the collection proxy" do
182
+ let(:history) { FooHistory.create }
183
+ let(:file1) { history.files.build }
184
+ let(:file2) { history.files.build }
185
+
186
+ before do
187
+ file1.content = "hello"
188
+ file2.content = "hola"
189
+ history.save
190
+ history.reload
191
+ end
192
+
193
+ it "deletes the contained resource via the collection proxy" do
194
+ expect(history.reload.files).to eq [file1, file2]
195
+ history.files.delete(file1)
196
+ expect(history.reload.files).to eq [file2]
197
+ end
198
+ end
199
+
200
+ end
201
+
202
+ end
203
+
204
+ describe "#include?" do
205
+
206
+ before do
207
+ class FooHistory < ActiveFedora::Base
208
+ directly_contains :files, has_member_relation: ::RDF::URI.new('http://example.com/hasFiles')
209
+ end
210
+ end
211
+
212
+ after do
213
+ Object.send(:remove_const, :FooHistory)
214
+ end
215
+
216
+ let(:foo) { FooHistory.create }
217
+
218
+ let!(:file1) { foo.files.build }
219
+
220
+ before do
221
+ file1.content = 'hmm'
222
+ foo.save
223
+ end
224
+
225
+ context "when it is not loaded" do
226
+ context "and it contains the file" do
227
+ subject { foo.reload.files.include? file1 }
228
+ it { is_expected.to be true }
229
+ end
230
+
231
+ context "and it doesn't contain the file" do
232
+ let!(:file2) { ActiveFedora::File.new.tap { |f| f.content= 'hmm'; f.save } }
233
+ subject { foo.reload.files.include? file2 }
234
+ it { is_expected.to be false }
235
+ end
236
+ end
237
+
238
+ context "when it is loaded" do
239
+ before { foo.files.to_a } # initial load of the association
240
+
241
+ context "and it contains the file" do
242
+ subject { foo.files.include? file1 }
243
+ it { is_expected.to be true }
244
+ end
245
+
246
+ context "and it doesn't contain the file" do
247
+ let!(:file2) { ActiveFedora::File.new.tap { |f| f.content= 'hmm'; f.save } }
248
+ subject { foo.files.include? file2 }
249
+ it { is_expected.to be false }
250
+ end
251
+ end
252
+ end
253
+
254
+ end
@@ -0,0 +1,102 @@
1
+ require 'spec_helper'
2
+
3
+ describe ActiveFedora::Base do
4
+ before do
5
+ class PageImage < ActiveFedora::Base
6
+ directly_contains :files, has_member_relation: ::RDF::URI.new("http://example.com/hasFiles"), class_name:"FileWithMetadata"
7
+ directly_contains_one :primary_file, through: :files, type: ::RDF::URI.new("http://example.com/primaryFile"), class_name:"FileWithMetadata"
8
+ directly_contains_one :special_versioned_file, through: :files, type: ::RDF::URI.new("http://example.com/featuredFile"), class_name:'VersionedFileWithMetadata'
9
+ end
10
+
11
+ class FileWithMetadata < ActiveFedora::File
12
+ include ActiveFedora::WithMetadata
13
+ end
14
+ class VersionedFileWithMetadata < ActiveFedora::File
15
+ include ActiveFedora::WithMetadata
16
+ has_many_versions
17
+ end
18
+ end
19
+
20
+ after do
21
+ Object.send(:remove_const, :PageImage)
22
+ Object.send(:remove_const, :FileWithMetadata)
23
+ Object.send(:remove_const, :VersionedFileWithMetadata)
24
+ end
25
+
26
+ let(:page_image) { PageImage.create }
27
+ let(:reloaded_page_image) { PageImage.find(page_image.id) }
28
+
29
+ let(:a_file) { page_image.files.build }
30
+ let(:primary_file) { page_image.build_primary_file }
31
+ let(:special_versioned_file) { page_image.build_special_versioned_file }
32
+ let(:primary_sub_image) { page_image.build_primary_sub_image }
33
+
34
+
35
+ context "#build" do
36
+ context "when container element is a type of ActiveFedora::File" do
37
+ before do
38
+ primary_file.content = "I'm in a container all alone!"
39
+ page_image.save!
40
+ end
41
+ subject { reloaded_page_image.primary_file }
42
+ it "initializes an object within the container" do
43
+ expect(subject.content).to eq("I'm in a container all alone!")
44
+ expect(subject.metadata_node.type).to include( ::RDF::URI.new("http://example.com/primaryFile") )
45
+ end
46
+ it "relies on info from the :through association, including class_name" do
47
+ expect(page_image.files).to include(primary_file)
48
+ expect(primary_file.uri.to_s).to include("/files/")
49
+ expect(subject.class).to eq FileWithMetadata
50
+ end
51
+ end
52
+ end
53
+
54
+ context "finder" do
55
+ subject { reloaded_page_image.primary_file }
56
+ context "when no matching child is set" do
57
+ before { page_image.files.build}
58
+ it { is_expected.to be_nil }
59
+ end
60
+ context "when a matching object is directly contained" do
61
+ before do
62
+ a_file.content = "I'm a file"
63
+ primary_file.content = "I am too"
64
+ page_image.save!
65
+ end
66
+ it "returns the matching object" do
67
+ expect(subject).to eq primary_file
68
+ end
69
+ end
70
+ context "if class_name is set" do
71
+ before do
72
+ a_file.content = "I'm a file"
73
+ special_versioned_file.content = "I am too"
74
+ page_image.save!
75
+ end
76
+ subject { reloaded_page_image.special_versioned_file }
77
+ it "uses the specified class to load objects" do
78
+ expect(subject).to eq special_versioned_file
79
+ expect(subject).to be_instance_of VersionedFileWithMetadata
80
+ end
81
+ end
82
+ end
83
+
84
+ describe "setter" do
85
+ before do
86
+ a_file.content = "I'm a file"
87
+ primary_file.content = "I am too"
88
+ page_image.save!
89
+ end
90
+ subject { reloaded_page_image.files }
91
+ it "replaces existing record without disturbing the other contents of the container" do
92
+ replacement_file = page_image.primary_file = FileWithMetadata.new
93
+ replacement_file.content = "I'm a replacement"
94
+ page_image.save
95
+ expect(subject).to_not include(primary_file)
96
+ expect(subject).to eq([a_file, replacement_file])
97
+ expect(reloaded_page_image.primary_file).to eq(replacement_file)
98
+ end
99
+
100
+ end
101
+
102
+ end