sprockets 3.6.0 → 3.7.2

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
- SHA1:
3
- metadata.gz: a1eef394792f4af6343438fcc3666a88ca893348
4
- data.tar.gz: 464e323e318b96534f12621a3f1a5dfc9a024425
2
+ SHA256:
3
+ metadata.gz: 46e0f0a150aa8333d2a1d2663167b6f20c1e77db067cea7b545f75927f770807
4
+ data.tar.gz: 5acd5cb5c64e240dd8180e91f34620195fa1433e625ee48a132fdae58be71ba5
5
5
  SHA512:
6
- metadata.gz: 446a6718c9ae7f0e94e57672680c7bbb2233855000dd813d3dc1867d0d3c6f12f3dcb43abe21f9a72bfcc05bff7524b9030eb771c342d4ea65fdde1169887f21
7
- data.tar.gz: e49c3925afb5988848f46439b1e9c3b5334932e599c13398f0a7a6a312dde2f228c0e679bd8fc898e80dd1861bc4fcfedfd807a9872b91b2af14be210870ab7d
6
+ metadata.gz: 97a06eb2e0767903da7bcda387211d881f3b98d57269a8abed5045e277db5f133f381c4f8fd23fcccf45a4032c85309841abba13b9218a52b21121a5a9bfc02a
7
+ data.tar.gz: 1d9c8d75bab64c366473226cc61806cd64c1951a67d90cc1220c1474e6a02cc5003b2dffb1b6324abefb7e7c8b292145635ac0bed6ae947a35393d67acd3c40e
data/CHANGELOG.md CHANGED
@@ -1,3 +1,30 @@
1
+ **3.7.2** (June 19, 2018)
2
+
3
+ * Security release for [CVE-2018-3760](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2018-3760).
4
+
5
+ **3.7.1** (December 19, 2016)
6
+
7
+ * Ruby 2.4 support for Sprockets 3.
8
+
9
+ **3.7.0** (July 21, 2016)
10
+
11
+ * Deprecated interfaces now emit deprecation warnings #345
12
+
13
+ **3.6.3** (July 1, 2016)
14
+
15
+ * Faster asset lookup in large directories #336
16
+ * Faster PathUtils.match_path_extname https://github.com/rails/sprockets/commit/697269cf81e5261fdd7072e32bd489403027fd7e
17
+ * Fixed uglifier comment stripping #326
18
+ * Error messages now show load path info #313
19
+
20
+ **3.6.2** (June 21, 2016)
21
+
22
+ * More performance improvements.
23
+
24
+ **3.6.1** (June 17, 2016)
25
+
26
+ * Some performance improvements.
27
+
1
28
  **3.6.0** (April 6, 2016)
2
29
 
3
30
  * Add `Manifest#find_sources` to return the source of the compiled assets.
@@ -84,7 +111,7 @@
84
111
 
85
112
  **3.0.0** (April 12, 2015)
86
113
 
87
- [Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/master/UPGRADING.md)
114
+ [Guide to upgrading from Sprockets 2.x to 3.x](https://github.com/rails/sprockets/blob/3.x/UPGRADING.md)
88
115
 
89
116
  * New processor API. Tilt interface is deprecated.
90
117
  * Improved file store caching backend.
data/bin/sprockets CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env ruby
2
+ $VERBOSE = nil
2
3
 
3
4
  require 'sprockets'
4
5
  require 'optparse'
@@ -36,7 +36,6 @@ module Sprockets
36
36
  # (default: 1000).
37
37
  def initialize(root, max_size = DEFAULT_MAX_SIZE, logger = self.class.default_logger)
38
38
  @root = root
39
- @size = find_caches.inject(0) { |n, (_, stat)| n + stat.size }
40
39
  @max_size = max_size
41
40
  @gc_size = max_size * 0.75
42
41
  @logger = logger
@@ -107,11 +106,11 @@ module Sprockets
107
106
  # Write data
108
107
  PathUtils.atomic_write(path) do |f|
109
108
  f.write(raw)
110
- @size += f.size unless exists
109
+ @size = size + f.size unless exists
111
110
  end
112
111
 
113
112
  # GC if necessary
114
- gc! if @size > @max_size
113
+ gc! if size > @max_size
115
114
 
116
115
  value
117
116
  end
@@ -120,7 +119,7 @@ module Sprockets
120
119
  #
121
120
  # Returns String.
122
121
  def inspect
123
- "#<#{self.class} size=#{@size}/#{@max_size}>"
122
+ "#<#{self.class} size=#{size}/#{@max_size}>"
124
123
  end
125
124
 
126
125
  private
@@ -138,6 +137,10 @@ module Sprockets
138
137
  }.sort_by { |_, stat| stat.mtime.to_i }
139
138
  end
140
139
 
140
+ def size
141
+ @size ||= compute_size(find_caches)
142
+ end
143
+
141
144
  def compute_size(caches)
142
145
  caches.inject(0) { |sum, (_, stat)| sum + stat.size }
143
146
  end
@@ -35,11 +35,12 @@ module Sprockets
35
35
  attr_reader :cache_key
36
36
 
37
37
  def initialize(options = {})
38
- @compiler = Autoload::Closure::Compiler.new(options)
38
+ @options = options
39
39
  @cache_key = "#{self.class.name}:#{Autoload::Closure::VERSION}:#{Autoload::Closure::COMPILER_VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
40
40
  end
41
41
 
42
42
  def call(input)
43
+ @compiler ||= Autoload::Closure::Compiler.new(@options)
43
44
  @compiler.compile(input[:data])
44
45
  end
45
46
  end
@@ -2,5 +2,16 @@ require 'sprockets/coffee_script_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- CoffeeScriptTemplate = CoffeeScriptProcessor
5
+ module CoffeeScriptTemplate
6
+ VERSION = CoffeeScriptProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ CoffeeScriptProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "CoffeeScriptTemplate is deprecated please use CoffeeScriptProcessor instead"
14
+ CoffeeScriptProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -0,0 +1,90 @@
1
+ module Sprockets
2
+ class Deprecation
3
+ THREAD_LOCAL__SILENCE_KEY = "_sprockets_deprecation_silence".freeze
4
+ DEFAULT_BEHAVIORS = {
5
+ raise: ->(message, callstack) {
6
+ e = DeprecationException.new(message)
7
+ e.set_backtrace(callstack.map(&:to_s))
8
+ raise e
9
+ },
10
+
11
+ stderr: ->(message, callstack) {
12
+ $stderr.puts(message)
13
+ },
14
+ }
15
+
16
+ attr_reader :callstack
17
+
18
+ def self.silence(&block)
19
+ Thread.current[THREAD_LOCAL__SILENCE_KEY] = true
20
+ block.call
21
+ ensure
22
+ Thread.current[THREAD_LOCAL__SILENCE_KEY] = false
23
+ end
24
+
25
+ def initialize(callstack = nil)
26
+ @callstack = callstack || caller(2)
27
+ end
28
+
29
+ def warn(message)
30
+ return if Thread.current[THREAD_LOCAL__SILENCE_KEY]
31
+ deprecation_message(message).tap do |m|
32
+ behavior.each { |b| b.call(m, callstack) }
33
+ end
34
+ end
35
+
36
+ private
37
+ def behavior
38
+ @behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
39
+ end
40
+
41
+ def behavior=(behavior)
42
+ @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b }
43
+ end
44
+
45
+ def deprecation_message(message = nil)
46
+ message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
47
+ "DEPRECATION WARNING: #{message} #{ deprecation_caller_message }"
48
+ end
49
+
50
+ def deprecation_caller_message
51
+ file, line, method = extract_callstack
52
+ if file
53
+ if line && method
54
+ "(called from #{method} at #{file}:#{line})"
55
+ else
56
+ "(called from #{file}:#{line})"
57
+ end
58
+ end
59
+ end
60
+
61
+ SPROCKETS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/"
62
+
63
+ def ignored_callstack(path)
64
+ path.start_with?(SPROCKETS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir'])
65
+ end
66
+
67
+ def extract_callstack
68
+ return _extract_callstack if callstack.first.is_a? String
69
+
70
+ offending_line = callstack.find { |frame|
71
+ frame.absolute_path && !ignored_callstack(frame.absolute_path)
72
+ } || callstack.first
73
+
74
+ [offending_line.path, offending_line.lineno, offending_line.label]
75
+ end
76
+
77
+ def _extract_callstack
78
+ offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
79
+
80
+ if offending_line
81
+ if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
82
+ md.captures
83
+ else
84
+ offending_line
85
+ end
86
+ end
87
+ end
88
+ end
89
+ private_constant :Deprecation
90
+ end
@@ -34,6 +34,56 @@ module Sprockets
34
34
  DIGEST_SIZES[bytes.bytesize]
35
35
  end
36
36
 
37
+ ADD_VALUE_TO_DIGEST = {
38
+ String => ->(val, digest) { digest << val },
39
+ FalseClass => ->(val, digest) { digest << 'FalseClass'.freeze },
40
+ TrueClass => ->(val, digest) { digest << 'TrueClass'.freeze },
41
+ NilClass => ->(val, digest) { digest << 'NilClass'.freeze },
42
+
43
+ Symbol => ->(val, digest) {
44
+ digest << 'Symbol'.freeze
45
+ digest << val.to_s
46
+ },
47
+ Integer => ->(val, digest) {
48
+ digest << 'Integer'.freeze
49
+ digest << val.to_s
50
+ },
51
+ Array => ->(val, digest) {
52
+ digest << 'Array'.freeze
53
+ val.each do |element|
54
+ ADD_VALUE_TO_DIGEST[element.class].call(element, digest)
55
+ end
56
+ },
57
+ Hash => ->(val, digest) {
58
+ digest << 'Hash'.freeze
59
+ val.sort.each do |array|
60
+ ADD_VALUE_TO_DIGEST[Array].call(array, digest)
61
+ end
62
+ },
63
+ Set => ->(val, digest) {
64
+ digest << 'Set'.freeze
65
+ ADD_VALUE_TO_DIGEST[Array].call(val.to_a, digest)
66
+ },
67
+ Encoding => ->(val, digest) {
68
+ digest << 'Encoding'.freeze
69
+ digest << val.name
70
+ },
71
+ }
72
+ if 0.class != Integer # Ruby < 2.4
73
+ ADD_VALUE_TO_DIGEST[Fixnum] = ->(val, digest) {
74
+ digest << 'Integer'.freeze
75
+ digest << val.to_s
76
+ }
77
+ ADD_VALUE_TO_DIGEST[Bignum] = ->(val, digest) {
78
+ digest << 'Integer'.freeze
79
+ digest << val.to_s
80
+ }
81
+ end
82
+ ADD_VALUE_TO_DIGEST.default_proc = ->(_, val) {
83
+ raise TypeError, "couldn't digest #{ val }"
84
+ }
85
+ private_constant :ADD_VALUE_TO_DIGEST
86
+
37
87
  # Internal: Generate a hexdigest for a nested JSON serializable object.
38
88
  #
39
89
  # This is used for generating cache keys, so its pretty important its
@@ -44,46 +94,8 @@ module Sprockets
44
94
  # Returns a String digest of the object.
45
95
  def digest(obj)
46
96
  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'.freeze
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
97
 
98
+ ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest)
87
99
  digest.digest
88
100
  end
89
101
 
@@ -2,5 +2,16 @@ require 'sprockets/eco_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- EcoTemplate = EcoProcessor
5
+ module EcoTemplate
6
+ VERSION = EcoProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ EcoProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "EcoTemplate is deprecated please use EcoProcessor instead"
14
+ EcoProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -2,5 +2,16 @@ require 'sprockets/ejs_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- EjsTemplate = EjsProcessor
5
+ module EjsTemplate
6
+ VERSION = EjsProcessor::VERSION
7
+
8
+ def self.cache_key
9
+ EjsProcessor.cache_key
10
+ end
11
+
12
+ def self.call(*args)
13
+ Deprecation.new.warn "EjsTemplate is deprecated please use EjsProcessor instead"
14
+ EjsProcessor.call(*args)
15
+ end
16
+ end
6
17
  end
@@ -51,6 +51,17 @@ module Sprockets
51
51
  # environment.register_engine '.coffee', CoffeeScriptProcessor
52
52
  #
53
53
  def register_engine(ext, klass, options = {})
54
+ unless options[:silence_deprecation]
55
+ msg = <<-MSG
56
+ Sprockets method `register_engine` is deprecated.
57
+ Please register a mime type using `register_mime_type` then
58
+ use `register_compressor` or `register_transformer`.
59
+ https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors
60
+ MSG
61
+
62
+ Deprecation.new([caller.first]).warn(msg)
63
+ end
64
+
54
65
  ext = Sprockets::Utils.normalize_extension(ext)
55
66
 
56
67
  self.computed_config = {}
@@ -2,5 +2,10 @@ require 'sprockets/erb_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- ERBTemplate = ERBProcessor
5
+ class ERBTemplate < ERBProcessor
6
+ def call(*args)
7
+ Deprecation.new.warn "ERBTemplate is deprecated please use ERBProcessor instead"
8
+ super
9
+ end
10
+ end
6
11
  end
@@ -161,7 +161,8 @@ module Sprockets
161
161
  end
162
162
  else
163
163
  args.each do |path|
164
- yield File.binread(File.join(dir, assets[path]))
164
+ asset = assets[path]
165
+ yield File.binread(File.join(dir, asset)) if asset
165
166
  end
166
167
  end
167
168
  end
@@ -55,7 +55,9 @@ module Sprockets
55
55
  if File.directory?(path)
56
56
  entries = Dir.entries(path, :encoding => Encoding.default_internal)
57
57
  entries.reject! { |entry|
58
- entry =~ /^\.|~$|^\#.*\#$/
58
+ entry.start_with?(".".freeze) ||
59
+ (entry.start_with?("#".freeze) && entry.end_with?("#".freeze)) ||
60
+ entry.end_with?("~".freeze)
59
61
  }
60
62
  entries.sort!
61
63
  else
@@ -146,16 +148,19 @@ module Sprockets
146
148
  #
147
149
  # Returns [String extname, Object value] or nil nothing matched.
148
150
  def match_path_extname(path, extensions)
149
- match, key = nil, ""
150
- path_extnames(path).reverse_each do |extname|
151
- key.prepend(extname)
152
- if value = extensions[key]
153
- match = [key.dup, value]
154
- elsif match
155
- break
151
+ basename = File.basename(path)
152
+
153
+ i = basename.index('.'.freeze)
154
+ while i && i < basename.length - 1
155
+ extname = basename[i..-1]
156
+ if value = extensions[extname]
157
+ return extname, value
156
158
  end
159
+
160
+ i = basename.index('.'.freeze, i+1)
157
161
  end
158
- match
162
+
163
+ nil
159
164
  end
160
165
 
161
166
  # Internal: Returns all parents for path
@@ -231,14 +231,24 @@ module Sprockets
231
231
  compute_transformers!
232
232
  end
233
233
 
234
+ def deprecate_legacy_processor_interface(interface)
235
+ msg = "You are using a deprecated processor interface #{ interface.inspect }.\n" +
236
+ "Please update your processor interface:\n" +
237
+ "https://github.com/rails/sprockets/blob/master/guides/extending_sprockets.md#supporting-all-versions-of-sprockets-in-processors\n"
238
+
239
+ Deprecation.new([caller[3]]).warn msg
240
+ end
241
+
234
242
  def wrap_processor(klass, proc)
235
243
  if !proc
236
244
  if klass.respond_to?(:call)
237
245
  klass
238
246
  else
247
+ deprecate_legacy_processor_interface(klass)
239
248
  LegacyTiltProcessor.new(klass)
240
249
  end
241
250
  elsif proc.respond_to?(:arity) && proc.arity == 2
251
+ deprecate_legacy_processor_interface(proc)
242
252
  LegacyProcProcessor.new(klass.to_s, proc)
243
253
  else
244
254
  proc
@@ -107,12 +107,10 @@ module Sprockets
107
107
  VALID_METADATA_VALUE_TYPES = Set.new([
108
108
  String,
109
109
  Symbol,
110
- Fixnum,
111
- Bignum,
112
110
  TrueClass,
113
111
  FalseClass,
114
112
  NilClass
115
- ]).freeze
113
+ ] + (0.class == Integer ? [Integer] : [Bignum, Fixnum])).freeze
116
114
 
117
115
  # Internal: Set of all nested compound metadata types that can nest values.
118
116
  VALID_METADATA_COMPOUND_TYPES = Set.new([
@@ -121,6 +119,17 @@ module Sprockets
121
119
  Set
122
120
  ]).freeze
123
121
 
122
+ # Internal: Hash of all "simple" value types allowed to be returned in
123
+ # processor metadata.
124
+ VALID_METADATA_VALUE_TYPES_HASH = VALID_METADATA_VALUE_TYPES.each_with_object({}) do |type, hash|
125
+ hash[type] = true
126
+ end.freeze
127
+
128
+ # Internal: Hash of all nested compound metadata types that can nest values.
129
+ VALID_METADATA_COMPOUND_TYPES_HASH = VALID_METADATA_COMPOUND_TYPES.each_with_object({}) do |type, hash|
130
+ hash[type] = true
131
+ end.freeze
132
+
124
133
  # Internal: Set of all allowed metadata types.
125
134
  VALID_METADATA_TYPES = (VALID_METADATA_VALUE_TYPES + VALID_METADATA_COMPOUND_TYPES).freeze
126
135
 
@@ -159,9 +168,9 @@ module Sprockets
159
168
  #
160
169
  # Returns true if class is in whitelist otherwise false.
161
170
  def valid_processor_metadata_value?(value)
162
- if VALID_METADATA_VALUE_TYPES.include?(value.class)
171
+ if VALID_METADATA_VALUE_TYPES_HASH[value.class]
163
172
  true
164
- elsif VALID_METADATA_COMPOUND_TYPES.include?(value.class)
173
+ elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
165
174
  value.all? { |v| valid_processor_metadata_value?(v) }
166
175
  else
167
176
  false
@@ -60,6 +60,7 @@ module Sprockets
60
60
  end
61
61
 
62
62
  message << " with type '#{options[:accept]}'" if options[:accept]
63
+ message << "\nChecked in these paths: \n #{ config[:paths].join("\n ") }"
63
64
 
64
65
  raise FileNotFound, message
65
66
  end
@@ -177,6 +178,7 @@ module Sprockets
177
178
  candidates = []
178
179
  entries = self.entries(dirname)
179
180
  entries.each do |entry|
181
+ next unless File.basename(entry).start_with?(basename)
180
182
  name, type, _, _ = parse_path_extnames(entry)
181
183
  if basename == name
182
184
  candidates << [File.join(dirname, entry), type]
@@ -25,5 +25,10 @@ module Sprockets
25
25
  end
26
26
 
27
27
  # Deprecated: Use Sprockets::SassProcessor::CacheStore instead.
28
- SassCacheStore = SassProcessor::CacheStore
28
+ class SassCacheStore < SassProcessor::CacheStore
29
+ def initialize(*args)
30
+ Deprecation.new.warn "SassCacheStore is deprecated please use SassProcessor::CacheStore instead"
31
+ super
32
+ end
33
+ end
29
34
  end
@@ -2,6 +2,18 @@ require 'sprockets/sass_processor'
2
2
 
3
3
  module Sprockets
4
4
  # Deprecated
5
- SassTemplate = SassProcessor
6
- ScssTemplate = ScssProcessor
5
+ class SassTemplate < SassProcessor
6
+ def self.call(*args)
7
+ Deprecation.new.warn "SassTemplate is deprecated please use SassProcessor instead"
8
+ super
9
+ end
10
+ end
11
+
12
+ # Deprecated
13
+ class ScssTemplate < ScssProcessor
14
+ def self.call(*args)
15
+ Deprecation.new.warn "ScssTemplate is deprecated please use ScssProcessor instead"
16
+ super
17
+ end
18
+ end
7
19
  end
@@ -23,7 +23,7 @@ module Sprockets
23
23
  start_time = Time.now.to_f
24
24
  time_elapsed = lambda { ((Time.now.to_f - start_time) * 1000).to_i }
25
25
 
26
- if env['REQUEST_METHOD'] != 'GET'
26
+ if !['GET', 'HEAD'].include?(env['REQUEST_METHOD'])
27
27
  return method_not_allowed_response
28
28
  end
29
29
 
@@ -39,7 +39,7 @@ module Sprockets
39
39
 
40
40
  # URLs containing a `".."` are rejected for security reasons.
41
41
  if forbidden_request?(path)
42
- return forbidden_response
42
+ return forbidden_response(env)
43
43
  end
44
44
 
45
45
  # Look up the asset.
@@ -86,10 +86,10 @@ module Sprockets
86
86
  not_modified_response(env, if_none_match)
87
87
  when :not_found
88
88
  logger.info "#{msg} 404 Not Found (#{time_elapsed.call}ms)"
89
- not_found_response
89
+ not_found_response(env)
90
90
  when :precondition_failed
91
91
  logger.info "#{msg} 412 Precondition Failed (#{time_elapsed.call}ms)"
92
- precondition_failed_response
92
+ precondition_failed_response(env)
93
93
  end
94
94
  rescue Exception => e
95
95
  logger.error "Error compiling asset #{path}:"
@@ -115,12 +115,20 @@ module Sprockets
115
115
  #
116
116
  # http://example.org/assets/../../../etc/passwd
117
117
  #
118
- path.include?("..") || absolute_path?(path)
118
+ path.include?("..") || absolute_path?(path) || path.include?("://")
119
+ end
120
+
121
+ def head_request?(env)
122
+ env['REQUEST_METHOD'] == 'HEAD'
119
123
  end
120
124
 
121
125
  # Returns a 200 OK response tuple
122
126
  def ok_response(asset, env)
123
- [ 200, headers(env, asset, asset.length), asset ]
127
+ if head_request?(env)
128
+ [ 200, headers(env, asset, 0), [] ]
129
+ else
130
+ [ 200, headers(env, asset, asset.length), asset ]
131
+ end
124
132
  end
125
133
 
126
134
  # Returns a 304 Not Modified response tuple
@@ -129,21 +137,33 @@ module Sprockets
129
137
  end
130
138
 
131
139
  # Returns a 403 Forbidden response tuple
132
- def forbidden_response
133
- [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
140
+ def forbidden_response(env)
141
+ if head_request?(env)
142
+ [ 403, { "Content-Type" => "text/plain", "Content-Length" => "0" }, [] ]
143
+ else
144
+ [ 403, { "Content-Type" => "text/plain", "Content-Length" => "9" }, [ "Forbidden" ] ]
145
+ end
134
146
  end
135
147
 
136
148
  # Returns a 404 Not Found response tuple
137
- def not_found_response
138
- [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
149
+ def not_found_response(env)
150
+ if head_request?(env)
151
+ [ 404, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
152
+ else
153
+ [ 404, { "Content-Type" => "text/plain", "Content-Length" => "9", "X-Cascade" => "pass" }, [ "Not found" ] ]
154
+ end
139
155
  end
140
156
 
141
157
  def method_not_allowed_response
142
158
  [ 405, { "Content-Type" => "text/plain", "Content-Length" => "18" }, [ "Method Not Allowed" ] ]
143
159
  end
144
160
 
145
- def precondition_failed_response
146
- [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
161
+ def precondition_failed_response(env)
162
+ if head_request?(env)
163
+ [ 412, { "Content-Type" => "text/plain", "Content-Length" => "0", "X-Cascade" => "pass" }, [] ]
164
+ else
165
+ [ 412, { "Content-Type" => "text/plain", "Content-Length" => "19", "X-Cascade" => "pass" }, [ "Precondition Failed" ] ]
166
+ end
147
167
  end
148
168
 
149
169
  # Returns a JavaScript response that re-throws a Ruby exception
@@ -41,14 +41,15 @@ module Sprockets
41
41
  options[:copyright] ||= false
42
42
  else
43
43
  # Uglifier >= 2.x
44
- options[:copyright] ||= :none
44
+ options[:comments] ||= :none
45
45
  end
46
46
 
47
- @uglifier = Autoload::Uglifier.new(options)
47
+ @options = options
48
48
  @cache_key = "#{self.class.name}:#{Autoload::Uglifier::VERSION}:#{VERSION}:#{DigestUtils.digest(options)}".freeze
49
49
  end
50
50
 
51
51
  def call(input)
52
+ @uglifier ||= Autoload::Uglifier.new(@options)
52
53
  @uglifier.compile(input[:data])
53
54
  end
54
55
  end
@@ -14,10 +14,8 @@ module Sprockets
14
14
  @env = env
15
15
  uri = uri.to_s
16
16
  if uri.include?("://".freeze)
17
- uri_array = uri.split("://".freeze)
18
- @scheme = uri_array.shift
19
- @scheme << "://".freeze
20
- @path = uri_array.join("".freeze)
17
+ @scheme, _, @path = uri.partition("://".freeze)
18
+ @scheme << "://".freeze
21
19
  else
22
20
  @scheme = "".freeze
23
21
  @path = uri
@@ -14,11 +14,15 @@ module Sprockets
14
14
  #
15
15
  # Returns false if .dup would raise a TypeError, otherwise true.
16
16
  def duplicable?(obj)
17
- case obj
18
- when NilClass, FalseClass, TrueClass, Symbol, Numeric
19
- false
20
- else
17
+ if RUBY_VERSION >= "2.4.0"
21
18
  true
19
+ else
20
+ case obj
21
+ when NilClass, FalseClass, TrueClass, Symbol, Numeric
22
+ false
23
+ else
24
+ true
25
+ end
22
26
  end
23
27
  end
24
28
 
@@ -74,16 +78,19 @@ module Sprockets
74
78
  def string_end_with_semicolon?(str)
75
79
  i = str.size - 1
76
80
  while i >= 0
77
- c = str[i]
81
+ c = str[i].ord
78
82
  i -= 1
79
- if c == "\n" || c == " " || c == "\t"
80
- next
81
- elsif c != ";"
82
- return false
83
- else
84
- return true
83
+
84
+ # Need to compare against the ordinals because the string can be UTF_8 or UTF_32LE encoded
85
+ # 0x0A == "\n"
86
+ # 0x20 == " "
87
+ # 0x09 == "\t"
88
+ # 0x3B == ";"
89
+ unless c == 0x0A || c == 0x20 || c == 0x09
90
+ return c === 0x3B
85
91
  end
86
92
  end
93
+
87
94
  true
88
95
  end
89
96
 
@@ -95,11 +102,21 @@ module Sprockets
95
102
  #
96
103
  # Returns buf String.
97
104
  def concat_javascript_sources(buf, source)
98
- if buf.bytesize > 0
99
- buf << ";" unless string_end_with_semicolon?(buf)
100
- buf << "\n" unless buf.end_with?("\n")
105
+ if source.bytesize > 0
106
+ buf << source
107
+
108
+ # If the source contains non-ASCII characters, indexing on it becomes O(N).
109
+ # This will lead to O(N^2) performance in string_end_with_semicolon?, so we should use 32 bit encoding to make sure indexing stays O(1)
110
+ source = source.encode(Encoding::UTF_32LE) unless source.ascii_only?
111
+
112
+ if !string_end_with_semicolon?(source)
113
+ buf << ";\n"
114
+ elsif source[source.size - 1].ord != 0x0A
115
+ buf << "\n"
116
+ end
101
117
  end
102
- buf << source
118
+
119
+ buf
103
120
  end
104
121
 
105
122
  # Internal: Prepends a leading "." to an extension if its missing.
@@ -1,3 +1,3 @@
1
1
  module Sprockets
2
- VERSION = "3.6.0"
2
+ VERSION = "3.7.2"
3
3
  end
data/lib/sprockets.rb CHANGED
@@ -4,6 +4,7 @@ require 'sprockets/cache'
4
4
  require 'sprockets/environment'
5
5
  require 'sprockets/errors'
6
6
  require 'sprockets/manifest'
7
+ require 'sprockets/deprecation'
7
8
 
8
9
  module Sprockets
9
10
  require 'sprockets/processor_utils'
@@ -122,25 +123,31 @@ module Sprockets
122
123
 
123
124
  # Mmm, CoffeeScript
124
125
  require 'sprockets/coffee_script_processor'
125
- register_engine '.coffee', CoffeeScriptProcessor, mime_type: 'application/javascript'
126
+ Deprecation.silence do
127
+ register_engine '.coffee', CoffeeScriptProcessor, mime_type: 'application/javascript', silence_deprecation: true
128
+ end
126
129
 
127
130
  # JST engines
128
131
  require 'sprockets/eco_processor'
129
132
  require 'sprockets/ejs_processor'
130
133
  require 'sprockets/jst_processor'
131
- register_engine '.jst', JstProcessor, mime_type: 'application/javascript'
132
- register_engine '.eco', EcoProcessor, mime_type: 'application/javascript'
133
- register_engine '.ejs', EjsProcessor, mime_type: 'application/javascript'
134
+ Deprecation.silence do
135
+ register_engine '.jst', JstProcessor, mime_type: 'application/javascript', silence_deprecation: true
136
+ register_engine '.eco', EcoProcessor, mime_type: 'application/javascript', silence_deprecation: true
137
+ register_engine '.ejs', EjsProcessor, mime_type: 'application/javascript', silence_deprecation: true
138
+ end
134
139
 
135
140
  # CSS engines
136
141
  require 'sprockets/sass_processor'
137
- register_engine '.sass', SassProcessor, mime_type: 'text/css'
138
- register_engine '.scss', ScssProcessor, mime_type: 'text/css'
142
+ Deprecation.silence do
143
+ register_engine '.sass', SassProcessor, mime_type: 'text/css', silence_deprecation: true
144
+ register_engine '.scss', ScssProcessor, mime_type: 'text/css', silence_deprecation: true
145
+ end
139
146
  register_bundle_metadata_reducer 'text/css', :sass_dependencies, Set.new, :+
140
147
 
141
148
  # Other
142
149
  require 'sprockets/erb_processor'
143
- register_engine '.erb', ERBProcessor, mime_type: 'text/plain'
150
+ register_engine '.erb', ERBProcessor, mime_type: 'text/plain', silence_deprecation: true
144
151
 
145
152
  register_dependency_resolver 'environment-version' do |env|
146
153
  env.version
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sprockets
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.6.0
4
+ version: 3.7.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Stephenson
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2016-04-06 00:00:00.000000000 Z
12
+ date: 2018-06-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rack
@@ -267,6 +267,7 @@ files:
267
267
  - lib/sprockets/configuration.rb
268
268
  - lib/sprockets/context.rb
269
269
  - lib/sprockets/dependencies.rb
270
+ - lib/sprockets/deprecation.rb
270
271
  - lib/sprockets/digest_utils.rb
271
272
  - lib/sprockets/directive_processor.rb
272
273
  - lib/sprockets/eco_processor.rb
@@ -332,7 +333,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
332
333
  version: '0'
333
334
  requirements: []
334
335
  rubyforge_project: sprockets
335
- rubygems_version: 2.5.1
336
+ rubygems_version: 2.7.6
336
337
  signing_key:
337
338
  specification_version: 4
338
339
  summary: Rack-based asset packaging system