sprockets 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e5f1a2b7d847a15dff3669ec28a2248484ee0831c88017fc67fee6afe7b6a6f1
4
- data.tar.gz: 2714999cde7d9f9340d0d7f2a98f3e48c9b46d099e36069dd380a12f6c270c54
3
+ metadata.gz: 3c5995147a647a6d47d625b6cc9f10586506f3832cff0070985ec9560ee3fc0d
4
+ data.tar.gz: 1befd6f705efbef88f05dc58b38f719f11b445f76c60a95f854a43ef8e84c21d
5
5
  SHA512:
6
- metadata.gz: db948451245c6a7e6cf20876368d040e6de9b3f178ab5fa0010070b9e834cd08036d449e35f3857a8443ac26fc5318ac20ab5cc16d91a4b65d8fc0f07a796939
7
- data.tar.gz: 2a6e4b9dbb1f2effa1ef15a4f861c7b5cadb6384713bf3452749f8f0be1405ab319d85b23272b1dbc3bdeda7837d0ce55f0caf62273e197eb6190511f0789097
6
+ metadata.gz: 9d47aea08307515c8a0fab29615fbde5f892c91300668afd83b2739032adeb77794d4303e6ecb56c570bc784695d25304f7481fa45c4ab7bbe0727281ee7deab
7
+ data.tar.gz: 6d0f0b116766053d96402f5d88602374829ef9610160bd8398a093db33ceaafe31a2f2b33a8d0c615769f0bbba7c39d867db90dfded9bc5ff35d0c0ff4482e36
data/CHANGELOG.md CHANGED
@@ -2,7 +2,12 @@
2
2
 
3
3
  Get upgrade notes from Sprockets 3.x to 4.x at https://github.com/rails/sprockets/blob/master/UPGRADING.md
4
4
 
5
- - Fix `Sprockets::Server` to return response headers to compatible with with Rack::Lint 2.0.
5
+ ## 4.2.0
6
+
7
+ - Rack 3 compatibility. [#758](https://github.com/rails/sprockets/pull/758)
8
+ - Fix thread safety of `Sprockets::CachedEnvironment` and `Sprockets::Cache::MemoryStore`. [#771](https://github.com/rails/sprockets/pull/771)
9
+ - Add support for Rack 3.0. Headers set by sprockets will now be lower case. [#758](https://github.com/rails/sprockets/pull/758)
10
+ - Make `Sprockets::Utils.module_include` thread safe on JRuby. [#759](https://github.com/rails/sprockets/pull/759)
6
11
 
7
12
  ## 4.1.0
8
13
 
data/README.md CHANGED
@@ -385,10 +385,10 @@ the current file won't work, it must be a logical path.
385
385
  `link` can also be used to include manifest files from mounted Rails engines:
386
386
 
387
387
  ```
388
- //= link my_engine
388
+ //= link my_engine_manifest
389
389
  ```
390
390
 
391
- This would find a manifest file at `my_engine/app/assets/config/my_engine.js` and include its directives.
391
+ This would find a manifest file at `my_engine/app/assets/config/my_engine_manifest.js` and include its directives.
392
392
 
393
393
  ### link_directory
394
394
 
@@ -525,7 +525,7 @@ Generated files are cached. If you're using an `ENV` var then
525
525
  when you change then ENV var the asset will be forced to
526
526
  recompile. This behavior is only true for environment variables,
527
527
  if you are pulling a value from somewhere else, such as a database,
528
- must manually invalidate the cache to see the change.
528
+ you must manually invalidate the cache to see the change.
529
529
 
530
530
  If you're using Rails, there are helpers you can use such as `asset_url`
531
531
  that will cause a recompile if the value changes.
@@ -22,6 +22,7 @@ module Sprockets
22
22
  def initialize(max_size = DEFAULT_MAX_SIZE)
23
23
  @max_size = max_size
24
24
  @cache = {}
25
+ @mutex = Mutex.new
25
26
  end
26
27
 
27
28
  # Public: Retrieve value from cache.
@@ -32,12 +33,14 @@ module Sprockets
32
33
  #
33
34
  # Returns Object or nil or the value is not set.
34
35
  def get(key)
35
- exists = true
36
- value = @cache.delete(key) { exists = false }
37
- if exists
38
- @cache[key] = value
39
- else
40
- nil
36
+ @mutex.synchronize do
37
+ exists = true
38
+ value = @cache.delete(key) { exists = false }
39
+ if exists
40
+ @cache[key] = value
41
+ else
42
+ nil
43
+ end
41
44
  end
42
45
  end
43
46
 
@@ -50,9 +53,11 @@ module Sprockets
50
53
  #
51
54
  # Returns Object value.
52
55
  def set(key, value)
53
- @cache.delete(key)
54
- @cache[key] = value
55
- @cache.shift if @cache.size > @max_size
56
+ @mutex.synchronize do
57
+ @cache.delete(key)
58
+ @cache[key] = value
59
+ @cache.shift if @cache.size > @max_size
60
+ end
56
61
  value
57
62
  end
58
63
 
@@ -60,14 +65,18 @@ module Sprockets
60
65
  #
61
66
  # Returns String.
62
67
  def inspect
63
- "#<#{self.class} size=#{@cache.size}/#{@max_size}>"
68
+ @mutex.synchronize do
69
+ "#<#{self.class} size=#{@cache.size}/#{@max_size}>"
70
+ end
64
71
  end
65
72
 
66
73
  # Public: Clear the cache
67
74
  #
68
75
  # Returns true
69
76
  def clear(options=nil)
70
- @cache.clear
77
+ @mutex.synchronize do
78
+ @cache.clear
79
+ end
71
80
  true
72
81
  end
73
82
  end
@@ -16,11 +16,11 @@ module Sprockets
16
16
  initialize_configuration(environment)
17
17
 
18
18
  @cache = environment.cache
19
- @stats = {}
20
- @entries = {}
21
- @uris = {}
22
- @processor_cache_keys = {}
23
- @resolved_dependencies = {}
19
+ @stats = Concurrent::Map.new
20
+ @entries = Concurrent::Map.new
21
+ @uris = Concurrent::Map.new
22
+ @processor_cache_keys = Concurrent::Map.new
23
+ @resolved_dependencies = Concurrent::Map.new
24
24
  end
25
25
 
26
26
  # No-op return self as cached environment.
@@ -31,27 +31,27 @@ module Sprockets
31
31
 
32
32
  # Internal: Cache Environment#entries
33
33
  def entries(path)
34
- @entries.fetch(path){ @entries[path] = super(path) }
34
+ @entries.fetch_or_store(path) { super(path) }
35
35
  end
36
36
 
37
37
  # Internal: Cache Environment#stat
38
38
  def stat(path)
39
- @stats.fetch(path){ @stats[path] = super(path) }
39
+ @stats.fetch_or_store(path) { super(path) }
40
40
  end
41
41
 
42
42
  # Internal: Cache Environment#load
43
43
  def load(uri)
44
- @uris.fetch(uri){ @uris[uri] = super(uri) }
44
+ @uris.fetch_or_store(uri) { super(uri) }
45
45
  end
46
46
 
47
47
  # Internal: Cache Environment#processor_cache_key
48
48
  def processor_cache_key(str)
49
- @processor_cache_keys.fetch(str){ @processor_cache_keys[str] = super(str) }
49
+ @processor_cache_keys.fetch_or_store(str) { super(str) }
50
50
  end
51
51
 
52
52
  # Internal: Cache Environment#resolve_dependency
53
53
  def resolve_dependency(str)
54
- @resolved_dependencies.fetch(str){ @resolved_dependencies[str] = super(str) }
54
+ @resolved_dependencies.fetch_or_store(str) { super(str) }
55
55
  end
56
56
 
57
57
  private
@@ -28,11 +28,11 @@ module Sprockets
28
28
 
29
29
  # Public: Remove Exporting processor `klass` for `mime_type`.
30
30
  #
31
- # environment.unregister_exporter '*/*', Sprockets::Exporters::Zlib
31
+ # environment.unregister_exporter '*/*', Sprockets::Exporters::ZlibExporter
32
32
  #
33
33
  # Can be called without a mime type
34
34
  #
35
- # environment.unregister_exporter Sprockets::Exporters::Zlib
35
+ # environment.unregister_exporter Sprockets::Exporters::ZlibExporter
36
36
  #
37
37
  # Does not remove any exporters that depend on `klass`.
38
38
  def unregister_exporter(mime_types, exporter = nil)
@@ -148,39 +148,39 @@ module Sprockets
148
148
  # Returns a 400 Forbidden response tuple
149
149
  def bad_request_response(env)
150
150
  if head_request?(env)
151
- [ 400, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
151
+ [ 400, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
152
152
  else
153
- [ 400, { "Content-Type" => "text/plain", "Content-Length" => "11" }, [ "Bad Request" ] ]
153
+ [ 400, { "content-type" => "text/plain", "content-length" => "11" }, [ "Bad Request" ] ]
154
154
  end
155
155
  end
156
156
 
157
157
  # Returns a 403 Forbidden response tuple
158
158
  def forbidden_response(env)
159
159
  if head_request?(env)
160
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
160
+ [ 403, { "content-type" => "text/plain", "content-length" => "0" }, [] ]
161
161
  else
162
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
162
+ [ 403, { "content-type" => "text/plain", "content-length" => "9" }, [ "Forbidden" ] ]
163
163
  end
164
164
  end
165
165
 
166
166
  # Returns a 404 Not Found response tuple
167
167
  def not_found_response(env)
168
168
  if head_request?(env)
169
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
169
+ [ 404, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
170
170
  else
171
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
171
+ [ 404, { "content-type" => "text/plain", "content-length" => "9", "x-cascade" => "pass" }, [ "Not found" ] ]
172
172
  end
173
173
  end
174
174
 
175
175
  def method_not_allowed_response
176
- [ 405, { "Content-Type" => "text/plain", "Content-Length" => "18" }, [ "Method Not Allowed" ] ]
176
+ [ 405, { "content-type" => "text/plain", "content-length" => "18" }, [ "Method Not Allowed" ] ]
177
177
  end
178
178
 
179
179
  def precondition_failed_response(env)
180
180
  if head_request?(env)
181
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
181
+ [ 412, { "content-type" => "text/plain", "content-length" => "0", "x-cascade" => "pass" }, [] ]
182
182
  else
183
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
183
+ [ 412, { "content-type" => "text/plain", "content-length" => "19", "x-cascade" => "pass" }, [ "Precondition Failed" ] ]
184
184
  end
185
185
  end
186
186
 
@@ -189,7 +189,7 @@ module Sprockets
189
189
  def javascript_exception_response(exception)
190
190
  err = "#{exception.class.name}: #{exception.message}\n (in #{exception.backtrace[0]})"
191
191
  body = "throw Error(#{err.inspect})"
192
- [ 200, { "Content-Type" => "application/javascript", "Content-Length" => body.bytesize.to_s }, [ body ] ]
192
+ [ 200, { "content-type" => "application/javascript", "content-length" => body.bytesize.to_s }, [ body ] ]
193
193
  end
194
194
 
195
195
  # Returns a CSS response that hides all elements on the page and
@@ -242,7 +242,7 @@ module Sprockets
242
242
  }
243
243
  CSS
244
244
 
245
- [ 200, { "Content-Type" => "text/css; charset=utf-8", "Content-Length" => body.bytesize.to_s }, [ body ] ]
245
+ [ 200, { "content-type" => "text/css; charset=utf-8", "content-length" => body.bytesize.to_s }, [ body ] ]
246
246
  end
247
247
 
248
248
  # Escape special characters for use inside a CSS content("...") string
@@ -258,18 +258,18 @@ module Sprockets
258
258
  headers = {}
259
259
 
260
260
  # Set caching headers
261
- headers["Cache-Control"] = +"public"
262
- headers["ETag"] = %("#{etag}")
261
+ headers["cache-control"] = +"public"
262
+ headers["etag"] = %("#{etag}")
263
263
 
264
264
  # If the request url contains a fingerprint, set a long
265
265
  # expires on the response
266
266
  if path_fingerprint(env["PATH_INFO"])
267
- headers["Cache-Control"] << ", max-age=31536000, immutable"
267
+ headers["cache-control"] << ", max-age=31536000, immutable"
268
268
 
269
269
  # Otherwise set `must-revalidate` since the asset could be modified.
270
270
  else
271
- headers["Cache-Control"] << ", must-revalidate"
272
- headers["Vary"] = "Accept-Encoding"
271
+ headers["cache-control"] << ", must-revalidate"
272
+ headers["vary"] = "Accept-Encoding"
273
273
  end
274
274
 
275
275
  headers
@@ -279,7 +279,7 @@ module Sprockets
279
279
  headers = {}
280
280
 
281
281
  # Set content length header
282
- headers["Content-Length"] = length.to_s
282
+ headers["content-length"] = length.to_s
283
283
 
284
284
  # Set content type header
285
285
  if type = asset.content_type
@@ -287,7 +287,7 @@ module Sprockets
287
287
  if type.start_with?("text/") && asset.charset
288
288
  type += "; charset=#{asset.charset}"
289
289
  end
290
- headers["Content-Type"] = type
290
+ headers["content-type"] = type
291
291
  end
292
292
 
293
293
  headers.merge(cache_headers(env, asset.etag))
@@ -53,7 +53,7 @@ module Sprockets
53
53
  path = path[1..-1]
54
54
  end
55
55
 
56
- [scheme, host, path, query]
56
+ [scheme, host || '', path, query]
57
57
  end
58
58
 
59
59
  # Internal: Join file: URI component parts into String.
@@ -118,33 +118,38 @@ module Sprockets
118
118
  buf
119
119
  end
120
120
 
121
+ MODULE_INCLUDE_MUTEX = Mutex.new
122
+ private_constant :MODULE_INCLUDE_MUTEX
123
+
121
124
  # Internal: Inject into target module for the duration of the block.
122
125
  #
123
126
  # mod - Module
124
127
  #
125
128
  # Returns result of block.
126
129
  def module_include(base, mod)
127
- old_methods = {}
130
+ MODULE_INCLUDE_MUTEX.synchronize do
131
+ old_methods = {}
128
132
 
129
- mod.instance_methods.each do |sym|
130
- old_methods[sym] = base.instance_method(sym) if base.method_defined?(sym)
131
- end
133
+ mod.instance_methods.each do |sym|
134
+ old_methods[sym] = base.instance_method(sym) if base.method_defined?(sym)
135
+ end
132
136
 
133
- mod.instance_methods.each do |sym|
134
- method = mod.instance_method(sym)
135
- if base.method_defined?(sym)
136
- base.send(:alias_method, sym, sym)
137
+ mod.instance_methods.each do |sym|
138
+ method = mod.instance_method(sym)
139
+ if base.method_defined?(sym)
140
+ base.send(:alias_method, sym, sym)
141
+ end
142
+ base.send(:define_method, sym, method)
137
143
  end
138
- base.send(:define_method, sym, method)
139
- end
140
144
 
141
- yield
142
- ensure
143
- mod.instance_methods.each do |sym|
144
- base.send(:undef_method, sym) if base.method_defined?(sym)
145
- end
146
- old_methods.each do |sym, method|
147
- base.send(:define_method, sym, method)
145
+ yield
146
+ ensure
147
+ mod.instance_methods.each do |sym|
148
+ base.send(:undef_method, sym) if base.method_defined?(sym)
149
+ end
150
+ old_methods.each do |sym, method|
151
+ base.send(:define_method, sym, method)
152
+ end
148
153
  end
149
154
  end
150
155
 
@@ -1,4 +1,4 @@
1
1
  # frozen_string_literal: true
2
2
  module Sprockets
3
- VERSION = "4.1.1"
3
+ VERSION = "4.2.0"
4
4
  end
metadata CHANGED
@@ -1,36 +1,36 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.1.1
4
+ version: 4.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
8
8
  - Joshua Peek
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2022-06-27 00:00:00.000000000 Z
12
+ date: 2022-12-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
16
16
  requirement: !ruby/object:Gem::Requirement
17
17
  requirements:
18
- - - ">"
18
+ - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '1'
20
+ version: 2.2.4
21
21
  - - "<"
22
22
  - !ruby/object:Gem::Version
23
- version: '3'
23
+ version: '4'
24
24
  type: :runtime
25
25
  prerelease: false
26
26
  version_requirements: !ruby/object:Gem::Requirement
27
27
  requirements:
28
- - - ">"
28
+ - - ">="
29
29
  - !ruby/object:Gem::Version
30
- version: '1'
30
+ version: 2.2.4
31
31
  - - "<"
32
32
  - !ruby/object:Gem::Version
33
- version: '3'
33
+ version: '4'
34
34
  - !ruby/object:Gem::Dependency
35
35
  name: concurrent-ruby
36
36
  requirement: !ruby/object:Gem::Requirement
@@ -219,14 +219,14 @@ dependencies:
219
219
  requirements:
220
220
  - - "~>"
221
221
  - !ruby/object:Gem::Version
222
- version: '0.6'
222
+ version: 2.0.0
223
223
  type: :development
224
224
  prerelease: false
225
225
  version_requirements: !ruby/object:Gem::Requirement
226
226
  requirements:
227
227
  - - "~>"
228
228
  - !ruby/object:Gem::Version
229
- version: '0.6'
229
+ version: 2.0.0
230
230
  - !ruby/object:Gem::Dependency
231
231
  name: rake
232
232
  requirement: !ruby/object:Gem::Requirement
@@ -423,7 +423,7 @@ homepage: https://github.com/rails/sprockets
423
423
  licenses:
424
424
  - MIT
425
425
  metadata: {}
426
- post_install_message:
426
+ post_install_message:
427
427
  rdoc_options: []
428
428
  require_paths:
429
429
  - lib
@@ -439,7 +439,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
439
439
  version: '0'
440
440
  requirements: []
441
441
  rubygems_version: 3.3.7
442
- signing_key:
442
+ signing_key:
443
443
  specification_version: 4
444
444
  summary: Rack-based asset packaging system
445
445
  test_files: []