Class: OcflTools::OcflVerify
- Inherits:
-
Object
- Object
- OcflTools::OcflVerify
- Defined in:
- lib/ocfl_tools/ocfl_verify.rb
Overview
Class to verify that an instance of OcflObject or OcflInventory is composed of valid data and structures.
Instance Attribute Summary collapse
-
#my_results ⇒ OcflTools::OcflResults
readonly
Containing check results.
Instance Method Summary collapse
-
#check_all ⇒ Ocfltools::OcflResults
Performs all checks on the given object and reports results.
-
#check_digestAlgorithm ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the digestAlgorithm attribute.
-
#check_fixity ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed fixity block, if present.
-
#check_head ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the head attribute.
-
#check_id ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the id attribute.
-
#check_manifest ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed manifest block.
-
#check_type ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the type attribute.
-
#check_versions ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed versions block.
-
#crosscheck_digests ⇒ Ocfltools::OcflResults
Checks the contents of the manifest block against the files and digests in the versions block to verify all files necessary to re-constitute the object at any version are correctly referenced in the OCFL Object.
-
#initialize(ocfl_object) ⇒ OcflVerify
constructor
Create a new OCFLVerify object, using an OcflTools::Ocflobject as source.
-
#preflight ⇒ Boolean
Verifies that the object passed to this class at instantiation responds to the expected methods and attributes.
-
#results ⇒ OcflTools::OcflResults
against this object.
Constructor Details
#initialize(ocfl_object) ⇒ OcflVerify
Create a new OCFLVerify object, using an OcflTools::Ocflobject as source.
11 12 13 14 15 16 17 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 11 def initialize(ocfl_object) @my_victim = ocfl_object @my_results = OcflTools::OcflResults.new # check .respond_to? first for all expected methods. preflight end |
Instance Attribute Details
#my_results ⇒ OcflTools::OcflResults (readonly)
Returns containing check results.
7 8 9 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 7 def my_results @my_results end |
Instance Method Details
#check_all ⇒ Ocfltools::OcflResults
Performs all checks on the given object and reports results.
27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 27 def check_all # Duck-typing the heck out of this, assuming @my_victim will respond to ocflobject methods. check_id check_type check_head check_fixity check_manifest check_versions crosscheck_digests check_digestAlgorithm @my_results end |
#check_digestAlgorithm ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the digestAlgorithm attribute.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 105 def check_digestAlgorithm # If there's no digestAlgorithm set in the inventory, that's a showstopper. if @my_victim.digestAlgorithm == nil @my_results.error('E222', 'check_digestAlgorithm', "Algorithm cannot be nil") return @my_results end # must be one of sha256 or sha512 if @my_victim.digestAlgorithm.downcase == 'sha256' @my_results.ok('O200', 'check_digestAlgorithm', 'OCFL 3.5.1 Inventory Algorithm is OK.') @my_results.info('I220', 'check_digestAlgorithm', "OCFL 3.5.1 #{@my_victim.digestAlgorithm.downcase} is a supported digest algorithm.") @my_results.warn('W220', 'check_digestAlgorithm', "OCFL 3.5.1 #{@my_victim.digestAlgorithm.downcase} SHOULD be Sha512.") elsif @my_victim.digestAlgorithm.downcase == 'sha512' @my_results.ok('O200', 'check_digestAlgorithm', 'OCFL 3.5.1 Inventory Algorithm is OK.') @my_results.info('I220', 'check_digestAlgorithm', "OCFL 3.5.1 #{@my_victim.digestAlgorithm.downcase} is a supported digest algorithm.") else @my_results.error('E223', 'check_digestAlgorithm', "OCFL 3.5.1 Algorithm #{@my_victim.digestAlgorithm} is not valid for OCFL use.") end @my_results end |
#check_fixity ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed fixity block, if present. We do not compute fixity here; only check existence.
212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 212 def check_fixity # If present, should have at least 1 sub-key and 1 value. errors = nil unless @my_victim.fixity.empty? @my_results.info('I111', 'check_fixity', 'Fixity block is present.') end # Set OcflTools.config.fixity_algorithms for what to look for. @my_victim.fixity.each do |algorithm, _digest| unless OcflTools.config.fixity_algorithms.include? algorithm @my_results.error('E111', 'check_fixity', "Fixity block contains unsupported algorithm #{algorithm}") errors = true end end if errors.nil? && !@my_victim.fixity.empty? @my_results.ok('O111', 'check_fixity', 'Fixity block is present and contains valid algorithms.') end @my_results end |
#check_head ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the head attribute.
67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 67 def check_head case @my_victim.head when nil @my_results.error('E212', 'check_head', 'OCFL 3.5.1 @head cannot be nil') when Integer @my_results.error('E213', 'check_head', 'OCFL 3.5.1 @head cannot be an Integer') when String version = OcflTools::Utils.version_string_to_int(@my_victim.head) target_version = @my_victim.version_id_list.max if version == target_version @my_results.ok('O200', 'check_head', 'OCFL 3.5.1 Inventory Head is OK.') @my_results.info('I200', 'check_head', "OCFL 3.5.1 Inventory Head version #{version} matches highest version in versions.") else @my_results.error('E214', 'check_head', "OCFL 3.5.1 Inventory Head version #{version} does not match expected version #{target_version}") end else # default case error @my_results.error('E911', 'check_head', 'An unknown error has occurred.') end @my_results end |
#check_id ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the id attribute. Id value MUST be present and SHOULD be a URI.
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 43 def check_id case @my_victim.id when nil @my_results.error('E202', 'check_id', 'OCFL 3.5.1 Object ID cannot be nil') return @my_results when 0 @my_results.error('E201', 'check_id', 'OCFL 3.5.1 Object ID cannot be 0 length') return @my_results when !String @my_results.error('E201', 'check_id', 'OCFL 3.5.1 Object ID must be a string.') return @my_results end if @my_victim.id =~ /\A#{URI::regexp}\z/ @my_results.ok('O200', 'check_id', 'OCFL 3.5.1 Inventory ID is OK.') return @my_results else @my_results.warn('W201', 'check_id', 'OCFL 3.5.1 Inventory ID present, but does not appear to be a URI.') return @my_results end end |
#check_manifest ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed manifest block.
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 128 def check_manifest # Should pass digest cross_check. # can be null if it passes cross_check? (empty inventories are valid, but warn) # There MUST be a block called 'manifests' errors = nil if @my_victim.manifest.nil? @my_results.error('E250', 'check_manifest', 'OCFL 3.5.2 there MUST be a manifest block.') errors = true elsif @my_victim.manifest == {} @my_results.error('E251', 'check_manifest', 'OCFL 3.5.2 manifest block cannot be empty.') errors = true end # TODO: Should check that it's a hash of digests and filepaths somehow...? # Get digest Algo type, use that to get key length. # check all keys in manifest to make sure they're all that length. if errors.nil? @my_results.ok('O200', 'check_manifest', 'OCFL 3.5.2 Inventory Manifest syntax is OK.') end @my_results end |
#check_type ⇒ Ocfltools::OcflResults
Checks OCFL Object for valid value in the type attribute.
91 92 93 94 95 96 97 98 99 100 101 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 91 def check_type case @my_victim.type when nil @my_results.error('E230', 'check_type', 'OCFL 3.5.1 Required OCFL key type not found.') when 'https://ocfl.io/1.0/spec/#inventory' @my_results.ok('O200', 'check_type', 'OCFL 3.5.1 Inventory Type is OK.') else @my_results.error('E231', 'check_type', 'OCFL 3.5.1 Required OCFL key type does not match expected value.') end @my_results end |
#check_versions ⇒ Ocfltools::OcflResults
Checks OCFL Object for a well-formed versions block.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 154 def check_versions version_count = @my_victim.version_id_list.length highest_version = @my_victim.version_id_list.max my_versions = @my_victim.version_id_list.sort @version_check = nil if version_count != highest_version @my_results.error('E014', 'check_versions', "OCFL 3.5.3 Found #{version_count} versions, but highest version is #{highest_version}") @version_check = true elsif version_count == highest_version @my_results.ok('O200', 'check_versions', "OCFL 3.5.3 Found #{version_count} versions, highest version is #{highest_version}") end # should be contiguous version numbers starting at 1. count = 0 until count == highest_version # (count - 1) is a proxy for the index in @my_victim.version_id_list.sort count += 1 if count != my_versions[count - 1] @my_results.error('E015', 'check_versions', "OCFL 3.5.3 Expected version sequence not found. Expected version #{count}, found version #{my_versions[count]}.") @version_check = true end end # We do NOT need to check the @versions.keys here for 'v0001', etc. # That's already been done when we looked at version_id_list and # checked for contiguous version numbers in my_versions. @my_victim.versions.each do |version, hash| %w[created message user state].each do |key| if hash.key?(key) == false @my_results.error('E016', 'check_versions', "OCFL 3.5.3.1 version #{version} is missing #{key} block.") @version_check = true next end # key is present, does it conform? case key when 'created' check_version_created(hash['created'], version) when 'user' check_version_user(hash['user'], version) when 'state' check_version_state(hash['state'], version) when 'message' (hash['message'], version) else @my_results.error('E111', 'check_versions', "OCFL 3.5.3.1 version #{version} contains unknown key #{key} block.") @version_check = true end end end if @version_check.nil? @my_results.ok('O200', 'check_versions', 'OCFL 3.5.3.1 version syntax is OK.') end @my_results end |
#crosscheck_digests ⇒ Ocfltools::OcflResults
Checks the contents of the manifest block against the files and digests in the versions block to verify all files necessary to re-constitute the object at any version are correctly referenced in the OCFL Object.
236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 236 def crosscheck_digests # requires values in @versions and @manifest. # verifies that every digest in @versions can be found in @manifest. errors = nil my_checksums = [] @my_victim.versions.each do |version, block| if !block.is_a?(Hash) @my_results.error('E111', 'crosscheck_digests', "version #{version} block is wrong type.") next end version_digests = block['state'] if !version_digests.is_a?(Hash) @my_results.error('E111', 'crosscheck_digests', "version #{version} state block is wrong type.") next end version_digests.each_key { |k| my_checksums << k } end unique_checksums = my_checksums.uniq # First check; there should be the same number of entries on both sides. if unique_checksums.length != @my_victim.manifest.length @my_results.error('E050', 'crosscheck_digests', "OCFL 3.5.3.1 Digests missing! #{unique_checksums.length} digests in versions vs. #{@my_victim.manifest.length} digests in manifest.") errors = true end # Second check; each entry in unique_checksums should have a match in @manifest. unique_checksums.each do |checksum| if @my_victim.manifest.member?(checksum) == false @my_results.error('E051', 'crosscheck_digests', "OCFL 3.5.3.1 Checksum #{checksum} not found in manifest!") errors = true end end if errors.nil? @my_results.ok('O200', 'crosscheck_digests', 'OCFL 3.5.3.1 Digests are OK.') end @my_results end |
#preflight ⇒ Boolean
Verifies that the object passed to this class at instantiation responds to the expected methods and attributes. Raises an exception on failure.
280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 280 def preflight # check for expected instance_variables with .instance_variable_defined?(@some_var) ['@id', '@head', '@type', '@digestAlgorithm', '@contentDirectory', '@manifest', '@versions', '@fixity'].each do |var| unless @my_victim.instance_variable_defined?(var) raise "Object does not have instance var #{var} defined" end end # check for all methods we need to validate OCFL structure %w[get_files get_current_files get_state version_id_list get_digest].each do |mthd| unless @my_victim.respond_to?(mthd) raise "Object does not respond to #{mthd}" end end end |
#results ⇒ OcflTools::OcflResults
against this object.
21 22 23 |
# File 'lib/ocfl_tools/ocfl_verify.rb', line 21 def results @my_results end |