sprockets 2.3.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of sprockets might be problematic. Click here for more details.

Files changed (84) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +2 -2
  3. data/README.md +332 -115
  4. data/bin/sprockets +8 -0
  5. data/lib/rake/sprocketstask.rb +25 -13
  6. data/lib/sprockets/asset.rb +143 -205
  7. data/lib/sprockets/autoload/closure.rb +7 -0
  8. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  9. data/lib/sprockets/autoload/eco.rb +7 -0
  10. data/lib/sprockets/autoload/ejs.rb +7 -0
  11. data/lib/sprockets/autoload/sass.rb +7 -0
  12. data/lib/sprockets/autoload/uglifier.rb +7 -0
  13. data/lib/sprockets/autoload/yui.rb +7 -0
  14. data/lib/sprockets/autoload.rb +11 -0
  15. data/lib/sprockets/base.rb +49 -257
  16. data/lib/sprockets/bower.rb +58 -0
  17. data/lib/sprockets/bundle.rb +65 -0
  18. data/lib/sprockets/cache/file_store.rb +165 -14
  19. data/lib/sprockets/cache/memory_store.rb +66 -0
  20. data/lib/sprockets/cache/null_store.rb +46 -0
  21. data/lib/sprockets/cache.rb +234 -0
  22. data/lib/sprockets/cached_environment.rb +69 -0
  23. data/lib/sprockets/closure_compressor.rb +53 -0
  24. data/lib/sprockets/coffee_script_processor.rb +25 -0
  25. data/lib/sprockets/coffee_script_template.rb +6 -0
  26. data/lib/sprockets/compressing.rb +74 -0
  27. data/lib/sprockets/configuration.rb +83 -0
  28. data/lib/sprockets/context.rb +125 -131
  29. data/lib/sprockets/dependencies.rb +73 -0
  30. data/lib/sprockets/digest_utils.rb +156 -0
  31. data/lib/sprockets/directive_processor.rb +209 -211
  32. data/lib/sprockets/eco_processor.rb +32 -0
  33. data/lib/sprockets/eco_template.rb +3 -35
  34. data/lib/sprockets/ejs_processor.rb +31 -0
  35. data/lib/sprockets/ejs_template.rb +3 -34
  36. data/lib/sprockets/encoding_utils.rb +258 -0
  37. data/lib/sprockets/engines.rb +45 -38
  38. data/lib/sprockets/environment.rb +17 -67
  39. data/lib/sprockets/erb_processor.rb +30 -0
  40. data/lib/sprockets/erb_template.rb +6 -0
  41. data/lib/sprockets/errors.rb +6 -13
  42. data/lib/sprockets/file_reader.rb +15 -0
  43. data/lib/sprockets/http_utils.rb +115 -0
  44. data/lib/sprockets/jst_processor.rb +35 -19
  45. data/lib/sprockets/legacy.rb +314 -0
  46. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  47. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  48. data/lib/sprockets/loader.rb +176 -0
  49. data/lib/sprockets/manifest.rb +179 -98
  50. data/lib/sprockets/manifest_utils.rb +45 -0
  51. data/lib/sprockets/mime.rb +114 -32
  52. data/lib/sprockets/path_dependency_utils.rb +85 -0
  53. data/lib/sprockets/path_digest_utils.rb +47 -0
  54. data/lib/sprockets/path_utils.rb +282 -0
  55. data/lib/sprockets/paths.rb +81 -0
  56. data/lib/sprockets/processing.rb +157 -189
  57. data/lib/sprockets/processor_utils.rb +103 -0
  58. data/lib/sprockets/resolve.rb +208 -0
  59. data/lib/sprockets/sass_cache_store.rb +19 -15
  60. data/lib/sprockets/sass_compressor.rb +59 -0
  61. data/lib/sprockets/sass_functions.rb +2 -0
  62. data/lib/sprockets/sass_importer.rb +2 -29
  63. data/lib/sprockets/sass_processor.rb +285 -0
  64. data/lib/sprockets/sass_template.rb +4 -44
  65. data/lib/sprockets/server.rb +109 -84
  66. data/lib/sprockets/transformers.rb +145 -0
  67. data/lib/sprockets/uglifier_compressor.rb +63 -0
  68. data/lib/sprockets/uri_utils.rb +190 -0
  69. data/lib/sprockets/utils.rb +193 -44
  70. data/lib/sprockets/version.rb +1 -1
  71. data/lib/sprockets/yui_compressor.rb +65 -0
  72. data/lib/sprockets.rb +144 -53
  73. metadata +248 -238
  74. data/lib/sprockets/asset_attributes.rb +0 -126
  75. data/lib/sprockets/bundled_asset.rb +0 -79
  76. data/lib/sprockets/caching.rb +0 -96
  77. data/lib/sprockets/charset_normalizer.rb +0 -41
  78. data/lib/sprockets/index.rb +0 -99
  79. data/lib/sprockets/processed_asset.rb +0 -152
  80. data/lib/sprockets/processor.rb +0 -32
  81. data/lib/sprockets/safety_colons.rb +0 -28
  82. data/lib/sprockets/scss_template.rb +0 -13
  83. data/lib/sprockets/static_asset.rb +0 -57
  84. data/lib/sprockets/trail.rb +0 -90
@@ -1,15 +1,13 @@
1
- require 'base64'
2
- require 'rack/utils'
3
- require 'sprockets/errors'
4
- require 'sprockets/utils'
5
1
  require 'pathname'
2
+ require 'rack/utils'
6
3
  require 'set'
4
+ require 'sprockets/errors'
7
5
 
8
6
  module Sprockets
9
- # `Context` provides helper methods to all `Tilt` processors. They
10
- # are typically accessed by ERB templates. You can mix in custom
11
- # helpers by injecting them into `Environment#context_class`. Do not
12
- # mix them into `Context` directly.
7
+ # Deprecated: `Context` provides helper methods to all processors.
8
+ # They are typically accessed by ERB templates. You can mix in custom helpers
9
+ # by injecting them into `Environment#context_class`. Do not mix them into
10
+ # `Context` directly.
13
11
  #
14
12
  # environment.context_class.class_eval do
15
13
  # include MyHelper
@@ -21,88 +19,86 @@ module Sprockets
21
19
  # The `Context` also collects dependencies declared by
22
20
  # assets. See `DirectiveProcessor` for an example of this.
23
21
  class Context
24
- attr_reader :environment, :pathname
25
- attr_reader :_required_paths, :_stubbed_assets
26
- attr_reader :_dependency_paths, :_dependency_assets
27
- attr_writer :__LINE__
28
-
29
- def initialize(environment, logical_path, pathname)
30
- @environment = environment
31
- @logical_path = logical_path
32
- @pathname = pathname
33
- @__LINE__ = nil
22
+ attr_reader :environment, :filename, :pathname
23
+
24
+ # Deprecated
25
+ attr_accessor :__LINE__
26
+
27
+ def initialize(input)
28
+ @environment = input[:environment]
29
+ @metadata = input[:metadata]
30
+ @load_path = input[:load_path]
31
+ @logical_path = input[:name]
32
+ @filename = input[:filename]
33
+ @dirname = File.dirname(@filename)
34
+ @pathname = Pathname.new(@filename)
35
+ @content_type = input[:content_type]
36
+
37
+ @required = Set.new(@metadata[:required])
38
+ @stubbed = Set.new(@metadata[:stubbed])
39
+ @links = Set.new(@metadata[:links])
40
+ @dependencies = Set.new(input[:metadata][:dependencies])
41
+ end
34
42
 
35
- @_required_paths = []
36
- @_stubbed_assets = Set.new
37
- @_dependency_paths = Set.new
38
- @_dependency_assets = Set.new([pathname.to_s])
43
+ def metadata
44
+ { required: @required,
45
+ stubbed: @stubbed,
46
+ links: @links,
47
+ dependencies: @dependencies }
39
48
  end
40
49
 
41
50
  # Returns the environment path that contains the file.
42
51
  #
43
52
  # If `app/javascripts` and `app/stylesheets` are in your path, and
44
- # current file is `app/javascripts/foo/bar.js`, `root_path` would
53
+ # current file is `app/javascripts/foo/bar.js`, `load_path` would
45
54
  # return `app/javascripts`.
46
- def root_path
47
- environment.paths.detect { |path| pathname.to_s[path] }
48
- end
55
+ attr_reader :load_path
56
+ alias_method :root_path, :load_path
49
57
 
50
58
  # Returns logical path without any file extensions.
51
59
  #
52
60
  # 'app/javascripts/application.js'
53
61
  # # => 'application'
54
62
  #
55
- def logical_path
56
- @logical_path.chomp(File.extname(@logical_path))
57
- end
63
+ attr_reader :logical_path
58
64
 
59
65
  # Returns content type of file
60
66
  #
61
67
  # 'application/javascript'
62
68
  # 'text/css'
63
69
  #
64
- def content_type
65
- environment.content_type_of(pathname)
66
- end
70
+ attr_reader :content_type
67
71
 
68
- # Given a logical path, `resolve` will find and return the fully
69
- # expanded path. Relative paths will also be resolved. An optional
70
- # `:content_type` restriction can be supplied to restrict the
71
- # search.
72
+ # Public: Given a logical path, `resolve` will find and return an Asset URI.
73
+ # Relative paths will also be resolved. An accept type maybe given to
74
+ # restrict the search.
72
75
  #
73
76
  # resolve("foo.js")
74
- # # => "/path/to/app/javascripts/foo.js"
77
+ # # => "file:///path/to/app/javascripts/foo.js?type=application/javascript"
75
78
  #
76
79
  # resolve("./bar.js")
77
- # # => "/path/to/app/javascripts/bar.js"
80
+ # # => "file:///path/to/app/javascripts/bar.js?type=application/javascript"
78
81
  #
79
- def resolve(path, options = {}, &block)
80
- pathname = Pathname.new(path)
81
- attributes = environment.attributes_for(pathname)
82
-
83
- if pathname.absolute?
84
- pathname
85
-
86
- elsif content_type = options[:content_type]
87
- content_type = self.content_type if content_type == :self
88
-
89
- if attributes.format_extension
90
- if content_type != attributes.content_type
91
- raise ContentTypeMismatch, "#{path} is " +
92
- "'#{attributes.content_type}', not '#{content_type}'"
93
- end
94
- end
95
-
96
- resolve(path) do |candidate|
97
- if self.content_type == environment.content_type_of(candidate)
98
- return candidate
99
- end
100
- end
82
+ # path - String logical or absolute path
83
+ # options
84
+ # accept - String content accept type
85
+ #
86
+ # Returns an Asset URI String.
87
+ def resolve(path, options = {})
88
+ uri, deps = environment.resolve!(path, options.merge(base_path: @dirname))
89
+ @dependencies.merge(deps)
90
+ uri
91
+ end
101
92
 
102
- raise FileNotFound, "couldn't find file '#{path}'"
103
- else
104
- environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
105
- end
93
+ # Public: Load Asset by AssetURI and track it as a dependency.
94
+ #
95
+ # uri - AssetURI
96
+ #
97
+ # Returns Asset.
98
+ def load(uri)
99
+ asset = environment.load(uri)
100
+ @dependencies.merge(asset.metadata[:dependencies])
101
+ asset
106
102
  end
107
103
 
108
104
  # `depend_on` allows you to state a dependency on a file without
@@ -112,7 +108,11 @@ module Sprockets
112
108
  # the dependency file with invalidate the cache of the
113
109
  # source file.
114
110
  def depend_on(path)
115
- @_dependency_paths << resolve(path).to_s
111
+ if environment.absolute_path?(path) && environment.directory?(path)
112
+ @dependencies << environment.build_file_digest_uri(path)
113
+ else
114
+ resolve(path, compat: false)
115
+ end
116
116
  nil
117
117
  end
118
118
 
@@ -124,9 +124,7 @@ module Sprockets
124
124
  # file. Unlike `depend_on`, this will include recursively include
125
125
  # the target asset's dependencies.
126
126
  def depend_on_asset(path)
127
- filename = resolve(path).to_s
128
- @_dependency_assets << filename
129
- nil
127
+ load(resolve(path, compat: false))
130
128
  end
131
129
 
132
130
  # `require_asset` declares `path` as a dependency of the file. The
@@ -139,9 +137,7 @@ module Sprockets
139
137
  # <%= require_asset "#{framework}.js" %>
140
138
  #
141
139
  def require_asset(path)
142
- pathname = resolve(path, :content_type => :self)
143
- depend_on_asset(pathname)
144
- @_required_paths << pathname.to_s
140
+ @required << resolve(path, accept: @content_type, pipeline: :self, compat: false)
145
141
  nil
146
142
  end
147
143
 
@@ -149,55 +145,19 @@ module Sprockets
149
145
  # `path` must be an asset which may or may not already be included
150
146
  # in the bundle.
151
147
  def stub_asset(path)
152
- @_stubbed_assets << resolve(path, :content_type => :self).to_s
148
+ @stubbed << resolve(path, accept: @content_type, pipeline: :self, compat: false)
153
149
  nil
154
150
  end
155
151
 
156
- # Tests if target path is able to be safely required into the
157
- # current concatenation.
158
- def asset_requirable?(path)
159
- pathname = resolve(path)
160
- content_type = environment.content_type_of(pathname)
161
- stat = environment.stat(path)
162
- return false unless stat && stat.file?
163
- self.content_type.nil? || self.content_type == content_type
164
- end
165
-
166
- # Reads `path` and runs processors on the file.
152
+ # `link_asset` declares an external dependency on an asset without directly
153
+ # including it. The target asset is returned from this function making it
154
+ # easy to construct a link to it.
167
155
  #
168
- # This allows you to capture the result of an asset and include it
169
- # directly in another.
170
- #
171
- # <%= evaluate "bar.js" %>
172
- #
173
- def evaluate(path, options = {})
174
- pathname = resolve(path)
175
- attributes = environment.attributes_for(pathname)
176
- processors = options[:processors] || attributes.processors
177
-
178
- if options[:data]
179
- result = options[:data]
180
- else
181
- if environment.respond_to?(:default_external_encoding)
182
- mime_type = environment.mime_types(pathname.extname)
183
- encoding = environment.encoding_for_mime_type(mime_type)
184
- result = Sprockets::Utils.read_unicode(pathname, encoding)
185
- else
186
- result = Sprockets::Utils.read_unicode(pathname)
187
- end
188
- end
189
-
190
- processors.each do |processor|
191
- begin
192
- template = processor.new(pathname.to_s) { result }
193
- result = template.render(self, {})
194
- rescue Exception => e
195
- annotate_exception! e
196
- raise
197
- end
198
- end
199
-
200
- result
156
+ # Returns an Asset or nil.
157
+ def link_asset(path)
158
+ asset = depend_on_asset(path)
159
+ @links << asset.uri
160
+ asset
201
161
  end
202
162
 
203
163
  # Returns a Base64-encoded `data:` URI with the contents of the
@@ -211,25 +171,59 @@ module Sprockets
211
171
  # $('<img>').attr('src', '<%= asset_data_uri 'avatar.jpg' %>')
212
172
  #
213
173
  def asset_data_uri(path)
214
- depend_on_asset(path)
215
- asset = environment.find_asset(path)
216
- base64 = Base64.encode64(asset.to_s).gsub(/\s+/, "")
217
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
174
+ asset = depend_on_asset(path)
175
+ data = EncodingUtils.base64(asset.source)
176
+ "data:#{asset.content_type};base64,#{Rack::Utils.escape(data)}"
218
177
  end
219
178
 
220
- private
221
- # Annotates exception backtrace with the original template that
222
- # the exception was raised in.
223
- def annotate_exception!(exception)
224
- location = pathname.to_s
225
- location << ":#{@__LINE__}" if @__LINE__
179
+ # Expands logical path to full url to asset.
180
+ #
181
+ # NOTE: This helper is currently not implemented and should be
182
+ # customized by the application. Though, in the future, some
183
+ # basics implemention may be provided with different methods that
184
+ # are required to be overridden.
185
+ def asset_path(path, options = {})
186
+ message = <<-EOS
187
+ Custom asset_path helper is not implemented
226
188
 
227
- exception.extend(Sprockets::EngineError)
228
- exception.sprockets_annotation = " (in #{location})"
229
- end
189
+ Extend your environment context with a custom method.
230
190
 
231
- def logger
232
- environment.logger
191
+ environment.context_class.class_eval do
192
+ def asset_path(path, options = {})
233
193
  end
194
+ end
195
+ EOS
196
+ raise NotImplementedError, message
197
+ end
198
+
199
+ # Expand logical image asset path.
200
+ def image_path(path)
201
+ asset_path(path, type: :image)
202
+ end
203
+
204
+ # Expand logical video asset path.
205
+ def video_path(path)
206
+ asset_path(path, type: :video)
207
+ end
208
+
209
+ # Expand logical audio asset path.
210
+ def audio_path(path)
211
+ asset_path(path, type: :audio)
212
+ end
213
+
214
+ # Expand logical font asset path.
215
+ def font_path(path)
216
+ asset_path(path, type: :font)
217
+ end
218
+
219
+ # Expand logical javascript asset path.
220
+ def javascript_path(path)
221
+ asset_path(path, type: :javascript)
222
+ end
223
+
224
+ # Expand logical stylesheet asset path.
225
+ def stylesheet_path(path)
226
+ asset_path(path, type: :stylesheet)
227
+ end
234
228
  end
235
229
  end
@@ -0,0 +1,73 @@
1
+ require 'sprockets/digest_utils'
2
+ require 'sprockets/path_digest_utils'
3
+ require 'sprockets/uri_utils'
4
+
5
+ module Sprockets
6
+ # `Dependencies` is an internal mixin whose public methods are exposed on the
7
+ # `Environment` and `CachedEnvironment` classes.
8
+ module Dependencies
9
+ include DigestUtils, PathDigestUtils, URIUtils
10
+
11
+ # Public: Mapping dependency schemes to resolver functions.
12
+ #
13
+ # key - String scheme
14
+ # value - Proc.call(Environment, String)
15
+ #
16
+ # Returns Hash.
17
+ def dependency_resolvers
18
+ config[:dependency_resolvers]
19
+ end
20
+
21
+ # Public: Default set of dependency URIs for assets.
22
+ #
23
+ # Returns Set of String URIs.
24
+ def dependencies
25
+ config[:dependencies]
26
+ end
27
+
28
+ # Public: Register new dependency URI resolver.
29
+ #
30
+ # scheme - String scheme
31
+ # block -
32
+ # environment - Environment
33
+ # uri - String dependency URI
34
+ #
35
+ # Returns nothing.
36
+ def register_dependency_resolver(scheme, &block)
37
+ self.config = hash_reassoc(config, :dependency_resolvers) do |hash|
38
+ hash.merge(scheme => block)
39
+ end
40
+ end
41
+
42
+ # Public: Add environmental dependency inheirted by all assets.
43
+ #
44
+ # uri - String dependency URI
45
+ #
46
+ # Returns nothing.
47
+ def add_dependency(uri)
48
+ self.config = hash_reassoc(config, :dependencies) do |set|
49
+ set + Set.new([uri])
50
+ end
51
+ end
52
+ alias_method :depend_on, :add_dependency
53
+
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
+ # Internal: Resolve dependency URIs.
62
+ #
63
+ # Returns resolved Object.
64
+ def resolve_dependency(str)
65
+ scheme = str[/([^:]+)/, 1]
66
+ if resolver = config[:dependency_resolvers][scheme]
67
+ resolver.call(self, str)
68
+ else
69
+ nil
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,156 @@
1
+ require 'digest/md5'
2
+ require 'digest/sha1'
3
+ require 'digest/sha2'
4
+ require 'set'
5
+
6
+ module Sprockets
7
+ # Internal: Hash functions and digest related utilities. Mixed into
8
+ # Environment.
9
+ module DigestUtils
10
+ extend self
11
+
12
+ # Internal: Default digest class.
13
+ #
14
+ # Returns a Digest::Base subclass.
15
+ def digest_class
16
+ Digest::SHA256
17
+ end
18
+
19
+ # Internal: Maps digest bytesize to the digest class.
20
+ DIGEST_SIZES = {
21
+ 16 => Digest::MD5,
22
+ 20 => Digest::SHA1,
23
+ 32 => Digest::SHA256,
24
+ 48 => Digest::SHA384,
25
+ 64 => Digest::SHA512
26
+ }
27
+
28
+ # Internal: Detect digest class hash algorithm for digest bytes.
29
+ #
30
+ # While not elegant, all the supported digests have a unique bytesize.
31
+ #
32
+ # Returns Digest::Base or nil.
33
+ def detect_digest_class(bytes)
34
+ DIGEST_SIZES[bytes.bytesize]
35
+ end
36
+
37
+ # Internal: Generate a hexdigest for a nested JSON serializable object.
38
+ #
39
+ # This is used for generating cache keys, so its pretty important its
40
+ # wicked fast. Microbenchmarks away!
41
+ #
42
+ # obj - A JSON serializable object.
43
+ #
44
+ # Returns a String digest of the object.
45
+ 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
86
+
87
+ digest.digest
88
+ end
89
+
90
+ # Internal: Pack a binary digest to a hex encoded string.
91
+ #
92
+ # bin - String bytes
93
+ #
94
+ # Returns hex String.
95
+ def pack_hexdigest(bin)
96
+ bin.unpack('H*').first
97
+ end
98
+
99
+ # Internal: Pack a binary digest to a base64 encoded string.
100
+ #
101
+ # bin - String bytes
102
+ #
103
+ # Returns base64 String.
104
+ def pack_base64digest(bin)
105
+ [bin].pack('m0')
106
+ end
107
+
108
+ # Internal: Pack a binary digest to a urlsafe base64 encoded string.
109
+ #
110
+ # bin - String bytes
111
+ #
112
+ # Returns urlsafe base64 String.
113
+ def pack_urlsafe_base64digest(bin)
114
+ str = pack_base64digest(bin)
115
+ str.tr!('+/'.freeze, '-_'.freeze)
116
+ str.tr!('='.freeze, ''.freeze)
117
+ str
118
+ end
119
+
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
127
+ }
128
+
129
+ # Internal: Generate a "named information" URI for use in the `integrity`
130
+ # attribute of an asset tag as per the subresource integrity specification.
131
+ #
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.
136
+ #
137
+ # Returns a String or nil if hash algorithm is incompatible.
138
+ def integrity_uri(digest, content_type = nil)
139
+ case digest
140
+ when Digest::Base
141
+ digest_class = digest.class
142
+ digest = digest.digest
143
+ when String
144
+ digest_class = DIGEST_SIZES[digest.bytesize]
145
+ else
146
+ raise TypeError, "unknown digest: #{digest.inspect}"
147
+ end
148
+
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
153
+ end
154
+ end
155
+ end
156
+ end