active-fedora 5.2.1 → 5.3.0

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.
data/Gemfile CHANGED
@@ -10,4 +10,4 @@ group :development, :test do
10
10
  end
11
11
 
12
12
  gem 'jruby-openssl', :platform=> :jruby
13
- gem 'nom-xml', :git => 'git://github.com/cbeer/nom-xml.git'
13
+ gem 'nom-xml', '>=0.5.1'
@@ -22,7 +22,7 @@ Gem::Specification.new do |s|
22
22
  s.add_dependency("activesupport", '>= 3.0.0')
23
23
  s.add_dependency("builder", '~> 3.0.0')
24
24
  s.add_dependency("mediashelf-loggable")
25
- s.add_dependency("rubydora", '~>1.0')
25
+ s.add_dependency("rubydora", '~>1.2')
26
26
  s.add_dependency("rdf")
27
27
  s.add_dependency("rdf-rdfxml", '~>0.3.8')
28
28
  s.add_dependency("deprecation")
@@ -304,7 +304,6 @@ module ActiveFedora
304
304
  solrize_profile(solr_doc)
305
305
  end
306
306
  datastreams.each_value do |ds|
307
- ds.ensure_xml_loaded if ds.respond_to? :ensure_xml_loaded ### Can't put this in the model because it's often implemented in Solrizer::XML::TerminologyBasedSolrizer
308
307
  solr_doc = ds.to_solr(solr_doc)
309
308
  end
310
309
  solr_doc = solrize_relationships(solr_doc) unless opts[:model_only]
@@ -5,7 +5,7 @@ module ActiveFedora
5
5
  extend Deprecation
6
6
  attr_writer :digital_object
7
7
  attr_accessor :last_modified, :fields
8
-
8
+
9
9
  def initialize(digital_object=nil, dsid=nil, options={})
10
10
  ## When you use the versions feature of rubydora (0.5.x), you need to have a 3 argument constructor
11
11
  self.fields={}
@@ -59,7 +59,7 @@ module ActiveFedora
59
59
  define_method field do
60
60
  ds = self.send(args[:to])
61
61
  val = if ds.kind_of?(ActiveFedora::RDFDatastream)
62
- ds.send(:get_values, field)
62
+ ds.send(field)
63
63
  else
64
64
  terminology = args[:at] || [field]
65
65
  ds.send(:term_values, *terminology)
@@ -72,7 +72,7 @@ module ActiveFedora
72
72
  define_method "#{field}=".to_sym do |v|
73
73
  ds = self.send(args[:to])
74
74
  if ds.kind_of?(ActiveFedora::RDFDatastream)
75
- ds.send(:set_value, field, v)
75
+ ds.send("#{field}=", v)
76
76
  else
77
77
  terminology = args[:at] || [field]
78
78
  ds.send(:update_indexed_attributes, {terminology => v})
@@ -5,20 +5,24 @@ require "solrizer/xml"
5
5
  #this class represents a xml metadata datastream
6
6
  module ActiveFedora
7
7
  class NokogiriDatastream < Datastream
8
-
9
- before_save do
10
- return unless xml_loaded
11
- content_will_change! if ng_xml_changed?
12
- end
13
8
 
9
+ before_save do
10
+ if content.blank?
11
+ logger.warn "Cowardly refusing to save a datastream with empty content: #{self.inspect}"
12
+ false
13
+ end
14
+ end
15
+
16
+ extend Deprecation
17
+ # include MetadataDatastreamHelper
14
18
  include OM::XML::Document
15
19
  include Solrizer::XML::TerminologyBasedSolrizer # this adds support for calling .to_solr
16
20
 
17
21
  alias_method(:om_term_values, :term_values) unless method_defined?(:om_term_values)
18
22
  alias_method(:om_update_values, :update_values) unless method_defined?(:om_update_values)
19
23
 
20
- attr_accessor :internal_solr_doc, :xml_loaded
21
-
24
+ attr_accessor :internal_solr_doc
25
+
22
26
  def self.default_attributes
23
27
  super.merge(:controlGroup => 'X', :mimeType => 'text/xml')
24
28
  end
@@ -47,16 +51,8 @@ module ActiveFedora
47
51
  Nokogiri::XML::Document.parse("<xml/>")
48
52
  end
49
53
 
50
- def save
51
- @content = to_xml if ng_xml_changed? and content_will_change!
52
- super
53
- end
54
-
55
-
56
54
  def ng_xml
57
55
  @ng_xml ||= begin
58
- self.xml_loaded = true
59
-
60
56
  if new?
61
57
  ## Load up the template
62
58
  self.class.xml_template
@@ -67,26 +63,16 @@ module ActiveFedora
67
63
  end
68
64
 
69
65
  def ng_xml=(new_xml)
70
-
71
- nokogiri_document = case new_xml
66
+ case new_xml
72
67
  when Nokogiri::XML::Document
73
- new_xml
68
+ @ng_xml = new_xml
74
69
  when Nokogiri::XML::Node
75
- Nokogiri::XML(new_xml.to_s) ## Cast a fragment to a document
70
+ @ng_xml = Nokogiri::XML(new_xml.to_s) ## Cast a fragment to a document
76
71
  when String
77
- Nokogiri::XML::Document.parse(new_xml)
72
+ @ng_xml = Nokogiri::XML::Document.parse(new_xml)
78
73
  else
79
74
  raise TypeError, "You passed a #{new_xml.class} into the ng_xml of the #{self.dsid} datastream. NokogiriDatastream.ng_xml= only accepts Nokogiri::XML::Document, Nokogiri::XML::Element, Nokogiri::XML::Node, or raw XML (String) as inputs."
80
75
  end
81
-
82
-
83
- new_xml_string = nokogiri_document.to_xml {|config| config.no_declaration}
84
-
85
- ng_xml_will_change! unless (xml_loaded && (new_xml_string.to_s.strip == (datastream_content || '').strip))
86
- self.xml_loaded=true
87
-
88
- @ng_xml = nokogiri_document
89
-
90
76
  end
91
77
 
92
78
  # don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
@@ -100,27 +86,7 @@ module ActiveFedora
100
86
 
101
87
  # don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
102
88
  def ng_xml_changed?
103
- return true if changed_attributes.has_key?('ng_xml')
104
-
105
- return false unless xml_loaded
106
-
107
- if new?
108
- !to_xml.empty?
109
- else
110
- (to_xml.strip != (datastream_content || '').strip)
111
- end
112
- end
113
-
114
- def changed?
115
- ng_xml_changed? || super
116
- end
117
-
118
- def content_changed?
119
- ng_xml_changed? || super
120
- end
121
-
122
- def has_content?
123
- xml_loaded || super
89
+ changed_attributes.has_key? 'ng_xml'
124
90
  end
125
91
 
126
92
  # Indicates that this datastream has metadata content.
@@ -129,21 +95,23 @@ module ActiveFedora
129
95
  true
130
96
  end
131
97
 
132
- def content=(content)
133
- content_will_change! unless (xml_loaded && (content == datastream_content))
134
- @content = content
135
- self.xml_loaded=true
136
- self.ng_xml = Nokogiri::XML::Document.parse(datastream_content)
98
+ def content
99
+ to_xml
137
100
  end
138
101
 
139
- alias :datastream_content :content
140
-
141
- def content
142
- return to_xml if xml_loaded or new?
143
-
144
- datastream_content
102
+ def datastream_content
103
+ @datastream_content ||= Nokogiri::XML(super).to_xml {|config| config.no_declaration}.strip
145
104
  end
146
105
 
106
+ def content=(content)
107
+ @ng_xml = Nokogiri::XML::Document.parse(content)
108
+ end
109
+
110
+ def content_changed?
111
+ return false if new? and !xml_loaded
112
+ super
113
+ end
114
+
147
115
  def to_xml(xml = nil)
148
116
  xml = self.ng_xml if xml.nil?
149
117
  ng_xml = self.ng_xml
@@ -164,7 +132,7 @@ module ActiveFedora
164
132
  end
165
133
  end
166
134
 
167
- return xml.to_xml {|config| config.no_declaration}
135
+ return xml.to_xml {|config| config.no_declaration}.strip
168
136
  end
169
137
 
170
138
  # ** Experimental **
@@ -427,6 +395,18 @@ module ActiveFedora
427
395
  om_term_values(*term_pointer)
428
396
  end
429
397
  end
398
+
399
+ # Deprecated methods left here for backwards compatibility
400
+ def ensure_xml_loaded; end
401
+ deprecation_deprecate :ensure_xml_loaded
402
+
403
+ def serialize!
404
+ end
405
+
406
+ def xml_loaded
407
+ instance_variable_defined? :@ng_xml
408
+ end
409
+
430
410
  end
431
411
  end
432
412
 
@@ -2,10 +2,12 @@ module ActiveFedora
2
2
  class RDFDatastream < Datastream
3
3
 
4
4
  before_save do
5
- return unless graph_changed?
6
- content_will_change!
7
- end
8
-
5
+ if content.blank?
6
+ logger.warn "Cowardly refusing to save a datastream with empty content: #{self.inspect}"
7
+ false
8
+ end
9
+ end
10
+
9
11
  # this enables a cleaner API for solr integration
10
12
  class IndexObject
11
13
  attr_accessor :data_type, :behaviors
@@ -24,154 +26,173 @@ module ActiveFedora
24
26
  end
25
27
  end
26
28
 
27
- module ModelMethods
28
- extend ActiveSupport::Concern
29
- module ClassMethods
30
- attr_accessor :vocabularies
31
- def config
32
- ActiveFedora::Predicates.predicate_config
33
- end
34
- def prefix(name)
35
- name = name.to_s unless name.is_a? String
36
- pre = self.to_s.sub(/RDFDatastream$/i, '').underscore
37
- return "#{pre}__#{name}".to_sym
38
- end
39
-
40
- ##
41
- # Register a ruby block that evaluates to the subject of the graph
42
- # By default, the block returns the current object's pid
43
- # @yield [ds] 'ds' is the datastream instance
44
- def rdf_subject &block
45
- if block_given?
46
- return @subject_block = block
47
- end
29
+ class << self
30
+ attr_accessor :vocabularies
31
+ def config
32
+ ActiveFedora::Predicates.predicate_config
33
+ end
34
+ def prefix(name)
35
+ name = name.to_s unless name.is_a? String
36
+ pre = self.to_s.sub(/RDFDatastream$/i, '').underscore
37
+ return "#{pre}__#{name}".to_sym
38
+ end
48
39
 
49
- @subject_block ||= lambda { |ds| "info:fedora/#{ds.pid}" }
40
+ ##
41
+ # Register a ruby block that evaluates to the subject of the graph
42
+ # By default, the block returns the current object's pid
43
+ # @yield [ds] 'ds' is the datastream instance
44
+ def rdf_subject &block
45
+ if block_given?
46
+ return @subject_block = block
50
47
  end
51
48
 
52
- def register_vocabularies(*vocabs)
53
- @vocabularies ||= {}
54
- vocabs.each do |v|
55
- if v.is_a?(RDF::Vocabulary) or (v.respond_to? :property and v.respond_to? :to_uri)
56
- @vocabularies[v.to_uri] = v
57
- else
58
- raise "not an RDF vocabulary: #{v}"
59
- end
49
+ @subject_block ||= lambda { |ds| RDF::URI.new("info:fedora/#{ds.pid}") }
50
+ end
51
+
52
+ def register_vocabularies(*vocabs)
53
+ @vocabularies ||= {}
54
+ vocabs.each do |v|
55
+ if v.is_a?(RDF::Vocabulary) or (v.respond_to? :property and v.respond_to? :to_uri)
56
+ @vocabularies[v.to_uri] = v
57
+ else
58
+ raise "not an RDF vocabulary: #{v}"
60
59
  end
61
- ActiveFedora::Predicates.vocabularies(@vocabularies)
62
- @vocabularies
63
60
  end
61
+ ActiveFedora::Predicates.vocabularies(@vocabularies)
62
+ @vocabularies
63
+ end
64
64
 
65
- def map_predicates(&block)
66
- yield self
65
+ def map_predicates(&block)
66
+ yield self
67
+ end
68
+ def method_missing(name, *args, &block)
69
+ args = args.first if args.respond_to? :first
70
+ raise "mapping must specify RDF vocabulary as :in argument" unless args.has_key? :in
71
+ vocab = args[:in]
72
+ predicate = args.fetch(:to, name)
73
+ raise "Vocabulary '#{vocab.inspect}' does not define property '#{predicate.inspect}'" unless vocab.respond_to? predicate
74
+ indexing = false
75
+ if block_given?
76
+ # needed for solrizer integration
77
+ indexing = true
78
+ iobj = IndexObject.new
79
+ yield iobj
80
+ data_type = iobj.data_type
81
+ behaviors = iobj.behaviors
67
82
  end
68
- def method_missing(name, *args, &block)
69
- args = args.first if args.respond_to? :first
70
- raise "mapping must specify RDF vocabulary as :in argument" unless args.has_key? :in
71
- vocab = args[:in]
72
- predicate = args.fetch(:to, name)
73
- raise "Vocabulary '#{vocab.inspect}' does not define property '#{predicate.inspect}'" unless vocab.respond_to? predicate
74
- indexing = false
75
- if block_given?
76
- # needed for solrizer integration
77
- indexing = true
78
- iobj = IndexObject.new
79
- yield iobj
80
- data_type = iobj.data_type
81
- behaviors = iobj.behaviors
82
- end
83
- # needed for AF::Predicates integration & drives all other
84
- # functionality below
85
- vocab = vocab.to_s
86
- name = self.prefix(name)
87
- if config
88
- if config[:predicate_mapping].has_key? vocab
89
- config[:predicate_mapping][vocab][name] = predicate
90
- else
91
- config[:predicate_mapping][vocab] = { name => predicate }
92
- end
93
- # stuff data_type and behaviors in there for to_solr support
94
- config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
95
- config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
83
+ # needed for AF::Predicates integration & drives all other
84
+ # functionality below
85
+ vocab = vocab.to_s
86
+ name = self.prefix(name)
87
+ if config
88
+ if config[:predicate_mapping].has_key? vocab
89
+ config[:predicate_mapping][vocab][name] = predicate
96
90
  else
97
- config = {
98
- :default_namespace => vocab,
99
- :predicate_mapping => {
100
- vocab => { name => predicate }
101
- }
102
- }
103
- # stuff data_type and behaviors in there for to_solr support
104
- config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
105
- config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
91
+ config[:predicate_mapping][vocab] = { name => predicate }
106
92
  end
93
+ # stuff data_type and behaviors in there for to_solr support
94
+ config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
95
+ config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
96
+ else
97
+ config = {
98
+ :default_namespace => vocab,
99
+ :predicate_mapping => {
100
+ vocab => { name => predicate }
101
+ }
102
+ }
103
+ # stuff data_type and behaviors in there for to_solr support
104
+ config[:predicate_mapping][vocab]["#{name}__type".to_sym] = data_type if indexing
105
+ config[:predicate_mapping][vocab]["#{name}__behaviors".to_sym] = behaviors if indexing
107
106
  end
108
107
  end
109
108
  end
109
+
110
+
110
111
  class TermProxy
111
- # @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
112
- # @param [ActiveFedora::RelationshipGraph] graph the graph
113
- # @param [Array] values an array of object values
114
- instance_methods.each { |m| undef_method m unless m.to_s =~ /^(?:nil\?|send|object_id|to_a)$|^__|^respond_to|proxy_/ }
115
-
116
- def initialize(graph, predicate, values=[])
112
+
113
+ attr_reader :graph, :subject, :predicate
114
+ delegate :class, :to_s, :==, :kind_of?, :each, :map, :empty?, :to => :values
115
+
116
+ def initialize(graph, subject, predicate)
117
117
  @graph = graph
118
+
119
+ @subject = subject
118
120
  @predicate = predicate
119
- @values = values
120
121
  end
122
+
121
123
  def <<(*values)
122
- @values.concat(values)
123
- values.each { |value| @graph.add(@predicate, value, true) }
124
- @graph.dirty = true
125
- @values
124
+ values.each { |value| graph.append(subject, predicate, value) }
125
+ values
126
126
  end
127
+
127
128
  def delete(*values)
128
129
  values.each do |value|
129
- unless @values.delete(value).nil?
130
- @graph.delete(@predicate, value)
131
- @graph.dirty = true
132
- end
130
+ graph.delete_predicate(subject, predicate, value)
133
131
  end
134
- @values
132
+
133
+ values
135
134
  end
136
- def method_missing(method, *args)
137
- unless @values.respond_to?(method)
138
- message = "undefined method `#{method.to_s}' for \"#{@values}\":#{@values.class.to_s}"
139
- raise NoMethodError, message
135
+
136
+ def values
137
+ values = []
138
+
139
+ graph.query(subject, predicate).each do |solution|
140
+ v = solution.value
141
+ v = v.to_s if v.is_a? RDF::Literal
142
+ values << v
140
143
  end
141
144
 
142
- if block_given?
143
- @values.send(method, *args) { |*block_args| yield(*block_args) }
145
+ values
146
+ end
147
+
148
+ def method_missing(method, *args, &block)
149
+
150
+ if values.respond_to? method
151
+ values.send(method, *args, &block)
144
152
  else
145
- @values.send(method, *args)
153
+ super
146
154
  end
147
-
148
155
  end
149
156
  end
150
157
 
151
- include ModelMethods
152
158
  attr_accessor :loaded
153
-
154
159
  def metadata?
155
160
  true
156
161
  end
162
+ def ensure_loaded
163
+ end
157
164
 
158
- def save
159
- @content = serialize if graph_changed? and content_will_change!
160
-
161
- super
165
+ def content
166
+ serialize
162
167
  end
163
168
 
164
169
  def content=(content)
165
- content_will_change!
166
170
  self.loaded = true
167
171
  @graph = deserialize(content)
168
172
  end
169
173
 
174
+ def content_changed?
175
+ return false if new? and !loaded
176
+ super
177
+ end
178
+
179
+ def changed?
180
+ super || content_changed?
181
+ end
182
+
170
183
  # returns a Hash, e.g.: {field => {:values => [], :type => :something, :behaviors => []}, ...}
171
184
  def fields
172
-
173
185
  field_map = {}
174
- graph.relationships.each do |predicate, values|
186
+
187
+ rdf_subject = self.rdf_subject
188
+ query = RDF::Query.new do
189
+ pattern [rdf_subject, :predicate, :value]
190
+ end
191
+
192
+ query.execute(graph).each do |solution|
193
+ predicate = solution.predicate
194
+ value = solution.value
195
+
175
196
  vocab_sym, name = predicate.qname
176
197
  uri, vocab = self.class.vocabularies.select { |ns, v| v.__prefix__ == vocab_sym }.first
177
198
  next unless vocab
@@ -182,13 +203,13 @@ module ActiveFedora
182
203
  next unless name and config.has_key?("#{name}__type".to_sym) and config.has_key?("#{name}__behaviors".to_sym)
183
204
  type = config["#{name}__type".to_sym]
184
205
  behaviors = config["#{name}__behaviors".to_sym]
185
- field_map[name.to_sym] = {:values => values.map {|v| v.to_s}, :type => type, :behaviors => behaviors}
206
+ field_map[name.to_sym] ||= {:values => [], :type => type, :behaviors => behaviors}
207
+ field_map[name.to_sym][:values] << value.to_s
186
208
  end
187
209
  field_map
188
210
  end
189
211
 
190
212
  def to_solr(solr_doc = Hash.new) # :nodoc:
191
-
192
213
  fields.each do |field_key, field_info|
193
214
  values = field_info.fetch(:values, false)
194
215
  if values
@@ -215,100 +236,90 @@ module ActiveFedora
215
236
  # Assumes that the datastream contains RDF content
216
237
  # @param [String] data the "rdf" node
217
238
  def deserialize(data = nil)
218
- graph = RelationshipGraph.new
219
- return graph if new? and data.nil?
239
+ repository = RDF::Repository.new
240
+ return repository if new? and data.nil?
220
241
 
221
242
  data ||= datastream_content
222
243
 
223
- RDF::Reader.for(serialization_format).new(data) do |reader|
224
- reader.each_statement do |statement|
225
- begin
226
- next unless statement.subject == rdf_subject
227
- rescue
228
- end
229
- literal = statement.object.kind_of?(RDF::Literal)
230
- object = literal ? statement.object.value : statement.object.to_s
231
- graph.add(statement.predicate, object, literal)
232
- end
244
+ RDF::Reader.for(serialization_format).new(data) do |reader|
245
+ reader.each_statement do |statement|
246
+ repository << statement
233
247
  end
248
+ end
234
249
 
235
- graph
250
+ repository
236
251
  end
237
252
 
238
253
  def graph
239
254
  @graph ||= begin
240
255
  self.loaded = true
241
256
  deserialize
242
- end
243
- end
244
-
245
- # alias the original datastream content
246
- alias :datastream_content :content
247
-
248
- def content
249
- # return the RDF graph content if it's available (or all we have)
250
- return serialize if loaded or new?
251
-
252
- # otherwise, grab the data from the datastore
253
- super
257
+ end
254
258
  end
255
-
256
- def graph_will_change!
257
- changed_attributes['graph'] = nil
258
- end
259
-
260
- def graph_changed?
261
- return true if changed_attributes.has_key?('graph')
262
- return false unless loaded
263
259
 
264
- if new?
265
- !serialize.empty?
266
- else
267
- serialize.strip != (datastream_content || '').strip
260
+ def query subject, predicate, &block
261
+ predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
262
+
263
+ q = RDF::Query.new do
264
+ pattern [subject, predicate, :value]
268
265
  end
269
266
 
270
- end
271
-
272
- def changed?
273
- graph_changed? || super
267
+ q.execute(graph, &block)
274
268
  end
275
269
 
276
270
  # @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
277
- def get_values(predicate)
278
-
271
+ def get_values(subject, predicate)
272
+
279
273
  predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
280
- results = graph[predicate]
281
- return if results.nil?
282
- values = []
283
- results.each do |object|
284
- values << (object.kind_of?(RDF::Literal) ? object.value : object.to_s)
285
- end
286
- TermProxy.new(graph, predicate, values)
274
+
275
+ return TermProxy.new(self, subject, predicate)
287
276
  end
288
277
 
289
278
  # if there are any existing statements with this predicate, replace them
290
279
  # @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
291
- def set_value(predicate, args)
280
+
281
+ def set_value(subject, predicate, values)
292
282
 
293
283
  predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
294
- graph.delete(predicate)
295
- args = [args] unless args.respond_to? :each
296
- args.each do |arg|
284
+
285
+ delete_predicate(subject, predicate)
286
+
287
+ Array(values).each do |arg|
297
288
  arg = arg.to_s if arg.kind_of? RDF::Literal
298
- graph.add(predicate, arg, true) unless arg.empty?
289
+ next if arg.empty?
290
+
291
+ graph.insert([subject, predicate, arg])
299
292
  end
300
- graph.dirty = true
301
- return TermProxy.new(graph, predicate, args)
293
+
294
+ return TermProxy.new(self, subject, predicate)
295
+ end
296
+
297
+ def delete_predicate(subject, predicate, values = nil)
298
+ predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
299
+
300
+ if values.nil?
301
+ query = RDF::Query.new do
302
+ pattern [subject, predicate, :value]
303
+ end
304
+
305
+ query.execute(graph).each do |solution|
306
+ graph.delete [subject, predicate, solution.value]
307
+ end
308
+ else
309
+ Array(values).each do |v|
310
+ graph.delete [subject, predicate, v]
311
+ end
312
+ end
313
+
302
314
  end
303
315
 
304
316
  # append a value
305
317
  # @param [Symbol, RDF::URI] predicate the predicate to insert into the graph
306
- def append(predicate, args)
307
-
308
- predicate = find_predicate(predicate) unless predicate.kind_of? RDF::URI
309
- graph.add(predicate, args, true)
310
- graph.dirty = true
311
- return TermProxy.new(graph, predicate, args)
318
+ def append(subject, predicate, args)
319
+ graph.insert([subject, predicate, args])
320
+
321
+
322
+ return TermProxy.new(self, subject, predicate)
312
323
  end
313
324
 
314
325
  def serialization_format
@@ -317,29 +328,54 @@ module ActiveFedora
317
328
 
318
329
  def method_missing(name, *args)
319
330
  if (md = /^([^=]+)=$/.match(name.to_s)) && pred = find_predicate(md[1])
320
- set_value(pred, *args)
331
+ set_value(rdf_subject, pred, *args)
321
332
  elsif pred = find_predicate(name)
322
- get_values(name)
333
+ get_values(rdf_subject, name)
323
334
  else
324
335
  super
325
336
  end
337
+ rescue ActiveFedora::UnregisteredPredicateError
338
+ super
326
339
  end
327
340
 
328
341
  ##
329
342
  # Get the subject for this rdf/xml datastream
330
343
  def rdf_subject
331
- @subject ||= self.class.rdf_subject.call(self)
344
+ @subject ||= begin
345
+ s = self.class.rdf_subject.call(self)
346
+ s &&= RDF::URI.new(s) if s.is_a? String
347
+ s
348
+ end
332
349
  end
333
350
 
351
+ def reset_rdf_subject!
352
+ @subject = nil
353
+ end
354
+
334
355
  # Creates a RDF datastream for insertion into a Fedora Object
335
356
  # Note: This method is implemented on SemanticNode instead of RelsExtDatastream because SemanticNode contains the relationships array
336
357
  def serialize
337
- out = RDF::Writer.for(serialization_format).buffer do |writer|
338
- graph.to_graph(rdf_subject).each_statement do |statement|
339
- writer << statement
340
- end
358
+ update_subjects_to_use_a_real_pid!
359
+ RDF::Writer.for(serialization_format).dump(graph)
360
+ end
361
+
362
+ def update_subjects_to_use_a_real_pid!
363
+ return unless new?
364
+
365
+ bad_subject = rdf_subject
366
+ reset_rdf_subject!
367
+ new_subject = rdf_subject
368
+
369
+ new_repository = RDF::Repository.new
370
+
371
+ graph.each_statement do |statement|
372
+ subject = statement.subject
373
+
374
+ subject &&= new_subject if subject == bad_subject
375
+ new_repository << [subject, statement.predicate, statement.object]
341
376
  end
342
- out
377
+
378
+ @graph = new_repository
343
379
  end
344
380
  end
345
381
  end
@@ -1,3 +1,3 @@
1
1
  module ActiveFedora
2
- VERSION = "5.2.1"
2
+ VERSION = "5.3.0"
3
3
  end
@@ -48,11 +48,11 @@ describe ActiveFedora::Datastream do
48
48
  ds.content = fixture('dino.jpg')
49
49
  @test_object.add_datastream(ds).should be_true
50
50
  @test_object.save
51
+ @test_object.datastreams[dsid].should_not be_changed
51
52
  to = ActiveFedora::Base.find(@test_object.pid)
52
53
  to.should_not be_nil
53
54
  to.datastreams[dsid].should_not be_nil
54
55
  to.datastreams[dsid].content.should == fixture('dino.jpg').read
55
-
56
56
  end
57
57
 
58
58
  it "should be able to set the versionable attribute" do
@@ -26,20 +26,13 @@ describe ActiveFedora::NtriplesRDFDatastream do
26
26
  Object.send(:remove_const, :MyDatastream)
27
27
  end
28
28
 
29
- it "should set and recall" do
30
- @subject.title = "John Doe"
29
+ it "should not try to send an empty datastream" do
31
30
  @subject.save
32
- f = RdfTest.find(@subject.pid)
33
- f.title.should == "John Doe"
34
- f.title = "Jane Doe"
35
- f.save
36
- new_object = RdfTest.find(@subject.pid)
37
- new_object.title.should == "Jane Doe"
38
-
39
31
  end
40
32
 
41
33
  it "should set and recall values" do
42
34
  @subject.title = 'War and Peace'
35
+ @subject.rdf.should be_changed
43
36
  @subject.based_near = "Moscow, Russia"
44
37
  @subject.related_url = "http://en.wikipedia.org/wiki/War_and_Peace"
45
38
  @subject.part = "this is a part"
@@ -55,6 +48,7 @@ describe ActiveFedora::NtriplesRDFDatastream do
55
48
  @subject.related_url = "http://en.wikipedia.org/wiki/War_and_Peace"
56
49
  @subject.part = "this is a part"
57
50
  @subject.save
51
+
58
52
  loaded = RdfTest.find(@subject.pid)
59
53
  loaded.title.should == 'War and Peace'
60
54
  loaded.based_near.should == ['Moscow, Russia']
@@ -82,6 +76,13 @@ describe ActiveFedora::NtriplesRDFDatastream do
82
76
  @subject.save
83
77
  @subject.title.should be_nil
84
78
  end
79
+
80
+ it "should be able to save a blank document" do
81
+ @subject.title = ""
82
+ @subject.save
83
+ end
84
+
85
+
85
86
  it "should delete values" do
86
87
  @subject.title = "Hamlet"
87
88
  @subject.related_url = "http://psu.edu/"
@@ -22,7 +22,6 @@ describe ActiveFedora::OmDatastream do
22
22
 
23
23
  describe "#changed?" do
24
24
  it "should not be changed if the new xml matches the old xml" do
25
-
26
25
  @pid = "hydrangea:fixture_mods_article2"
27
26
  @test_object = HydrangeaArticle2.find(@pid)
28
27
 
@@ -30,6 +29,27 @@ describe ActiveFedora::OmDatastream do
30
29
 
31
30
  @test_object.descMetadata.should_not be_changed
32
31
  end
32
+
33
+
34
+ it "should not be changed if there are minor differences in whitespace" do
35
+
36
+ obj = HydrangeaArticle2.new
37
+ obj.descMetadata.content = "<a>1</a>"
38
+ obj.save
39
+ obj.descMetadata.should_not be_changed
40
+ obj.descMetadata.content = "<a>1</a>\n"
41
+ obj.descMetadata.should_not be_changed
42
+
43
+ end
44
+ end
45
+
46
+ describe "empty datastream content" do
47
+ it "should not break when there is empty datastream content" do
48
+ obj = HydrangeaArticle2.new
49
+ obj.descMetadata.content = ""
50
+ obj.save
51
+
52
+ end
33
53
  end
34
54
 
35
55
  describe '.term_values' do
@@ -81,6 +81,12 @@ describe ActiveFedora::DatastreamCollections do
81
81
  @test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg",:file=>@f})
82
82
  end
83
83
 
84
+ it "should allow access to file content" do
85
+ @test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg",:file=>@f})
86
+ @test_object2.save!
87
+ @test_object2.thumbnail[0].content
88
+ end
89
+
84
90
  it "should raise an error if neither a blob nor file is set" do
85
91
  expect { @test_object2.add_named_datastream("thumbnail",{:content_type=>"image/jpeg"}) }.to raise_error
86
92
  end
@@ -61,30 +61,6 @@ describe ActiveFedora::Datastream do
61
61
  end
62
62
  end
63
63
 
64
- describe '#save' do
65
- it "should set changed" do
66
- mock_repo = mock('repository')
67
- mock_repo.stub(:config).and_return({})
68
- mock_repo.stub(:add_datastream).with(:versionable => true, :pid => @test_object.pid, :dsid => 'abcd', :controlGroup => 'M', :dsState => 'A', :content => 'hi there')
69
- mock_repo.stub(:datastream).with(:dsid => 'abcd', :pid => @test_object.pid).and_return('')
70
- @test_object.inner_object.stub(:repository).and_return(mock_repo)
71
- @test_datastream.save
72
- @test_datastream.should_not be_changed
73
- end
74
- end
75
-
76
- describe '.content=' do
77
- it "should update the content and ng_xml, marking the datastream as changed" do
78
- sample_xml = "<foo><xmlelement/></foo>"
79
- @test_datastream.instance_variable_get(:@changed_attributes).clear
80
- @test_datastream.should_not be_changed
81
- @test_datastream.content.should_not be_equivalent_to(sample_xml)
82
- @test_datastream.content = sample_xml
83
- @test_datastream.should be_changed
84
- @test_datastream.content.should be_equivalent_to(sample_xml)
85
- end
86
- end
87
-
88
64
  it "should have mimeType accessors" do
89
65
  ds1 = ActiveFedora::Datastream.new
90
66
  ds1.mimeType = "text/foo"
@@ -53,7 +53,7 @@ describe ActiveFedora::NtriplesRDFDatastream do
53
53
  @subject.created.should be_kind_of Array
54
54
  end
55
55
  it "should have method missing" do
56
- lambda{@subject.frank}.should raise_exception ActiveFedora::UnregisteredPredicateError
56
+ lambda{@subject.frank}.should raise_exception NoMethodError
57
57
  end
58
58
 
59
59
  it "should set fields" do
@@ -69,7 +69,7 @@ describe ActiveFedora::NtriplesRDFDatastream do
69
69
  @subject.publisher.should == ["Penn State", "St. Martin's Press"]
70
70
  end
71
71
  it "should delete fields" do
72
- @subject.related_url.delete("http://google.com/")
72
+ @subject.related_url.delete(RDF::URI("http://google.com/"))
73
73
  @subject.related_url.should == []
74
74
  end
75
75
  end
@@ -166,10 +166,10 @@ describe ActiveFedora::NtriplesRDFDatastream do
166
166
  map.rights(:in => RDF::DC)
167
167
  end
168
168
  end
169
- end
170
- before(:each) do
171
169
  @subject = MyDatastream.new(@inner_object, 'solr_rdf')
172
170
  @subject.content = File.new('spec/fixtures/solr_rdf_descMetadata.nt').read
171
+ end
172
+ before(:each) do
173
173
  @subject.stub(:pid => 'test:1')
174
174
  @subject.stub(:new? => false)
175
175
  @sample_fields = {:my_datastream__publisher => {:values => ["publisher1"], :type => :string, :behaviors => [:facetable, :sortable, :searchable, :displayable]},
@@ -272,15 +272,6 @@ describe ActiveFedora::NtriplesRDFDatastream do
272
272
  @obj.save
273
273
  end
274
274
 
275
- describe '.content=' do
276
- it "should update the content and graph, marking the datastream as changed" do
277
- sample_rdf = File.new('spec/fixtures/mixed_rdf_descMetadata.nt').read
278
- @obj.stub(:new? => false)
279
- @obj.should_not be_changed
280
- @obj.content = sample_rdf
281
- @obj.should be_changed
282
- end
283
- end
284
275
  it "should save content properly upon save" do
285
276
  foo = Foo.new(:pid => 'test:1')
286
277
  foo.title = 'Hamlet'
@@ -22,6 +22,7 @@ describe ActiveFedora::OmDatastream do
22
22
  @test_ds = ActiveFedora::OmDatastream.new(@mock_inner, "descMetadata")
23
23
  @test_ds.stub(:new? => false, :profile => {}, :datastream_content => '<test_xml/>')
24
24
  @test_ds.content="<test_xml/>"
25
+ @test_ds.stub(:new? => false)
25
26
  end
26
27
 
27
28
  after(:each) do
@@ -46,6 +47,7 @@ describe ActiveFedora::OmDatastream do
46
47
  it "should initialize from #xml_template if no xml is provided" do
47
48
  ActiveFedora::OmDatastream.should_receive(:xml_template).and_return("<fake template/>")
48
49
  n = ActiveFedora::OmDatastream.new
50
+ n.ensure_xml_loaded
49
51
  n.ng_xml.should be_equivalent_to("<fake template/>")
50
52
  end
51
53
  end
@@ -158,15 +160,6 @@ describe ActiveFedora::OmDatastream do
158
160
  @mods_ds.get_values("--my xpath--").should == ["abstract1", "abstract2"]
159
161
  end
160
162
  end
161
-
162
- describe '#from_xml' do
163
- it "should work when a template datastream is passed in" do
164
- mods_xml = Nokogiri::XML::Document.parse( fixture(File.join("mods_articles", "hydrangea_article1.xml")) )
165
- tmpl = Hydra::ModsArticleDatastream.new
166
- Hydra::ModsArticleDatastream.from_xml(mods_xml,tmpl).ng_xml.root.to_xml.should == mods_xml.root.to_xml
167
- end
168
- end
169
-
170
163
 
171
164
  it 'should provide .fields' do
172
165
  @test_ds.should respond_to(:fields)
@@ -177,6 +170,7 @@ describe ActiveFedora::OmDatastream do
177
170
  @test_ds.should respond_to(:save)
178
171
  end
179
172
  it "should persist the product of .to_xml in fedora" do
173
+ @mock_repo.stub(:datastream).and_return('')
180
174
  @test_ds.stub(:new? => true)
181
175
  @test_ds.stub(:to_xml => "fake xml")
182
176
  @mock_repo.should_receive(:add_datastream).with(:pid => nil, :dsid => 'descMetadata', :versionable => true, :content => 'fake xml', :controlGroup => 'X', :dsState => 'A', :mimeType=>'text/xml')
@@ -192,11 +186,11 @@ describe ActiveFedora::OmDatastream do
192
186
  it "should update the content" do
193
187
  subject.stub(:new? => false )
194
188
  subject.content = "<a />"
195
- subject.datastream_content.should == '<a />'
189
+ subject.content.should == '<a/>'
196
190
  end
197
191
 
198
192
  it "should mark the object as changed" do
199
- subject.stub(:new? => false )
193
+ subject.stub(:new? => false, :controlGroup => 'M')
200
194
  subject.content = "<a />"
201
195
  subject.should be_changed
202
196
  end
@@ -211,6 +205,7 @@ describe ActiveFedora::OmDatastream do
211
205
 
212
206
  describe 'ng_xml=' do
213
207
  before do
208
+ @mock_inner.stub(:new? => true)
214
209
  @test_ds2 = ActiveFedora::OmDatastream.new(@mock_inner, "descMetadata")
215
210
  end
216
211
  it "should parse raw xml for you" do
@@ -225,9 +220,9 @@ describe ActiveFedora::OmDatastream do
225
220
  @test_ds2.ng_xml.to_xml.should be_equivalent_to("<xmlelement/>")
226
221
  end
227
222
  it "should mark the datastream as changed" do
223
+ @test_ds2.stub(:new? => false, :controlGroup => 'M')
228
224
  @test_ds2.should_not be_changed
229
225
  @test_ds2.ng_xml = @sample_raw_xml
230
- @test_ds2.ng_xml_changed?.should be_true
231
226
  @test_ds2.should be_changed
232
227
  @test_ds2.instance_variable_get(:@content).should be_nil
233
228
  end
@@ -240,7 +235,7 @@ describe ActiveFedora::OmDatastream do
240
235
 
241
236
  it "should ng_xml.to_xml" do
242
237
  @test_ds.stub(:ng_xml => Nokogiri::XML::Document.parse("<text_document/>"))
243
- @test_ds.to_xml.should == "<text_document/>\n"
238
+ @test_ds.to_xml.should == "<text_document/>"
244
239
  end
245
240
 
246
241
  it 'should accept an optional Nokogiri::XML Document as an argument and insert its fields into that (mocked test)' do
@@ -53,16 +53,6 @@ describe ActiveFedora::QualifiedDublinCoreDatastream do
53
53
 
54
54
  end
55
55
 
56
- it "should parse dcterms and dcelements from xml" do
57
- doc = Nokogiri::XML::Document.parse(File.open( File.dirname(__FILE__)+'/../fixtures/changeme155.xml') )
58
- stream = doc.xpath('//foxml:datastream[@ID=\'dublin_core\']/foxml:datastreamVersion/foxml:xmlContent/dc')
59
- ds = ActiveFedora::QualifiedDublinCoreDatastream.new
60
- n = ActiveFedora::QualifiedDublinCoreDatastream.from_xml(stream.to_xml, ds)
61
- n.spatial.should == ["Boston [7013445]", "Dorchester [7013575]", "Roxbury [7015002]"]
62
- n.title.should == ["Oral history with Frances Addelson, 1997 November 14"]
63
- end
64
-
65
-
66
56
  it "should default dc elements to :multiple=>true" do
67
57
  @test_ds.fields.values.each do |s|
68
58
  s.has_key?(:multiple).should == true
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: active-fedora
3
3
  version: !ruby/object:Gem::Version
4
- version: 5.2.1
4
+ version: 5.3.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -11,7 +11,7 @@ authors:
11
11
  autorequire:
12
12
  bindir: bin
13
13
  cert_chain: []
14
- date: 2012-12-12 00:00:00.000000000 Z
14
+ date: 2012-12-20 00:00:00.000000000 Z
15
15
  dependencies:
16
16
  - !ruby/object:Gem::Dependency
17
17
  name: rsolr
@@ -132,7 +132,7 @@ dependencies:
132
132
  requirements:
133
133
  - - ~>
134
134
  - !ruby/object:Gem::Version
135
- version: '1.0'
135
+ version: '1.2'
136
136
  type: :runtime
137
137
  prerelease: false
138
138
  version_requirements: !ruby/object:Gem::Requirement
@@ -140,7 +140,7 @@ dependencies:
140
140
  requirements:
141
141
  - - ~>
142
142
  - !ruby/object:Gem::Version
143
- version: '1.0'
143
+ version: '1.2'
144
144
  - !ruby/object:Gem::Dependency
145
145
  name: rdf
146
146
  requirement: !ruby/object:Gem::Requirement
@@ -547,7 +547,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
547
547
  version: '0'
548
548
  segments:
549
549
  - 0
550
- hash: -1381095155313457398
550
+ hash: 1953384027412583445
551
551
  requirements: []
552
552
  rubyforge_project: rubyfedora
553
553
  rubygems_version: 1.8.23