active-fedora 7.0.0.rc2 → 7.0.0.rc3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (90) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +13 -3
  3. data/CONTRIBUTORS.md +1 -0
  4. data/Gemfile +2 -3
  5. data/active-fedora.gemspec +4 -3
  6. data/gemfiles/rails3.gemfile +1 -7
  7. data/gemfiles/rails4.1.gemfile +5 -0
  8. data/gemfiles/rails4.gemfile +1 -6
  9. data/lib/active_fedora.rb +6 -6
  10. data/lib/active_fedora/associations/association_scope.rb +1 -1
  11. data/lib/active_fedora/base.rb +2 -0
  12. data/lib/active_fedora/datastream.rb +29 -2
  13. data/lib/active_fedora/datastream_collections.rb +2 -2
  14. data/lib/active_fedora/datastream_hash.rb +1 -1
  15. data/lib/active_fedora/datastreams.rb +4 -23
  16. data/lib/active_fedora/file_configurator.rb +8 -7
  17. data/lib/active_fedora/om_datastream.rb +1 -1
  18. data/lib/active_fedora/rdf.rb +9 -0
  19. data/lib/active_fedora/rdf/configurable.rb +59 -0
  20. data/lib/active_fedora/rdf/identifiable.rb +59 -0
  21. data/lib/active_fedora/rdf/indexing.rb +24 -23
  22. data/lib/active_fedora/rdf/list.rb +154 -0
  23. data/lib/active_fedora/{ntriples_rdf_datastream.rb → rdf/ntriples_rdf_datastream.rb} +0 -0
  24. data/lib/active_fedora/rdf/object_resource.rb +20 -0
  25. data/lib/active_fedora/rdf/properties.rb +108 -0
  26. data/lib/active_fedora/rdf/rdf_datastream.rb +113 -0
  27. data/lib/active_fedora/{rdfxml_rdf_datastream.rb → rdf/rdfxml_rdf_datastream.rb} +0 -0
  28. data/lib/active_fedora/rdf/repositories.rb +36 -0
  29. data/lib/active_fedora/rdf/resource.rb +324 -0
  30. data/lib/active_fedora/rdf/term.rb +188 -0
  31. data/lib/active_fedora/relation.rb +1 -0
  32. data/lib/active_fedora/relation/finder_methods.rb +16 -17
  33. data/lib/active_fedora/relation/merger.rb +1 -1
  34. data/lib/active_fedora/relation/query_methods.rb +13 -5
  35. data/lib/active_fedora/reload_on_save.rb +16 -0
  36. data/lib/active_fedora/rubydora_connection.rb +0 -1
  37. data/lib/active_fedora/sharding.rb +1 -1
  38. data/lib/active_fedora/version.rb +1 -1
  39. data/script/console +10 -11
  40. data/spec/config_helper.rb +1 -1
  41. data/spec/fixtures/solr_rdf_descMetadata.nt +1 -1
  42. data/spec/integration/auditable_spec.rb +1 -1
  43. data/spec/integration/base_spec.rb +21 -3
  44. data/spec/integration/complex_rdf_datastream_spec.rb +32 -55
  45. data/spec/integration/field_to_solr_name_spec.rb +6 -8
  46. data/spec/integration/has_many_associations_spec.rb +10 -3
  47. data/spec/integration/load_from_solr_spec.rb +15 -17
  48. data/spec/integration/ntriples_datastream_spec.rb +19 -23
  49. data/spec/integration/om_datastream_spec.rb +1 -1
  50. data/spec/integration/rdf_nested_attributes_spec.rb +51 -70
  51. data/spec/integration/relation_spec.rb +24 -11
  52. data/spec/integration/scoped_query_spec.rb +5 -1
  53. data/spec/samples/hydra-mods_article_datastream.rb +4 -0
  54. data/spec/samples/hydra-rights_metadata_datastream.rb +5 -0
  55. data/spec/samples/marpa-dc_datastream.rb +6 -1
  56. data/spec/samples/special_thing.rb +5 -5
  57. data/spec/spec_helper.rb +0 -3
  58. data/spec/support/an_active_model.rb +5 -12
  59. data/spec/unit/active_fedora_spec.rb +2 -2
  60. data/spec/unit/attributes_spec.rb +4 -8
  61. data/spec/unit/base_datastream_management_spec.rb +5 -29
  62. data/spec/unit/base_spec.rb +4 -0
  63. data/spec/unit/code_configurator_spec.rb +2 -2
  64. data/spec/unit/config_spec.rb +2 -2
  65. data/spec/unit/core_spec.rb +2 -4
  66. data/spec/unit/datastream_spec.rb +15 -0
  67. data/spec/unit/datastreams_spec.rb +1 -12
  68. data/spec/unit/file_configurator_spec.rb +1 -1
  69. data/spec/unit/ntriples_datastream_spec.rb +52 -57
  70. data/spec/unit/om_datastream_spec.rb +3 -3
  71. data/spec/unit/query_spec.rb +3 -4
  72. data/spec/unit/rdf_configurable_spec.rb +37 -0
  73. data/spec/unit/rdf_datastream_spec.rb +5 -7
  74. data/spec/unit/rdf_list_nested_attributes_spec.rb +22 -36
  75. data/spec/unit/rdf_list_spec.rb +26 -38
  76. data/spec/unit/rdf_properties_spec.rb +70 -0
  77. data/spec/unit/rdf_repositories_spec.rb +28 -0
  78. data/spec/unit/rdf_resource_datastream_spec.rb +287 -0
  79. data/spec/unit/rdf_resource_spec.rb +341 -0
  80. data/spec/unit/rdfxml_rdf_datastream_spec.rb +10 -26
  81. data/spec/unit/reload_on_save_spec.rb +24 -0
  82. data/spec/unit/solr_service_spec.rb +3 -3
  83. metadata +45 -16
  84. data/lib/active_fedora/rdf_datastream.rb +0 -113
  85. data/lib/active_fedora/rdf_list.rb +0 -162
  86. data/lib/active_fedora/rdf_node.rb +0 -332
  87. data/lib/active_fedora/rdf_node/term_proxy.rb +0 -141
  88. data/lib/active_fedora/rdf_object.rb +0 -24
  89. data/lib/active_fedora/yaml_adaptor.rb +0 -12
  90. data/spec/unit/rdf_node_spec.rb +0 -36
@@ -0,0 +1,36 @@
1
+ module ActiveFedora::Rdf
2
+ ##
3
+ # Defines module methods for registering an RDF::Repository for
4
+ # persistence of Resources.
5
+ #
6
+ # This allows any triplestore (or other storage platform) with an
7
+ # RDF::Repository implementation to be used for persistence of
8
+ # resources that will be shared between ActiveFedora::Base objects.
9
+ #
10
+ # ActiveFedora::Rdf::Repositories.add_repository :blah, RDF::Repository.new
11
+ #
12
+ # Multiple repositories can be registered to keep different kinds of
13
+ # resources seperate. This is configurable on subclasses of Resource
14
+ # at the class level.
15
+ #
16
+ # @see Configurable
17
+ module Repositories
18
+
19
+ def add_repository(name, repo)
20
+ raise "Repositories must be an RDF::Repository" unless repo.kind_of? RDF::Repository
21
+ repositories[name] = repo
22
+ end
23
+ module_function :add_repository
24
+
25
+ def clear_repositories!
26
+ @repositories = {}
27
+ end
28
+ module_function :clear_repositories!
29
+
30
+ def repositories
31
+ @repositories ||= {}
32
+ end
33
+ module_function :repositories
34
+
35
+ end
36
+ end
@@ -0,0 +1,324 @@
1
+ module ActiveFedora::Rdf
2
+ ##
3
+ # Defines a generic RDF `Resource` as an RDF::Graph with property
4
+ # configuration, accessors, and some other methods for managing
5
+ # resources as discrete subgraphs which can be maintained by a Hydra
6
+ # datastream model.
7
+ #
8
+ # Resources can be instances of ActiveFedora::Rdf::Resource
9
+ # directly, but more often they will be instances of subclasses with
10
+ # registered properties and configuration. e.g.
11
+ #
12
+ # class License < Resource
13
+ # configure repository: :default
14
+ # property :title, predicate: RDF::DC.title, class_name: RDF::Literal do |index|
15
+ # index.as :displayable, :facetable
16
+ # end
17
+ # end
18
+ class Resource < RDF::Graph
19
+ @@type_registry
20
+ extend Configurable
21
+ extend Properties
22
+ extend Deprecation
23
+ include ActiveFedora::Rdf::NestedAttributes
24
+ attr_accessor :parent
25
+
26
+ class << self
27
+ def type_registry
28
+ @@type_registry ||= {}
29
+ end
30
+
31
+ ##
32
+ # Adapter for a consistent interface for creating a new node from a URI.
33
+ # Similar functionality should exist in all objects which can become a node.
34
+ def from_uri(uri,vals=nil)
35
+ new(uri, vals)
36
+ end
37
+ end
38
+
39
+ def writable?
40
+ !frozen?
41
+ end
42
+
43
+ ##
44
+ # Initialize an instance of this resource class. Defaults to a
45
+ # blank node subject. In addition to RDF::Graph parameters, you
46
+ # can pass in a URI and/or a parent to build a resource from a
47
+ # existing data.
48
+ #
49
+ # You can pass in only a parent with:
50
+ # Resource.new(nil, parent)
51
+ #
52
+ # @see RDF::Graph
53
+ def initialize(*args, &block)
54
+ resource_uri = args.shift unless args.first.is_a?(Hash)
55
+ self.parent = args.shift unless args.first.is_a?(Hash)
56
+ set_subject!(resource_uri) if resource_uri
57
+ super(*args, &block)
58
+ reload
59
+ # Append type to graph if necessary.
60
+ self.get_values(:type) << self.class.type if self.class.type.kind_of?(RDF::URI) && type.empty?
61
+ end
62
+
63
+ def graph
64
+ Deprecation.warn Resource, "graph is redundant & deprecated. It will be removed in active-fedora 8.0.0.", caller
65
+ self
66
+ end
67
+
68
+ def final_parent
69
+ @final_parent ||= begin
70
+ parent = self.parent
71
+ while parent && parent.parent && parent.parent != parent
72
+ parent = parent.parent
73
+ end
74
+ parent
75
+ end
76
+ end
77
+
78
+ def attributes=(values)
79
+ raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
80
+ values.with_indifferent_access.each do |key, value|
81
+ if self.singleton_class.properties.keys.include?(key)
82
+ set_value(rdf_subject, key, value)
83
+ elsif self.singleton_class.nested_attributes_options.keys.map{ |k| "#{k}_attributes"}.include?(key)
84
+ send("#{key}=".to_sym, value)
85
+ end
86
+ end
87
+ end
88
+
89
+ def rdf_subject
90
+ @rdf_subject ||= RDF::Node.new
91
+ end
92
+
93
+ def node?
94
+ return true if rdf_subject.kind_of? RDF::Node
95
+ false
96
+ end
97
+
98
+ def to_term
99
+ rdf_subject
100
+ end
101
+
102
+ def base_uri
103
+ self.class.base_uri
104
+ end
105
+
106
+ def type
107
+ self.get_values(:type).to_a.map{|x| x.rdf_subject}
108
+ end
109
+
110
+ def type=(type)
111
+ raise "Type must be an RDF::URI" unless type.kind_of? RDF::URI
112
+ self.update(RDF::Statement.new(rdf_subject, RDF.type, type))
113
+ end
114
+
115
+ ##
116
+ # Look for labels in various default fields, prioritizing
117
+ # configured label fields
118
+ def rdf_label
119
+ labels = Array(self.class.rdf_label)
120
+ labels += default_labels
121
+ labels.each do |label|
122
+ values = get_values(label)
123
+ return values unless values.empty?
124
+ end
125
+ node? ? [] : [rdf_subject.to_s]
126
+ end
127
+
128
+ def fields
129
+ properties.keys.map(&:to_sym).reject{|x| x == :type}
130
+ end
131
+
132
+ ##
133
+ # Load data from URI
134
+ def fetch
135
+ load(rdf_subject)
136
+ self
137
+ end
138
+
139
+ def persist!
140
+ raise "failed when trying to persist to non-existant repository or parent resource" unless repository
141
+ repository.delete [rdf_subject,nil,nil] unless node?
142
+ if node?
143
+ repository.statements.each do |statement|
144
+ repository.send(:delete_statement, statement) if statement.subject == rdf_subject
145
+ end
146
+ end
147
+ repository << self
148
+ @persisted = true
149
+ end
150
+
151
+ def persisted?
152
+ @persisted ||= false
153
+ return (@persisted and parent.persisted?) if parent
154
+ @persisted
155
+ end
156
+
157
+ ##
158
+ # Repopulates the graph from the repository or parent resource.
159
+ def reload
160
+ @term_cache ||= {}
161
+ if self.class.repository == :parent
162
+ return false if final_parent.nil?
163
+ end
164
+ self << repository.query(subject: rdf_subject)
165
+ unless empty?
166
+ @persisted = true
167
+ end
168
+ true
169
+ end
170
+
171
+ ##
172
+ # Adds or updates a property with supplied values.
173
+ #
174
+ # Handles two argument patterns. The recommended pattern is:
175
+ # set_value(property, values)
176
+ #
177
+ # For backwards compatibility, there is support for explicitly
178
+ # passing the rdf_subject to be used in the statement:
179
+ # set_value(uri, property, values)
180
+ #
181
+ # @note This method will delete existing statements with the correct subject and predicate from the graph
182
+ def set_value(*args)
183
+ # Add support for legacy 3-parameter syntax
184
+ if args.length > 3 || args.length < 2
185
+ raise ArgumentError("wrong number of arguments (#{args.length} for 2-3)")
186
+ end
187
+ values = args.pop
188
+ get_term(args).set(values)
189
+ end
190
+
191
+ ##
192
+ # Returns an array of values belonging to the property
193
+ # requested. Elements in the array may RdfResource objects or a
194
+ # valid datatype.
195
+ #
196
+ # Handles two argument patterns. The recommended pattern is:
197
+ # get_values(property)
198
+ #
199
+ # For backwards compatibility, there is support for explicitly
200
+ # passing the rdf_subject to be used in th statement:
201
+ # get_values(uri, property)
202
+ def get_values(*args)
203
+ get_term(args)
204
+ end
205
+
206
+ def get_term(args)
207
+ @term_cache ||= {}
208
+ term = ActiveFedora::Rdf::Term.new(self, args)
209
+ @term_cache["#{term.rdf_subject}/#{term.property}"] ||= term
210
+ @term_cache["#{term.rdf_subject}/#{term.property}"]
211
+ end
212
+
213
+ ##
214
+ # Set a new rdf_subject for the resource.
215
+ #
216
+ # This raises an error if the current subject is not a blank node,
217
+ # and returns false if it can't figure out how to make a URI from
218
+ # the param. Otherwise it creates a URI for the resource and
219
+ # rebuilds the graph with the updated URI.
220
+ #
221
+ # Will try to build a uri as an extension of the class's base_uri
222
+ # if appropriate.
223
+ #
224
+ # @param [#to_uri, #to_s] uri_or_str the uri or string to use
225
+ def set_subject!(uri_or_str)
226
+ raise "Refusing update URI when one is already assigned!" unless node?
227
+ # Refusing set uri to an empty string.
228
+ return false if uri_or_str.nil? or uri_or_str.to_s.empty?
229
+ # raise "Refusing update URI! This object is persisted to a datastream." if persisted?
230
+ old_subject = rdf_subject
231
+ @rdf_subject = get_uri(uri_or_str)
232
+
233
+ each_statement do |statement|
234
+ if statement.subject == old_subject
235
+ delete(statement)
236
+ self << RDF::Statement.new(rdf_subject, statement.predicate, statement.object)
237
+ elsif statement.object == old_subject
238
+ delete(statement)
239
+ self << RDF::Statement.new(statement.subject, statement.predicate, rdf_subject)
240
+ end
241
+ end
242
+ end
243
+
244
+ def destroy
245
+ clear
246
+ persist!
247
+ parent.destroy_child(self)
248
+ end
249
+
250
+ def destroy_child(child)
251
+ statements.each do |statement|
252
+ delete_statement(statement) if statement.subject == child.rdf_subject || statement.object == child.rdf_subject
253
+ end
254
+ end
255
+
256
+ def new_record?
257
+ not persisted?
258
+ end
259
+
260
+ ##
261
+ # @return [String] the string to index in solr
262
+ def solrize
263
+ node? ? rdf_label : rdf_subject.to_s
264
+ end
265
+
266
+ def mark_for_destruction
267
+ @marked_for_destruction = true
268
+ end
269
+
270
+ def marked_for_destruction?
271
+ @marked_for_destruction
272
+ end
273
+
274
+ private
275
+
276
+ def properties
277
+ self.singleton_class.properties
278
+ end
279
+
280
+ def property_for_predicate(predicate)
281
+ properties.each do |property, values|
282
+ return property if values[:predicate] == predicate
283
+ end
284
+ return nil
285
+ end
286
+
287
+ def default_labels
288
+ [RDF::SKOS.prefLabel,
289
+ RDF::DC.title,
290
+ RDF::RDFS.label,
291
+ RDF::SKOS.altLabel,
292
+ RDF::SKOS.hiddenLabel]
293
+ end
294
+
295
+ ##
296
+ # Return the repository (or parent) that this resource should
297
+ # write to when persisting.
298
+ def repository
299
+ @repository ||=
300
+ if self.class.repository == :parent
301
+ final_parent
302
+ else
303
+ ActiveFedora::Rdf::Repositories.repositories[self.class.repository]
304
+ end
305
+ end
306
+
307
+ private
308
+
309
+ ##
310
+ # Takes a URI or String and aggressively tries to create a valid RDF URI.
311
+ # Combines the input with base_uri if appropriate.
312
+ #
313
+ # @TODO: URI.scheme_list is naive and incomplete. Find a better way to check for an existing scheme.
314
+ def get_uri(uri_or_str)
315
+ return uri_or_str.to_uri if uri_or_str.respond_to? :to_uri
316
+ return uri_or_str if uri_or_str.kind_of? RDF::Node
317
+ uri_or_str = uri_or_str.to_s
318
+ return RDF::Node(uri_or_str[2..-1]) if uri_or_str.start_with? '_:'
319
+ return RDF::URI(uri_or_str) if RDF::URI(uri_or_str).valid? and (URI.scheme_list.include?(RDF::URI.new(uri_or_str).scheme.upcase) or RDF::URI.new(uri_or_str).scheme == 'info')
320
+ return RDF::URI(self.base_uri.to_s + (self.base_uri.to_s[-1,1] =~ /(\/|#)/ ? '' : '/') + uri_or_str) if base_uri && !uri_or_str.start_with?(base_uri.to_s)
321
+ raise RuntimeError "could not make a valid RDF::URI from #{uri_or_str}"
322
+ end
323
+ end
324
+ end
@@ -0,0 +1,188 @@
1
+ module ActiveFedora::Rdf
2
+ class Term
3
+ attr_accessor :parent, :value_arguments, :node_cache
4
+ delegate *(Array.public_instance_methods - [:__send__, :__id__, :class, :object_id] + [:as_json]), :to => :result
5
+ def initialize(parent, value_arguments)
6
+ self.parent = parent
7
+ self.value_arguments = value_arguments
8
+ end
9
+
10
+ def clear
11
+ set(nil)
12
+ end
13
+
14
+ def result
15
+ result = parent.query(:subject => rdf_subject, :predicate => predicate)
16
+ .map{|x| convert_object(x.object)}
17
+ .reject(&:nil?)
18
+ return result if !property_config || property_config[:multivalue]
19
+ result.first
20
+ end
21
+
22
+ def set(values)
23
+ values = [values].compact unless values.kind_of?(Array)
24
+ empty_property
25
+ values.each do |val|
26
+ set_value(val)
27
+ end
28
+ parent.persist! if parent.class.repository == :parent && parent.send(:repository)
29
+ end
30
+
31
+ def empty_property
32
+ parent.query([rdf_subject, predicate, nil]).each_statement do |statement|
33
+ if !uri_class(statement.object) || uri_class(statement.object) == class_for_property
34
+ parent.delete(statement)
35
+ end
36
+ end
37
+ end
38
+
39
+ def build(attributes={})
40
+ new_subject = attributes.key?('id') ? attributes.delete('id') : RDF::Node.new
41
+ node = make_node(new_subject)
42
+ node.attributes = attributes
43
+ if parent.kind_of? List::ListResource
44
+ parent.list << node
45
+ return node
46
+ elsif node.kind_of? RDF::List
47
+ self.push node.rdf_subject
48
+ return node
49
+ end
50
+ self.push node
51
+ node
52
+ end
53
+
54
+ def first_or_create(attributes={})
55
+ result.first || build(attributes)
56
+ end
57
+
58
+ def delete(*values)
59
+ values.each do |value|
60
+ parent.delete([rdf_subject, predicate, value])
61
+ end
62
+ end
63
+
64
+ def << (values)
65
+ values = Array.wrap(result) | Array.wrap(values)
66
+ self.set(values)
67
+ end
68
+
69
+ alias_method :push, :<<
70
+
71
+ def property_config
72
+ return type_property if (property == RDF.type || property.to_s == "type") && !parent.send(:properties)[property]
73
+ parent.send(:properties)[property]
74
+ end
75
+
76
+ def type_property
77
+ {:multivalue => true, :predicate => RDF.type}
78
+ end
79
+
80
+ def reset!
81
+ end
82
+
83
+ def property
84
+ value_arguments.last
85
+ end
86
+
87
+ def rdf_subject
88
+ raise ArgumentError("wrong number of arguments (#{value_arguments.length} for 1-2)") if value_arguments.length < 1 || value_arguments.length > 2
89
+ if value_arguments.length > 1
90
+ value_arguments.first
91
+ else
92
+ parent.rdf_subject
93
+ end
94
+ end
95
+
96
+ protected
97
+
98
+ def node_cache
99
+ @node_cache ||= {}
100
+ end
101
+
102
+ def set_value(val)
103
+ object = val
104
+ val = val.resource if val.respond_to?(:resource)
105
+ val = value_to_node(val)
106
+ if val.kind_of? Resource
107
+ node_cache[val.rdf_subject] = nil
108
+ add_child_node(val, object)
109
+ return
110
+ end
111
+ val = val.to_uri if val.respond_to? :to_uri
112
+ raise 'value must be an RDF URI, Node, Literal, or a valid datatype. See RDF::Literal' unless
113
+ val.kind_of? RDF::Value or val.kind_of? RDF::Literal
114
+ parent.insert [rdf_subject, predicate, val]
115
+ end
116
+
117
+ def value_to_node(val)
118
+ valid_datatype?(val) ? RDF::Literal(val) : val
119
+ end
120
+
121
+ def add_child_node(resource,object=nil)
122
+ parent.insert [rdf_subject, predicate, resource.rdf_subject]
123
+ resource.parent = parent unless resource.frozen?
124
+ self.node_cache[resource.rdf_subject] = (object ? object : resource)
125
+ resource.persist! if resource.class.repository == :parent
126
+ end
127
+
128
+ def predicate
129
+ return property_config[:predicate] unless property.kind_of? RDF::URI
130
+ property
131
+ end
132
+
133
+ def valid_datatype?(val)
134
+ val.is_a? String or val.is_a? Date or val.is_a? Time or val.is_a? Numeric or val.is_a? Symbol or val == !!val
135
+ end
136
+
137
+ # Converts an object to the appropriate class.
138
+ def convert_object(value)
139
+ value = value.object if value.kind_of? RDF::Literal
140
+ value = make_node(value) if value.kind_of? RDF::Resource
141
+ value
142
+ end
143
+
144
+ ##
145
+ # Build a child resource or return it from this object's cache
146
+ #
147
+ # Builds the resource from the class_name specified for the
148
+ # property.
149
+ def make_node(value)
150
+ klass = class_for_value(value)
151
+ value = RDF::Node.new if value.nil?
152
+ node = node_cache[value] if node_cache[value]
153
+ node ||= klass.from_uri(value,parent)
154
+ return nil if property_config[:class_name] && class_for_value(value) != class_for_property
155
+ self.node_cache[value] ||= node
156
+ node
157
+ end
158
+
159
+ def final_parent
160
+ @final_parent ||= begin
161
+ parent = self.parent
162
+ while parent != parent.parent && parent.parent
163
+ parent = parent.parent
164
+ end
165
+ return parent.datastream if parent.respond_to?(:datastream) && parent.datastream
166
+ parent
167
+ end
168
+ end
169
+
170
+ def class_for_value(v)
171
+ uri_class(v) || class_for_property
172
+ end
173
+
174
+ def uri_class(v)
175
+ v = RDF::URI.new(v) if v.kind_of? String
176
+ type_uri = parent.query([v, RDF.type, nil]).to_a.first.try(:object)
177
+ ActiveFedora::Rdf::Resource.type_registry[type_uri]
178
+ end
179
+
180
+ def class_for_property
181
+ klass = property_config[:class_name]
182
+ klass ||= ActiveFedora::Rdf::Resource
183
+ klass = ActiveFedora.class_from_string(klass, final_parent.class) if klass.kind_of? String
184
+ klass
185
+ end
186
+
187
+ end
188
+ end