sprockets 2.12.5 → 3.7.2

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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +296 -0
  3. data/LICENSE +2 -2
  4. data/README.md +235 -262
  5. data/bin/sprockets +1 -0
  6. data/lib/rake/sprocketstask.rb +5 -4
  7. data/lib/sprockets/asset.rb +143 -212
  8. data/lib/sprockets/autoload/closure.rb +7 -0
  9. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  10. data/lib/sprockets/autoload/eco.rb +7 -0
  11. data/lib/sprockets/autoload/ejs.rb +7 -0
  12. data/lib/sprockets/autoload/sass.rb +7 -0
  13. data/lib/sprockets/autoload/uglifier.rb +7 -0
  14. data/lib/sprockets/autoload/yui.rb +7 -0
  15. data/lib/sprockets/autoload.rb +11 -0
  16. data/lib/sprockets/base.rb +56 -393
  17. data/lib/sprockets/bower.rb +58 -0
  18. data/lib/sprockets/bundle.rb +69 -0
  19. data/lib/sprockets/cache/file_store.rb +168 -14
  20. data/lib/sprockets/cache/memory_store.rb +66 -0
  21. data/lib/sprockets/cache/null_store.rb +46 -0
  22. data/lib/sprockets/cache.rb +236 -0
  23. data/lib/sprockets/cached_environment.rb +69 -0
  24. data/lib/sprockets/closure_compressor.rb +35 -10
  25. data/lib/sprockets/coffee_script_processor.rb +25 -0
  26. data/lib/sprockets/coffee_script_template.rb +17 -0
  27. data/lib/sprockets/compressing.rb +44 -23
  28. data/lib/sprockets/configuration.rb +83 -0
  29. data/lib/sprockets/context.rb +86 -144
  30. data/lib/sprockets/dependencies.rb +73 -0
  31. data/lib/sprockets/deprecation.rb +90 -0
  32. data/lib/sprockets/digest_utils.rb +180 -0
  33. data/lib/sprockets/directive_processor.rb +207 -211
  34. data/lib/sprockets/eco_processor.rb +32 -0
  35. data/lib/sprockets/eco_template.rb +9 -30
  36. data/lib/sprockets/ejs_processor.rb +31 -0
  37. data/lib/sprockets/ejs_template.rb +9 -29
  38. data/lib/sprockets/encoding_utils.rb +261 -0
  39. data/lib/sprockets/engines.rb +53 -35
  40. data/lib/sprockets/environment.rb +17 -64
  41. data/lib/sprockets/erb_processor.rb +30 -0
  42. data/lib/sprockets/erb_template.rb +11 -0
  43. data/lib/sprockets/errors.rb +4 -13
  44. data/lib/sprockets/file_reader.rb +15 -0
  45. data/lib/sprockets/http_utils.rb +117 -0
  46. data/lib/sprockets/jst_processor.rb +35 -15
  47. data/lib/sprockets/legacy.rb +330 -0
  48. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  49. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  50. data/lib/sprockets/loader.rb +325 -0
  51. data/lib/sprockets/manifest.rb +202 -127
  52. data/lib/sprockets/manifest_utils.rb +45 -0
  53. data/lib/sprockets/mime.rb +112 -31
  54. data/lib/sprockets/path_dependency_utils.rb +85 -0
  55. data/lib/sprockets/path_digest_utils.rb +47 -0
  56. data/lib/sprockets/path_utils.rb +287 -0
  57. data/lib/sprockets/paths.rb +42 -19
  58. data/lib/sprockets/processing.rb +178 -126
  59. data/lib/sprockets/processor_utils.rb +180 -0
  60. data/lib/sprockets/resolve.rb +211 -0
  61. data/lib/sprockets/sass_cache_store.rb +22 -17
  62. data/lib/sprockets/sass_compressor.rb +39 -15
  63. data/lib/sprockets/sass_functions.rb +2 -70
  64. data/lib/sprockets/sass_importer.rb +2 -30
  65. data/lib/sprockets/sass_processor.rb +292 -0
  66. data/lib/sprockets/sass_template.rb +12 -59
  67. data/lib/sprockets/server.rb +129 -84
  68. data/lib/sprockets/transformers.rb +145 -0
  69. data/lib/sprockets/uglifier_compressor.rb +39 -12
  70. data/lib/sprockets/unloaded_asset.rb +137 -0
  71. data/lib/sprockets/uri_tar.rb +98 -0
  72. data/lib/sprockets/uri_utils.rb +188 -0
  73. data/lib/sprockets/utils/gzip.rb +67 -0
  74. data/lib/sprockets/utils.rb +210 -44
  75. data/lib/sprockets/version.rb +1 -1
  76. data/lib/sprockets/yui_compressor.rb +39 -11
  77. data/lib/sprockets.rb +142 -81
  78. metadata +96 -90
  79. data/lib/sprockets/asset_attributes.rb +0 -137
  80. data/lib/sprockets/bundled_asset.rb +0 -78
  81. data/lib/sprockets/caching.rb +0 -96
  82. data/lib/sprockets/charset_normalizer.rb +0 -41
  83. data/lib/sprockets/index.rb +0 -100
  84. data/lib/sprockets/processed_asset.rb +0 -152
  85. data/lib/sprockets/processor.rb +0 -32
  86. data/lib/sprockets/safety_colons.rb +0 -28
  87. data/lib/sprockets/scss_template.rb +0 -13
  88. data/lib/sprockets/static_asset.rb +0 -60
@@ -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
@@ -1,32 +0,0 @@
1
- require 'tilt'
2
-
3
- module Sprockets
4
- # `Processor` creates an anonymous processor class from a block.
5
- #
6
- # register_preprocessor 'text/css', :my_processor do |context, data|
7
- # # ...
8
- # end
9
- #
10
- class Processor < Tilt::Template
11
- # `processor` is a lambda or block
12
- def self.processor
13
- @processor
14
- end
15
-
16
- def self.name
17
- "Sprockets::Processor (#{@name})"
18
- end
19
-
20
- def self.to_s
21
- name
22
- end
23
-
24
- def prepare
25
- end
26
-
27
- # Call processor block with `context` and `data`.
28
- def evaluate(context, locals)
29
- self.class.processor.call(context, data)
30
- end
31
- end
32
- end
@@ -1,28 +0,0 @@
1
- require 'tilt'
2
-
3
- module Sprockets
4
- # For JS developers who are colonfobic, concatenating JS files using
5
- # the module pattern usually leads to syntax errors.
6
- #
7
- # The `SafetyColons` processor will insert missing semicolons to the
8
- # end of the file.
9
- #
10
- # This behavior can be disabled with:
11
- #
12
- # environment.unregister_postprocessor 'application/javascript', Sprockets::SafetyColons
13
- #
14
- class SafetyColons < Tilt::Template
15
- def prepare
16
- end
17
-
18
- def evaluate(context, locals, &block)
19
- # If the file is blank or ends in a semicolon, leave it as is
20
- if data =~ /\A\s*\Z/m || data =~ /;\s*\Z/m
21
- data
22
- else
23
- # Otherwise, append a semicolon and newline
24
- "#{data};\n"
25
- end
26
- end
27
- end
28
- end
@@ -1,13 +0,0 @@
1
- require 'sprockets/sass_template'
2
-
3
- module Sprockets
4
- # Scss handler to replace Tilt's builtin one. See `SassTemplate` and
5
- # `SassImporter` for more infomation.
6
- class ScssTemplate < SassTemplate
7
- self.default_mime_type = 'text/css'
8
-
9
- def syntax
10
- :scss
11
- end
12
- end
13
- end
@@ -1,60 +0,0 @@
1
- require 'sprockets/asset'
2
- require 'fileutils'
3
- require 'zlib'
4
-
5
- module Sprockets
6
- # `StaticAsset`s are used for files that are served verbatim without
7
- # any processing or concatenation. These are typical images and
8
- # other binary files.
9
- class StaticAsset < Asset
10
- # Returns file contents as its `source`.
11
- def source
12
- # File is read everytime to avoid memory bloat of large binary files
13
- pathname.open('rb') { |f| f.read }
14
- end
15
-
16
- # Implemented for Rack SendFile support.
17
- def to_path
18
- pathname.to_s
19
- end
20
-
21
- # Save asset to disk.
22
- def write_to(filename, options = {})
23
- # Gzip contents if filename has '.gz'
24
- unless options.key?(:compress)
25
- options[:compress] = File.extname(filename) == '.gz' && File.extname(logical_path) != '.gz'
26
- end
27
-
28
- FileUtils.mkdir_p File.dirname(filename)
29
-
30
- if options[:compress]
31
- # Open file and run it through `Zlib`
32
- pathname.open('rb') do |rd|
33
- File.open("#{filename}+", 'wb') do |wr|
34
- gz = Zlib::GzipWriter.new(wr, Zlib::BEST_COMPRESSION)
35
- gz.mtime = mtime.to_i
36
- buf = ""
37
- while rd.read(16384, buf)
38
- gz.write(buf)
39
- end
40
- gz.close
41
- end
42
- end
43
- else
44
- # If no compression needs to be done, we can just copy it into place.
45
- FileUtils.cp(pathname, "#{filename}+")
46
- end
47
-
48
- # Atomic write
49
- FileUtils.mv("#{filename}+", filename)
50
-
51
- # Set mtime correctly
52
- File.utime(mtime, mtime, filename)
53
-
54
- nil
55
- ensure
56
- # Ensure tmp file gets cleaned up
57
- FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
58
- end
59
- end
60
- end