active-fedora 5.0.0 → 5.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/History.txt +14 -1
  2. data/README.textile +6 -0
  3. data/active-fedora.gemspec +1 -1
  4. data/lib/active_fedora.rb +2 -0
  5. data/lib/active_fedora/associations.rb +22 -2
  6. data/lib/active_fedora/associations/association_collection.rb +37 -0
  7. data/lib/active_fedora/associations/belongs_to_association.rb +8 -0
  8. data/lib/active_fedora/associations/has_many_association.rb +2 -0
  9. data/lib/active_fedora/base.rb +43 -6
  10. data/lib/active_fedora/datastream.rb +13 -37
  11. data/lib/active_fedora/datastreams.rb +2 -6
  12. data/lib/active_fedora/digital_object.rb +8 -1
  13. data/lib/active_fedora/metadata_datastream_helper.rb +2 -2
  14. data/lib/active_fedora/nokogiri_datastream.rb +55 -16
  15. data/lib/active_fedora/persistence.rb +14 -9
  16. data/lib/active_fedora/railtie.rb +15 -0
  17. data/lib/active_fedora/rdf_datastream.rb +4 -0
  18. data/lib/active_fedora/rdfxml_rdf_datastream.rb +2 -6
  19. data/lib/active_fedora/reflection.rb +11 -0
  20. data/lib/active_fedora/relationships.rb +4 -4
  21. data/lib/active_fedora/rels_ext_datastream.rb +21 -6
  22. data/lib/active_fedora/semantic_node.rb +3 -3
  23. data/lib/active_fedora/test_support.rb +38 -0
  24. data/lib/active_fedora/version.rb +1 -1
  25. data/lib/generators/active_fedora/config/USAGE +9 -0
  26. data/lib/generators/active_fedora/config/config_generator.rb +10 -0
  27. data/lib/generators/active_fedora/config/fedora/fedora_generator.rb +12 -0
  28. data/lib/generators/active_fedora/config/fedora/templates/fedora.yml +14 -0
  29. data/lib/generators/active_fedora/config/fedora/templates/fedora_conf/conf/development/fedora.fcfg +953 -0
  30. data/lib/generators/active_fedora/config/fedora/templates/fedora_conf/conf/test/fedora.fcfg +953 -0
  31. data/lib/generators/active_fedora/config/solr/solr_generator.rb +12 -0
  32. data/lib/generators/active_fedora/config/solr/templates/solr.yml +10 -0
  33. data/lib/generators/active_fedora/config/solr/templates/solr_conf/conf/schema.xml +692 -0
  34. data/lib/generators/active_fedora/config/solr/templates/solr_conf/conf/solrconfig.xml +299 -0
  35. data/lib/generators/active_fedora/config/solr/templates/solr_conf/solr.xml +35 -0
  36. data/lib/generators/active_fedora/model/USAGE +9 -0
  37. data/lib/generators/active_fedora/model/model_generator.rb +21 -0
  38. data/lib/generators/active_fedora/model/templates/model.rb.erb +6 -0
  39. data/lib/generators/active_fedora/model/templates/model_spec.rb.erb +21 -0
  40. data/lib/tasks/active_fedora_dev.rake +8 -0
  41. data/spec/fixtures/hydrangea_fixture_mods_article2.foxml.xml +234 -0
  42. data/spec/integration/associations_spec.rb +76 -15
  43. data/spec/integration/base_spec.rb +38 -10
  44. data/spec/integration/datastreams_spec.rb +24 -2
  45. data/spec/integration/nokogiri_datastream_spec.rb +23 -5
  46. data/spec/unit/base_extra_spec.rb +0 -1
  47. data/spec/unit/base_spec.rb +7 -47
  48. data/spec/unit/datastream_collections_spec.rb +0 -7
  49. data/spec/unit/datastream_spec.rb +7 -16
  50. data/spec/unit/datastreams_spec.rb +2 -2
  51. data/spec/unit/nokogiri_datastream_spec.rb +31 -20
  52. data/spec/unit/ntriples_datastream_spec.rb +7 -10
  53. data/spec/unit/persistence_spec.rb +0 -11
  54. data/spec/unit/qualified_dublin_core_datastream_spec.rb +1 -2
  55. data/spec/unit/relationships_spec.rb +5 -5
  56. data/spec/unit/rels_ext_datastream_spec.rb +14 -9
  57. data/spec/unit/semantic_node_spec.rb +4 -4
  58. metadata +25 -6
@@ -1,7 +1,20 @@
1
1
  5.0.0
2
2
  Depend on solrizer 2.0.0 (for HYDRA-827 DO NOT index terms by default)
3
3
  Lazily initialize solr, so that the message goes into the log, not the console
4
-
4
+ Depend on om 1.8.0
5
+ Require Ruby >= 1.9.3
6
+ Support for ISO 8601 date formats
7
+ New before_delete callback available on ActiveFedora objects
8
+ HYDRA-883: RDFDatastreams should handle Literals as object values
9
+ Zero argument constructors for datastreams
10
+ Deprecated in this version:
11
+ * FileManagment
12
+ * named relationships
13
+ Removed in this version:
14
+ * ruby-fedora
15
+ * MetadataDatastream
16
+ * methods: .field, .add, .to_xml, .file_streams, .new_object=
17
+ # rcov dependency
5
18
 
6
19
  4.5.1
7
20
  Removes .rvmrc and Gemfile.lock from version control (devs should deal with these themselves)
@@ -17,6 +17,12 @@ h2. Getting Started
17
17
 
18
18
  The "ActiveFedora Console Tour":https://github.com/projecthydra/active_fedora/wiki/Getting-Started:-Console-Tour gives you a brief tour through ActiveFedora's features on the command line.
19
19
 
20
+ h2. Generators
21
+
22
+ You can generate a model inheriting from ActiveFedora::Base.
23
+
24
+ <pre>rails generate active_fedora:model Book</pre>
25
+
20
26
  h2. Testing (this Gem)
21
27
 
22
28
  In order to run the RSpec tests, you need to have a copy of the ActiveFedora source code, and then run bundle install in the source directory.
@@ -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", '~>0.5.13')
25
+ s.add_dependency("rubydora", '~>0.8.0')
26
26
  s.add_dependency("rdf")
27
27
  s.add_dependency("rdf-rdfxml", '~>0.3.8')
28
28
  s.add_dependency("deprecation")
@@ -19,6 +19,7 @@ module ActiveFedora #:nodoc:
19
19
  class ConfigurationError < RuntimeError; end # :nodoc:
20
20
  class AssociationTypeMismatch < RuntimeError; end # :nodoc:
21
21
  class UnregisteredPredicateError < RuntimeError; end # :nodoc:
22
+ class RecordNotSaved < RuntimeError; end # :nodoc:
22
23
 
23
24
 
24
25
  eager_autoload do
@@ -153,3 +154,4 @@ end
153
154
  load File.join(File.dirname(__FILE__),"tasks/active_fedora.rake") if defined?(Rake)
154
155
  I18n.load_path << File.dirname(__FILE__) + '/active_fedora/locale/en.yml'
155
156
 
157
+ require 'active_fedora/railtie' if defined?(Rails)
@@ -77,8 +77,8 @@ module ActiveFedora
77
77
  reflection = create_belongs_to_reflection(association_id, options)
78
78
 
79
79
  association_accessor_methods(reflection, BelongsToAssociation)
80
- # association_constructor_method(:build, reflection, BelongsToAssociation)
81
- # association_constructor_method(:create, reflection, BelongsToAssociation)
80
+ association_constructor_method(:build, reflection, BelongsToAssociation)
81
+ association_constructor_method(:create, reflection, BelongsToAssociation)
82
82
  #configure_dependency_for_belongs_to(reflection)
83
83
  end
84
84
 
@@ -157,6 +157,7 @@ module ActiveFedora
157
157
 
158
158
  def create_has_many_reflection(association_id, options)
159
159
  create_reflection(:has_many, association_id, options, self)
160
+ #collection_accessor_methods(reflection, HasManyAssociation)
160
161
  end
161
162
 
162
163
  def create_belongs_to_reflection(association_id, options)
@@ -266,6 +267,25 @@ module ActiveFedora
266
267
  end
267
268
  end
268
269
  end
270
+
271
+ def association_constructor_method(constructor, reflection, association_proxy_class)
272
+ redefine_method("#{constructor}_#{reflection.name}") do |*params|
273
+ attributees = params.first unless params.empty?
274
+ replace_existing = params[1].nil? ? true : params[1]
275
+ association = association_instance_get(reflection.name)
276
+
277
+ unless association
278
+ association = association_proxy_class.new(self, reflection)
279
+ association_instance_set(reflection.name, association)
280
+ end
281
+
282
+ # if association_proxy_class == HasOneAssociation
283
+ # association.send(constructor, attributees, replace_existing)
284
+ # else
285
+ association.send(constructor, attributees)
286
+ #end
287
+ end
288
+ end
269
289
  end
270
290
  end
271
291
  end
@@ -97,6 +97,24 @@ module ActiveFedora
97
97
  _records.each { |record| @target.delete(record) }
98
98
  end
99
99
  end
100
+
101
+ def create(attrs = {})
102
+ if attrs.is_a?(Array)
103
+ attrs.collect { |attr| create(attr) }
104
+ else
105
+ create_record(attrs) do |record|
106
+ yield(record) if block_given?
107
+ record.save
108
+ end
109
+ end
110
+ end
111
+
112
+ def create!(attrs = {})
113
+ create_record(attrs) do |record|
114
+ yield(record) if block_given?
115
+ record.save!
116
+ end
117
+ end
100
118
 
101
119
 
102
120
  def load_target
@@ -167,6 +185,19 @@ module ActiveFedora
167
185
 
168
186
 
169
187
  private
188
+ def create_record(attrs)
189
+ attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
190
+ ensure_owner_is_not_new
191
+ record = @reflection.klass.create do
192
+ @reflection.build_association(attrs)
193
+ end
194
+ set_belongs_to_association_for(record)
195
+ if block_given?
196
+ add_record_to_target_with_callbacks(record) { |*block_args| yield(*block_args) }
197
+ else
198
+ add_record_to_target_with_callbacks(record)
199
+ end
200
+ end
170
201
 
171
202
  def build_record(attrs)
172
203
  #attrs.update(@reflection.options[:conditions]) if @reflection.options[:conditions].is_a?(Hash)
@@ -187,6 +218,12 @@ module ActiveFedora
187
218
  yield(records, old_records)
188
219
  #records.each { |record| callback(:after_remove, record) }
189
220
  end
221
+
222
+ def ensure_owner_is_not_new
223
+ if @owner.new_record?
224
+ raise ActiveFedora::RecordNotSaved, "You cannot call create unless the parent is saved"
225
+ end
226
+ end
190
227
 
191
228
  end
192
229
  end
@@ -2,6 +2,14 @@ module ActiveFedora
2
2
  module Associations
3
3
  class BelongsToAssociation < AssociationProxy #:nodoc:
4
4
 
5
+ def create(attributes = {})
6
+ replace(@reflection.create_association(attributes))
7
+ end
8
+
9
+ def build(attributes = {})
10
+ replace(@reflection.build_association(attributes))
11
+ end
12
+
5
13
  def replace(record)
6
14
  if record.nil?
7
15
  @owner.clear_relationship(@reflection.options[:property])
@@ -44,6 +44,8 @@ module ActiveFedora
44
44
  r.remove_relationship(@reflection.options[:property], @owner)
45
45
  end
46
46
  end
47
+
48
+
47
49
  end
48
50
  end
49
51
  end
@@ -42,6 +42,10 @@ module ActiveFedora
42
42
  end
43
43
  end
44
44
 
45
+ def new?
46
+ new_object?
47
+ end
48
+
45
49
  # Has this object been saved?
46
50
  def new_object?
47
51
  inner_object.new?
@@ -73,6 +77,10 @@ module ActiveFedora
73
77
  run_callbacks :initialize
74
78
  end
75
79
 
80
+ # Reloads the object from Fedora.
81
+ def reload
82
+ init_with(self.class.find(self.pid).inner_object)
83
+ end
76
84
 
77
85
  # Initialize an empty model object and set the +inner_obj+
78
86
  # example:
@@ -91,7 +99,7 @@ module ActiveFedora
91
99
  ## Replace existing unchanged datastreams with the definitions found in this class if they have a different type.
92
100
  ## Any datastream that is deleted here will cause a reload from fedora, so avoid it whenever possible
93
101
  ds_specs.keys.each do |key|
94
- if !@inner_object.datastreams[key].changed.include?('content') && @inner_object.datastreams[key].class != self.class.ds_specs[key][:type]
102
+ if !@inner_object.datastreams[key].content_changed? && @inner_object.datastreams[key].class != self.class.ds_specs[key][:type]
95
103
  @inner_object.datastreams.delete(key)
96
104
  end
97
105
  end
@@ -137,10 +145,37 @@ module ActiveFedora
137
145
  ds_specs[dsid] ? ds_specs[dsid].fetch(:type, ActiveFedora::Datastream) : ActiveFedora::Datastream
138
146
  end
139
147
 
140
- def self.create(args = {})
141
- obj = self.new(args)
142
- obj.save
143
- obj
148
+ # Creates an object (or multiple objects) and saves it to the repository, if validations pass.
149
+ # The resulting object is returned whether the object was saved successfully to the repository or not.
150
+ #
151
+ # The +attributes+ parameter can be either be a Hash or an Array of Hashes. These Hashes describe the
152
+ # attributes on the objects that are to be created.
153
+ #
154
+ # ==== Examples
155
+ # # Create a single new object
156
+ # User.create(:first_name => 'Jamie')
157
+ #
158
+ # # Create an Array of new objects
159
+ # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }])
160
+ #
161
+ # # Create a single object and pass it into a block to set other attributes.
162
+ # User.create(:first_name => 'Jamie') do |u|
163
+ # u.is_admin = false
164
+ # end
165
+ #
166
+ # # Creating an Array of new objects using a block, where the block is executed for each object:
167
+ # User.create([{ :first_name => 'Jamie' }, { :first_name => 'Jeremy' }]) do |u|
168
+ # u.is_admin = false
169
+ # end
170
+ def self.create(attributes = nil, &block)
171
+ if attributes.is_a?(Array)
172
+ attributes.collect { |attr| create(attr, &block) }
173
+ else
174
+ object = new(attributes)
175
+ yield(object) if block_given?
176
+ object.save
177
+ object
178
+ end
144
179
  end
145
180
 
146
181
  def clone
@@ -248,7 +283,9 @@ module ActiveFedora
248
283
  comparison_object.pid == pid &&
249
284
  !comparison_object.new_record?)
250
285
  end
251
-
286
+
287
+
288
+
252
289
  def inspect
253
290
  "#<#{self.class}:#{self.hash} @pid=\"#{pid}\" >"
254
291
  end
@@ -2,32 +2,18 @@ module ActiveFedora
2
2
 
3
3
  #This class represents a Fedora datastream
4
4
  class Datastream < Rubydora::Datastream
5
-
5
+ extend Deprecation
6
6
  attr_writer :digital_object
7
7
  attr_accessor :last_modified, :fields
8
- before_create :add_mime_type, :add_ds_location, :validate_content_present
9
8
 
10
9
  def initialize(digital_object=nil, dsid=nil, options={})
11
10
  ## When you use the versions feature of rubydora (0.5.x), you need to have a 3 argument constructor
12
11
  self.fields={}
13
12
  super
14
13
  end
15
-
16
- def size
17
- self.profile['dsSize']
18
- end
19
-
20
- def add_mime_type
21
- self.mimeType = 'text/xml' unless self.mimeType
22
- end
23
-
24
- def add_ds_location
25
- if self.controlGroup == 'E'
26
- end
27
- end
28
14
 
29
15
  def inspect
30
- "#<#{self.class}:#{self.hash} @pid=\"#{digital_object ? pid : nil}\" @dsid=\"#{dsid}\" @controlGroup=\"#{controlGroup}\" @dirty=\"#{dirty}\" @mimeType=\"#{mimeType}\" >"
16
+ "#<#{self.class}:#{self.hash} @pid=\"#{digital_object ? pid : nil}\" @dsid=\"#{dsid}\" @controlGroup=\"#{controlGroup}\" changed=\"#{changed?}\" @mimeType=\"#{mimeType}\" >"
31
17
  end
32
18
 
33
19
  #compatibility method for rails' url generators. This method will
@@ -42,6 +28,7 @@ module ActiveFedora
42
28
  def dirty?
43
29
  changed?
44
30
  end
31
+ deprecation_deprecate :dirty?
45
32
 
46
33
  # @abstract Override this in your concrete datastream class.
47
34
  # @return [boolean] does this datastream contain metadata (not file data)
@@ -53,49 +40,37 @@ module ActiveFedora
53
40
  def dirty
54
41
  changed?
55
42
  end
43
+ deprecation_deprecate :dirty
56
44
 
57
45
  # Deprecated
58
46
  def dirty=(value)
59
47
  if value
60
- lastModifiedDate_will_change! # an innocent hack to pretend something has changed
48
+ content_will_change! # an innocent hack to pretend something has changed
61
49
  else
62
50
  changed_attributes.clear
63
51
  end
64
52
  end
53
+ deprecation_deprecate :dirty=
65
54
 
66
55
  def new_object?
67
56
  new?
68
57
  end
58
+ deprecation_deprecate :new_object?
69
59
 
70
60
  def validate_content_present
71
- case controlGroup
72
- when 'X','M'
73
- @content.present?
74
- when 'E','R'
75
- dsLocation.present?
76
- else
77
- raise "Invalid control group: #{controlGroup.inspect}"
78
- end
61
+ has_content?
79
62
  end
80
63
 
81
64
  def save
82
- run_callbacks :save do
83
- return create if new?
84
- repository.modify_datastream to_api_params.merge({ :pid => pid, :dsid => dsid })
85
- reset_profile_attributes
86
- self
87
- end
65
+ super
66
+ self
88
67
  end
89
68
 
90
69
  def create
91
- run_callbacks :create do
92
- repository.add_datastream to_api_params.merge({ :pid => pid, :dsid => dsid })
93
- reset_profile_attributes
94
- self
95
- end
70
+ super
71
+ self
96
72
  end
97
73
 
98
-
99
74
  # serializes any changed data into the content field
100
75
  def serialize!
101
76
  end
@@ -103,6 +78,7 @@ module ActiveFedora
103
78
  # @param [ActiveFedora::Datastream] tmpl the Datastream object that you are building
104
79
  # @param [Nokogiri::XML::Node] node the "foxml:datastream" node from a FOXML file
105
80
  def self.from_xml(tmpl, node)
81
+ Deprecation.deprecated_method_warning(self, :from_xml)
106
82
  tmpl.controlGroup= node['CONTROL_GROUP']
107
83
  tmpl
108
84
  end
@@ -21,10 +21,6 @@ module ActiveFedora
21
21
 
22
22
  def serialize_datastreams
23
23
  datastreams.each {|k, ds| ds.serialize! }
24
- self.metadata_is_dirty = datastreams.any? do |k,ds|
25
- ds.changed? && ds.metadata?
26
- end
27
- true
28
24
  end
29
25
 
30
26
  # Adds the disseminator location to the datastream after the pid has been established
@@ -225,7 +221,7 @@ module ActiveFedora
225
221
  # @option args [Boolean] :versionable Should versioned datastreams be stored
226
222
  # @yield block executed by some kinds of datastreams
227
223
  def has_metadata(args, &block)
228
- spec = {:autocreate => args.fetch(:autocreate, true), :type => args[:type], :label => args.fetch(:label,""), :control_group => args[:control_group], :disseminator => args.fetch(:disseminator,""), :url => args.fetch(:url,""),:block => block}
224
+ spec = {:autocreate => args.fetch(:autocreate, false), :type => args[:type], :label => args.fetch(:label,""), :control_group => args[:control_group], :disseminator => args.fetch(:disseminator,""), :url => args.fetch(:url,""),:block => block}
229
225
  spec[:versionable] = args[:versionable] if args.has_key? :versionable
230
226
  ds_specs[args[:name]]= spec
231
227
  end
@@ -240,7 +236,7 @@ module ActiveFedora
240
236
  # @option args [Boolean] :autocreate Always create this datastream on new objects
241
237
  # @option args [Boolean] :versionable Should versioned datastreams be stored
242
238
  def has_file_datastream(args = {})
243
- spec = {:autocreate => args.fetch(:autocreate, true), :type => args.fetch(:type,ActiveFedora::Datastream),
239
+ spec = {:autocreate => args.fetch(:autocreate, false), :type => args.fetch(:type,ActiveFedora::Datastream),
244
240
  :label => args.fetch(:label,"File Datastream"), :control_group => args.fetch(:control_group,"M")}
245
241
  spec[:versionable] = args[:versionable] if args.has_key? :versionable
246
242
  ds_specs[args.fetch(:name, "content")]= spec
@@ -33,9 +33,16 @@ module ActiveFedora
33
33
  def self.find(original_class, pid)
34
34
  conn = original_class.connection_for_pid(pid)
35
35
  obj = Deprecation.silence(Rubydora::DigitalObject) do
36
- super(pid, conn)
36
+ begin
37
+ super(pid, conn)
38
+ rescue Rubydora::FedoraInvalidRequest => e
39
+ # PID is nil
40
+ raise ActiveFedora::ObjectNotFoundError, "Unable to find '#{pid}' in fedora. See logger for details."
41
+ end
37
42
  end
38
43
  obj.original_class = original_class
44
+ # PID is not found, but was "well-formed" for its Fedora request. So
45
+ # an object is instantiated with that PID.
39
46
  raise ActiveFedora::ObjectNotFoundError, "Unable to find '#{pid}' in fedora" if obj.new?
40
47
  obj
41
48
  end
@@ -30,8 +30,8 @@ module ActiveFedora::MetadataDatastreamHelper
30
30
  end
31
31
 
32
32
  def serialize! # :nodoc:
33
- if dirty?
34
- return unless xml_loaded
33
+ if changed?
34
+ return unless xml_loaded or new?
35
35
  self.content = self.to_xml
36
36
  end
37
37
  end
@@ -6,14 +6,18 @@ require "solrizer/xml"
6
6
  module ActiveFedora
7
7
  class NokogiriDatastream < Datastream
8
8
 
9
- include MetadataDatastreamHelper
9
+ before_save do
10
+ return unless xml_loaded
11
+ content_will_change! if ng_xml_changed?
12
+ end
13
+
10
14
  include OM::XML::Document
11
15
  include Solrizer::XML::TerminologyBasedSolrizer # this adds support for calling .to_solr
12
16
 
13
17
  alias_method(:om_term_values, :term_values) unless method_defined?(:om_term_values)
14
18
  alias_method(:om_update_values, :update_values) unless method_defined?(:om_update_values)
15
19
 
16
- attr_accessor :internal_solr_doc
20
+ attr_accessor :internal_solr_doc, :xml_loaded
17
21
 
18
22
  def self.default_attributes
19
23
  super.merge(:controlGroup => 'X', :mimeType => 'text/xml')
@@ -32,8 +36,10 @@ module ActiveFedora
32
36
  tmpl.ng_xml = xml
33
37
  else
34
38
  tmpl.ng_xml = Nokogiri::XML::Document.parse(xml)
35
- end
36
- tmpl.send(:dirty=, false)
39
+ end
40
+
41
+ tmpl.ng_xml_doesnt_change!
42
+
37
43
  return tmpl
38
44
  end
39
45
 
@@ -49,34 +55,59 @@ module ActiveFedora
49
55
  ## Load up the template
50
56
  self.class.xml_template
51
57
  else
52
- Nokogiri::XML::Document.parse(content)
58
+ Nokogiri::XML::Document.parse(datastream_content)
53
59
  end
54
60
  end
55
61
  end
56
62
 
57
63
  def ng_xml=(new_xml)
58
- ng_xml_will_change!
59
- self.xml_loaded=true
60
- case new_xml
64
+
65
+ nokogiri_document = case new_xml
61
66
  when Nokogiri::XML::Document
62
- @ng_xml = new_xml
67
+ new_xml
63
68
  when Nokogiri::XML::Node
64
- @ng_xml = Nokogiri::XML(new_xml.to_s) ## Cast a fragment to a document
69
+ Nokogiri::XML(new_xml.to_s) ## Cast a fragment to a document
65
70
  when String
66
- @ng_xml = Nokogiri::XML::Document.parse(new_xml)
71
+ Nokogiri::XML::Document.parse(new_xml)
67
72
  else
68
73
  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."
69
74
  end
75
+
76
+
77
+ new_xml_string = nokogiri_document.to_xml {|config| config.no_declaration}
78
+
79
+ ng_xml_will_change! unless (xml_loaded && (new_xml_string.to_s.strip == datastream_content.strip))
80
+ self.xml_loaded=true
81
+
82
+ @ng_xml = nokogiri_document
83
+
70
84
  end
71
85
 
72
86
  # don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
73
87
  def ng_xml_will_change!
74
88
  changed_attributes['ng_xml'] = nil
75
89
  end
90
+
91
+ def ng_xml_doesnt_change!
92
+ changed_attributes.delete('ng_xml')
93
+ end
76
94
 
77
95
  # don't want content eagerly loaded by proxy, so implementing methods that would be implemented by define_attribute_methods
78
96
  def ng_xml_changed?
79
- changed_attributes.has_key? 'ng_xml'
97
+ changed_attributes.has_key? 'ng_xml' ||
98
+ (xml_loaded && (to_xml != datastream_content) )
99
+ end
100
+
101
+ def changed?
102
+ ng_xml_changed? || super
103
+ end
104
+
105
+ def content_changed?
106
+ ng_xml_changed? || super
107
+ end
108
+
109
+ def has_content?
110
+ xml_loaded || super
80
111
  end
81
112
 
82
113
  # Indicates that this datastream has metadata content.
@@ -84,13 +115,21 @@ module ActiveFedora
84
115
  def metadata?
85
116
  true
86
117
  end
87
-
118
+
88
119
  def content=(content)
89
- super
120
+ content_will_change! unless (xml_loaded && (content == datastream_content))
121
+ @content = content
90
122
  self.xml_loaded=true
91
- @ng_xml = Nokogiri::XML::Document.parse(content)
123
+ self.ng_xml = Nokogiri::XML::Document.parse(datastream_content)
124
+ end
125
+
126
+ alias :datastream_content :content
127
+
128
+ def content
129
+ return to_xml if xml_loaded or new?
130
+
131
+ datastream_content
92
132
  end
93
-
94
133
 
95
134
  def to_xml(xml = nil)
96
135
  xml = self.ng_xml if xml.nil?