sprockets 3.0.3 → 4.2.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 (95) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +101 -0
  3. data/{LICENSE → MIT-LICENSE} +2 -2
  4. data/README.md +531 -276
  5. data/bin/sprockets +12 -7
  6. data/lib/rake/sprocketstask.rb +9 -4
  7. data/lib/sprockets/add_source_map_comment_to_asset_processor.rb +60 -0
  8. data/lib/sprockets/asset.rb +41 -28
  9. data/lib/sprockets/autoload/babel.rb +8 -0
  10. data/lib/sprockets/autoload/closure.rb +1 -0
  11. data/lib/sprockets/autoload/coffee_script.rb +1 -0
  12. data/lib/sprockets/autoload/eco.rb +1 -0
  13. data/lib/sprockets/autoload/ejs.rb +1 -0
  14. data/lib/sprockets/autoload/jsminc.rb +8 -0
  15. data/lib/sprockets/autoload/sass.rb +1 -0
  16. data/lib/sprockets/autoload/sassc.rb +8 -0
  17. data/lib/sprockets/autoload/uglifier.rb +1 -0
  18. data/lib/sprockets/autoload/yui.rb +1 -0
  19. data/lib/sprockets/autoload/zopfli.rb +7 -0
  20. data/lib/sprockets/autoload.rb +5 -0
  21. data/lib/sprockets/babel_processor.rb +66 -0
  22. data/lib/sprockets/base.rb +61 -13
  23. data/lib/sprockets/bower.rb +6 -3
  24. data/lib/sprockets/bundle.rb +41 -5
  25. data/lib/sprockets/cache/file_store.rb +32 -7
  26. data/lib/sprockets/cache/memory_store.rb +28 -10
  27. data/lib/sprockets/cache/null_store.rb +8 -0
  28. data/lib/sprockets/cache.rb +43 -6
  29. data/lib/sprockets/cached_environment.rb +15 -20
  30. data/lib/sprockets/closure_compressor.rb +6 -11
  31. data/lib/sprockets/coffee_script_processor.rb +20 -6
  32. data/lib/sprockets/compressing.rb +62 -2
  33. data/lib/sprockets/configuration.rb +5 -9
  34. data/lib/sprockets/context.rb +99 -25
  35. data/lib/sprockets/dependencies.rb +10 -9
  36. data/lib/sprockets/digest_utils.rb +103 -62
  37. data/lib/sprockets/directive_processor.rb +64 -36
  38. data/lib/sprockets/eco_processor.rb +4 -3
  39. data/lib/sprockets/ejs_processor.rb +4 -3
  40. data/lib/sprockets/encoding_utils.rb +1 -0
  41. data/lib/sprockets/environment.rb +9 -4
  42. data/lib/sprockets/erb_processor.rb +34 -21
  43. data/lib/sprockets/errors.rb +1 -0
  44. data/lib/sprockets/exporters/base.rb +71 -0
  45. data/lib/sprockets/exporters/file_exporter.rb +24 -0
  46. data/lib/sprockets/exporters/zlib_exporter.rb +33 -0
  47. data/lib/sprockets/exporters/zopfli_exporter.rb +14 -0
  48. data/lib/sprockets/exporting.rb +73 -0
  49. data/lib/sprockets/file_reader.rb +1 -0
  50. data/lib/sprockets/http_utils.rb +25 -7
  51. data/lib/sprockets/jsminc_compressor.rb +32 -0
  52. data/lib/sprockets/jst_processor.rb +11 -10
  53. data/lib/sprockets/loader.rb +244 -62
  54. data/lib/sprockets/manifest.rb +100 -46
  55. data/lib/sprockets/manifest_utils.rb +9 -6
  56. data/lib/sprockets/mime.rb +8 -42
  57. data/lib/sprockets/npm.rb +52 -0
  58. data/lib/sprockets/path_dependency_utils.rb +3 -11
  59. data/lib/sprockets/path_digest_utils.rb +2 -1
  60. data/lib/sprockets/path_utils.rb +107 -22
  61. data/lib/sprockets/paths.rb +1 -0
  62. data/lib/sprockets/preprocessors/default_source_map.rb +49 -0
  63. data/lib/sprockets/processing.rb +32 -52
  64. data/lib/sprockets/processor_utils.rb +38 -39
  65. data/lib/sprockets/resolve.rb +177 -97
  66. data/lib/sprockets/sass_cache_store.rb +1 -0
  67. data/lib/sprockets/sass_compressor.rb +21 -17
  68. data/lib/sprockets/sass_functions.rb +1 -0
  69. data/lib/sprockets/sass_importer.rb +1 -0
  70. data/lib/sprockets/sass_processor.rb +46 -18
  71. data/lib/sprockets/sassc_compressor.rb +56 -0
  72. data/lib/sprockets/sassc_processor.rb +297 -0
  73. data/lib/sprockets/server.rb +77 -44
  74. data/lib/sprockets/source_map_processor.rb +66 -0
  75. data/lib/sprockets/source_map_utils.rb +483 -0
  76. data/lib/sprockets/transformers.rb +63 -35
  77. data/lib/sprockets/uglifier_compressor.rb +23 -20
  78. data/lib/sprockets/unloaded_asset.rb +139 -0
  79. data/lib/sprockets/uri_tar.rb +99 -0
  80. data/lib/sprockets/uri_utils.rb +14 -14
  81. data/lib/sprockets/utils/gzip.rb +99 -0
  82. data/lib/sprockets/utils.rb +63 -71
  83. data/lib/sprockets/version.rb +2 -1
  84. data/lib/sprockets/yui_compressor.rb +5 -14
  85. data/lib/sprockets.rb +105 -33
  86. metadata +157 -27
  87. data/lib/sprockets/coffee_script_template.rb +0 -6
  88. data/lib/sprockets/eco_template.rb +0 -6
  89. data/lib/sprockets/ejs_template.rb +0 -6
  90. data/lib/sprockets/engines.rb +0 -81
  91. data/lib/sprockets/erb_template.rb +0 -6
  92. data/lib/sprockets/legacy.rb +0 -314
  93. data/lib/sprockets/legacy_proc_processor.rb +0 -35
  94. data/lib/sprockets/legacy_tilt_processor.rb +0 -29
  95. data/lib/sprockets/sass_template.rb +0 -7
@@ -1,10 +1,10 @@
1
- require 'pathname'
1
+ # frozen_string_literal: true
2
2
  require 'rack/utils'
3
3
  require 'set'
4
4
  require 'sprockets/errors'
5
+ require 'delegate'
5
6
 
6
7
  module Sprockets
7
- # Deprecated: `Context` provides helper methods to all processors.
8
8
  # They are typically accessed by ERB templates. You can mix in custom helpers
9
9
  # by injecting them into `Environment#context_class`. Do not mix them into
10
10
  # `Context` directly.
@@ -19,10 +19,25 @@ module Sprockets
19
19
  # The `Context` also collects dependencies declared by
20
20
  # assets. See `DirectiveProcessor` for an example of this.
21
21
  class Context
22
- attr_reader :environment, :filename, :pathname
22
+ # Internal: Proxy for ENV that keeps track of the environment variables used
23
+ class ENVProxy < SimpleDelegator
24
+ def initialize(context)
25
+ @context = context
26
+ super(ENV)
27
+ end
23
28
 
24
- # Deprecated
25
- attr_accessor :__LINE__
29
+ def [](key)
30
+ @context.depend_on_env(key)
31
+ super
32
+ end
33
+
34
+ def fetch(key, *)
35
+ @context.depend_on_env(key)
36
+ super
37
+ end
38
+ end
39
+
40
+ attr_reader :environment, :filename
26
41
 
27
42
  def initialize(input)
28
43
  @environment = input[:environment]
@@ -31,7 +46,6 @@ module Sprockets
31
46
  @logical_path = input[:name]
32
47
  @filename = input[:filename]
33
48
  @dirname = File.dirname(@filename)
34
- @pathname = Pathname.new(@filename)
35
49
  @content_type = input[:content_type]
36
50
 
37
51
  @required = Set.new(@metadata[:required])
@@ -47,6 +61,10 @@ module Sprockets
47
61
  dependencies: @dependencies }
48
62
  end
49
63
 
64
+ def env_proxy
65
+ ENVProxy.new(self)
66
+ end
67
+
50
68
  # Returns the environment path that contains the file.
51
69
  #
52
70
  # If `app/javascripts` and `app/stylesheets` are in your path, and
@@ -79,13 +97,13 @@ module Sprockets
79
97
  # resolve("./bar.js")
80
98
  # # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
81
99
  #
82
- # path - String logical or absolute path
83
- # options
84
- # accept - String content accept type
100
+ # path - String logical or absolute path
101
+ # accept - String content accept type
85
102
  #
86
103
  # Returns an Asset URI String.
87
- def resolve(path, options = {})
88
- uri, deps = environment.resolve!(path, options.merge(base_path: @dirname))
104
+ def resolve(path, **kargs)
105
+ kargs[:base_path] = @dirname
106
+ uri, deps = environment.resolve!(path, **kargs)
89
107
  @dependencies.merge(deps)
90
108
  uri
91
109
  end
@@ -105,15 +123,13 @@ module Sprockets
105
123
  # including it.
106
124
  #
107
125
  # This is used for caching purposes. Any changes made to
108
- # the dependency file with invalidate the cache of the
126
+ # the dependency file will invalidate the cache of the
109
127
  # source file.
110
128
  def depend_on(path)
111
- path = path.to_s if path.is_a?(Pathname)
112
-
113
129
  if environment.absolute_path?(path) && environment.stat(path)
114
130
  @dependencies << environment.build_file_digest_uri(path)
115
131
  else
116
- resolve(path, compat: false)
132
+ resolve(path)
117
133
  end
118
134
  nil
119
135
  end
@@ -123,10 +139,19 @@ module Sprockets
123
139
  #
124
140
  # This is used for caching purposes. Any changes that would
125
141
  # invalidate the dependency asset will invalidate the source
126
- # file. Unlike `depend_on`, this will include recursively include
142
+ # file. Unlike `depend_on`, this will recursively include
127
143
  # the target asset's dependencies.
128
144
  def depend_on_asset(path)
129
- load(resolve(path, compat: false))
145
+ load(resolve(path))
146
+ end
147
+
148
+ # `depend_on_env` allows you to state a dependency on an environment
149
+ # variable.
150
+ #
151
+ # This is used for caching purposes. Any changes in the value of the
152
+ # environment variable will invalidate the cache of the source file.
153
+ def depend_on_env(key)
154
+ @dependencies << "env:#{key}"
130
155
  end
131
156
 
132
157
  # `require_asset` declares `path` as a dependency of the file. The
@@ -139,7 +164,7 @@ module Sprockets
139
164
  # <%= require_asset "#{framework}.js" %>
140
165
  #
141
166
  def require_asset(path)
142
- @required << resolve(path, accept: @content_type, pipeline: :self, compat: false)
167
+ @required << resolve(path, accept: @content_type, pipeline: :self)
143
168
  nil
144
169
  end
145
170
 
@@ -147,7 +172,7 @@ module Sprockets
147
172
  # `path` must be an asset which may or may not already be included
148
173
  # in the bundle.
149
174
  def stub_asset(path)
150
- @stubbed << resolve(path, accept: @content_type, pipeline: :self, compat: false)
175
+ @stubbed << resolve(path, accept: @content_type, pipeline: :self)
151
176
  nil
152
177
  end
153
178
 
@@ -162,9 +187,10 @@ module Sprockets
162
187
  asset
163
188
  end
164
189
 
165
- # Returns a Base64-encoded `data:` URI with the contents of the
166
- # asset at the specified path, and marks that path as a dependency
167
- # of the current file.
190
+ # Returns a `data:` URI with the contents of the asset at the specified
191
+ # path, and marks that path as a dependency of the current file.
192
+ #
193
+ # Uses URI encoding for SVG files, base64 encoding for all the other files.
168
194
  #
169
195
  # Use `asset_data_uri` from ERB with CSS or JavaScript assets:
170
196
  #
@@ -174,15 +200,18 @@ module Sprockets
174
200
  #
175
201
  def asset_data_uri(path)
176
202
  asset = depend_on_asset(path)
177
- data = EncodingUtils.base64(asset.source)
178
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(data)}"
203
+ if asset.content_type == 'image/svg+xml'
204
+ svg_asset_data_uri(asset)
205
+ else
206
+ base64_asset_data_uri(asset)
207
+ end
179
208
  end
180
209
 
181
210
  # Expands logical path to full url to asset.
182
211
  #
183
212
  # NOTE: This helper is currently not implemented and should be
184
213
  # customized by the application. Though, in the future, some
185
- # basics implemention may be provided with different methods that
214
+ # basic implementation may be provided with different methods that
186
215
  # are required to be overridden.
187
216
  def asset_path(path, options = {})
188
217
  message = <<-EOS
@@ -227,5 +256,50 @@ Extend your environment context with a custom method.
227
256
  def stylesheet_path(path)
228
257
  asset_path(path, type: :stylesheet)
229
258
  end
259
+
260
+ protected
261
+
262
+ # Returns a URI-encoded data URI (always "-quoted).
263
+ def svg_asset_data_uri(asset)
264
+ svg = asset.source.dup
265
+ optimize_svg_for_uri_escaping!(svg)
266
+ data = Rack::Utils.escape(svg)
267
+ optimize_quoted_uri_escapes!(data)
268
+ "\"data:#{asset.content_type};charset=utf-8,#{data}\""
269
+ end
270
+
271
+ # Returns a Base64-encoded data URI.
272
+ def base64_asset_data_uri(asset)
273
+ data = Rack::Utils.escape(EncodingUtils.base64(asset.source))
274
+ "data:#{asset.content_type};base64,#{data}"
275
+ end
276
+
277
+ # Optimizes an SVG for being URI-escaped.
278
+ #
279
+ # This method only performs these basic but crucial optimizations:
280
+ # * Replaces " with ', because ' does not need escaping.
281
+ # * Removes comments, meta, doctype, and newlines.
282
+ # * Collapses whitespace.
283
+ def optimize_svg_for_uri_escaping!(svg)
284
+ # Remove comments, xml meta, and doctype
285
+ svg.gsub!(/<!--.*?-->|<\?.*?\?>|<!.*?>/m, '')
286
+ # Replace consecutive whitespace and newlines with a space
287
+ svg.gsub!(/\s+/, ' ')
288
+ # Collapse inter-tag whitespace
289
+ svg.gsub!('> <', '><')
290
+ # Replace " with '
291
+ svg.gsub!(/([\w:])="(.*?)"/, "\\1='\\2'")
292
+ svg.strip!
293
+ end
294
+
295
+ # Un-escapes characters in the given URI-escaped string that do not need
296
+ # escaping in "-quoted data URIs.
297
+ def optimize_quoted_uri_escapes!(escaped)
298
+ escaped.gsub!('%3D', '=')
299
+ escaped.gsub!('%3A', ':')
300
+ escaped.gsub!('%2F', '/')
301
+ escaped.gsub!('%27', "'")
302
+ escaped.tr!('+', ' ')
303
+ end
230
304
  end
231
305
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  require 'sprockets/digest_utils'
2
3
  require 'sprockets/path_digest_utils'
3
4
  require 'sprockets/uri_utils'
@@ -39,7 +40,7 @@ module Sprockets
39
40
  end
40
41
  end
41
42
 
42
- # Public: Add environmental dependency inheirted by all assets.
43
+ # Public: Add environmental dependency inherited by all assets.
43
44
  #
44
45
  # uri - String dependency URI
45
46
  #
@@ -51,18 +52,18 @@ module Sprockets
51
52
  end
52
53
  alias_method :depend_on, :add_dependency
53
54
 
54
- # Internal: Resolve set of dependency URIs.
55
- #
56
- # Returns Array of resolved Objects.
57
- def resolve_dependencies(uris)
58
- uris.map { |uri| resolve_dependency(uri) }
59
- end
60
-
61
55
  # Internal: Resolve dependency URIs.
62
56
  #
63
57
  # Returns resolved Object.
64
58
  def resolve_dependency(str)
65
- scheme = str[/([^:]+)/, 1]
59
+ # Optimize for the most common scheme to
60
+ # save 22k allocations on an average Spree app.
61
+ scheme = if str.start_with?('file-digest:'.freeze)
62
+ 'file-digest'.freeze
63
+ else
64
+ str[/([^:]+)/, 1]
65
+ end
66
+
66
67
  if resolver = config[:dependency_resolvers][scheme]
67
68
  resolver.call(self, str)
68
69
  else
@@ -1,4 +1,4 @@
1
- require 'digest/md5'
1
+ # frozen_string_literal: true
2
2
  require 'digest/sha1'
3
3
  require 'digest/sha2'
4
4
  require 'set'
@@ -18,7 +18,6 @@ module Sprockets
18
18
 
19
19
  # Internal: Maps digest bytesize to the digest class.
20
20
  DIGEST_SIZES = {
21
- 16 => Digest::MD5,
22
21
  20 => Digest::SHA1,
23
22
  32 => Digest::SHA256,
24
23
  48 => Digest::SHA384,
@@ -34,6 +33,49 @@ module Sprockets
34
33
  DIGEST_SIZES[bytes.bytesize]
35
34
  end
36
35
 
36
+ ADD_VALUE_TO_DIGEST = {
37
+ String => ->(val, digest) { digest << val },
38
+ FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
39
+ TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
40
+ NilClass => ->(val, digest) { digest << 'NilClass'.freeze },
41
+
42
+ Symbol => ->(val, digest) {
43
+ digest << 'Symbol'.freeze
44
+ digest << val.to_s
45
+ },
46
+ Integer => ->(val, digest) {
47
+ digest << 'Integer'.freeze
48
+ digest << val.to_s
49
+ },
50
+ Array => ->(val, digest) {
51
+ digest << 'Array'.freeze
52
+ val.each do |element|
53
+ ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
54
+ end
55
+ },
56
+ Hash => ->(val, digest) {
57
+ digest << 'Hash'.freeze
58
+ val.sort.each do |array|
59
+ ADD_VALUE_TO_DIGEST[Array].call(array, digest)
60
+ end
61
+ },
62
+ Set => ->(val, digest) {
63
+ digest << 'Set'.freeze
64
+ ADD_VALUE_TO_DIGEST[Array].call(val, digest)
65
+ },
66
+ Encoding => ->(val, digest) {
67
+ digest << 'Encoding'.freeze
68
+ digest << val.name
69
+ }
70
+ }
71
+
72
+ ADD_VALUE_TO_DIGEST.compare_by_identity.rehash
73
+
74
+ ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
75
+ raise TypeError, "couldn't digest #{ val }"
76
+ }
77
+ private_constant :ADD_VALUE_TO_DIGEST
78
+
37
79
  # Internal: Generate a hexdigest for a nested JSON serializable object.
38
80
  #
39
81
  # This is used for generating cache keys, so its pretty important its
@@ -43,48 +85,18 @@ module Sprockets
43
85
  #
44
86
  # Returns a String digest of the object.
45
87
  def digest(obj)
46
- digest = digest_class.new
47
- queue = [obj]
48
-
49
- while queue.length > 0
50
- obj = queue.shift
51
- klass = obj.class
52
-
53
- if klass == String
54
- digest << obj
55
- elsif klass == Symbol
56
- digest << 'Symbol'
57
- digest << obj.to_s
58
- elsif klass == Fixnum
59
- digest << 'Fixnum'
60
- digest << obj.to_s
61
- elsif klass == Bignum
62
- digest << 'Bignum'
63
- digest << obj.to_s
64
- elsif klass == TrueClass
65
- digest << 'TrueClass'
66
- elsif klass == FalseClass
67
- digest << 'FalseClass'
68
- elsif klass == NilClass
69
- digest << 'NilClass'
70
- elsif klass == Array
71
- digest << 'Array'
72
- queue.concat(obj)
73
- elsif klass == Hash
74
- digest << 'Hash'
75
- queue.concat(obj.sort)
76
- elsif klass == Set
77
- digest << 'Set'
78
- queue.concat(obj.to_a)
79
- elsif klass == Encoding
80
- digest << 'Encoding'
81
- digest << obj.name
82
- else
83
- raise TypeError, "couldn't digest #{klass}"
84
- end
85
- end
88
+ build_digest(obj).digest
89
+ end
86
90
 
87
- digest.digest
91
+ # Internal: Generate a hexdigest for a nested JSON serializable object.
92
+ #
93
+ # The same as `pack_hexdigest(digest(obj))`.
94
+ #
95
+ # obj - A JSON serializable object.
96
+ #
97
+ # Returns a String digest of the object.
98
+ def hexdigest(obj)
99
+ build_digest(obj).hexdigest!
88
100
  end
89
101
 
90
102
  # Internal: Pack a binary digest to a hex encoded string.
@@ -93,7 +105,16 @@ module Sprockets
93
105
  #
94
106
  # Returns hex String.
95
107
  def pack_hexdigest(bin)
96
- bin.unpack('H*').first
108
+ bin.unpack('H*'.freeze).first
109
+ end
110
+
111
+ # Internal: Unpack a hex encoded digest string into binary bytes.
112
+ #
113
+ # hex - String hex
114
+ #
115
+ # Returns binary String.
116
+ def unpack_hexdigest(hex)
117
+ [hex].pack('H*')
97
118
  end
98
119
 
99
120
  # Internal: Pack a binary digest to a base64 encoded string.
@@ -117,25 +138,20 @@ module Sprockets
117
138
  str
118
139
  end
119
140
 
120
- # Internal: Maps digest class to the named information hash algorithm name.
121
- #
122
- # http://www.iana.org/assignments/named-information/named-information.xhtml
123
- NI_HASH_ALGORITHMS = {
124
- Digest::SHA256 => 'sha-256'.freeze,
125
- Digest::SHA384 => 'sha-384'.freeze,
126
- Digest::SHA512 => 'sha-512'.freeze
141
+ # Internal: Maps digest class to the CSP hash algorithm name.
142
+ HASH_ALGORITHMS = {
143
+ Digest::SHA256 => 'sha256'.freeze,
144
+ Digest::SHA384 => 'sha384'.freeze,
145
+ Digest::SHA512 => 'sha512'.freeze
127
146
  }
128
147
 
129
- # Internal: Generate a "named information" URI for use in the `integrity`
130
- # attribute of an asset tag as per the subresource integrity specification.
148
+ # Public: Generate hash for use in the `integrity` attribute of an asset tag
149
+ # as per the subresource integrity specification.
131
150
  #
132
- # digest - The String byte digest of the asset content.
133
- # content_type - The content-type the asset will be served with. This *must*
134
- # be accurate if provided. Otherwise, subresource integrity
135
- # will block the loading of the asset.
151
+ # digest - The String byte digest of the asset content.
136
152
  #
137
153
  # Returns a String or nil if hash algorithm is incompatible.
138
- def integrity_uri(digest, content_type = nil)
154
+ def integrity_uri(digest)
139
155
  case digest
140
156
  when Digest::Base
141
157
  digest_class = digest.class
@@ -146,11 +162,36 @@ module Sprockets
146
162
  raise TypeError, "unknown digest: #{digest.inspect}"
147
163
  end
148
164
 
149
- if hash_name = NI_HASH_ALGORITHMS[digest_class]
150
- uri = "ni:///#{hash_name};#{pack_urlsafe_base64digest(digest)}"
151
- uri << "?ct=#{content_type}" if content_type
152
- uri
165
+ if hash_name = HASH_ALGORITHMS[digest_class]
166
+ "#{hash_name}-#{pack_base64digest(digest)}"
153
167
  end
154
168
  end
169
+
170
+ # Public: Generate hash for use in the `integrity` attribute of an asset tag
171
+ # as per the subresource integrity specification.
172
+ #
173
+ # digest - The String hexbyte digest of the asset content.
174
+ #
175
+ # Returns a String or nil if hash algorithm is incompatible.
176
+ def hexdigest_integrity_uri(hexdigest)
177
+ integrity_uri(unpack_hexdigest(hexdigest))
178
+ end
179
+
180
+ # Internal: Checks an asset name for a valid digest
181
+ #
182
+ # name - The name of the asset
183
+ #
184
+ # Returns true if the name contains a digest like string and .digested before the extension
185
+ def already_digested?(name)
186
+ return name =~ /-([0-9a-zA-Z]{7,128})\.digested/
187
+ end
188
+
189
+ private
190
+ def build_digest(obj)
191
+ digest = digest_class.new
192
+
193
+ ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
194
+ digest
195
+ end
155
196
  end
156
197
  end