active-fedora 5.0.0 → 5.1.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.
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?