sprockets 2.2.3 → 2.12.5
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.
- checksums.yaml +5 -5
- data/README.md +135 -4
- data/bin/sprockets +8 -0
- data/lib/rake/sprocketstask.rb +24 -13
- data/lib/sprockets.rb +52 -8
- data/lib/sprockets/asset.rb +17 -8
- data/lib/sprockets/asset_attributes.rb +15 -4
- data/lib/sprockets/base.rb +155 -15
- data/lib/sprockets/bundled_asset.rb +5 -6
- data/lib/sprockets/caching.rb +39 -39
- data/lib/sprockets/closure_compressor.rb +22 -0
- data/lib/sprockets/compressing.rb +73 -0
- data/lib/sprockets/context.rb +57 -3
- data/lib/sprockets/directive_processor.rb +3 -1
- data/lib/sprockets/engines.rb +4 -4
- data/lib/sprockets/environment.rb +12 -15
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/index.rb +1 -0
- data/lib/sprockets/jst_processor.rb +2 -6
- data/lib/sprockets/manifest.rb +77 -19
- data/lib/sprockets/mime.rb +5 -4
- data/lib/sprockets/{trail.rb → paths.rb} +5 -37
- data/lib/sprockets/processed_asset.rb +1 -1
- data/lib/sprockets/processing.rb +3 -77
- data/lib/sprockets/processor.rb +1 -1
- data/lib/sprockets/sass_cache_store.rb +29 -0
- data/lib/sprockets/sass_compressor.rb +27 -0
- data/lib/sprockets/sass_functions.rb +70 -0
- data/lib/sprockets/sass_importer.rb +30 -0
- data/lib/sprockets/sass_template.rb +66 -0
- data/lib/sprockets/scss_template.rb +13 -0
- data/lib/sprockets/server.rb +1 -1
- data/lib/sprockets/static_asset.rb +4 -1
- data/lib/sprockets/uglifier_compressor.rb +29 -0
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +27 -0
- metadata +88 -7
data/lib/sprockets/context.rb
CHANGED
@@ -53,7 +53,7 @@ module Sprockets
|
|
53
53
|
# # => 'application'
|
54
54
|
#
|
55
55
|
def logical_path
|
56
|
-
@logical_path
|
56
|
+
@logical_path.chomp(File.extname(@logical_path))
|
57
57
|
end
|
58
58
|
|
59
59
|
# Returns content type of file
|
@@ -81,7 +81,11 @@ module Sprockets
|
|
81
81
|
attributes = environment.attributes_for(pathname)
|
82
82
|
|
83
83
|
if pathname.absolute?
|
84
|
-
pathname
|
84
|
+
if environment.stat(pathname)
|
85
|
+
pathname
|
86
|
+
else
|
87
|
+
raise FileNotFound, "couldn't find file '#{pathname}'"
|
88
|
+
end
|
85
89
|
|
86
90
|
elsif content_type = options[:content_type]
|
87
91
|
content_type = self.content_type if content_type == :self
|
@@ -101,7 +105,7 @@ module Sprockets
|
|
101
105
|
|
102
106
|
raise FileNotFound, "couldn't find file '#{path}'"
|
103
107
|
else
|
104
|
-
environment.resolve(path, :base_path => self.pathname.dirname, &block)
|
108
|
+
environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
|
105
109
|
end
|
106
110
|
end
|
107
111
|
|
@@ -217,6 +221,56 @@ module Sprockets
|
|
217
221
|
"data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
|
218
222
|
end
|
219
223
|
|
224
|
+
# Expands logical path to full url to asset.
|
225
|
+
#
|
226
|
+
# NOTE: This helper is currently not implemented and should be
|
227
|
+
# customized by the application. Though, in the future, some
|
228
|
+
# basics implemention may be provided with different methods that
|
229
|
+
# are required to be overridden.
|
230
|
+
def asset_path(path, options = {})
|
231
|
+
message = <<-EOS
|
232
|
+
Custom asset_path helper is not implemented
|
233
|
+
|
234
|
+
Extend your environment context with a custom method.
|
235
|
+
|
236
|
+
environment.context_class.class_eval do
|
237
|
+
def asset_path(path, options = {})
|
238
|
+
end
|
239
|
+
end
|
240
|
+
EOS
|
241
|
+
raise NotImplementedError, message
|
242
|
+
end
|
243
|
+
|
244
|
+
# Expand logical image asset path.
|
245
|
+
def image_path(path)
|
246
|
+
asset_path(path, :type => :image)
|
247
|
+
end
|
248
|
+
|
249
|
+
# Expand logical video asset path.
|
250
|
+
def video_path(path)
|
251
|
+
asset_path(path, :type => :video)
|
252
|
+
end
|
253
|
+
|
254
|
+
# Expand logical audio asset path.
|
255
|
+
def audio_path(path)
|
256
|
+
asset_path(path, :type => :audio)
|
257
|
+
end
|
258
|
+
|
259
|
+
# Expand logical font asset path.
|
260
|
+
def font_path(path)
|
261
|
+
asset_path(path, :type => :font)
|
262
|
+
end
|
263
|
+
|
264
|
+
# Expand logical javascript asset path.
|
265
|
+
def javascript_path(path)
|
266
|
+
asset_path(path, :type => :javascript)
|
267
|
+
end
|
268
|
+
|
269
|
+
# Expand logical stylesheet asset path.
|
270
|
+
def stylesheet_path(path)
|
271
|
+
asset_path(path, :type => :stylesheet)
|
272
|
+
end
|
273
|
+
|
220
274
|
private
|
221
275
|
# Annotates exception backtrace with the original template that
|
222
276
|
# the exception was raised in.
|
@@ -65,7 +65,7 @@ module Sprockets
|
|
65
65
|
# //= require "foo"
|
66
66
|
#
|
67
67
|
DIRECTIVE_PATTERN = /
|
68
|
-
^
|
68
|
+
^ \W* = \s* (\w+.*?) (\*\/)? $
|
69
69
|
/x
|
70
70
|
|
71
71
|
attr_reader :pathname
|
@@ -92,6 +92,8 @@ module Sprockets
|
|
92
92
|
@context = context
|
93
93
|
|
94
94
|
@result = ""
|
95
|
+
@result.force_encoding(body.encoding) if body.respond_to?(:encoding)
|
96
|
+
|
95
97
|
@has_written_body = false
|
96
98
|
|
97
99
|
process_directives
|
data/lib/sprockets/engines.rb
CHANGED
@@ -28,12 +28,12 @@ module Sprockets
|
|
28
28
|
# Sprockets.register_engine '.sass', SassTemplate
|
29
29
|
#
|
30
30
|
module Engines
|
31
|
-
# Returns
|
32
|
-
#
|
33
|
-
#
|
31
|
+
# Returns a `Hash` of `Engine`s registered on the `Environment`.
|
32
|
+
# If an `ext` argument is supplied, the `Engine` associated with
|
33
|
+
# that extension will be returned.
|
34
34
|
#
|
35
35
|
# environment.engines
|
36
|
-
# # =>
|
36
|
+
# # => {".coffee" => CoffeeScriptTemplate, ".sass" => SassTemplate, ...}
|
37
37
|
#
|
38
38
|
# environment.engines('.coffee')
|
39
39
|
# # => CoffeeScriptTemplate
|
@@ -1,9 +1,6 @@
|
|
1
1
|
require 'sprockets/base'
|
2
|
-
require 'sprockets/charset_normalizer'
|
3
2
|
require 'sprockets/context'
|
4
|
-
require 'sprockets/directive_processor'
|
5
3
|
require 'sprockets/index'
|
6
|
-
require 'sprockets/safety_colons'
|
7
4
|
|
8
5
|
require 'hike'
|
9
6
|
require 'logger'
|
@@ -35,24 +32,24 @@ module Sprockets
|
|
35
32
|
@digest_class = ::Digest::MD5
|
36
33
|
@version = ''
|
37
34
|
|
38
|
-
@mime_types =
|
35
|
+
@mime_types = Sprockets.registered_mime_types
|
39
36
|
@engines = Sprockets.engines
|
40
|
-
@preprocessors =
|
41
|
-
@postprocessors =
|
42
|
-
@bundle_processors =
|
37
|
+
@preprocessors = Sprockets.preprocessors
|
38
|
+
@postprocessors = Sprockets.postprocessors
|
39
|
+
@bundle_processors = Sprockets.bundle_processors
|
40
|
+
@compressors = Sprockets.compressors
|
41
|
+
|
42
|
+
Sprockets.paths.each do |path|
|
43
|
+
append_path(path)
|
44
|
+
end
|
43
45
|
|
44
46
|
@engines.each do |ext, klass|
|
45
47
|
add_engine_to_trail(ext, klass)
|
46
48
|
end
|
47
49
|
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
register_preprocessor 'text/css', DirectiveProcessor
|
52
|
-
register_preprocessor 'application/javascript', DirectiveProcessor
|
53
|
-
|
54
|
-
register_postprocessor 'application/javascript', SafetyColons
|
55
|
-
register_bundle_processor 'text/css', CharsetNormalizer
|
50
|
+
@mime_types.each do |ext, type|
|
51
|
+
@trail.append_extension(ext)
|
52
|
+
end
|
56
53
|
|
57
54
|
expire_index!
|
58
55
|
|
data/lib/sprockets/errors.rb
CHANGED
data/lib/sprockets/index.rb
CHANGED
@@ -2,9 +2,7 @@ require 'tilt'
|
|
2
2
|
|
3
3
|
module Sprockets
|
4
4
|
class JstProcessor < Tilt::Template
|
5
|
-
|
6
|
-
'application/javascript'
|
7
|
-
end
|
5
|
+
self.default_mime_type = 'application/javascript'
|
8
6
|
|
9
7
|
def self.default_namespace
|
10
8
|
'this.JST'
|
@@ -18,9 +16,7 @@ module Sprockets
|
|
18
16
|
|
19
17
|
def evaluate(scope, locals, &block)
|
20
18
|
<<-JST
|
21
|
-
(function() {
|
22
|
-
#{namespace} || (#{namespace} = {});
|
23
|
-
#{namespace}[#{scope.logical_path.inspect}] = #{indent(data)};
|
19
|
+
(function() { #{namespace} || (#{namespace} = {}); #{namespace}[#{scope.logical_path.inspect}] = #{indent(data)};
|
24
20
|
}).call(this);
|
25
21
|
JST
|
26
22
|
end
|
data/lib/sprockets/manifest.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'multi_json'
|
2
|
+
require 'securerandom'
|
2
3
|
require 'time'
|
3
4
|
|
4
5
|
module Sprockets
|
@@ -18,26 +19,50 @@ module Sprockets
|
|
18
19
|
# a full path to the manifest json file. The file may or may not
|
19
20
|
# already exist. The dirname of the `path` will be used to write
|
20
21
|
# compiled assets to. Otherwise, if the path is a directory, the
|
21
|
-
# filename will default
|
22
|
+
# filename will default a random "manifest-123.json" file in that
|
23
|
+
# directory.
|
22
24
|
#
|
23
25
|
# Manifest.new(environment, "./public/assets/manifest.json")
|
24
26
|
#
|
25
|
-
def initialize(
|
26
|
-
|
27
|
+
def initialize(*args)
|
28
|
+
if args.first.is_a?(Base) || args.first.nil?
|
29
|
+
@environment = args.shift
|
30
|
+
end
|
27
31
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
32
|
+
@dir, @path = args[0], args[1]
|
33
|
+
|
34
|
+
# Expand paths
|
35
|
+
@dir = File.expand_path(@dir) if @dir
|
36
|
+
@path = File.expand_path(@path) if @path
|
37
|
+
|
38
|
+
# If path is given as the second arg
|
39
|
+
if @dir && File.extname(@dir) != ""
|
40
|
+
@dir, @path = nil, @dir
|
41
|
+
end
|
42
|
+
|
43
|
+
# Default dir to the directory of the path
|
44
|
+
@dir ||= File.dirname(@path) if @path
|
45
|
+
|
46
|
+
# If directory is given w/o path, pick a random manifest.json location
|
47
|
+
if @dir && @path.nil?
|
48
|
+
# Find the first manifest.json in the directory
|
49
|
+
paths = Dir[File.join(@dir, "manifest*.json")]
|
50
|
+
if paths.any?
|
51
|
+
@path = paths.first
|
52
|
+
else
|
53
|
+
@path = File.join(@dir, "manifest-#{SecureRandom.hex(16)}.json")
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
unless @dir && @path
|
58
|
+
raise ArgumentError, "manifest requires output path"
|
34
59
|
end
|
35
60
|
|
36
61
|
data = nil
|
37
62
|
|
38
63
|
begin
|
39
64
|
if File.exist?(@path)
|
40
|
-
data =
|
65
|
+
data = json_decode(File.read(@path))
|
41
66
|
end
|
42
67
|
rescue MultiJson::DecodeError => e
|
43
68
|
logger.error "#{@path} is invalid: #{e.class} #{e.message}"
|
@@ -83,14 +108,19 @@ module Sprockets
|
|
83
108
|
# compile("application.js")
|
84
109
|
#
|
85
110
|
def compile(*args)
|
111
|
+
unless environment
|
112
|
+
raise Error, "manifest requires environment for compilation"
|
113
|
+
end
|
114
|
+
|
86
115
|
paths = environment.each_logical_path(*args).to_a +
|
87
|
-
args.flatten.select { |fn| Pathname.new(fn).absolute? }
|
116
|
+
args.flatten.select { |fn| Pathname.new(fn).absolute? if fn.is_a?(String)}
|
88
117
|
|
89
118
|
paths.each do |path|
|
90
119
|
if asset = find_asset(path)
|
91
120
|
files[asset.digest_path] = {
|
92
121
|
'logical_path' => asset.logical_path,
|
93
122
|
'mtime' => asset.mtime.iso8601,
|
123
|
+
'size' => asset.bytesize,
|
94
124
|
'digest' => asset.digest
|
95
125
|
}
|
96
126
|
assets[asset.logical_path] = asset.digest_path
|
@@ -102,12 +132,13 @@ module Sprockets
|
|
102
132
|
else
|
103
133
|
logger.info "Writing #{target}"
|
104
134
|
asset.write_to target
|
135
|
+
asset.write_to "#{target}.gz" if asset.is_a?(BundledAsset)
|
105
136
|
end
|
106
137
|
|
107
|
-
save
|
108
|
-
asset
|
109
138
|
end
|
110
139
|
end
|
140
|
+
save
|
141
|
+
paths
|
111
142
|
end
|
112
143
|
|
113
144
|
# Removes file from directory and from manifest. `filename` must
|
@@ -117,6 +148,7 @@ module Sprockets
|
|
117
148
|
#
|
118
149
|
def remove(filename)
|
119
150
|
path = File.join(dir, filename)
|
151
|
+
gzip = "#{path}.gz"
|
120
152
|
logical_path = files[filename]['logical_path']
|
121
153
|
|
122
154
|
if assets[logical_path] == filename
|
@@ -125,10 +157,11 @@ module Sprockets
|
|
125
157
|
|
126
158
|
files.delete(filename)
|
127
159
|
FileUtils.rm(path) if File.exist?(path)
|
160
|
+
FileUtils.rm(gzip) if File.exist?(gzip)
|
128
161
|
|
129
162
|
save
|
130
163
|
|
131
|
-
logger.
|
164
|
+
logger.info "Removed #{filename}"
|
132
165
|
|
133
166
|
nil
|
134
167
|
end
|
@@ -151,7 +184,7 @@ module Sprockets
|
|
151
184
|
# Wipe directive
|
152
185
|
def clobber
|
153
186
|
FileUtils.rm_r(@dir) if File.exist?(@dir)
|
154
|
-
logger.
|
187
|
+
logger.info "Removed #{@dir}"
|
155
188
|
nil
|
156
189
|
end
|
157
190
|
|
@@ -177,21 +210,46 @@ module Sprockets
|
|
177
210
|
ms = benchmark do
|
178
211
|
asset = environment.find_asset(logical_path)
|
179
212
|
end
|
180
|
-
logger.
|
213
|
+
logger.debug "Compiled #{logical_path} (#{ms}ms)"
|
181
214
|
asset
|
182
215
|
end
|
183
216
|
|
184
217
|
# Persist manfiest back to FS
|
185
218
|
def save
|
186
|
-
FileUtils.mkdir_p
|
219
|
+
FileUtils.mkdir_p File.dirname(path)
|
187
220
|
File.open(path, 'w') do |f|
|
188
|
-
f.write
|
221
|
+
f.write json_encode(@data)
|
189
222
|
end
|
190
223
|
end
|
191
224
|
|
192
225
|
private
|
226
|
+
# Feature detect newer MultiJson API
|
227
|
+
if MultiJson.respond_to?(:dump)
|
228
|
+
def json_decode(obj)
|
229
|
+
MultiJson.load(obj)
|
230
|
+
end
|
231
|
+
|
232
|
+
def json_encode(obj)
|
233
|
+
MultiJson.dump(obj)
|
234
|
+
end
|
235
|
+
else
|
236
|
+
def json_decode(obj)
|
237
|
+
MultiJson.decode(obj)
|
238
|
+
end
|
239
|
+
|
240
|
+
def json_encode(obj)
|
241
|
+
MultiJson.encode(obj)
|
242
|
+
end
|
243
|
+
end
|
244
|
+
|
193
245
|
def logger
|
194
|
-
environment
|
246
|
+
if environment
|
247
|
+
environment.logger
|
248
|
+
else
|
249
|
+
logger = Logger.new($stderr)
|
250
|
+
logger.level = Logger::FATAL
|
251
|
+
logger
|
252
|
+
end
|
195
253
|
end
|
196
254
|
|
197
255
|
def benchmark
|
data/lib/sprockets/mime.rb
CHANGED
@@ -15,6 +15,11 @@ module Sprockets
|
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
18
|
+
# Returns a `Hash` of explicitly registered mime types.
|
19
|
+
def registered_mime_types
|
20
|
+
@mime_types.dup
|
21
|
+
end
|
22
|
+
|
18
23
|
if {}.respond_to?(:key)
|
19
24
|
def extension_for_mime_type(type)
|
20
25
|
mime_types.key(type)
|
@@ -41,8 +46,4 @@ module Sprockets
|
|
41
46
|
end
|
42
47
|
end
|
43
48
|
end
|
44
|
-
|
45
|
-
# Extend Sprockets module to provide global registry
|
46
|
-
extend Mime
|
47
|
-
@mime_types = {}
|
48
49
|
end
|
@@ -1,16 +1,11 @@
|
|
1
|
-
require 'sprockets/errors'
|
2
|
-
require 'pathname'
|
3
|
-
|
4
1
|
module Sprockets
|
5
|
-
|
6
|
-
# the `Environment` and `Index` classes.
|
7
|
-
module Trail
|
2
|
+
module Paths
|
8
3
|
# Returns `Environment` root.
|
9
4
|
#
|
10
5
|
# All relative paths are expanded with root as its base. To be
|
11
6
|
# useful set this to your applications root directory. (`Rails.root`)
|
12
7
|
def root
|
13
|
-
trail.root.dup
|
8
|
+
@trail.root.dup
|
14
9
|
end
|
15
10
|
|
16
11
|
# Returns an `Array` of path `String`s.
|
@@ -21,14 +16,13 @@ module Sprockets
|
|
21
16
|
# have no affect on the environment. See `append_path`,
|
22
17
|
# `prepend_path`, and `clear_paths`.
|
23
18
|
def paths
|
24
|
-
trail.paths.dup
|
19
|
+
@trail.paths.dup
|
25
20
|
end
|
26
21
|
|
27
22
|
# Prepend a `path` to the `paths` list.
|
28
23
|
#
|
29
24
|
# Paths at the end of the `Array` have the least priority.
|
30
25
|
def prepend_path(path)
|
31
|
-
expire_index!
|
32
26
|
@trail.prepend_path(path)
|
33
27
|
end
|
34
28
|
|
@@ -36,7 +30,6 @@ module Sprockets
|
|
36
30
|
#
|
37
31
|
# Paths at the beginning of the `Array` have a higher priority.
|
38
32
|
def append_path(path)
|
39
|
-
expire_index!
|
40
33
|
@trail.append_path(path)
|
41
34
|
end
|
42
35
|
|
@@ -46,7 +39,6 @@ module Sprockets
|
|
46
39
|
# completely wipe the paths list and reappend them in the order
|
47
40
|
# you want.
|
48
41
|
def clear_paths
|
49
|
-
expire_index!
|
50
42
|
@trail.paths.dup.each { |path| @trail.remove_path(path) }
|
51
43
|
end
|
52
44
|
|
@@ -57,34 +49,10 @@ module Sprockets
|
|
57
49
|
# # => [".js", ".css", ".coffee", ".sass", ...]
|
58
50
|
#
|
59
51
|
def extensions
|
60
|
-
trail.extensions.dup
|
61
|
-
end
|
62
|
-
|
63
|
-
# Finds the expanded real path for a given logical path by
|
64
|
-
# searching the environment's paths.
|
65
|
-
#
|
66
|
-
# resolve("application.js")
|
67
|
-
# # => "/path/to/app/javascripts/application.js.coffee"
|
68
|
-
#
|
69
|
-
# A `FileNotFound` exception is raised if the file does not exist.
|
70
|
-
def resolve(logical_path, options = {})
|
71
|
-
# If a block is given, preform an iterable search
|
72
|
-
if block_given?
|
73
|
-
args = attributes_for(logical_path).search_paths + [options]
|
74
|
-
trail.find(*args) do |path|
|
75
|
-
yield Pathname.new(path)
|
76
|
-
end
|
77
|
-
else
|
78
|
-
resolve(logical_path, options) do |pathname|
|
79
|
-
return pathname
|
80
|
-
end
|
81
|
-
raise FileNotFound, "couldn't find file '#{logical_path}'"
|
82
|
-
end
|
52
|
+
@trail.extensions.dup
|
83
53
|
end
|
84
54
|
|
85
55
|
protected
|
86
|
-
|
87
|
-
@trail
|
88
|
-
end
|
56
|
+
attr_reader :trail
|
89
57
|
end
|
90
58
|
end
|