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
@@ -0,0 +1,7 @@
1
+ module ActiveFedora
2
+ class FileRelation < Relation
3
+ def load_from_fedora(id, _)
4
+ klass.new(klass.id_to_uri(id))
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,87 @@
1
+ module ActiveFedora
2
+ module Identifiable
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ ##
7
+ # :singleton-method
8
+ #
9
+ # Accepts a proc that takes an id and transforms it to a URI
10
+ mattr_reader :translate_id_to_uri
11
+
12
+ # This method is mixed into ActiveFedora::Base and ActiveFedora::File, so don't
13
+ # overwrite the value if it's already set.
14
+ @@translate_id_to_uri ||= Core::FedoraIdTranslator
15
+
16
+ def self.translate_id_to_uri=(translator)
17
+ @@translate_id_to_uri = translator || Core::FedoraIdTranslator
18
+ end
19
+
20
+ ##
21
+ # :singleton-method
22
+ #
23
+ # Accepts a proc that takes a uri and transforms it to an id
24
+ mattr_reader :translate_uri_to_id
25
+
26
+ # This method is mixed into ActiveFedora::Base and ActiveFedora::File, so don't
27
+ # overwrite the value if it's already set.
28
+ @@translate_uri_to_id ||= Core::FedoraUriTranslator
29
+
30
+ def self.translate_uri_to_id=(translator)
31
+ @@translate_uri_to_id = translator || Core::FedoraUriTranslator
32
+ end
33
+ end
34
+
35
+ def id
36
+ if uri.kind_of?(::RDF::URI) && uri.value.blank?
37
+ nil
38
+ elsif uri.present?
39
+ self.class.uri_to_id(URI.parse(uri))
40
+ end
41
+ end
42
+
43
+ def id=(id)
44
+ raise "ID has already been set to #{self.id}" if self.id
45
+ @ldp_source = build_ldp_resource(id.to_s)
46
+ end
47
+
48
+
49
+ # TODO: Remove after we no longer support #pid.
50
+ def pid
51
+ Deprecation.warn FedoraAttributes, "#{self.class}#pid is deprecated and will be removed in active-fedora 10.0. Use #{self.class}#id instead."
52
+ id
53
+ end
54
+
55
+ # @return [RDF::URI] the uri for this resource
56
+ def uri
57
+ @ldp_source.subject_uri
58
+ end
59
+
60
+
61
+ module ClassMethods
62
+ ##
63
+ # Transforms an id into a uri
64
+ # if translate_id_to_uri is set it uses that proc, otherwise just the default
65
+ def id_to_uri(id)
66
+ translate_id_to_uri.call(id)
67
+ end
68
+
69
+ ##
70
+ # Transforms a uri into an id
71
+ # if translate_uri_to_id is set it uses that proc, otherwise just the default
72
+ def uri_to_id(uri)
73
+ translate_uri_to_id.call(uri)
74
+ end
75
+
76
+ ##
77
+ # Provides the common interface for ActiveTriples::Identifiable
78
+ def from_uri(uri,_)
79
+ begin
80
+ self.find(uri_to_id(uri))
81
+ rescue ActiveFedora::ObjectNotFoundError, Ldp::Gone
82
+ ActiveTriples::Resource.new(uri)
83
+ end
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,21 @@
1
+ module ActiveFedora
2
+ class InboundRelationConnection < SimpleDelegator
3
+ def get(*args)
4
+ result = __getobj__.get(*args) do |req|
5
+ prefer_headers = Ldp::PreferHeaders.new(req.headers["Prefer"])
6
+ prefer_headers.include = prefer_headers.include | include_uris
7
+ req.headers["Prefer"] = prefer_headers.to_s
8
+ yield req if block_given?
9
+ end
10
+ result
11
+ end
12
+
13
+ private
14
+
15
+ def include_uris
16
+ [
17
+ RDF::Fcrepo4.InboundReferences
18
+ ]
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,10 @@
1
+ module ActiveFedora
2
+ module Indexers
3
+ extend ActiveSupport::Autoload
4
+
5
+ eager_autoload do
6
+ autoload :NullIndexer
7
+ autoload :GlobalIndexer
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,30 @@
1
+ module ActiveFedora::Indexers
2
+ ##
3
+ # Applies indexing hints to any given property, independent of what that
4
+ # property
5
+ class GlobalIndexer
6
+ # @param [Array<Symbol>] index_types The indexing hints to use.
7
+ def initialize(index_types=nil)
8
+ @index_types = Array.wrap(index_types)
9
+ end
10
+
11
+
12
+ # The global indexer acts as both an indexer factory and an indexer, since
13
+ # the property doesn't matter.
14
+ def new(property)
15
+ self
16
+ end
17
+
18
+ # @param [ActiveFedora::Indexing::Map::IndexObject, #as] index_obj The indexing
19
+ # object to call #as on.
20
+ def index(index_obj)
21
+ unless index_types.empty?
22
+ index_obj.as(*index_types)
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ attr_reader :index_types
29
+ end
30
+ end
@@ -0,0 +1,12 @@
1
+ module ActiveFedora::Indexers
2
+ ##
3
+ # An indexer which does nothing with the given index object.
4
+ class NullIndexer
5
+ include Singleton
6
+ def new(_)
7
+ self
8
+ end
9
+ def index(_)
10
+ end
11
+ end
12
+ end
@@ -17,10 +17,12 @@ module ActiveFedora::Indexing
17
17
  # this enables a cleaner API for solr integration
18
18
  class IndexObject
19
19
  attr_accessor :data_type, :behaviors
20
+ attr_reader :key
20
21
 
21
- def initialize(&block)
22
+ def initialize(name, &block)
22
23
  @behaviors = []
23
24
  @data_type = :string
25
+ @key = name
24
26
  yield self if block_given?
25
27
  end
26
28
 
@@ -33,14 +35,11 @@ module ActiveFedora::Indexing
33
35
  end
34
36
 
35
37
  def dup
36
- self.class.new do |idx|
38
+ self.class.new(@key) do |idx|
37
39
  idx.behaviors = @behaviors.dup
38
40
  end
39
41
  end
40
42
 
41
- def defaults
42
- :noop
43
- end
44
43
  end
45
44
  end
46
45
  end
@@ -1,15 +1,9 @@
1
1
  module ActiveFedora
2
2
  class IndexingService
3
3
  attr_reader :object
4
- # Object must respond to
5
- # create_date
6
- # modified_date
7
- # has_model
8
- # id
9
- # to_json
10
- # attached_files
11
- # []
12
- # and it's class must respond to
4
+
5
+ # @param [#create_date, #modified_date, #has_model, #id, #to_json, #attached_files, #[]] obj
6
+ # The class of obj must respond to these methods:
13
7
  # inspect
14
8
  # outgoing_reflections
15
9
  def initialize(obj)
@@ -42,7 +36,6 @@ module ActiveFedora
42
36
  object.attached_files.each do |name, file|
43
37
  solr_doc.merge! file.to_solr(solr_doc, name: name.to_s)
44
38
  end
45
- solr_doc = solrize_relationships(solr_doc)
46
39
  solr_doc = solrize_rdf_assertions(solr_doc)
47
40
  yield(solr_doc) if block_given?
48
41
  solr_doc
@@ -62,18 +55,6 @@ module ActiveFedora
62
55
  m_time
63
56
  end
64
57
 
65
- # Serialize the datastream's RDF relationships to solr
66
- # @param [Hash] solr_doc @deafult an empty Hash
67
- def solrize_relationships(solr_doc = Hash.new)
68
- object.class.outgoing_reflections.values.each do |reflection|
69
- solr_key = reflection.solr_key
70
- Array(object[reflection.foreign_key]).compact.each do |v|
71
- ::Solrizer::Extractor.insert_solr_field_value(solr_doc, solr_key, v )
72
- end
73
- end
74
- solr_doc
75
- end
76
-
77
58
  # Serialize the resource's RDF relationships to solr
78
59
  # @param [Hash] solr_doc @deafult an empty Hash
79
60
  def solrize_rdf_assertions(solr_doc = Hash.new)
@@ -54,10 +54,16 @@ module ActiveFedora
54
54
 
55
55
  # FakeQuery exists to adapt the hash to the RDF interface used by RDF associations in ActiveFedora
56
56
  class FakeQuery
57
+ include ::Enumerable
58
+
57
59
  def initialize(values)
58
60
  @values = values || []
59
61
  end
60
62
 
63
+ def each(&block)
64
+ enum_statement.each(&block)
65
+ end
66
+
61
67
  def enum_statement
62
68
  @values.map {|v| FakeStatement.new(v) }
63
69
  end
@@ -87,6 +93,8 @@ module ActiveFedora
87
93
  ::RDF::URI.new(nil)
88
94
  end
89
95
 
96
+ # Called by Associations::RDF#replace to add data to this resource represenation
97
+ # @param [Array] vals an array of 3 elements (subject, predicate, object) to insert
90
98
  def insert(vals)
91
99
  _, pred, val = vals
92
100
  set_value(reflection(pred), [val])
@@ -0,0 +1,24 @@
1
+ module ActiveFedora
2
+ module Pathing
3
+ extend ActiveSupport::Concern
4
+
5
+ included do
6
+ def uri_prefix
7
+ nil
8
+ end
9
+
10
+ def has_uri_prefix?
11
+ !uri_prefix.nil?
12
+ end
13
+
14
+ def root_resource_path
15
+ if has_uri_prefix?
16
+ ActiveFedora.fedora.base_path + "/" + self.uri_prefix
17
+ else
18
+ ActiveFedora.fedora.base_path
19
+ end
20
+ end
21
+ end
22
+
23
+ end
24
+ end
@@ -47,11 +47,6 @@ module ActiveFedora
47
47
  return self if new_record?
48
48
 
49
49
  @destroyed = true
50
- reflections.each_pair do |name, reflection|
51
- if reflection.macro == :has_many
52
- association(name.to_sym).delete_all
53
- end
54
- end
55
50
 
56
51
  id = self.id ## cache so it's still available after delete
57
52
  # Clear out the ETag
@@ -141,7 +136,8 @@ module ActiveFedora
141
136
 
142
137
  def create_or_update(*args)
143
138
  raise ReadOnlyRecord if readonly?
144
- new_record? ? create_record(*args) : update_record(*args)
139
+ result = new_record? ? create_record(*args) : update_record(*args)
140
+ result != false
145
141
  end
146
142
 
147
143
  # Deals with preparing new object to be saved to Fedora, then pushes it and its attached files into Fedora.
@@ -149,7 +145,6 @@ module ActiveFedora
149
145
  assign_rdf_subject
150
146
  serialize_attached_files
151
147
  @ldp_source = @ldp_source.create
152
- @resource = nil
153
148
  assign_uri_to_attached_files
154
149
  save_attached_files
155
150
  refresh
@@ -184,10 +179,22 @@ module ActiveFedora
184
179
  @ldp_source = if !id && new_id = assign_id
185
180
  LdpResource.new(ActiveFedora.fedora.connection, self.class.id_to_uri(new_id), @resource)
186
181
  else
187
- LdpResource.new(ActiveFedora.fedora.connection, @ldp_source.subject, @resource, ActiveFedora.fedora.host + ActiveFedora.fedora.base_path)
182
+ LdpResource.new(ActiveFedora.fedora.connection, @ldp_source.subject, @resource, ActiveFedora.fedora.host + base_path_for_resource)
188
183
  end
189
184
  end
190
185
 
186
+ def base_path_for_resource
187
+ init_root_path if self.has_uri_prefix?
188
+ self.root_resource_path
189
+ end
190
+
191
+ def init_root_path
192
+ path = self.root_resource_path.gsub(/^\//,"")
193
+ ActiveFedora.fedora.connection.head(path)
194
+ rescue Ldp::NotFound
195
+ ActiveFedora.fedora.connection.put(path, "")
196
+ end
197
+
191
198
  def assign_uri_to_attached_files
192
199
  attached_files.each do |name, ds|
193
200
  ds.uri= "#{uri}/#{name}"
@@ -9,5 +9,7 @@ module ActiveFedora
9
9
  autoload :Identifiable
10
10
  autoload :Persistence
11
11
  autoload :ProjectHydra
12
+ autoload :FieldMap
13
+ autoload :FieldMapEntry
12
14
  end
13
15
  end
@@ -8,5 +8,6 @@ module ActiveFedora::RDF
8
8
  property :lastModified
9
9
  property :status
10
10
  property :ServerManaged
11
+ property :InboundReferences
11
12
  end
12
13
  end
@@ -0,0 +1,90 @@
1
+ module ActiveFedora::RDF
2
+ # Transient class that maps solr field names, without their suffixes, to the values and behaviors that
3
+ # are used to transforming them for insertion into the solr document.
4
+ # It partially extends Ruby's Hash class, similar to the way ActiveFedora::Indexing::Map does,
5
+ # but only with selected methods as outlined in def_delegators.
6
+ class FieldMap
7
+ extend Forwardable
8
+
9
+ def_delegators :@hash, :[], :[]=, :each, :keys
10
+
11
+ def initialize(hash = {}, &block)
12
+ @hash = hash
13
+ yield self if block_given?
14
+ end
15
+
16
+ # Inserts each solr field map configuration into the FieldMap class
17
+ # @param [Symbol] name the name of the property on the object that we're indexing
18
+ # @param [Object] index_field_config an instance of ActiveFedora::Indexing::Map::IndexObject
19
+ # @param [Object] object the instance of ActiveFedora::Base which is being indexed into Solr
20
+ def insert(name, index_field_config, object)
21
+ self[index_field_config.key.to_s] ||= FieldMapEntry.new
22
+ PolymorphicBuilder.new(self[index_field_config.key.to_s], index_field_config, object, name).build
23
+ end
24
+
25
+ # Supports assigning the delegate class that calls .build to insert the fields into the solr document.
26
+ # @attr [Object] entry instance of ActiveFedora::RDF::FieldMapEntry which will contain the values of the solr field
27
+ # @attr [Object] index_field_config an instance of ActiveFedora::Indexing::Map::IndexObject
28
+ # @attr [Object] object the instance of ActiveFedora::Base which is being indexed into Solr
29
+ # @attr [Symbol] name the name of the property on the object that we're indexing
30
+ class PolymorphicBuilder
31
+
32
+ attr_accessor :entry, :index_field_config, :object, :name
33
+
34
+ def initialize(entry, index_field_config, object, name)
35
+ @entry = entry
36
+ @index_field_config = index_field_config
37
+ @object = object
38
+ @name = name
39
+ self
40
+ end
41
+
42
+ def build
43
+ delegate_class.new(entry, index_field_config, object, name).build
44
+ end
45
+
46
+ private
47
+
48
+ def delegate_class
49
+ kind_of_af_base? ? ResourceBuilder : PropertyBuilder
50
+ end
51
+
52
+ def kind_of_af_base?
53
+ config = properties[name.to_s]
54
+ config && config[:class_name] && config[:class_name] < ActiveFedora::Base
55
+ end
56
+
57
+ def properties
58
+ object.class.properties
59
+ end
60
+
61
+ end
62
+
63
+ # Abstract class that implements the PolymorphicBuilder interface and is used for
64
+ # for building FieldMap entries. You can extend this object to create your own
65
+ # builder for creating the values in your solr fields.
66
+ class Builder < PolymorphicBuilder
67
+ def build
68
+ type = index_field_config.data_type
69
+ behaviors = index_field_config.behaviors
70
+ return unless type and behaviors
71
+ entry.merge!(type, behaviors, find_values)
72
+ end
73
+ end
74
+
75
+ # Builds a FieldMap entry for a resource such as an ActiveFedora::Base object and returns the uri as the value.
76
+ class ResourceBuilder < Builder
77
+ def find_values
78
+ object.send(name).map(&:uri)
79
+ end
80
+ end
81
+
82
+ # Builds a FieldMap entry for a rdf property and returns the values
83
+ class PropertyBuilder < Builder
84
+ def find_values
85
+ Array(object.send(name))
86
+ end
87
+ end
88
+
89
+ end
90
+ end