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