sprockets 2.2.3 → 2.12.3

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.

checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: be373494a4e64c06e55a9ad11e2c9efae09f1492
4
- data.tar.gz: b683ce4b0ed64e683ea98d0b5af268bdeca3f584
3
+ metadata.gz: 4ac3ec814692936eab4dc58704519ca15c383880
4
+ data.tar.gz: 1888571f870ed8cb1a4e7a36dd78b2c7079991ed
5
5
  SHA512:
6
- metadata.gz: fa430704b4ef87304b8a128cb83fbb64c66e24d0bdae3d9e9e343bbebd56bf8823f65cba4a0ad1eb33204308c814910ebdd9c2b570c33fbbf89a2fadd2383b33
7
- data.tar.gz: 785eb7a9f36afa38e6f010a573240768a9620ed216f4b20614835ffe9564d258a0e5340c9e8dbf3b538e8b960d9f7fd22342581b5e597dbbfc4e892bac7f7d3a
6
+ metadata.gz: 5a11411a3911b1bb069ec8b350e3017d96377f70a7a41b62db3b8da1616186c57dd31a9d746f01cc7b16c1e717dd7dfcc1c513a2d92420a4ddbc7f1ee292bdb0
7
+ data.tar.gz: 036a48e5dc1c97776e9aa455e6b254ecfcd83edbd0cabc1c999c1b23f4881685458f9e2683c35e38d9ad72946facbefe05b2bdef962d9cc2ab9fa73c74780b82
data/README.md CHANGED
@@ -159,9 +159,9 @@ variables, mixins, operations and functions.
159
159
 
160
160
  If the `less` gem is available to your application, you can use LESS
161
161
  to write CSS assets in Sprockets. Note that the LESS compiler is
162
- written in JavaScript, and at the time of this writing, the `less` gem
163
- depends on `therubyracer` which embeds the V8 JavaScript runtime in
164
- Ruby.
162
+ written in JavaScript and the `less` gem (on MRI) uses `therubyracer`
163
+ which embeds the V8 JavaScript runtime in Ruby, while on JRuby you're
164
+ going to need `therubyrhino` gem installed.
165
165
 
166
166
  To write CSS assets with LESS, use the extension `.css.less`.
167
167
 
@@ -336,6 +336,18 @@ source file before any subsequent `require` or `include` directives.
336
336
  including it in the bundle. This is useful when you need to expire an
337
337
  asset's cache in response to a change in another file.
338
338
 
339
+ ### The `depend_on_asset` Directive ###
340
+
341
+ `depend_on_asset` *path* works like `depend_on`, but operates
342
+ recursively reading the the file and following the directives found.
343
+
344
+ ### The `stub` Directive ###
345
+
346
+ `stub` *path* allows dependency to be excluded from the asset bundle.
347
+ The *path* must be a valid asset and may or may not already be part
348
+ of the bundle. Once stubbed, it is blacklisted and can't be brought
349
+ back by any other `require`.
350
+
339
351
  # Development #
340
352
 
341
353
  ## Contributing ##
@@ -354,7 +366,126 @@ submit a pull request.
354
366
 
355
367
  ## Version History ##
356
368
 
357
- **2.2.0** (Unreleased)
369
+ **2.12.3** (October 28, 2014)
370
+
371
+ * Security: Fix directory traversal bug in development mode server.
372
+
373
+ **2.12.2** (September 5, 2014)
374
+
375
+ * Ensure internal asset lookups calls are still restricted to load paths within
376
+ asset compiles. Though, you should not depend on internal asset resolves to be
377
+ completely restricted for security reasons. Assets themselves should be
378
+ considered full scripting environments with filesystem access.
379
+
380
+ **2.12.1** (April 17, 2014)
381
+
382
+ * Fix making manifest target directory when its different than the output directory.
383
+
384
+ **2.12.0** (March 13, 2014)
385
+
386
+ * Avoid context reference in SassImporter hack so its Marshallable. Fixes
387
+ issues with Sass 3.3.x.
388
+
389
+ **2.11.0** (February 19, 2014)
390
+
391
+ * Support for `.bower.json`
392
+
393
+ **2.10.0** (May 24, 2013)
394
+
395
+ * Support for `bower.json`
396
+
397
+ **2.9.3** (April 20, 2013)
398
+
399
+ * Fixed sass caching bug
400
+
401
+ **2.9.2** (April 8, 2013)
402
+
403
+ * Improve file freshness check performance
404
+ * Directive processor encoding fixes
405
+
406
+ **2.9.1** (April 6, 2013)
407
+
408
+ * Support for Uglifier 2.x
409
+
410
+ **2.9.0** (February 25, 2013)
411
+
412
+ * Write out gzipped variants of bundled assets.
413
+
414
+ **2.8.2** (December 10, 2012)
415
+
416
+ * Fixed top level Sass constant references
417
+ * Fixed manifest logger when environment is disabled
418
+
419
+ **2.8.1** (October 31, 2012)
420
+
421
+ * Fixed Sass importer bug
422
+
423
+ **2.8.0** (October 16, 2012)
424
+
425
+ * Allow manifest location to be seperated from output directory
426
+ * Pass logical path and absolute path to each_logical_path iterator
427
+
428
+ **2.7.0** (October 10, 2012)
429
+
430
+ * Added --css-compressor and --js-compressor command line flags
431
+ * Added css/js compressor shorthand
432
+ * Change default manifest.json filename to be a randomized manifest-16HEXBYTES.json
433
+ * Allow nil environment to be passed to manifest
434
+ * Allow manifest instance to be set on rake task
435
+
436
+ **2.6.0** (September 19, 2012)
437
+
438
+ * Added bower component.json require support
439
+
440
+ **2.5.0** (September 4, 2012)
441
+
442
+ * Fixed Ruby 2.0 RegExp warning
443
+ * Provide stubbed implementation of context *_path helpers
444
+ * Add SassCompressor
445
+
446
+ **2.4.5** (July 10, 2012)
447
+
448
+ * Tweaked some logger levels
449
+
450
+ **2.4.4** (July 2, 2012)
451
+
452
+ * Canonicalize logical path extensions
453
+ * Check absolute paths passed to depend_on
454
+
455
+ **2.4.3** (May 16, 2012)
456
+
457
+ * Exposed :sprockets in sass options
458
+ * Include dependency paths in asset mtime
459
+
460
+ **2.4.2** (May 7, 2012)
461
+
462
+ * Fixed MultiJson feature detect
463
+
464
+ **2.4.1** (April 26, 2012)
465
+
466
+ * Fixed MultiJson API change
467
+ * Fixed gzip mtime
468
+
469
+ **2.4.0** (March 27, 2012)
470
+
471
+ * Added global path registry
472
+ * Added global processor registry
473
+
474
+ **2.3.2** (March 26, 2012)
475
+
476
+ * Fix Context#logical_path with dots
477
+
478
+ **2.3.1** (February 11, 2012)
479
+
480
+ * Added bytesize to manifest
481
+ * Added Asset#bytesize alias
482
+ * Security: Check path for forbidden access after unescaping
483
+
484
+ **2.3.0** (January 16, 2012)
485
+
486
+ * Added special Sass importer that automatically tracks any `@import`ed files.
487
+
488
+ **2.2.0** (January 10, 2012)
358
489
 
359
490
  * Added `sprockets` command line utility.
360
491
  * Added rake/sprocketstask.
data/bin/sprockets CHANGED
@@ -40,6 +40,14 @@ OptionParser.new do |opts|
40
40
  manifest = Sprockets::Manifest.new(environment, directory)
41
41
  end
42
42
 
43
+ opts.on("--css-compressor=COMPRESSOR", "Use CSS compressor") do |compressor|
44
+ environment.css_compressor = compressor.to_sym
45
+ end
46
+
47
+ opts.on("--js-compressor=COMPRESSOR", "Use JavaScript compressor") do |compressor|
48
+ environment.js_compressor = compressor.to_sym
49
+ end
50
+
43
51
  opts.on("--noenv", "Disables .sprocketsrc file") do
44
52
  end
45
53
 
@@ -37,6 +37,24 @@ module Rake
37
37
  end
38
38
  attr_writer :environment
39
39
 
40
+ # Returns cached indexed environment
41
+ def index
42
+ @index ||= environment.index if environment
43
+ end
44
+
45
+ # `Manifest` instance used for already compiled assets.
46
+ #
47
+ # Will be created by default if an environment and output
48
+ # directory are given
49
+ def manifest
50
+ if !@manifest.is_a?(Sprockets::Manifest) && @manifest.respond_to?(:call)
51
+ @manifest = @manifest.call
52
+ else
53
+ @manifest
54
+ end
55
+ end
56
+ attr_writer :manifest
57
+
40
58
  # Directory to write compiled assets too. As well as the manifest file.
41
59
  #
42
60
  # t.output = "./public/assets"
@@ -79,6 +97,7 @@ module Rake
79
97
  def initialize(name = :assets)
80
98
  @name = name
81
99
  @environment = lambda { Sprockets::Environment.new(Dir.pwd) }
100
+ @manifest = lambda { Sprockets::Manifest.new(index, output) }
82
101
  @logger = Logger.new($stderr)
83
102
  @logger.level = Logger::INFO
84
103
  @keep = 2
@@ -117,24 +136,16 @@ module Rake
117
136
  end
118
137
 
119
138
  private
120
- # Returns cached indexed environment
121
- def index
122
- @index ||= environment.index
123
- end
124
-
125
- # Returns manifest for tasks
126
- def manifest
127
- @manifest ||= Sprockets::Manifest.new(index, output)
128
- end
129
-
130
139
  # Sub out environment logger with our rake task logger that
131
140
  # writes to stderr.
132
141
  def with_logger
133
- old_logger = index.logger
134
- index.logger = @logger
142
+ if env = manifest.environment
143
+ old_logger = env.logger
144
+ env.logger = @logger
145
+ end
135
146
  yield
136
147
  ensure
137
- index.logger = old_logger
148
+ env.logger = old_logger if env
138
149
  end
139
150
  end
140
151
  end
data/lib/sprockets.rb CHANGED
@@ -3,7 +3,6 @@ require 'sprockets/version'
3
3
  module Sprockets
4
4
  # Environment
5
5
  autoload :Base, "sprockets/base"
6
- autoload :Engines, "sprockets/engines"
7
6
  autoload :Environment, "sprockets/environment"
8
7
  autoload :Index, "sprockets/index"
9
8
  autoload :Manifest, "sprockets/manifest"
@@ -15,14 +14,16 @@ module Sprockets
15
14
  autoload :StaticAsset, "sprockets/static_asset"
16
15
 
17
16
  # Processing
18
- autoload :CharsetNormalizer, "sprockets/charset_normalizer"
19
17
  autoload :Context, "sprockets/context"
20
- autoload :DirectiveProcessor, "sprockets/directive_processor"
21
18
  autoload :EcoTemplate, "sprockets/eco_template"
22
19
  autoload :EjsTemplate, "sprockets/ejs_template"
23
20
  autoload :JstProcessor, "sprockets/jst_processor"
24
21
  autoload :Processor, "sprockets/processor"
25
- autoload :SafetyColons, "sprockets/safety_colons"
22
+ autoload :SassCacheStore, "sprockets/sass_cache_store"
23
+ autoload :SassFunctions, "sprockets/sass_functions"
24
+ autoload :SassImporter, "sprockets/sass_importer"
25
+ autoload :SassTemplate, "sprockets/sass_template"
26
+ autoload :ScssTemplate, "sprockets/scss_template"
26
27
 
27
28
  # Internal utilities
28
29
  autoload :ArgumentError, "sprockets/errors"
@@ -39,8 +40,51 @@ module Sprockets
39
40
  end
40
41
 
41
42
  # Extend Sprockets module to provide global registry
42
- extend Engines
43
- @engines = {}
43
+ require 'hike'
44
+ require 'sprockets/engines'
45
+ require 'sprockets/mime'
46
+ require 'sprockets/processing'
47
+ require 'sprockets/compressing'
48
+ require 'sprockets/paths'
49
+ extend Engines, Mime, Processing, Compressing, Paths
50
+
51
+ @trail = Hike::Trail.new(File.expand_path('..', __FILE__))
52
+ @mime_types = {}
53
+ @engines = {}
54
+ @preprocessors = Hash.new { |h, k| h[k] = [] }
55
+ @postprocessors = Hash.new { |h, k| h[k] = [] }
56
+ @bundle_processors = Hash.new { |h, k| h[k] = [] }
57
+ @compressors = Hash.new { |h, k| h[k] = {} }
58
+
59
+ register_mime_type 'text/css', '.css'
60
+ register_mime_type 'application/javascript', '.js'
61
+
62
+ require 'sprockets/directive_processor'
63
+ register_preprocessor 'text/css', DirectiveProcessor
64
+ register_preprocessor 'application/javascript', DirectiveProcessor
65
+
66
+ require 'sprockets/safety_colons'
67
+ register_postprocessor 'application/javascript', SafetyColons
68
+
69
+ require 'sprockets/charset_normalizer'
70
+ register_bundle_processor 'text/css', CharsetNormalizer
71
+
72
+ require 'sprockets/sass_compressor'
73
+ register_compressor 'text/css', :sass, SassCompressor
74
+ register_compressor 'text/css', :scss, SassCompressor
75
+
76
+ require 'sprockets/yui_compressor'
77
+ register_compressor 'text/css', :yui, YUICompressor
78
+
79
+ require 'sprockets/closure_compressor'
80
+ register_compressor 'application/javascript', :closure, ClosureCompressor
81
+
82
+ require 'sprockets/uglifier_compressor'
83
+ register_compressor 'application/javascript', :uglifier, UglifierCompressor
84
+ register_compressor 'application/javascript', :uglify, UglifierCompressor
85
+
86
+ require 'sprockets/yui_compressor'
87
+ register_compressor 'application/javascript', :yui, YUICompressor
44
88
 
45
89
  # Cherry pick the default Tilt engines that make sense for
46
90
  # Sprockets. We don't need ones that only generate html like HAML.
@@ -55,8 +99,8 @@ module Sprockets
55
99
 
56
100
  # CSS engines
57
101
  register_engine '.less', Tilt::LessTemplate
58
- register_engine '.sass', Tilt::SassTemplate
59
- register_engine '.scss', Tilt::ScssTemplate
102
+ register_engine '.sass', SassTemplate
103
+ register_engine '.scss', ScssTemplate
60
104
 
61
105
  # Other
62
106
  register_engine '.erb', Tilt::ERBTemplate
@@ -30,13 +30,17 @@ module Sprockets
30
30
 
31
31
  attr_reader :logical_path, :pathname
32
32
  attr_reader :content_type, :mtime, :length, :digest
33
+ alias_method :bytesize, :length
33
34
 
34
35
  def initialize(environment, logical_path, pathname)
36
+ raise ArgumentError, "Asset logical path has no extension: #{logical_path}" if File.extname(logical_path) == ""
37
+
35
38
  @root = environment.root
36
39
  @logical_path = logical_path.to_s
37
40
  @pathname = Pathname.new(pathname)
38
41
  @content_type = environment.content_type_of(pathname)
39
- @mtime = environment.stat(pathname).mtime
42
+ # drop precision to 1 second, same pattern followed elsewhere
43
+ @mtime = Time.at(environment.stat(pathname).mtime.to_i)
40
44
  @length = environment.stat(pathname).size
41
45
  @digest = environment.file_digest(pathname).hexdigest
42
46
  end
@@ -55,8 +59,7 @@ module Sprockets
55
59
  end
56
60
 
57
61
  if mtime = coder['mtime']
58
- # Parse time string
59
- @mtime = Time.parse(mtime)
62
+ @mtime = Time.at(mtime)
60
63
  end
61
64
 
62
65
  if length = coder['length']
@@ -71,7 +74,7 @@ module Sprockets
71
74
  coder['logical_path'] = logical_path
72
75
  coder['pathname'] = relativize_root_path(pathname).to_s
73
76
  coder['content_type'] = content_type
74
- coder['mtime'] = mtime.iso8601
77
+ coder['mtime'] = mtime.to_i
75
78
  coder['length'] = length
76
79
  coder['digest'] = digest
77
80
  end
@@ -144,12 +147,12 @@ module Sprockets
144
147
  if options[:compress]
145
148
  # Run contents through `Zlib`
146
149
  gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
150
+ gz.mtime = mtime.to_i
147
151
  gz.write to_s
148
152
  gz.close
149
153
  else
150
154
  # Write out as is
151
155
  f.write to_s
152
- f.close
153
156
  end
154
157
  end
155
158
 
@@ -233,7 +236,7 @@ module Sprockets
233
236
  return false
234
237
  end
235
238
 
236
- # Compare dependency mime to the actual mtime. If the
239
+ # Compare dependency mtime to the actual mtime. If the
237
240
  # dependency mtime is newer than the actual mtime, the file
238
241
  # hasn't changed since we created this `Asset` instance.
239
242
  #
@@ -241,7 +244,11 @@ module Sprockets
241
244
  # stale. Many deployment environments may recopy or recheckout
242
245
  # assets on each deploy. In this case the mtime would be the
243
246
  # time of deploy rather than modified time.
244
- if mtime >= stat.mtime
247
+ #
248
+ # Note: to_i is used in eql? and write_to we assume fidelity of 1 second
249
+ # if people save files more frequently than 1 second sprockets may
250
+ # not pick it up, by design
251
+ if mtime.to_i >= stat.mtime.to_i
245
252
  return true
246
253
  end
247
254
 
@@ -17,10 +17,21 @@ module Sprockets
17
17
  def search_paths
18
18
  paths = [pathname.to_s]
19
19
 
20
- if pathname.basename(extensions.join).to_s != 'index'
21
- path_without_extensions = extensions.inject(pathname) { |p, ext| p.sub(ext, '') }
22
- index_path = path_without_extensions.join("index#{extensions.join}").to_s
23
- paths << index_path
20
+ extension = format_extension
21
+ path_without_extension = extension ?
22
+ pathname.sub(extension, '') :
23
+ pathname
24
+
25
+ # optimization: bower.json can only be nested one level deep
26
+ if !path_without_extension.to_s.index('/')
27
+ paths << path_without_extension.join(".bower.json").to_s
28
+ paths << path_without_extension.join("bower.json").to_s
29
+ # DEPRECATED bower configuration file
30
+ paths << path_without_extension.join("component.json").to_s
31
+ end
32
+
33
+ if pathname.basename(extension.to_s).to_s != 'index'
34
+ paths << path_without_extension.join("index#{extension}").to_s
24
35
  end
25
36
 
26
37
  paths
@@ -1,17 +1,17 @@
1
1
  require 'sprockets/asset_attributes'
2
2
  require 'sprockets/bundled_asset'
3
3
  require 'sprockets/caching'
4
+ require 'sprockets/errors'
4
5
  require 'sprockets/processed_asset'
5
- require 'sprockets/processing'
6
6
  require 'sprockets/server'
7
7
  require 'sprockets/static_asset'
8
- require 'sprockets/trail'
8
+ require 'multi_json'
9
9
  require 'pathname'
10
10
 
11
11
  module Sprockets
12
12
  # `Base` class for `Environment` and `Index`.
13
13
  class Base
14
- include Caching, Processing, Server, Trail
14
+ include Caching, Paths, Mime, Processing, Compressing, Engines, Server
15
15
 
16
16
  # Returns a `Digest` implementation class.
17
17
  #
@@ -98,6 +98,114 @@ module Sprockets
98
98
  @cache = cache
99
99
  end
100
100
 
101
+ def prepend_path(path)
102
+ # Overrides the global behavior to expire the index
103
+ expire_index!
104
+ super
105
+ end
106
+
107
+ def append_path(path)
108
+ # Overrides the global behavior to expire the index
109
+ expire_index!
110
+ super
111
+ end
112
+
113
+ def clear_paths
114
+ # Overrides the global behavior to expire the index
115
+ expire_index!
116
+ super
117
+ end
118
+
119
+ # Finds the expanded real path for a given logical path by
120
+ # searching the environment's paths.
121
+ #
122
+ # resolve("application.js")
123
+ # # => "/path/to/app/javascripts/application.js.coffee"
124
+ #
125
+ # A `FileNotFound` exception is raised if the file does not exist.
126
+ def resolve(logical_path, options = {})
127
+ # If a block is given, preform an iterable search
128
+ if block_given?
129
+ args = attributes_for(logical_path).search_paths + [options]
130
+ @trail.find(*args) do |path|
131
+ pathname = Pathname.new(path)
132
+ if %w( .bower.json bower.json component.json ).include?(pathname.basename.to_s)
133
+ bower = json_decode(pathname.read)
134
+ case bower['main']
135
+ when String
136
+ yield pathname.dirname.join(bower['main'])
137
+ when Array
138
+ extname = File.extname(logical_path)
139
+ bower['main'].each do |fn|
140
+ if extname == "" || extname == File.extname(fn)
141
+ yield pathname.dirname.join(fn)
142
+ end
143
+ end
144
+ end
145
+ else
146
+ yield pathname
147
+ end
148
+ end
149
+ else
150
+ resolve(logical_path, options) do |pathname|
151
+ return pathname
152
+ end
153
+ raise FileNotFound, "couldn't find file '#{logical_path}'"
154
+ end
155
+ end
156
+
157
+ # Register a new mime type.
158
+ def register_mime_type(mime_type, ext)
159
+ # Overrides the global behavior to expire the index
160
+ expire_index!
161
+ @trail.append_extension(ext)
162
+ super
163
+ end
164
+
165
+ # Registers a new Engine `klass` for `ext`.
166
+ def register_engine(ext, klass)
167
+ # Overrides the global behavior to expire the index
168
+ expire_index!
169
+ add_engine_to_trail(ext, klass)
170
+ super
171
+ end
172
+
173
+ def register_preprocessor(mime_type, klass, &block)
174
+ # Overrides the global behavior to expire the index
175
+ expire_index!
176
+ super
177
+ end
178
+
179
+ def unregister_preprocessor(mime_type, klass)
180
+ # Overrides the global behavior to expire the index
181
+ expire_index!
182
+ super
183
+ end
184
+
185
+ def register_postprocessor(mime_type, klass, &block)
186
+ # Overrides the global behavior to expire the index
187
+ expire_index!
188
+ super
189
+ end
190
+
191
+ def unregister_postprocessor(mime_type, klass)
192
+ # Overrides the global behavior to expire the index
193
+ expire_index!
194
+ super
195
+ end
196
+
197
+ def register_bundle_processor(mime_type, klass, &block)
198
+ # Overrides the global behavior to expire the index
199
+ expire_index!
200
+ super
201
+ end
202
+
203
+ def unregister_bundle_processor(mime_type, klass)
204
+ # Overrides the global behavior to expire the index
205
+ expire_index!
206
+ super
207
+ end
208
+
101
209
  # Return an `Index`. Must be implemented by the subclass.
102
210
  def index
103
211
  raise NotImplementedError
@@ -113,14 +221,14 @@ module Sprockets
113
221
  #
114
222
  # Subclasses may cache this method.
115
223
  def entries(pathname)
116
- trail.entries(pathname)
224
+ @trail.entries(pathname)
117
225
  end
118
226
 
119
227
  # Works like `File.stat`.
120
228
  #
121
229
  # Subclasses may cache this method.
122
230
  def stat(path)
123
- trail.stat(path)
231
+ @trail.stat(path)
124
232
  end
125
233
 
126
234
  # Read and compute digest of filename.
@@ -153,7 +261,7 @@ module Sprockets
153
261
  # Find asset by logical path or expanded path.
154
262
  def find_asset(path, options = {})
155
263
  logical_path = path
156
- pathname = Pathname.new(path)
264
+ pathname = Pathname.new(path).cleanpath
157
265
 
158
266
  if pathname.absolute?
159
267
  return unless stat(pathname)
@@ -161,6 +269,16 @@ module Sprockets
161
269
  else
162
270
  begin
163
271
  pathname = resolve(logical_path)
272
+
273
+ # If logical path is missing a mime type extension, append
274
+ # the absolute path extname so it has one.
275
+ #
276
+ # Ensures some consistency between finding "foo/bar" vs
277
+ # "foo/bar.js".
278
+ if File.extname(logical_path) == ""
279
+ expanded_logical_path = attributes_for(pathname).logical_path
280
+ logical_path += File.extname(expanded_logical_path)
281
+ end
164
282
  rescue FileNotFound
165
283
  return nil
166
284
  end
@@ -210,13 +328,20 @@ module Sprockets
210
328
  nil
211
329
  end
212
330
 
213
- def each_logical_path(*args)
331
+ def each_logical_path(*args, &block)
214
332
  return to_enum(__method__, *args) unless block_given?
215
333
  filters = args.flatten
216
334
  files = {}
217
335
  each_file do |filename|
218
336
  if logical_path = logical_path_for_filename(filename, filters)
219
- yield logical_path unless files[logical_path]
337
+ unless files[logical_path]
338
+ if block.arity == 2
339
+ yield logical_path, filename.to_s
340
+ else
341
+ yield logical_path
342
+ end
343
+ end
344
+
220
345
  files[logical_path] = true
221
346
  end
222
347
  end
@@ -275,14 +400,14 @@ module Sprockets
275
400
  def logical_path_for_filename(filename, filters)
276
401
  logical_path = attributes_for(filename).logical_path.to_s
277
402
 
278
- if matches_filter(filters, logical_path)
403
+ if matches_filter(filters, logical_path, filename)
279
404
  return logical_path
280
405
  end
281
406
 
282
407
  # If filename is an index file, retest with alias
283
408
  if File.basename(logical_path)[/[^\.]+/, 0] == 'index'
284
409
  path = logical_path.sub(/\/index\./, '.')
285
- if matches_filter(filters, path)
410
+ if matches_filter(filters, path, filename)
286
411
  return path
287
412
  end
288
413
  end
@@ -290,18 +415,33 @@ module Sprockets
290
415
  nil
291
416
  end
292
417
 
293
- def matches_filter(filters, filename)
418
+ def matches_filter(filters, logical_path, filename)
294
419
  return true if filters.empty?
295
420
 
296
421
  filters.any? do |filter|
297
422
  if filter.is_a?(Regexp)
298
- filter.match(filename)
423
+ filter.match(logical_path)
299
424
  elsif filter.respond_to?(:call)
300
- filter.call(filename)
425
+ if filter.arity == 1
426
+ filter.call(logical_path)
427
+ else
428
+ filter.call(logical_path, filename.to_s)
429
+ end
301
430
  else
302
- File.fnmatch(filter.to_s, filename)
431
+ File.fnmatch(filter.to_s, logical_path)
303
432
  end
304
433
  end
305
434
  end
435
+
436
+ # Feature detect newer MultiJson API
437
+ if MultiJson.respond_to?(:dump)
438
+ def json_decode(obj)
439
+ MultiJson.load(obj)
440
+ end
441
+ else
442
+ def json_decode(obj)
443
+ MultiJson.decode(obj)
444
+ end
445
+ end
306
446
  end
307
447
  end