lib/sprockets/digest_utils.rb in sprockets-4.0.0.beta2 vs lib/sprockets/digest_utils.rb in sprockets-4.0.0.beta3

- old
+ new

@@ -1,5 +1,6 @@ +# frozen_string_literal: true require 'digest/md5' require 'digest/sha1' require 'digest/sha2' require 'set' @@ -32,61 +33,75 @@ # Returns Digest::Base or nil. def detect_digest_class(bytes) DIGEST_SIZES[bytes.bytesize] end + ADD_VALUE_TO_DIGEST = { + String => ->(val, digest) { digest << val }, + FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze }, + TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze }, + NilClass => ->(val, digest) { digest << 'NilClass'.freeze }, + + Symbol => ->(val, digest) { + digest << 'Symbol'.freeze + digest << val.to_s + }, + Fixnum => ->(val, digest) { + digest << 'Fixnum'.freeze + digest << val.to_s + }, + Bignum => ->(val, digest) { + digest << 'Bignum'.freeze + digest << val.to_s + }, + Array => ->(val, digest) { + digest << 'Array'.freeze + val.each do |element| + ADD_VALUE_TO_DIGEST[element.class].call(element, digest) + end + }, + Hash => ->(val, digest) { + digest << 'Hash'.freeze + val.sort.each do |array| + ADD_VALUE_TO_DIGEST[Array].call(array, digest) + end + }, + Set => ->(val, digest) { + digest << 'Set'.freeze + ADD_VALUE_TO_DIGEST[Array].call(val, digest) + }, + Encoding => ->(val, digest) { + digest << 'Encoding'.freeze + digest << val.name + }, + } + ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) { + raise TypeError, "couldn't digest #{ val }" + } + private_constant :ADD_VALUE_TO_DIGEST + # Internal: Generate a hexdigest for a nested JSON serializable object. # # This is used for generating cache keys, so its pretty important its # wicked fast. Microbenchmarks away! # # obj - A JSON serializable object. # # Returns a String digest of the object. def digest(obj) - digest = digest_class.new - queue = [obj] + build_digest(obj).digest + end - while queue.length > 0 - obj = queue.shift - klass = obj.class - - if klass == String - digest << obj - elsif klass == Symbol - digest << 'Symbol' - digest << obj.to_s - elsif klass == Fixnum - digest << 'Fixnum' - digest << obj.to_s - elsif klass == Bignum - digest << 'Bignum' - digest << obj.to_s - elsif klass == TrueClass - digest << 'TrueClass' - elsif klass == FalseClass - digest << 'FalseClass' - elsif klass == NilClass - digest << 'NilClass'.freeze - elsif klass == Array - digest << 'Array' - queue.concat(obj) - elsif klass == Hash - digest << 'Hash' - queue.concat(obj.sort) - elsif klass == Set - digest << 'Set' - queue.concat(obj.to_a) - elsif klass == Encoding - digest << 'Encoding' - digest << obj.name - else - raise TypeError, "couldn't digest #{klass}" - end - end - - digest.digest + # Internal: Generate a hexdigest for a nested JSON serializable object. + # + # The same as `pack_hexdigest(digest(obj))`. + # + # obj - A JSON serializable object. + # + # Returns a String digest of the object. + def hexdigest(obj) + build_digest(obj).hexdigest! end # Internal: Pack a binary digest to a hex encoded string. # # bin - String bytes @@ -162,7 +177,15 @@ # # Returns a String or nil if hash algorithm is incompatible. def hexdigest_integrity_uri(hexdigest) integrity_uri(unpack_hexdigest(hexdigest)) end + + private + def build_digest(obj) + digest = digest_class.new + + ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest) + digest + end end end