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.

Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +2 -2
  3. data/README.md +61 -34
  4. data/lib/rake/sprocketstask.rb +5 -4
  5. data/lib/sprockets.rb +123 -85
  6. data/lib/sprockets/asset.rb +161 -200
  7. data/lib/sprockets/asset_uri.rb +64 -0
  8. data/lib/sprockets/base.rb +138 -373
  9. data/lib/sprockets/bower.rb +56 -0
  10. data/lib/sprockets/bundle.rb +32 -0
  11. data/lib/sprockets/cache.rb +220 -0
  12. data/lib/sprockets/cache/file_store.rb +145 -13
  13. data/lib/sprockets/cache/memory_store.rb +66 -0
  14. data/lib/sprockets/cache/null_store.rb +46 -0
  15. data/lib/sprockets/cached_environment.rb +103 -0
  16. data/lib/sprockets/closure_compressor.rb +30 -12
  17. data/lib/sprockets/coffee_script_template.rb +23 -0
  18. data/lib/sprockets/compressing.rb +20 -25
  19. data/lib/sprockets/configuration.rb +95 -0
  20. data/lib/sprockets/context.rb +68 -131
  21. data/lib/sprockets/directive_processor.rb +138 -179
  22. data/lib/sprockets/eco_template.rb +10 -19
  23. data/lib/sprockets/ejs_template.rb +10 -19
  24. data/lib/sprockets/encoding_utils.rb +246 -0
  25. data/lib/sprockets/engines.rb +40 -29
  26. data/lib/sprockets/environment.rb +10 -66
  27. data/lib/sprockets/erb_template.rb +23 -0
  28. data/lib/sprockets/errors.rb +5 -13
  29. data/lib/sprockets/http_utils.rb +97 -0
  30. data/lib/sprockets/jst_processor.rb +28 -15
  31. data/lib/sprockets/lazy_processor.rb +15 -0
  32. data/lib/sprockets/legacy.rb +23 -0
  33. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  34. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  35. data/lib/sprockets/manifest.rb +128 -99
  36. data/lib/sprockets/mime.rb +114 -33
  37. data/lib/sprockets/path_utils.rb +179 -0
  38. data/lib/sprockets/paths.rb +13 -26
  39. data/lib/sprockets/processing.rb +198 -107
  40. data/lib/sprockets/resolve.rb +289 -0
  41. data/lib/sprockets/sass_compressor.rb +36 -17
  42. data/lib/sprockets/sass_template.rb +269 -46
  43. data/lib/sprockets/server.rb +113 -83
  44. data/lib/sprockets/transformers.rb +69 -0
  45. data/lib/sprockets/uglifier_compressor.rb +36 -15
  46. data/lib/sprockets/utils.rb +161 -44
  47. data/lib/sprockets/version.rb +1 -1
  48. data/lib/sprockets/yui_compressor.rb +37 -12
  49. metadata +64 -106
  50. data/lib/sprockets/asset_attributes.rb +0 -137
  51. data/lib/sprockets/bundled_asset.rb +0 -78
  52. data/lib/sprockets/caching.rb +0 -96
  53. data/lib/sprockets/charset_normalizer.rb +0 -41
  54. data/lib/sprockets/index.rb +0 -100
  55. data/lib/sprockets/processed_asset.rb +0 -152
  56. data/lib/sprockets/processor.rb +0 -32
  57. data/lib/sprockets/safety_colons.rb +0 -28
  58. data/lib/sprockets/sass_cache_store.rb +0 -29
  59. data/lib/sprockets/sass_functions.rb +0 -70
  60. data/lib/sprockets/sass_importer.rb +0 -30
  61. data/lib/sprockets/scss_template.rb +0 -13
  62. 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
@@ -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
@@ -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