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,113 @@
1
+ module ActiveFedora
2
+ module Associations
3
+ # Filters a DirectContainer relationship, returning the first item that matches the given :type
4
+ class DirectlyContainsOneAssociation < SingularAssociation #:nodoc:
5
+
6
+ # Finds objects contained by the container predicate (either the configured has_member_relation or ldp:contains)
7
+ # TODO: Refactor this to use solr (for efficiency) instead of parsing the RDF graph. Requires indexing ActiveFedora::File objects into solr, including their RDF.type and, if possible, the id of their container
8
+ def find_target
9
+ # filtered_objects = container_association_proxy.to_a.select { |o| o.metadata_node.type.include?(options[:type]) }
10
+ query_node = if container_predicate = options[:has_member_relation]
11
+ owner
12
+ else
13
+ container_predicate = ::RDF::Vocab::LDP.contains
14
+ container_association.container # Use the :through association's container
15
+ end
16
+
17
+ contained_uris = query_node.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
18
+ contained_uris.each do |object_uri|
19
+ contained_object = klass.find(klass.uri_to_id(object_uri))
20
+ return contained_object if get_type_from_record(contained_object).include?(options[:type])
21
+ end
22
+ return nil # if nothing was found & returned while iterating on contained_uris, return nil
23
+ end
24
+
25
+ # Adds record to the DirectContainer identified by the container_association
26
+ # Relies on container_association.initialize_attributes to appropriately set things like record.uri
27
+ def add_to_container(record)
28
+ container_association.add_to_target(record) # adds record to corresponding Container
29
+ # TODO is send necessary?
30
+ container_association.send(:initialize_attributes, record) # Uses the :through association initialize the record with things like the correct URI for a direclty contained object
31
+ end
32
+
33
+ # Replaces association +target+ with +record+
34
+ # Ensures that this association's +type+ is set on the record and adds the record to the association's DirectContainer
35
+ def replace(record, *)
36
+ if record
37
+ raise_on_type_mismatch(record)
38
+ remove_existing_target
39
+ add_type_to_record(record, options[:type])
40
+ add_to_container(record)
41
+ else
42
+ remove_existing_target
43
+ end
44
+
45
+ self.target = record
46
+ end
47
+
48
+ def updated?
49
+ @updated
50
+ end
51
+
52
+ private
53
+
54
+ def remove_existing_target
55
+ @target ||= find_target
56
+ if @target
57
+ container_association_proxy.delete @target
58
+ @updated = true
59
+ end
60
+ end
61
+
62
+ # Overrides initialize_attributes to ensure that record is initialized with attributes from the corresponding container
63
+ def initialize_attributes(record)
64
+ super
65
+ container_association.initialize_attributes(record)
66
+ end
67
+
68
+ # Returns the Reflection corresponding to the direct container association that's being filtered
69
+ def container_reflection
70
+ @container_reflection ||= @owner.class.reflect_on_association(@reflection.options[:through])
71
+ end
72
+
73
+ # Returns the DirectContainerAssociation corresponding to the direct container that's being filtered
74
+ def container_association
75
+ container_association_proxy.proxy_association
76
+ end
77
+
78
+ # Returns the ContainerAssociationProxy corresponding to the direct container that's being filtered
79
+ def container_association_proxy
80
+ @owner.send(@reflection.options[:through])
81
+ end
82
+
83
+ # Adds type_uri to the RDF.type assertions on record
84
+ def add_type_to_record(record, type_uri)
85
+ metadata_node = metadata_node_for_record(record)
86
+ types = metadata_node.type
87
+ unless types.include?(type_uri)
88
+ types << type_uri
89
+ metadata_node.set_value(:type, types)
90
+ end
91
+ return record
92
+ end
93
+
94
+ # Returns the RDF.type assertions for the record
95
+ def get_type_from_record(record)
96
+ metadata_node_for_record(record).type
97
+ end
98
+
99
+ # Returns the RDF node that contains metadata like RDF.type assertions for the record
100
+ # Sometimes this is the record, other times it's record.metadata_node
101
+ def metadata_node_for_record(record)
102
+ if record.respond_to?(:type) && record.respond_to?(:set_value)
103
+ return record
104
+ elsif record.respond_to?(:metadata_node)
105
+ return record.metadata_node
106
+ else
107
+ raise ArgumentError, "record must either have a metadata node or must respond to .type"
108
+ end
109
+ end
110
+
111
+ end
112
+ end
113
+ end
@@ -46,20 +46,6 @@ module ActiveFedora
46
46
  result && records
47
47
  end
48
48
 
49
-
50
- def find_target
51
- page_size = @reflection.options[:solr_page_size]
52
- page_size ||= 200
53
- ids = owner[reflection.foreign_key]
54
- return [] if ids.blank?
55
- solr_result = []
56
- 0.step(ids.size,page_size) do |startIdx|
57
- query = ActiveFedora::SolrQueryBuilder.construct_query_for_ids(ids.slice(startIdx,page_size))
58
- solr_result += ActiveFedora::SolrService.query(query, rows: page_size)
59
- end
60
- return ActiveFedora::QueryResultBuilder.reify_solr_results(solr_result)
61
- end
62
-
63
49
  # In a HABTM, just look in the RDF, no need to run a count query from solr.
64
50
  def count(options = {})
65
51
  owner[reflection.foreign_key].size
@@ -96,6 +82,12 @@ module ActiveFedora
96
82
  owner[reflection.foreign_key]
97
83
  end
98
84
 
85
+ def find_target
86
+ ids = owner[reflection.foreign_key]
87
+ return [] if ids.blank?
88
+ ActiveFedora::Base.find(ids)
89
+ end
90
+
99
91
  end
100
92
  end
101
93
  end
@@ -35,19 +35,16 @@ module ActiveFedora
35
35
  record[inverse.foreign_key] = owner.id
36
36
  else # HABTM
37
37
  record[inverse.foreign_key] ||= []
38
- #TODO use primary_key instead of `owner.id`
39
38
  record[inverse.foreign_key] += [owner.id]
40
39
  end
41
40
  elsif owner.persisted?
42
41
  inverse = reflection.inverse_of
43
42
  if inverse && inverse.collection?
44
43
  record[inverse.foreign_key] ||= []
45
- #TODO use primary_key instead of `owner.id`
46
44
  record[inverse.foreign_key] += [owner.id]
47
45
  elsif inverse && inverse.klass == ActiveFedora::Base
48
46
  record[inverse.foreign_key] = owner.id
49
47
  else
50
- #TODO use primary_key instead of `owner.id`
51
48
  record[reflection.foreign_key] = owner.id
52
49
  end
53
50
  end
@@ -0,0 +1,30 @@
1
+ module ActiveFedora::Associations
2
+ ##
3
+ # A composite object for an array of IDs. This abstracts away the fact that an
4
+ # ID might be either a relative ID or a URI to a resource.
5
+ class IDComposite
6
+ attr_reader :ids, :id_translator
7
+ include Enumerable
8
+ def initialize(ids, id_translator)
9
+ @ids = ids
10
+ @id_translator = id_translator
11
+ end
12
+
13
+ # @return [Array<relative_id>]
14
+ def each
15
+ ids.each do |id|
16
+ yield convert(id)
17
+ end
18
+ end
19
+
20
+ private
21
+
22
+ def convert(id)
23
+ if id.start_with?("http")
24
+ id_translator.call(id)
25
+ else
26
+ id
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,90 @@
1
+ module ActiveFedora
2
+ module Associations
3
+ class IndirectlyContainsAssociation < ContainsAssociation #:nodoc:
4
+
5
+ # TODO we may want to split this into two subclasses, one for has_member_relation
6
+ # and the other for is_member_of_relation
7
+
8
+ def insert_record(record, force = true, validate = true)
9
+ container.save!
10
+ if force
11
+ record.save!
12
+ else
13
+ return false unless record.save(validate: validate)
14
+ end
15
+
16
+ save_through_record(record)
17
+
18
+ return true
19
+ end
20
+
21
+ def find_target
22
+ if container_predicate = options[:has_member_relation]
23
+ uris = owner.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
24
+ uris.map { |object_uri| klass.find(klass.uri_to_id(object_uri)) }
25
+ else # is_member_of_relation
26
+ # TODO this is a lot of reads. Avoid this path
27
+ container_predicate = ::RDF::Vocab::LDP.contains
28
+ proxy_uris = container.resource.query(predicate: container_predicate).map { |r| r.object.to_s }
29
+ proxy_uris.map { |uri| proxy_class.find(proxy_class.uri_to_id(uri))[options[:foreign_key]] }
30
+ end
31
+
32
+
33
+ end
34
+
35
+ def container
36
+ @container ||= begin
37
+ IndirectContainer.find_or_initialize(ActiveFedora::Base.uri_to_id(uri)).tap do |container|
38
+ container.parent = @owner
39
+ container.has_member_relation = Array(options[:has_member_relation])
40
+ container.is_member_of_relation = Array(options[:is_member_of_relation])
41
+ container.inserted_content_relation = Array(options[:inserted_content_relation])
42
+ end
43
+ end
44
+ end
45
+
46
+ protected
47
+
48
+ def initialize_attributes(record) #:nodoc:
49
+ #record.uri = ActiveFedora::Base.id_to_uri(container.mint_id)
50
+ # set_inverse_instance(record)
51
+ end
52
+
53
+ private
54
+
55
+ def delete_records(records, method)
56
+ container.reload # Reload container to get updated LDP.contains
57
+ records.each do |record|
58
+ delete_record(record)
59
+ end
60
+ end
61
+
62
+ def delete_record(record)
63
+ record_proxy_finder.find(record).delete
64
+ end
65
+
66
+ def record_proxy_finder
67
+ ContainedFinder.new(container: container, repository: composite_proxy_repository)
68
+ end
69
+
70
+ def composite_proxy_repository
71
+ RecordComposite::Repository.new(base_repository: proxy_class)
72
+ end
73
+
74
+ def save_through_record(record)
75
+ build_proxy_node({}) do |node|
76
+ node[options[:foreign_key]] = record
77
+ node.save
78
+ end
79
+ end
80
+
81
+ def build_proxy_node(attributes, &block)
82
+ proxy_class.new({ id: container.mint_id }.merge(attributes), &block)
83
+ end
84
+
85
+ def proxy_class
86
+ @proxy_class ||= options[:through].constantize
87
+ end
88
+ end
89
+ end
90
+ end
@@ -33,9 +33,15 @@ module ActiveFedora
33
33
  end
34
34
  end
35
35
 
36
- # TODO Detect when this is the only relationship for this predicate, then skip the filtering.
37
36
  def filtering_required?
38
- reflection.klass != ActiveFedora::Base
37
+ return false if reflection.klass == ActiveFedora::Base
38
+ reflections_with_same_predicate.count > 1
39
+ end
40
+
41
+ # Count the number of reflections that have the same predicate as the reflection
42
+ # for this association.
43
+ def reflections_with_same_predicate
44
+ owner.class.outgoing_reflections.select { |k, v| v.options[:predicate] == reflection.predicate }
39
45
  end
40
46
 
41
47
  # @return [Array<RDF::URI>]
@@ -48,8 +54,6 @@ module ActiveFedora
48
54
  owner.resource.query(subject: owner.rdf_subject, predicate: reflection.predicate).enum_statement
49
55
  end
50
56
 
51
-
52
- # TODO this is a huge waste of time that can be completely avoided if the attributes aren't sharing predicates.
53
57
  # @return [Array<RDF::URI>]
54
58
  def filter_by_class(candidate_uris)
55
59
  return [] if candidate_uris.empty?
@@ -0,0 +1,39 @@
1
+ module ActiveFedora::Associations
2
+ ##
3
+ # A Composite for records - currently only supports delete interface.
4
+ # The goal is to push commands down to the containing records.
5
+ class RecordComposite
6
+ attr_reader :records
7
+ include Enumerable
8
+ def initialize(records:)
9
+ @records = records
10
+ end
11
+
12
+ def each
13
+ records.each do |record|
14
+ yield record
15
+ end
16
+ end
17
+
18
+ def delete
19
+ self.each(&:delete)
20
+ end
21
+ ##
22
+ # A Repository which returns a composite from #find instead of a single
23
+ # record. Delegates find to a base repository.
24
+ class Repository
25
+ attr_reader :base_repository
26
+ delegate :translate_uri_to_id, to: :base_repository
27
+ def initialize(base_repository:)
28
+ @base_repository = base_repository
29
+ end
30
+
31
+ def find(ids)
32
+ records = ids.map do |id|
33
+ base_repository.find(id)
34
+ end
35
+ RecordComposite.new(records: records)
36
+ end
37
+ end
38
+ end
39
+ end
@@ -124,7 +124,7 @@ module ActiveFedora
124
124
  private
125
125
  def create_singleton_association(file_path)
126
126
  self.undeclared_files << file_path.to_sym
127
- association = Associations::ContainsAssociation.new(self, Reflection::AssociationReflection.new(:contains, file_path, {class_name: 'ActiveFedora::File'}, self.class))
127
+ association = Associations::BasicContainsAssociation.new(self, Reflection::AssociationReflection.new(:contains, file_path, {class_name: 'ActiveFedora::File'}, self.class))
128
128
  @association_cache[file_path.to_sym] = association
129
129
 
130
130
  self.singleton_class.send :define_method, accessor_name(file_path) do
@@ -177,7 +177,7 @@ module ActiveFedora
177
177
  elsif properties.key?(:delegate_to)
178
178
  define_delegated_accessor([name], properties.delete(:delegate_to), properties.reverse_merge(multiple: true), &block)
179
179
  else
180
- raise "You must provide `:datastream' or `:predicate' options to property"
180
+ raise "You must provide `:delegate_to' or `:predicate' options to property"
181
181
  end
182
182
  end
183
183
 
@@ -186,7 +186,7 @@ module ActiveFedora
186
186
  def define_active_triple_accessor(name, properties, &block)
187
187
  warn_duplicate_predicates name, properties
188
188
  properties = { multiple: true }.merge(properties)
189
- find_or_create_defined_attribute(name, nil, properties)
189
+ find_or_create_defined_attribute(name, ActiveTripleAttribute, properties)
190
190
  raise ArgumentError, "#{name} is a keyword and not an acceptable property name." if protected_property_name? name
191
191
  reflection = ActiveFedora::Attributes::PropertyBuilder.build(self, name, properties, &block)
192
192
  ActiveTriples::Reflection.add_reflection self, name, reflection
@@ -197,6 +197,10 @@ module ActiveFedora
197
197
  def define_delegated_accessor(fields, delegate_target, options, &block)
198
198
  define_attribute_methods fields
199
199
  fields.each do |f|
200
+ klass = datastream_class_for_name(delegate_target)
201
+ attribute_properties = options.merge(delegate_target: delegate_target, klass: klass)
202
+ find_or_create_defined_attribute f, attribute_class(klass), attribute_properties
203
+
200
204
  create_attribute_reader(f, delegate_target, options)
201
205
  create_attribute_setter(f, delegate_target, options)
202
206
  add_attribute_indexing_config(f, &block) if block_given?
@@ -204,8 +208,7 @@ module ActiveFedora
204
208
  end
205
209
 
206
210
  def add_attribute_indexing_config(name, &block)
207
- # TODO the hash can be initalized to return on of these
208
- index_config[name] ||= ActiveFedora::Indexing::Map::IndexObject.new &block
211
+ index_config[name] ||= ActiveFedora::Indexing::Map::IndexObject.new(name, &block)
209
212
  end
210
213
 
211
214
  def warn_duplicate_predicates new_name, new_properties
@@ -215,31 +218,46 @@ module ActiveFedora
215
218
  end
216
219
  end
217
220
 
218
- def find_or_create_defined_attribute(field, dsid, args)
219
- delegated_attributes[field] ||= DelegatedAttribute.new(field, dsid, datastream_class_for_name(dsid), args)
221
+ # @param [Symbol] field the field to find or create
222
+ # @param [Class] klass the class to use to delegate the attribute (e.g.
223
+ # ActiveTripleAttribute, OmAttribute, or RdfDatastreamAttribute)
224
+ # @param [Hash] args
225
+ # @option args [String] :delegate_target the path to the delegate
226
+ # @option args [Class] :klass the class to create
227
+ # @option args [true,false] :multiple (false) true for multi-value fields
228
+ # @option args [Array<Symbol>] :at path to a deep node
229
+ # @return [DelegatedAttribute] the found or created attribute
230
+ def find_or_create_defined_attribute(field, klass, args)
231
+ delegated_attributes[field] ||= klass.new(field, args)
220
232
  end
221
233
 
222
234
  # @param [String] dsid the datastream id
223
235
  # @return [Class] the class of the datastream
224
236
  def datastream_class_for_name(dsid)
225
- reflection = reflect_on_association(dsid)
237
+ reflection = reflect_on_association(dsid.to_sym)
226
238
  reflection ? reflection.klass : ActiveFedora::File
227
239
  end
228
240
 
229
241
  def create_attribute_reader(field, dsid, args)
230
- find_or_create_defined_attribute(field, dsid, args)
231
-
232
242
  define_method field do |*opts|
233
243
  array_reader(field, *opts)
234
244
  end
235
245
  end
236
246
 
237
247
  def create_attribute_setter(field, dsid, args)
238
- find_or_create_defined_attribute(field, dsid, args)
239
248
  define_method "#{field}=".to_sym do |v|
240
249
  self[field]=v
241
250
  end
242
251
  end
252
+
253
+ def attribute_class(klass)
254
+ if klass < ActiveFedora::RDFDatastream
255
+ RdfDatastreamAttribute
256
+ else
257
+ OmAttribute
258
+ end
259
+ end
260
+
243
261
  end
244
262
  end
245
263
  end