active-fedora 7.0.0.rc2 → 7.0.0.rc3

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 (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