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
@@ -1,332 +0,0 @@
1
- module ActiveFedora
2
- module RdfNode
3
- extend ActiveSupport::Concern
4
- extend ActiveSupport::Autoload
5
- include ActiveFedora::Rdf::NestedAttributes
6
-
7
- autoload :TermProxy
8
-
9
- # Mapping from URI to ruby class
10
- def self.rdf_registry
11
- @@rdf_registry ||= {}
12
- end
13
-
14
- # Comparison Operator
15
- # Checks that
16
- # * RDF subject id (URI) is same
17
- # * Class is the same
18
- # * Both objects reference the same RDF graph in memory
19
- def ==(other_object)
20
- self.class == other_object.class &&
21
- self.rdf_subject.id == other_object.rdf_subject.id &&
22
- self.graph.object_id == other_object.graph.object_id
23
- end
24
-
25
- ##
26
- # Get the subject for this rdf object
27
- def rdf_subject
28
- @subject ||= begin
29
- s = self.class.rdf_subject.call(self)
30
- s &&= RDF::URI.new(s) if s.is_a? String
31
- s
32
- end
33
- end
34
-
35
- def reset_rdf_subject!
36
- @subject = nil
37
- end
38
-
39
- def reset_child_cache!
40
- @target = {}
41
- end
42
-
43
- # @param [RDF::URI] subject the base node to start the search from
44
- # @param [Symbol] term the term to get the values for
45
- def get_values(subject, term)
46
- options = config_for_term_or_uri(term)
47
- @target ||= {}
48
- @target[term.to_s] ||= TermProxy.new(self, subject, options)
49
- end
50
-
51
- def target_class(conf)
52
- ActiveFedora.class_from_string(conf.class_name, self.class) if conf.class_name
53
- end
54
-
55
- def mark_for_destruction
56
- @marked_for_destruction = true
57
- end
58
-
59
- def marked_for_destruction?
60
- @marked_for_destruction
61
- end
62
-
63
- def new_record= val
64
- @new_record = val
65
- end
66
-
67
- def new_record?
68
- @new_record
69
- end
70
-
71
- # if there are any existing statements with this predicate, replace them
72
- # @param [RDF::URI] subject the subject to insert into the graph
73
- # @param [Symbol, RDF::URI] term the term to insert into the graph
74
- # @param [Array,#to_s] values the value/values to insert into the graph
75
- def set_value(subject, term, values)
76
- options = config_for_term_or_uri(term)
77
- predicate = options.predicate
78
- values = Array(values)
79
-
80
- raise "can't modify frozen #{self.class}" if graph.frozen?
81
- remove_existing_values(subject, predicate, values)
82
-
83
- values.each do |arg|
84
- if arg.respond_to?(:rdf_subject) # an RdfObject
85
- graph.insert([subject, predicate, arg.rdf_subject ])
86
- else
87
- arg = arg.to_s if arg.kind_of? RDF::Literal
88
- graph.insert([subject, predicate, arg])
89
- end
90
- end
91
-
92
- @target ||= {}
93
- proxy = @target[term.to_s]
94
- proxy ||= TermProxy.new(self, subject, options)
95
- proxy.reset!
96
- proxy
97
-
98
- end
99
-
100
- # Be careful with destroy. It will still be in the cache untill you call reset()
101
- def destroy
102
- # delete any statements about this rdf_subject
103
- subject = rdf_subject
104
- query = RDF::Query.new do
105
- pattern [subject, :predicate, :value]
106
- end
107
-
108
- query.execute(graph).each do |solution|
109
- graph.delete [subject, solution.predicate, solution.value]
110
- end
111
-
112
- # delete any statements that reference this rdf_subject
113
- query = RDF::Query.new do
114
- pattern [:subject, :predicate, subject]
115
- end
116
-
117
- query.execute(graph).each do |solution|
118
- graph.delete [solution.subject, solution.predicate, subject]
119
- end
120
- end
121
-
122
- # @option [Hash] values the values to assign to this rdf node.
123
- def attributes=(values)
124
- raise ArgumentError, "values must be a Hash, you provided #{values.class}" unless values.kind_of? Hash
125
- values.with_indifferent_access.each do |key, value|
126
- if self.class.config.keys.include?(key)
127
- set_value(rdf_subject, key, value)
128
- elsif nested_attributes_options.keys.map{ |k| "#{k}_attributes"}.include?(key)
129
- send("#{key}=".to_sym, value)
130
- end
131
- end
132
- end
133
-
134
- def delete_predicate(subject, predicate, values = nil)
135
- predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
136
-
137
- if values.nil?
138
- query = RDF::Query.new do
139
- pattern [subject, predicate, :value]
140
- end
141
-
142
- query.execute(graph).each do |solution|
143
- graph.delete [subject, predicate, solution.value]
144
- end
145
- else
146
- Array(values).each do |v|
147
- graph.delete [subject, predicate, v]
148
- end
149
- end
150
- reset_child_cache!
151
- end
152
-
153
- # append a value
154
- # @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
155
- def append(subject, predicate, args)
156
- options = config_for_term_or_uri(predicate)
157
- graph.insert([subject, predicate, args])
158
- end
159
-
160
- def insert_child(predicate, node)
161
- graph.insert([rdf_subject, predicate, node.rdf_subject])
162
- end
163
-
164
-
165
- # In Rails 4 you can do "delegate :config_for_term_or_uri, :class", but in rails 3 it breaks.
166
- def config_for_term_or_uri(val)
167
- self.class.config_for_term_or_uri(val)
168
- end
169
-
170
- # @param [Symbol, RDF::URI] term predicate the predicate to insert into the graph
171
- def find_predicate(term)
172
- conf = config_for_term_or_uri(term)
173
- conf ? conf.predicate : nil
174
- end
175
-
176
- def query subject, predicate, &block
177
- predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
178
-
179
- q = RDF::Query.new do
180
- pattern [subject, predicate, :value]
181
- end
182
-
183
- q.execute(graph, &block)
184
- end
185
-
186
- private
187
-
188
- def remove_existing_values(subject, predicate, values)
189
- if values.any? { |x| x.respond_to?(:rdf_subject)}
190
- values.each do |arg|
191
- if arg.respond_to?(:rdf_subject) # an RdfObject
192
- # can't just delete_predicate, have to delete the predicate with the class
193
- values_to_delete = find_values_with_class(subject, predicate, arg.class.rdf_type)
194
- delete_predicate(subject, predicate, values_to_delete)
195
- else
196
- delete_predicate(subject, predicate)
197
- end
198
- end
199
- else
200
- delete_predicate(subject, predicate)
201
- end
202
- end
203
-
204
-
205
- def find_values_with_class(subject, predicate, rdf_type)
206
- matching = []
207
- query = RDF::Query.new do
208
- pattern [subject, predicate, :value]
209
- end
210
- query.execute(graph).each do |solution|
211
- if rdf_type
212
- query2 = RDF::Query.new do
213
- pattern [solution.value, RDF.type, rdf_type]
214
- end
215
- query2.execute(graph).each do |sol2|
216
- matching << solution.value
217
- end
218
- else
219
- matching << solution.value
220
- end
221
- end
222
- matching
223
- end
224
-
225
- class Builder
226
- def initialize(parent)
227
- @parent = parent
228
- @parent.create_node_accessor(:type)
229
- end
230
-
231
- def build(&block)
232
- yield self
233
- end
234
-
235
- def method_missing(name, *args, &block)
236
- args = args.first if args.respond_to? :first
237
- raise "mapping for '#{name}' must specify RDF vocabulary as :in argument" unless args.kind_of?(Hash) && args.has_key?(:in)
238
- vocab = args.delete(:in)
239
- field = args.delete(:to) {name}.to_sym
240
- raise "Vocabulary '#{vocab.inspect}' does not define property '#{field.inspect}'" unless vocab.respond_to? field
241
- @parent.config[name] = Rdf::NodeConfig.new(name, vocab.send(field), args).tap do |config|
242
- config.with_index(&block) if block_given?
243
- end
244
-
245
- @parent.create_node_accessor(name)
246
- end
247
-
248
- end
249
-
250
- module ClassMethods
251
-
252
- def create_node_accessor(name)
253
- class_eval <<-eoruby, __FILE__, __LINE__ + 1
254
- def #{name}=(*args)
255
- set_value(rdf_subject, :#{name}, *args)
256
- end
257
- def #{name}
258
- get_values(rdf_subject, :#{name})
259
- end
260
- eoruby
261
- end
262
-
263
- def config
264
- @config ||= if superclass.respond_to? :config
265
- superclass.config.dup
266
- else
267
- {}.with_indifferent_access
268
- end
269
- end
270
-
271
- # List of symbols representing the fields for this terminology.
272
- # ':type' is excluded because it represents RDF.type and is a fixed value
273
- # @see rdf_type
274
- def fields
275
- config.keys.map(&:to_sym) - [:type]
276
- end
277
-
278
- def map_predicates(&block)
279
- builder = Builder.new(self)
280
- builder.build &block
281
- end
282
-
283
- # Provide the value for the RDF.type of this node
284
- # @example
285
- # class Location
286
- # include ActiveFedora::RdfObject
287
- # rdf_type RDF::EbuCore.Location
288
- # end
289
- def rdf_type(uri_or_string=nil)
290
- if uri_or_string
291
- uri = uri_or_string.kind_of?(RDF::URI) ? uri_or_string : RDF::URI.new(uri_or_string)
292
- self.config[:type] = Rdf::NodeConfig.new(:type, RDF.type)
293
- @rdf_type = uri
294
- logger.warn "Duplicate RDF Class. Trying to register #{self} for #{uri} but it is already registered for #{ActiveFedora::RdfNode.rdf_registry[uri]}" if ActiveFedora::RdfNode.rdf_registry.key? uri
295
- ActiveFedora::RdfNode.rdf_registry[uri] = self
296
- end
297
- @rdf_type
298
- end
299
-
300
- def config_for_term_or_uri(term)
301
- case term
302
- when RDF::URI
303
- config.each { |k, v| return v if v.predicate == term}
304
- else
305
- config[term.to_sym]
306
- end
307
- end
308
-
309
- def config_for_predicate(predicate)
310
- config.each do |term, value|
311
- return term, value if value.predicate == predicate
312
- end
313
- return nil
314
- end
315
-
316
- ##
317
- # Register a ruby block that evaluates to the subject of the graph
318
- # By default, the block returns the current object's pid
319
- # @yield [ds] 'ds' is the datastream instance
320
- def rdf_subject &block
321
- if block_given?
322
- return @subject_block = block
323
- end
324
-
325
- # Create a B-node if they don't supply the rdf_subject
326
- @subject_block ||= lambda { |ds| RDF::Node.new }
327
- end
328
-
329
- end
330
- end
331
- end
332
-
@@ -1,141 +0,0 @@
1
- module ActiveFedora
2
- module RdfNode
3
- class TermProxy
4
-
5
- attr_reader :parent, :subject, :options
6
- delegate *(Array.public_instance_methods - [:__send__, :__id__, :class, :object_id] + [:as_json]), :to => :target
7
-
8
-
9
- # @param parent RdfNode
10
- # @param subject RDF::URI
11
- # @param options Hash
12
- def initialize(parent, subject, options)
13
- @parent = parent
14
- @subject = subject
15
- @options = options
16
- end
17
-
18
-
19
- def build(attributes={})
20
- node = mint_node(attributes)
21
- parent.insert_child(options.predicate, node)
22
- reset!
23
- new_node = target.find { |n| n.rdf_subject == node.rdf_subject}
24
- new_node = node unless new_node #if it's a list, the find doesn't work, just use the new node
25
- new_node.new_record = true
26
- new_node
27
- end
28
-
29
- def first_or_create(attributes={})
30
- first || build(attributes)
31
- end
32
-
33
- # Remove all matching nodes from the graph
34
- def clear
35
- parent.query(subject, options.predicate).each do |solution|
36
- # TODO - Recursive delete
37
- # Delete everythign we're pointing at.
38
- parent.graph.delete([solution.value, nil, nil]) if solution.value.uri?
39
- end
40
- # Delete all the assertions about this object
41
- parent.graph.delete([subject, nil, nil])
42
- reset!
43
- end
44
-
45
- def reset!
46
- @target = nil
47
- end
48
-
49
- # @param [Hash] attributes
50
- # @option attributes id the rdf subject to use for the node, if omitted the new node will be a b-node
51
- def mint_node(attributes)
52
- new_subject = attributes.key?('id') ? RDF::URI.new(attributes.delete('id')) : RDF::Node.new
53
- return parent.target_class(options).new(parent.graph, new_subject).tap do |node|
54
- node.attributes = attributes if attributes
55
- end
56
- end
57
-
58
- def <<(*values)
59
- values.each { |value| parent.append(subject, options.predicate, value) }
60
- reset!
61
- values
62
- end
63
-
64
- def delete(*values)
65
- values.each do |value|
66
- parent.delete_predicate(subject, options.predicate, value)
67
- end
68
-
69
- values
70
- end
71
-
72
- def target
73
- @target ||= load_values
74
- end
75
-
76
- # Get the values off of the rdf nodes this proxy targets
77
- def load_values
78
- values = parent.query(subject, options.predicate)
79
- .map {|solution| coerce_to_primitive_type(solution.value)}
80
- .select { |v| correct_rdf_type_for_term?(v)}
81
- .map {|v| coerce_to_rdf_type(v) }
82
-
83
- options.multivalue ? values : values.first
84
- end
85
-
86
- private
87
-
88
- def coerce_to_rdf_type(v)
89
- if options.class_name
90
- class_from_rdf_type(v).new(parent.graph, v)
91
- else
92
- v
93
- end
94
- end
95
-
96
- # If the user provided options[:class_name], we should query to make sure this
97
- # potential solution is of the right RDF.type
98
- def correct_rdf_type_for_term?(v)
99
- !options.class_name || (options.class_name && class_from_rdf_type(v) == ActiveFedora.class_from_string(options.class_name, parent.class))
100
- end
101
-
102
- def coerce_to_primitive_type(v)
103
- v = v.to_s if v.is_a? RDF::Literal
104
- case options.type
105
- when :date
106
- Date.parse(v)
107
- when :integer
108
- v.to_i
109
- else
110
- v
111
- end
112
- end
113
-
114
- def target_class
115
- parent.target_class(options)
116
- end
117
-
118
- # Look for a RDF.type assertion on this node to see if an RDF class is specified.
119
- # Two classes may be valid for the same predicate (e.g. hasMember)
120
- # If no RDF.type assertion is found, fall back to using target_class
121
- def class_from_rdf_type(subject)
122
- unless subject.kind_of?(RDF::Node) || subject.kind_of?(RDF::URI)
123
- raise ArgumentError, "Expected the value of #{options.predicate} to be an RDF object but it is a #{subject.class} #{subject.inspect}"
124
- end
125
- q = RDF::Query.new do
126
- pattern [subject, RDF.type, :value]
127
- end
128
-
129
- type_uri = []
130
- q.execute(parent.graph).each do |sol|
131
- type_uri << sol.value
132
- end
133
-
134
- klass = ActiveFedora::RdfNode.rdf_registry[type_uri.first]
135
- klass ||= target_class
136
- klass
137
- end
138
-
139
- end
140
- end
141
- end