sprockets 2.12.5 → 3.0.0.beta.1
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 +5 -5
- data/LICENSE +2 -2
- data/README.md +61 -34
- data/lib/rake/sprocketstask.rb +5 -4
- data/lib/sprockets.rb +123 -85
- data/lib/sprockets/asset.rb +161 -200
- data/lib/sprockets/asset_uri.rb +64 -0
- data/lib/sprockets/base.rb +138 -373
- data/lib/sprockets/bower.rb +56 -0
- data/lib/sprockets/bundle.rb +32 -0
- data/lib/sprockets/cache.rb +220 -0
- data/lib/sprockets/cache/file_store.rb +145 -13
- data/lib/sprockets/cache/memory_store.rb +66 -0
- data/lib/sprockets/cache/null_store.rb +46 -0
- data/lib/sprockets/cached_environment.rb +103 -0
- data/lib/sprockets/closure_compressor.rb +30 -12
- data/lib/sprockets/coffee_script_template.rb +23 -0
- data/lib/sprockets/compressing.rb +20 -25
- data/lib/sprockets/configuration.rb +95 -0
- data/lib/sprockets/context.rb +68 -131
- data/lib/sprockets/directive_processor.rb +138 -179
- data/lib/sprockets/eco_template.rb +10 -19
- data/lib/sprockets/ejs_template.rb +10 -19
- data/lib/sprockets/encoding_utils.rb +246 -0
- data/lib/sprockets/engines.rb +40 -29
- data/lib/sprockets/environment.rb +10 -66
- data/lib/sprockets/erb_template.rb +23 -0
- data/lib/sprockets/errors.rb +5 -13
- data/lib/sprockets/http_utils.rb +97 -0
- data/lib/sprockets/jst_processor.rb +28 -15
- data/lib/sprockets/lazy_processor.rb +15 -0
- data/lib/sprockets/legacy.rb +23 -0
- data/lib/sprockets/legacy_proc_processor.rb +35 -0
- data/lib/sprockets/legacy_tilt_processor.rb +29 -0
- data/lib/sprockets/manifest.rb +128 -99
- data/lib/sprockets/mime.rb +114 -33
- data/lib/sprockets/path_utils.rb +179 -0
- data/lib/sprockets/paths.rb +13 -26
- data/lib/sprockets/processing.rb +198 -107
- data/lib/sprockets/resolve.rb +289 -0
- data/lib/sprockets/sass_compressor.rb +36 -17
- data/lib/sprockets/sass_template.rb +269 -46
- data/lib/sprockets/server.rb +113 -83
- data/lib/sprockets/transformers.rb +69 -0
- data/lib/sprockets/uglifier_compressor.rb +36 -15
- data/lib/sprockets/utils.rb +161 -44
- data/lib/sprockets/version.rb +1 -1
- data/lib/sprockets/yui_compressor.rb +37 -12
- metadata +64 -106
- data/lib/sprockets/asset_attributes.rb +0 -137
- data/lib/sprockets/bundled_asset.rb +0 -78
- data/lib/sprockets/caching.rb +0 -96
- data/lib/sprockets/charset_normalizer.rb +0 -41
- data/lib/sprockets/index.rb +0 -100
- data/lib/sprockets/processed_asset.rb +0 -152
- data/lib/sprockets/processor.rb +0 -32
- data/lib/sprockets/safety_colons.rb +0 -28
- data/lib/sprockets/sass_cache_store.rb +0 -29
- data/lib/sprockets/sass_functions.rb +0 -70
- data/lib/sprockets/sass_importer.rb +0 -30
- data/lib/sprockets/scss_template.rb +0 -13
- data/lib/sprockets/static_asset.rb +0 -60
@@ -1,78 +0,0 @@
|
|
1
|
-
require 'sprockets/asset'
|
2
|
-
require 'sprockets/errors'
|
3
|
-
require 'fileutils'
|
4
|
-
require 'set'
|
5
|
-
require 'zlib'
|
6
|
-
|
7
|
-
module Sprockets
|
8
|
-
# `BundledAsset`s are used for files that need to be processed and
|
9
|
-
# concatenated with other assets. Use for `.js` and `.css` files.
|
10
|
-
class BundledAsset < Asset
|
11
|
-
attr_reader :source
|
12
|
-
|
13
|
-
def initialize(environment, logical_path, pathname)
|
14
|
-
super(environment, logical_path, pathname)
|
15
|
-
|
16
|
-
@processed_asset = environment.find_asset(pathname, :bundle => false)
|
17
|
-
@required_assets = @processed_asset.required_assets
|
18
|
-
@dependency_paths = @processed_asset.dependency_paths
|
19
|
-
|
20
|
-
# Explode Asset into parts and gather the dependency bodies
|
21
|
-
@source = to_a.map { |dependency| dependency.to_s }.join
|
22
|
-
|
23
|
-
# Run bundle processors on concatenated source
|
24
|
-
context = environment.context_class.new(environment, logical_path, pathname)
|
25
|
-
@source = context.evaluate(pathname, :data => @source,
|
26
|
-
:processors => environment.bundle_processors(content_type))
|
27
|
-
|
28
|
-
@mtime = (to_a + @dependency_paths).map(&:mtime).max
|
29
|
-
@length = Rack::Utils.bytesize(source)
|
30
|
-
@digest = environment.digest.update(source).hexdigest
|
31
|
-
end
|
32
|
-
|
33
|
-
# Initialize `BundledAsset` from serialized `Hash`.
|
34
|
-
def init_with(environment, coder)
|
35
|
-
super
|
36
|
-
|
37
|
-
@processed_asset = environment.find_asset(pathname, :bundle => false)
|
38
|
-
@required_assets = @processed_asset.required_assets
|
39
|
-
|
40
|
-
if @processed_asset.dependency_digest != coder['required_assets_digest']
|
41
|
-
raise UnserializeError, "processed asset belongs to a stale environment"
|
42
|
-
end
|
43
|
-
|
44
|
-
@source = coder['source']
|
45
|
-
end
|
46
|
-
|
47
|
-
# Serialize custom attributes in `BundledAsset`.
|
48
|
-
def encode_with(coder)
|
49
|
-
super
|
50
|
-
|
51
|
-
coder['source'] = source
|
52
|
-
coder['required_assets_digest'] = @processed_asset.dependency_digest
|
53
|
-
end
|
54
|
-
|
55
|
-
# Get asset's own processed contents. Excludes any of its required
|
56
|
-
# dependencies but does run any processors or engines on the
|
57
|
-
# original file.
|
58
|
-
def body
|
59
|
-
@processed_asset.source
|
60
|
-
end
|
61
|
-
|
62
|
-
# Return an `Array` of `Asset` files that are declared dependencies.
|
63
|
-
def dependencies
|
64
|
-
to_a.reject { |a| a.eql?(@processed_asset) }
|
65
|
-
end
|
66
|
-
|
67
|
-
# Expand asset into an `Array` of parts.
|
68
|
-
def to_a
|
69
|
-
required_assets
|
70
|
-
end
|
71
|
-
|
72
|
-
# Checks if Asset is stale by comparing the actual mtime and
|
73
|
-
# digest to the inmemory model.
|
74
|
-
def fresh?(environment)
|
75
|
-
@processed_asset.fresh?(environment)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
end
|
data/lib/sprockets/caching.rb
DELETED
@@ -1,96 +0,0 @@
|
|
1
|
-
module Sprockets
|
2
|
-
# `Caching` is an internal mixin whose public methods are exposed on
|
3
|
-
# the `Environment` and `Index` classes.
|
4
|
-
module Caching
|
5
|
-
# Low level cache getter for `key`. Checks a number of supported
|
6
|
-
# cache interfaces.
|
7
|
-
def cache_get(key)
|
8
|
-
# `Cache#get(key)` for Memcache
|
9
|
-
if cache.respond_to?(:get)
|
10
|
-
cache.get(key)
|
11
|
-
|
12
|
-
# `Cache#[key]` so `Hash` can be used
|
13
|
-
elsif cache.respond_to?(:[])
|
14
|
-
cache[key]
|
15
|
-
|
16
|
-
# `Cache#read(key)` for `ActiveSupport::Cache` support
|
17
|
-
elsif cache.respond_to?(:read)
|
18
|
-
cache.read(key)
|
19
|
-
|
20
|
-
else
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Low level cache setter for `key`. Checks a number of supported
|
26
|
-
# cache interfaces.
|
27
|
-
def cache_set(key, value)
|
28
|
-
# `Cache#set(key, value)` for Memcache
|
29
|
-
if cache.respond_to?(:set)
|
30
|
-
cache.set(key, value)
|
31
|
-
|
32
|
-
# `Cache#[key]=value` so `Hash` can be used
|
33
|
-
elsif cache.respond_to?(:[]=)
|
34
|
-
cache[key] = value
|
35
|
-
|
36
|
-
# `Cache#write(key, value)` for `ActiveSupport::Cache` support
|
37
|
-
elsif cache.respond_to?(:write)
|
38
|
-
cache.write(key, value)
|
39
|
-
end
|
40
|
-
|
41
|
-
value
|
42
|
-
end
|
43
|
-
|
44
|
-
protected
|
45
|
-
# Cache helper method. Takes a `path` argument which maybe a
|
46
|
-
# logical path or fully expanded path. The `&block` is passed
|
47
|
-
# for finding and building the asset if its not in cache.
|
48
|
-
def cache_asset(path)
|
49
|
-
# If `cache` is not set, return fast
|
50
|
-
if cache.nil?
|
51
|
-
yield
|
52
|
-
|
53
|
-
# Check cache for `path`
|
54
|
-
elsif (asset = Asset.from_hash(self, cache_get_hash(path.to_s))) && asset.fresh?(self)
|
55
|
-
asset
|
56
|
-
|
57
|
-
# Otherwise yield block that slowly finds and builds the asset
|
58
|
-
elsif asset = yield
|
59
|
-
hash = {}
|
60
|
-
asset.encode_with(hash)
|
61
|
-
|
62
|
-
# Save the asset to its path
|
63
|
-
cache_set_hash(path.to_s, hash)
|
64
|
-
|
65
|
-
# Since path maybe a logical or full pathname, save the
|
66
|
-
# asset its its full path too
|
67
|
-
if path.to_s != asset.pathname.to_s
|
68
|
-
cache_set_hash(asset.pathname.to_s, hash)
|
69
|
-
end
|
70
|
-
|
71
|
-
asset
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|
75
|
-
private
|
76
|
-
# Strips `Environment#root` from key to make the key work
|
77
|
-
# consisently across different servers. The key is also hashed
|
78
|
-
# so it does not exceed 250 characters.
|
79
|
-
def expand_cache_key(key)
|
80
|
-
File.join('sprockets', digest_class.hexdigest(key.sub(root, '')))
|
81
|
-
end
|
82
|
-
|
83
|
-
def cache_get_hash(key)
|
84
|
-
hash = cache_get(expand_cache_key(key))
|
85
|
-
if hash.is_a?(Hash) && digest.hexdigest == hash['_version']
|
86
|
-
hash
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def cache_set_hash(key, hash)
|
91
|
-
hash['_version'] = digest.hexdigest
|
92
|
-
cache_set(expand_cache_key(key), hash)
|
93
|
-
hash
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
@@ -1,41 +0,0 @@
|
|
1
|
-
require 'tilt'
|
2
|
-
|
3
|
-
module Sprockets
|
4
|
-
# Some browsers have issues with stylesheets that contain multiple
|
5
|
-
# `@charset` definitions. The issue surfaces while using Sass since
|
6
|
-
# it inserts a `@charset` at the top of each file. Then Sprockets
|
7
|
-
# concatenates them together.
|
8
|
-
#
|
9
|
-
# The `CharsetNormalizer` processor strips out multiple `@charset`
|
10
|
-
# definitions.
|
11
|
-
#
|
12
|
-
# The current implementation is naive. It picks the first `@charset`
|
13
|
-
# it sees and strips the others. This works for most people because
|
14
|
-
# the other definitions are usually `UTF-8`. A more sophisticated
|
15
|
-
# approach would be to re-encode stylesheets with mixed encodings.
|
16
|
-
#
|
17
|
-
# This behavior can be disabled with:
|
18
|
-
#
|
19
|
-
# environment.unregister_bundle_processor 'text/css', Sprockets::CharsetNormalizer
|
20
|
-
#
|
21
|
-
class CharsetNormalizer < Tilt::Template
|
22
|
-
def prepare
|
23
|
-
end
|
24
|
-
|
25
|
-
def evaluate(context, locals, &block)
|
26
|
-
charset = nil
|
27
|
-
|
28
|
-
# Find and strip out any `@charset` definitions
|
29
|
-
filtered_data = data.gsub(/^@charset "([^"]+)";$/) {
|
30
|
-
charset ||= $1; ""
|
31
|
-
}
|
32
|
-
|
33
|
-
if charset
|
34
|
-
# If there was a charset, move it to the top
|
35
|
-
"@charset \"#{charset}\";#{filtered_data}"
|
36
|
-
else
|
37
|
-
data
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
data/lib/sprockets/index.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'sprockets/base'
|
2
|
-
|
3
|
-
module Sprockets
|
4
|
-
# `Index` is a special cached version of `Environment`.
|
5
|
-
#
|
6
|
-
# The expection is that all of its file system methods are cached
|
7
|
-
# for the instances lifetime. This makes `Index` much faster. This
|
8
|
-
# behavior is ideal in production environments where the file system
|
9
|
-
# is immutable.
|
10
|
-
#
|
11
|
-
# `Index` should not be initialized directly. Instead use
|
12
|
-
# `Environment#index`.
|
13
|
-
class Index < Base
|
14
|
-
def initialize(environment)
|
15
|
-
@environment = environment
|
16
|
-
|
17
|
-
if environment.respond_to?(:default_external_encoding)
|
18
|
-
@default_external_encoding = environment.default_external_encoding
|
19
|
-
end
|
20
|
-
|
21
|
-
# Copy environment attributes
|
22
|
-
@logger = environment.logger
|
23
|
-
@context_class = environment.context_class
|
24
|
-
@cache = environment.cache
|
25
|
-
@trail = environment.trail.index
|
26
|
-
@digest = environment.digest
|
27
|
-
@digest_class = environment.digest_class
|
28
|
-
@version = environment.version
|
29
|
-
@mime_types = environment.mime_types
|
30
|
-
@engines = environment.engines
|
31
|
-
@preprocessors = environment.preprocessors
|
32
|
-
@postprocessors = environment.postprocessors
|
33
|
-
@bundle_processors = environment.bundle_processors
|
34
|
-
@compressors = environment.compressors
|
35
|
-
|
36
|
-
# Initialize caches
|
37
|
-
@assets = {}
|
38
|
-
@digests = {}
|
39
|
-
end
|
40
|
-
|
41
|
-
# No-op return self as index
|
42
|
-
def index
|
43
|
-
self
|
44
|
-
end
|
45
|
-
|
46
|
-
# Cache calls to `file_digest`
|
47
|
-
def file_digest(pathname)
|
48
|
-
key = pathname.to_s
|
49
|
-
if @digests.key?(key)
|
50
|
-
@digests[key]
|
51
|
-
else
|
52
|
-
@digests[key] = super
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
# Cache `find_asset` calls
|
57
|
-
def find_asset(path, options = {})
|
58
|
-
options[:bundle] = true unless options.key?(:bundle)
|
59
|
-
if asset = @assets[cache_key_for(path, options)]
|
60
|
-
asset
|
61
|
-
elsif asset = super
|
62
|
-
logical_path_cache_key = cache_key_for(path, options)
|
63
|
-
full_path_cache_key = cache_key_for(asset.pathname, options)
|
64
|
-
|
65
|
-
# Cache on Index
|
66
|
-
@assets[logical_path_cache_key] = @assets[full_path_cache_key] = asset
|
67
|
-
|
68
|
-
# Push cache upstream to Environment
|
69
|
-
@environment.instance_eval do
|
70
|
-
@assets[logical_path_cache_key] = @assets[full_path_cache_key] = asset
|
71
|
-
end
|
72
|
-
|
73
|
-
asset
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
protected
|
78
|
-
# Index is immutable, any methods that try to clear the cache
|
79
|
-
# should bomb.
|
80
|
-
def expire_index!
|
81
|
-
raise TypeError, "can't modify immutable index"
|
82
|
-
end
|
83
|
-
|
84
|
-
# Cache asset building in memory and in persisted cache.
|
85
|
-
def build_asset(path, pathname, options)
|
86
|
-
# Memory cache
|
87
|
-
key = cache_key_for(pathname, options)
|
88
|
-
if @assets.key?(key)
|
89
|
-
@assets[key]
|
90
|
-
else
|
91
|
-
@assets[key] = begin
|
92
|
-
# Persisted cache
|
93
|
-
cache_asset(key) do
|
94
|
-
super
|
95
|
-
end
|
96
|
-
end
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
end
|
@@ -1,152 +0,0 @@
|
|
1
|
-
require 'sprockets/asset'
|
2
|
-
require 'sprockets/utils'
|
3
|
-
|
4
|
-
module Sprockets
|
5
|
-
class ProcessedAsset < Asset
|
6
|
-
def initialize(environment, logical_path, pathname)
|
7
|
-
super
|
8
|
-
|
9
|
-
start_time = Time.now.to_f
|
10
|
-
|
11
|
-
context = environment.context_class.new(environment, logical_path, pathname)
|
12
|
-
@source = context.evaluate(pathname)
|
13
|
-
@length = Rack::Utils.bytesize(source)
|
14
|
-
@digest = environment.digest.update(source).hexdigest
|
15
|
-
|
16
|
-
build_required_assets(environment, context)
|
17
|
-
build_dependency_paths(environment, context)
|
18
|
-
|
19
|
-
@dependency_digest = compute_dependency_digest(environment)
|
20
|
-
|
21
|
-
elapsed_time = ((Time.now.to_f - start_time) * 1000).to_i
|
22
|
-
environment.logger.debug "Compiled #{logical_path} (#{elapsed_time}ms) (pid #{Process.pid})"
|
23
|
-
end
|
24
|
-
|
25
|
-
# Interal: Used to check equality
|
26
|
-
attr_reader :dependency_digest
|
27
|
-
|
28
|
-
attr_reader :source
|
29
|
-
|
30
|
-
# Initialize `BundledAsset` from serialized `Hash`.
|
31
|
-
def init_with(environment, coder)
|
32
|
-
super
|
33
|
-
|
34
|
-
@source = coder['source']
|
35
|
-
@dependency_digest = coder['dependency_digest']
|
36
|
-
|
37
|
-
@required_assets = coder['required_paths'].map { |p|
|
38
|
-
p = expand_root_path(p)
|
39
|
-
|
40
|
-
unless environment.paths.detect { |path| p[path] }
|
41
|
-
raise UnserializeError, "#{p} isn't in paths"
|
42
|
-
end
|
43
|
-
|
44
|
-
p == pathname.to_s ? self : environment.find_asset(p, :bundle => false)
|
45
|
-
}
|
46
|
-
@dependency_paths = coder['dependency_paths'].map { |h|
|
47
|
-
DependencyFile.new(expand_root_path(h['path']), h['mtime'], h['digest'])
|
48
|
-
}
|
49
|
-
end
|
50
|
-
|
51
|
-
# Serialize custom attributes in `BundledAsset`.
|
52
|
-
def encode_with(coder)
|
53
|
-
super
|
54
|
-
|
55
|
-
coder['source'] = source
|
56
|
-
coder['dependency_digest'] = dependency_digest
|
57
|
-
|
58
|
-
coder['required_paths'] = required_assets.map { |a|
|
59
|
-
relativize_root_path(a.pathname).to_s
|
60
|
-
}
|
61
|
-
coder['dependency_paths'] = dependency_paths.map { |d|
|
62
|
-
{ 'path' => relativize_root_path(d.pathname).to_s,
|
63
|
-
'mtime' => d.mtime.iso8601,
|
64
|
-
'digest' => d.digest }
|
65
|
-
}
|
66
|
-
end
|
67
|
-
|
68
|
-
# Checks if Asset is stale by comparing the actual mtime and
|
69
|
-
# digest to the inmemory model.
|
70
|
-
def fresh?(environment)
|
71
|
-
# Check freshness of all declared dependencies
|
72
|
-
@dependency_paths.all? { |dep| dependency_fresh?(environment, dep) }
|
73
|
-
end
|
74
|
-
|
75
|
-
protected
|
76
|
-
class DependencyFile < Struct.new(:pathname, :mtime, :digest)
|
77
|
-
def initialize(pathname, mtime, digest)
|
78
|
-
pathname = Pathname.new(pathname) unless pathname.is_a?(Pathname)
|
79
|
-
mtime = Time.parse(mtime) if mtime.is_a?(String)
|
80
|
-
super
|
81
|
-
end
|
82
|
-
|
83
|
-
def eql?(other)
|
84
|
-
other.is_a?(DependencyFile) &&
|
85
|
-
pathname.eql?(other.pathname) &&
|
86
|
-
mtime.eql?(other.mtime) &&
|
87
|
-
digest.eql?(other.digest)
|
88
|
-
end
|
89
|
-
|
90
|
-
def hash
|
91
|
-
pathname.to_s.hash
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
private
|
96
|
-
def build_required_assets(environment, context)
|
97
|
-
@required_assets = resolve_dependencies(environment, context._required_paths + [pathname.to_s]) -
|
98
|
-
resolve_dependencies(environment, context._stubbed_assets.to_a)
|
99
|
-
end
|
100
|
-
|
101
|
-
def resolve_dependencies(environment, paths)
|
102
|
-
assets = []
|
103
|
-
cache = {}
|
104
|
-
|
105
|
-
paths.each do |path|
|
106
|
-
if path == self.pathname.to_s
|
107
|
-
unless cache[self]
|
108
|
-
cache[self] = true
|
109
|
-
assets << self
|
110
|
-
end
|
111
|
-
elsif asset = environment.find_asset(path, :bundle => false)
|
112
|
-
asset.required_assets.each do |asset_dependency|
|
113
|
-
unless cache[asset_dependency]
|
114
|
-
cache[asset_dependency] = true
|
115
|
-
assets << asset_dependency
|
116
|
-
end
|
117
|
-
end
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
assets
|
122
|
-
end
|
123
|
-
|
124
|
-
def build_dependency_paths(environment, context)
|
125
|
-
dependency_paths = {}
|
126
|
-
|
127
|
-
context._dependency_paths.each do |path|
|
128
|
-
dep = DependencyFile.new(path, environment.stat(path).mtime, environment.file_digest(path).hexdigest)
|
129
|
-
dependency_paths[dep] = true
|
130
|
-
end
|
131
|
-
|
132
|
-
context._dependency_assets.each do |path|
|
133
|
-
if path == self.pathname.to_s
|
134
|
-
dep = DependencyFile.new(pathname, environment.stat(path).mtime, environment.file_digest(path).hexdigest)
|
135
|
-
dependency_paths[dep] = true
|
136
|
-
elsif asset = environment.find_asset(path, :bundle => false)
|
137
|
-
asset.dependency_paths.each do |d|
|
138
|
-
dependency_paths[d] = true
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
@dependency_paths = dependency_paths.keys
|
144
|
-
end
|
145
|
-
|
146
|
-
def compute_dependency_digest(environment)
|
147
|
-
required_assets.inject(environment.digest) { |digest, asset|
|
148
|
-
digest.update asset.digest
|
149
|
-
}.hexdigest
|
150
|
-
end
|
151
|
-
end
|
152
|
-
end
|