moab-versioning 4.2.1 → 4.2.2
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.
- checksums.yaml +4 -4
- data/lib/moab.rb +1 -1
- data/lib/moab/bagger.rb +15 -15
- data/lib/moab/config.rb +0 -2
- data/lib/moab/deposit_bag_validator.rb +1 -1
- data/lib/moab/file_group.rb +13 -15
- data/lib/moab/file_group_difference.rb +18 -21
- data/lib/moab/file_group_difference_subset.rb +2 -4
- data/lib/moab/file_instance.rb +1 -3
- data/lib/moab/file_instance_difference.rb +3 -5
- data/lib/moab/file_inventory.rb +17 -27
- data/lib/moab/file_inventory_difference.rb +5 -7
- data/lib/moab/file_manifestation.rb +4 -6
- data/lib/moab/file_signature.rb +29 -40
- data/lib/moab/signature_catalog.rb +11 -13
- data/lib/moab/signature_catalog_entry.rb +1 -3
- data/lib/moab/storage_object.rb +12 -19
- data/lib/moab/storage_object_validator.rb +22 -8
- data/lib/moab/storage_object_version.rb +25 -27
- data/lib/moab/storage_repository.rb +6 -13
- data/lib/moab/storage_services.rb +6 -8
- data/lib/moab/utc_time.rb +0 -2
- data/lib/moab/verification_result.rb +0 -2
- data/lib/moab/version_metadata.rb +1 -3
- data/lib/moab/version_metadata_entry.rb +2 -4
- data/lib/moab/version_metadata_event.rb +0 -2
- data/lib/serializer/manifest.rb +5 -5
- data/lib/serializer/serializable.rb +34 -34
- data/lib/stanford/active_fedora_object.rb +0 -2
- data/lib/stanford/content_inventory.rb +22 -20
- data/lib/stanford/dor_metadata.rb +0 -2
- data/lib/stanford/storage_object_validator.rb +0 -2
- data/lib/stanford/storage_repository.rb +1 -2
- data/lib/stanford/storage_services.rb +5 -7
- metadata +3 -3
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'moab'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Moab
         | 
| 4 2 | 
             
              # A class to represent a version subdirectory within an object's home directory in preservation storage
         | 
| 5 3 | 
             
              # ====Data Model
         | 
| @@ -32,7 +30,7 @@ module Moab | |
| 32 30 | 
             
                def initialize(storage_object, version_id)
         | 
| 33 31 | 
             
                  if version_id.is_a?(Integer)
         | 
| 34 32 | 
             
                    @version_id = version_id
         | 
| 35 | 
            -
                  elsif version_id.is_a?(String)  | 
| 33 | 
            +
                  elsif version_id.is_a?(String) && version_id =~ /^v(\d+)$/
         | 
| 36 34 | 
             
                    @version_id = version_id.sub(/^v/, '').to_i
         | 
| 37 35 | 
             
                  else
         | 
| 38 36 | 
             
                    raise "version_id (#{version_id}) is not in a recognized format"
         | 
| @@ -40,7 +38,7 @@ module Moab | |
| 40 38 | 
             
                  @version_name = StorageObject.version_dirname(@version_id)
         | 
| 41 39 | 
             
                  @version_pathname = storage_object.object_pathname.join(@version_name)
         | 
| 42 40 | 
             
                  @storage_object = storage_object
         | 
| 43 | 
            -
                  @inventory_cache =  | 
| 41 | 
            +
                  @inventory_cache = {}
         | 
| 44 42 | 
             
                end
         | 
| 45 43 |  | 
| 46 44 | 
             
                # @return [String] The unique identifier concatenating digital object id with version id
         | 
| @@ -110,10 +108,10 @@ module Moab | |
| 110 108 | 
             
                # @see FileInventory#read_xml_file
         | 
| 111 109 | 
             
                def file_inventory(type)
         | 
| 112 110 | 
             
                  if version_id > 0
         | 
| 113 | 
            -
                    return @inventory_cache[type] if @inventory_cache. | 
| 111 | 
            +
                    return @inventory_cache[type] if @inventory_cache.key?(type)
         | 
| 114 112 | 
             
                    @inventory_cache[type] = FileInventory.read_xml_file(@version_pathname.join('manifests'), type)
         | 
| 115 113 | 
             
                  else
         | 
| 116 | 
            -
                    groups = [ | 
| 114 | 
            +
                    groups = %w[content metadata].collect { |id| FileGroup.new(:group_id => id) }
         | 
| 117 115 | 
             
                    FileInventory.new(
         | 
| 118 116 | 
             
                      :type => 'version',
         | 
| 119 117 | 
             
                      :digital_object_id => @storage_object.digital_object_id,
         | 
| @@ -208,12 +206,12 @@ module Moab | |
| 208 206 | 
             
                end
         | 
| 209 207 |  | 
| 210 208 | 
             
                # @return [VerificationResult] return result of testing correctness of version manifests
         | 
| 211 | 
            -
                def verify_version_storage | 
| 212 | 
            -
                  result = VerificationResult.new( | 
| 213 | 
            -
                  result.subentities <<  | 
| 214 | 
            -
                  result.subentities <<  | 
| 215 | 
            -
                  result.subentities <<  | 
| 216 | 
            -
                  result.verified = result.subentities.all? | 
| 209 | 
            +
                def verify_version_storage
         | 
| 210 | 
            +
                  result = VerificationResult.new(composite_key)
         | 
| 211 | 
            +
                  result.subentities << verify_manifest_inventory
         | 
| 212 | 
            +
                  result.subentities << verify_version_inventory
         | 
| 213 | 
            +
                  result.subentities << verify_version_additions
         | 
| 214 | 
            +
                  result.verified = result.subentities.all?(&:verified)
         | 
| 217 215 | 
             
                  result
         | 
| 218 216 | 
             
                end
         | 
| 219 217 |  | 
| @@ -221,8 +219,8 @@ module Moab | |
| 221 219 | 
             
                def verify_manifest_inventory
         | 
| 222 220 | 
             
                  # read/parse manifestInventory.xml
         | 
| 223 221 | 
             
                  result = VerificationResult.new("manifest_inventory")
         | 
| 224 | 
            -
                  manifest_inventory =  | 
| 225 | 
            -
                  result.subentities << VerificationResult.verify_value('composite_key',  | 
| 222 | 
            +
                  manifest_inventory = file_inventory('manifests')
         | 
| 223 | 
            +
                  result.subentities << VerificationResult.verify_value('composite_key', composite_key, manifest_inventory.composite_key)
         | 
| 226 224 | 
             
                  result.subentities << VerificationResult.verify_truth('manifests_group', !manifest_inventory.group_empty?('manifests'))
         | 
| 227 225 | 
             
                  # measure the manifest signatures of the files in the directory (excluding manifestInventory.xml)
         | 
| 228 226 | 
             
                  directory_inventory = FileInventory.new.inventory_from_directory(@version_pathname.join('manifests'), 'manifests')
         | 
| @@ -236,7 +234,7 @@ module Moab | |
| 236 234 | 
             
                  compare_result.verified = (diff.difference_count == 0)
         | 
| 237 235 | 
             
                  compare_result.details = diff.differences_detail
         | 
| 238 236 | 
             
                  result.subentities << compare_result
         | 
| 239 | 
            -
                  result.verified = result.subentities.all? | 
| 237 | 
            +
                  result.verified = result.subentities.all?(&:verified)
         | 
| 240 238 | 
             
                  result
         | 
| 241 239 | 
             
                end
         | 
| 242 240 |  | 
| @@ -244,10 +242,10 @@ module Moab | |
| 244 242 | 
             
                def verify_signature_catalog
         | 
| 245 243 | 
             
                  result = VerificationResult.new("signature_catalog")
         | 
| 246 244 | 
             
                  signature_catalog = self.signature_catalog
         | 
| 247 | 
            -
                  result.subentities << VerificationResult.verify_value('signature_key',  | 
| 245 | 
            +
                  result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
         | 
| 248 246 | 
             
                  found = 0
         | 
| 249 | 
            -
                  missing =  | 
| 250 | 
            -
                  object_pathname =  | 
| 247 | 
            +
                  missing = []
         | 
| 248 | 
            +
                  object_pathname = storage_object.object_pathname
         | 
| 251 249 | 
             
                  signature_catalog.entries.each do |catalog_entry|
         | 
| 252 250 | 
             
                    storage_location = object_pathname.join(catalog_entry.storage_path)
         | 
| 253 251 | 
             
                    if storage_location.exist?
         | 
| @@ -264,19 +262,19 @@ module Moab | |
| 264 262 | 
             
                  }
         | 
| 265 263 | 
             
                  file_result.details['missing'] = missing unless missing.empty?
         | 
| 266 264 | 
             
                  result.subentities << file_result
         | 
| 267 | 
            -
                  result.verified = result.subentities.all? | 
| 265 | 
            +
                  result.verified = result.subentities.all?(&:verified)
         | 
| 268 266 | 
             
                  result
         | 
| 269 267 | 
             
                end
         | 
| 270 268 |  | 
| 271 269 | 
             
                # @return [Boolean] true if files & signatures listed in version inventory can all be found
         | 
| 272 270 | 
             
                def verify_version_inventory
         | 
| 273 271 | 
             
                  result = VerificationResult.new("version_inventory")
         | 
| 274 | 
            -
                  version_inventory =  | 
| 275 | 
            -
                  result.subentities << VerificationResult.verify_value('inventory_key',  | 
| 272 | 
            +
                  version_inventory = file_inventory('version')
         | 
| 273 | 
            +
                  result.subentities << VerificationResult.verify_value('inventory_key', composite_key, version_inventory.composite_key)
         | 
| 276 274 | 
             
                  signature_catalog = self.signature_catalog
         | 
| 277 | 
            -
                  result.subentities << VerificationResult.verify_value('signature_key',  | 
| 275 | 
            +
                  result.subentities << VerificationResult.verify_value('signature_key', composite_key, signature_catalog.composite_key)
         | 
| 278 276 | 
             
                  found = 0
         | 
| 279 | 
            -
                  missing =  | 
| 277 | 
            +
                  missing = []
         | 
| 280 278 | 
             
                  version_inventory.groups.each do |group|
         | 
| 281 279 | 
             
                    group.files.each do |file|
         | 
| 282 280 | 
             
                      file.instances.each do |instance|
         | 
| @@ -298,15 +296,15 @@ module Moab | |
| 298 296 | 
             
                  }
         | 
| 299 297 | 
             
                  file_result.details['missing'] = missing unless missing.empty?
         | 
| 300 298 | 
             
                  result.subentities << file_result
         | 
| 301 | 
            -
                  result.verified = result.subentities.all? | 
| 299 | 
            +
                  result.verified = result.subentities.all?(&:verified)
         | 
| 302 300 | 
             
                  result
         | 
| 303 301 | 
             
                end
         | 
| 304 302 |  | 
| 305 303 | 
             
                # @return [Boolean] returns true if files in data folder match files listed in version addtions inventory
         | 
| 306 304 | 
             
                def verify_version_additions
         | 
| 307 305 | 
             
                  result = VerificationResult.new("version_additions")
         | 
| 308 | 
            -
                  version_additions =  | 
| 309 | 
            -
                  result.subentities << VerificationResult.verify_value('composite_key',  | 
| 306 | 
            +
                  version_additions = file_inventory('additions')
         | 
| 307 | 
            +
                  result.subentities << VerificationResult.verify_value('composite_key', composite_key, version_additions.composite_key)
         | 
| 310 308 | 
             
                  data_directory = @version_pathname.join('data')
         | 
| 311 309 | 
             
                  directory_inventory = FileInventory.new(:type => 'directory').inventory_from_directory(data_directory)
         | 
| 312 310 | 
             
                  diff = FileInventoryDifference.new
         | 
| @@ -315,7 +313,7 @@ module Moab | |
| 315 313 | 
             
                  compare_result.verified = (diff.difference_count == 0)
         | 
| 316 314 | 
             
                  compare_result.details = diff.differences_detail
         | 
| 317 315 | 
             
                  result.subentities << compare_result
         | 
| 318 | 
            -
                  result.verified = result.subentities.all? | 
| 316 | 
            +
                  result.verified = result.subentities.all?(&:verified)
         | 
| 319 317 | 
             
                  result
         | 
| 320 318 | 
             
                end
         | 
| 321 319 |  | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'moab'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Moab
         | 
| 4 2 | 
             
              # A class to represent the SDR repository store
         | 
| 5 3 | 
             
              #
         | 
| @@ -58,9 +56,9 @@ module Moab | |
| 58 56 | 
             
                end
         | 
| 59 57 |  | 
| 60 58 | 
             
                # @param object_id [String] The identifier of the digital object
         | 
| 61 | 
            -
                # @return [ | 
| 59 | 
            +
                # @return [String] The branch segment of the object deposit path
         | 
| 60 | 
            +
                # @note Override this method in a subclass
         | 
| 62 61 | 
             
                def deposit_branch(object_id)
         | 
| 63 | 
            -
                   #todo This method should be customized, or overridden in a subclass
         | 
| 64 62 | 
             
                  object_id
         | 
| 65 63 | 
             
                end
         | 
| 66 64 |  | 
| @@ -77,7 +75,7 @@ module Moab | |
| 77 75 | 
             
                    return root if root_trunk_branch.exist?
         | 
| 78 76 | 
             
                  end
         | 
| 79 77 | 
             
                  # Search for the object's directory in the deposit areas
         | 
| 80 | 
            -
                  if include_deposit  | 
| 78 | 
            +
                  if include_deposit && deposit_trunk
         | 
| 81 79 | 
             
                    branch = deposit_branch(object_id)
         | 
| 82 80 | 
             
                    storage_roots.each do |root|
         | 
| 83 81 | 
             
                      root_trunk = root.join(deposit_trunk)
         | 
| @@ -119,11 +117,8 @@ module Moab | |
| 119 117 | 
             
                def storage_object(object_id, create = false)
         | 
| 120 118 | 
             
                  storage_object = find_storage_object(object_id)
         | 
| 121 119 | 
             
                  unless storage_object.object_pathname.exist?
         | 
| 122 | 
            -
                     | 
| 123 | 
            -
             | 
| 124 | 
            -
                    else
         | 
| 125 | 
            -
                      raise Moab::ObjectNotFoundException, "No storage object found for #{object_id}"
         | 
| 126 | 
            -
                    end
         | 
| 120 | 
            +
                    raise Moab::ObjectNotFoundException, "No storage object found for #{object_id}" unless create
         | 
| 121 | 
            +
                    storage_object.object_pathname.mkpath
         | 
| 127 122 | 
             
                  end
         | 
| 128 123 | 
             
                  storage_object
         | 
| 129 124 | 
             
                end
         | 
| @@ -132,9 +127,7 @@ module Moab | |
| 132 127 | 
             
                # @param druid [String] The object identifier
         | 
| 133 128 | 
             
                # @return [void] transfer the object to the preservation repository
         | 
| 134 129 | 
             
                def store_new_object_version(druid, bag_pathname)
         | 
| 135 | 
            -
                  storage_object | 
| 136 | 
            -
                  new_version = storage_object.ingest_bag(bag_pathname)
         | 
| 137 | 
            -
                  new_version
         | 
| 130 | 
            +
                  storage_object(druid, create = true).ingest_bag(bag_pathname)
         | 
| 138 131 | 
             
                end
         | 
| 139 132 | 
             
              end
         | 
| 140 133 | 
             
            end
         | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'moab'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Moab
         | 
| 4 2 | 
             
              # An interface class to support access to SDR storage via a RESTful server
         | 
| 5 3 | 
             
              #
         | 
| @@ -79,7 +77,7 @@ module Moab | |
| 79 77 | 
             
                # @param [String] object_id The digital object identifier of the object
         | 
| 80 78 | 
             
                # @return [Pathname] Pathname object containing the full path for the specified file
         | 
| 81 79 | 
             
                def self.version_metadata(object_id)
         | 
| 82 | 
            -
                   | 
| 80 | 
            +
                  retrieve_file('metadata', 'versionMetadata.xml', object_id)
         | 
| 83 81 | 
             
                end
         | 
| 84 82 |  | 
| 85 83 | 
             
                # @param [String] object_id The digital object identifier of the object
         | 
| @@ -87,11 +85,11 @@ module Moab | |
| 87 85 | 
             
                # @return [FileInventory] the file inventory for the specified object version
         | 
| 88 86 | 
             
                def self.retrieve_file_group(file_category, object_id, version_id = nil)
         | 
| 89 87 | 
             
                  storage_object_version = @@repository.storage_object(object_id).find_object_version(version_id)
         | 
| 90 | 
            -
                  if file_category =~ /manifest/
         | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 88 | 
            +
                  inventory_type = if file_category =~ /manifest/
         | 
| 89 | 
            +
                                     file_category = 'manifests'
         | 
| 90 | 
            +
                                   else
         | 
| 91 | 
            +
                                     'version'
         | 
| 92 | 
            +
                                   end
         | 
| 95 93 | 
             
                  inventory = storage_object_version.file_inventory(inventory_type)
         | 
| 96 94 | 
             
                  inventory.group(file_category)
         | 
| 97 95 | 
             
                end
         | 
    
        data/lib/moab/utc_time.rb
    CHANGED
    
    
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'moab'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Moab
         | 
| 4 2 | 
             
              # The descriptive information about a digital object's collection of versions
         | 
| 5 3 | 
             
              #
         | 
| @@ -19,7 +17,7 @@ module Moab | |
| 19 17 |  | 
| 20 18 | 
             
                # (see Serializable#initialize)
         | 
| 21 19 | 
             
                def initialize(opts = {})
         | 
| 22 | 
            -
                  @versions =  | 
| 20 | 
            +
                  @versions = []
         | 
| 23 21 | 
             
                  super(opts)
         | 
| 24 22 | 
             
                end
         | 
| 25 23 |  | 
| @@ -1,5 +1,3 @@ | |
| 1 | 
            -
            require 'moab'
         | 
| 2 | 
            -
             | 
| 3 1 | 
             
            module Moab
         | 
| 4 2 | 
             
              # The descriptive attributes of a digital object version.
         | 
| 5 3 | 
             
              #
         | 
| @@ -18,13 +16,13 @@ module Moab | |
| 18 16 |  | 
| 19 17 | 
             
                # (see Serializable#initialize)
         | 
| 20 18 | 
             
                def initialize(opts = {})
         | 
| 21 | 
            -
                  @events =  | 
| 19 | 
            +
                  @events = []
         | 
| 22 20 | 
             
                  super(opts)
         | 
| 23 21 | 
             
                end
         | 
| 24 22 |  | 
| 25 23 | 
             
                # @attribute
         | 
| 26 24 | 
             
                # @return [Integer] The object version number (A sequential integer)
         | 
| 27 | 
            -
                attribute :version_id, Integer, :tag => 'versionId', :key => true, :on_save =>  | 
| 25 | 
            +
                attribute :version_id, Integer, :tag => 'versionId', :key => true, :on_save => proc { |n| n.to_s }
         | 
| 28 26 |  | 
| 29 27 | 
             
                # @attribute
         | 
| 30 28 | 
             
                # @return [String] "an external version label that increments the most significant digit for major revisions,
         | 
    
        data/lib/serializer/manifest.rb
    CHANGED
    
    | @@ -19,7 +19,7 @@ module Serializer | |
| 19 19 | 
             
                  if filename
         | 
| 20 20 | 
             
                    filename
         | 
| 21 21 | 
             
                  else
         | 
| 22 | 
            -
                    cname =  | 
| 22 | 
            +
                    cname = name.split(/::/).last
         | 
| 23 23 | 
             
                    cname[0, 1].downcase + cname[1..-1] + '.xml'
         | 
| 24 24 | 
             
                  end
         | 
| 25 25 | 
             
                end
         | 
| @@ -29,7 +29,7 @@ module Serializer | |
| 29 29 | 
             
                # @param filename [String] Optional filename if one wishes to override the default filename
         | 
| 30 30 | 
             
                # @return [Pathname] The location of the xml file
         | 
| 31 31 | 
             
                def self.xml_pathname(parent_dir, filename = nil)
         | 
| 32 | 
            -
                  Pathname.new(parent_dir).join( | 
| 32 | 
            +
                  Pathname.new(parent_dir).join(xml_filename(filename))
         | 
| 33 33 | 
             
                end
         | 
| 34 34 |  | 
| 35 35 | 
             
                # @api external
         | 
| @@ -37,7 +37,7 @@ module Serializer | |
| 37 37 | 
             
                # @param filename [String] Optional filename if one wishes to override the default filename
         | 
| 38 38 | 
             
                # @return [Boolean] Returns true if the xml file exists
         | 
| 39 39 | 
             
                def self.xml_pathname_exist?(parent_dir, filename = nil)
         | 
| 40 | 
            -
                   | 
| 40 | 
            +
                  xml_pathname(parent_dir, filename).exist?
         | 
| 41 41 | 
             
                end
         | 
| 42 42 |  | 
| 43 43 | 
             
                # @api external
         | 
| @@ -46,7 +46,7 @@ module Serializer | |
| 46 46 | 
             
                # @return [Serializable] Read the xml file and return the parsed XML
         | 
| 47 47 | 
             
                # @example {include:file:spec/features/serializer/read_xml_spec.rb}
         | 
| 48 48 | 
             
                def self.read_xml_file(parent_dir, filename = nil)
         | 
| 49 | 
            -
                   | 
| 49 | 
            +
                  parse(xml_pathname(parent_dir, filename).read)
         | 
| 50 50 | 
             
                end
         | 
| 51 51 |  | 
| 52 52 | 
             
                # @api external
         | 
| @@ -56,7 +56,7 @@ module Serializer | |
| 56 56 | 
             
                # @return [void] Serializize the in-memory object to a xml file instance
         | 
| 57 57 | 
             
                def self.write_xml_file(xml_object, parent_dir, filename = nil)
         | 
| 58 58 | 
             
                  parent_dir.mkpath
         | 
| 59 | 
            -
                   | 
| 59 | 
            +
                  xml_pathname(parent_dir, filename).open('w') do |f|
         | 
| 60 60 | 
             
                    xmlBuilder = Nokogiri::XML::Builder.new(:encoding => 'UTF-8')
         | 
| 61 61 | 
             
                    xmlBuilder = xml_object.to_xml(xmlBuilder)
         | 
| 62 62 | 
             
                    f << xmlBuilder.to_xml
         | 
| @@ -19,11 +19,8 @@ module Serializer | |
| 19 19 | 
             
                #   The symbols should correspond to attributes declared using HappyMapper syntax
         | 
| 20 20 | 
             
                def initialize(opts = {})
         | 
| 21 21 | 
             
                  opts.each do |key, value|
         | 
| 22 | 
            -
                     | 
| 23 | 
            -
             | 
| 24 | 
            -
                    else
         | 
| 25 | 
            -
                      raise "#{key} is not a variable name in #{self.class.name}"
         | 
| 26 | 
            -
                    end
         | 
| 22 | 
            +
                    raise "#{key} is not a variable name in #{self.class.name}" unless variable_names.include?(key.to_s) || key == :test
         | 
| 23 | 
            +
                    instance_variable_set("@#{key}", value)
         | 
| 27 24 | 
             
                  end
         | 
| 28 25 | 
             
                end
         | 
| 29 26 |  | 
| @@ -45,7 +42,7 @@ module Serializer | |
| 45 42 | 
             
                # @api internal
         | 
| 46 43 | 
             
                # @return [Array] Extract the names of the variables
         | 
| 47 44 | 
             
                def variable_names
         | 
| 48 | 
            -
                  variables.collect | 
| 45 | 
            +
                  variables.collect(&:name)
         | 
| 49 46 | 
             
                end
         | 
| 50 47 |  | 
| 51 48 | 
             
                # @api internal
         | 
| @@ -54,7 +51,7 @@ module Serializer | |
| 54 51 | 
             
                #   This follows the same convention as used by DataMapper
         | 
| 55 52 | 
             
                # @see http://datamapper.org/docs/properties.html
         | 
| 56 53 | 
             
                def key_name
         | 
| 57 | 
            -
                   | 
| 54 | 
            +
                  unless defined?(@key_name)
         | 
| 58 55 | 
             
                    @key_name = nil
         | 
| 59 56 | 
             
                    self.class.attributes.each do |attribute|
         | 
| 60 57 | 
             
                      if attribute.options[:key]
         | 
| @@ -69,7 +66,7 @@ module Serializer | |
| 69 66 | 
             
                # @api internal
         | 
| 70 67 | 
             
                # @return [String] For the current object instance, return the string to use as a hash key
         | 
| 71 68 | 
             
                def key
         | 
| 72 | 
            -
                  return  | 
| 69 | 
            +
                  return send(key_name) if key_name
         | 
| 73 70 | 
             
                  nil
         | 
| 74 71 | 
             
                end
         | 
| 75 72 |  | 
| @@ -79,10 +76,10 @@ module Serializer | |
| 79 76 | 
             
                #   If the array member has a field tagged as a key, that field will be used as the hash.key.
         | 
| 80 77 | 
             
                #   Otherwise the index position of the array member will be used as the key
         | 
| 81 78 | 
             
                def array_to_hash(array, summary = false)
         | 
| 82 | 
            -
                  item_hash =  | 
| 79 | 
            +
                  item_hash = {}
         | 
| 83 80 | 
             
                  array.each_index do |index|
         | 
| 84 81 | 
             
                    item = array[index]
         | 
| 85 | 
            -
                    ikey =  | 
| 82 | 
            +
                    ikey = item.respond_to?(:key) && item.key ? item.key : index
         | 
| 86 83 | 
             
                    item_hash[ikey] = item.respond_to?(:to_hash) ? item.to_hash(summary) : item
         | 
| 87 84 | 
             
                  end
         | 
| 88 85 | 
             
                  item_hash
         | 
| @@ -92,26 +89,26 @@ module Serializer | |
| 92 89 | 
             
                # @return [Hash] Recursively generate an Hash containing the object's properties
         | 
| 93 90 | 
             
                # @param summary [Boolean] Controls the depth and detail of recursion
         | 
| 94 91 | 
             
                def to_hash(summary = false)
         | 
| 95 | 
            -
                  oh =  | 
| 92 | 
            +
                  oh = {}
         | 
| 96 93 | 
             
                  vars = summary ? variables.select { |v| summary_fields.include?(v.name) } : variables
         | 
| 97 94 | 
             
                  vars.each do |variable|
         | 
| 98 95 | 
             
                    key = variable.name.to_s
         | 
| 99 | 
            -
                    value =  | 
| 100 | 
            -
                    case value
         | 
| 101 | 
            -
             | 
| 102 | 
            -
             | 
| 103 | 
            -
             | 
| 104 | 
            -
             | 
| 105 | 
            -
             | 
| 106 | 
            -
             | 
| 107 | 
            -
             | 
| 96 | 
            +
                    value = send(variable.name)
         | 
| 97 | 
            +
                    oh[key] = case value
         | 
| 98 | 
            +
                              when Array
         | 
| 99 | 
            +
                                array_to_hash(value, summary)
         | 
| 100 | 
            +
                              when Serializable
         | 
| 101 | 
            +
                                value.to_hash
         | 
| 102 | 
            +
                              else
         | 
| 103 | 
            +
                                value
         | 
| 104 | 
            +
                              end
         | 
| 108 105 | 
             
                  end
         | 
| 109 106 | 
             
                  oh
         | 
| 110 107 | 
             
                end
         | 
| 111 108 |  | 
| 112 109 | 
             
                # @return [Hash] Calls to_hash(summary=true)
         | 
| 113 110 | 
             
                def summary
         | 
| 114 | 
            -
                   | 
| 111 | 
            +
                  to_hash(summary = true)
         | 
| 115 112 | 
             
                end
         | 
| 116 113 |  | 
| 117 114 | 
             
                # @api internal
         | 
| @@ -120,13 +117,13 @@ module Serializer | |
| 120 117 | 
             
                def diff(other)
         | 
| 121 118 | 
             
                  raise "Cannot compare different classes" if self.class != other.class
         | 
| 122 119 | 
             
                  left = other.to_hash
         | 
| 123 | 
            -
                  right =  | 
| 124 | 
            -
                  if  | 
| 120 | 
            +
                  right = to_hash
         | 
| 121 | 
            +
                  if key.nil? || other.key.nil?
         | 
| 125 122 | 
             
                    ltag = :old
         | 
| 126 123 | 
             
                    rtag = :new
         | 
| 127 124 | 
             
                  else
         | 
| 128 125 | 
             
                    ltag = other.key
         | 
| 129 | 
            -
                    rtag =  | 
| 126 | 
            +
                    rtag = key
         | 
| 130 127 | 
             
                  end
         | 
| 131 128 | 
             
                  Serializable.deep_diff(ltag, left, rtag, right)
         | 
| 132 129 | 
             
                end
         | 
| @@ -136,23 +133,26 @@ module Serializer | |
| 136 133 | 
             
                # @return [Hash] Generate a hash containing the differences between two hashes
         | 
| 137 134 | 
             
                #   (recursively descend parallel trees of hashes)
         | 
| 138 135 | 
             
                # @see https://gist.github.com/146844
         | 
| 139 | 
            -
                def  | 
| 140 | 
            -
                  diff =  | 
| 136 | 
            +
                def self.deep_diff(*hashes)
         | 
| 137 | 
            +
                  diff = {}
         | 
| 141 138 | 
             
                  case hashes.length
         | 
| 142 139 | 
             
                  when 4
         | 
| 143 140 | 
             
                    ltag, left, rtag, right = hashes
         | 
| 144 141 | 
             
                  when 2
         | 
| 145 | 
            -
                    ltag | 
| 142 | 
            +
                    ltag = :left
         | 
| 143 | 
            +
                    left = hashes[0]
         | 
| 144 | 
            +
                    rtag = :right
         | 
| 145 | 
            +
                    right = hashes[1]
         | 
| 146 146 | 
             
                  else
         | 
| 147 147 | 
             
                    raise ArgumentError, "wrong number of arguments (#{hashes.length} for 2 or 4)"
         | 
| 148 148 | 
             
                  end
         | 
| 149 149 | 
             
                  (left.keys | right.keys).each do |k|
         | 
| 150 150 | 
             
                    if left[k] != right[k]
         | 
| 151 | 
            -
                      if left[k].is_a?(Hash) && right[k].is_a?(Hash)
         | 
| 152 | 
            -
             | 
| 153 | 
            -
             | 
| 154 | 
            -
             | 
| 155 | 
            -
             | 
| 151 | 
            +
                      diff[k] = if left[k].is_a?(Hash) && right[k].is_a?(Hash)
         | 
| 152 | 
            +
                                  deep_diff(ltag, left[k], rtag, right[k])
         | 
| 153 | 
            +
                                else
         | 
| 154 | 
            +
                                  Hash.[](ltag, left[k], rtag, right[k])
         | 
| 155 | 
            +
                                end
         | 
| 156 156 | 
             
                    end
         | 
| 157 157 | 
             
                  end
         | 
| 158 158 | 
             
                  diff
         | 
| @@ -161,14 +161,14 @@ module Serializer | |
| 161 161 | 
             
                # @api internal
         | 
| 162 162 | 
             
                # @return [String] Generate JSON output from a hash of the object's variables
         | 
| 163 163 | 
             
                def to_json(summary = false)
         | 
| 164 | 
            -
                  hash =  | 
| 164 | 
            +
                  hash = to_hash(summary)
         | 
| 165 165 | 
             
                  JSON.pretty_generate(hash)
         | 
| 166 166 | 
             
                end
         | 
| 167 167 |  | 
| 168 168 | 
             
                # @api internal
         | 
| 169 169 | 
             
                # @return [String] Generate YAML output from a hash of the object's variables
         | 
| 170 170 | 
             
                def to_yaml(summary = false)
         | 
| 171 | 
            -
                   | 
| 171 | 
            +
                  to_hash(summary).to_yaml
         | 
| 172 172 | 
             
                end
         | 
| 173 173 | 
             
              end
         | 
| 174 174 | 
             
            end
         |