sprockets 3.0.0.beta.6 → 3.0.0.beta.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +171 -100
  3. data/lib/rake/sprocketstask.rb +2 -2
  4. data/lib/sprockets.rb +69 -63
  5. data/lib/sprockets/asset.rb +2 -61
  6. data/lib/sprockets/autoload_processor.rb +48 -0
  7. data/lib/sprockets/base.rb +4 -6
  8. data/lib/sprockets/bower.rb +8 -5
  9. data/lib/sprockets/bundle.rb +9 -13
  10. data/lib/sprockets/cache.rb +19 -14
  11. data/lib/sprockets/cache/file_store.rb +2 -1
  12. data/lib/sprockets/cached_environment.rb +15 -68
  13. data/lib/sprockets/closure_compressor.rb +17 -4
  14. data/lib/sprockets/coffee_script_processor.rb +26 -0
  15. data/lib/sprockets/coffee_script_template.rb +3 -20
  16. data/lib/sprockets/compressing.rb +10 -4
  17. data/lib/sprockets/configuration.rb +21 -37
  18. data/lib/sprockets/context.rb +37 -67
  19. data/lib/sprockets/dependencies.rb +73 -0
  20. data/lib/sprockets/digest_utils.rb +8 -2
  21. data/lib/sprockets/directive_processor.rb +122 -165
  22. data/lib/sprockets/eco_processor.rb +32 -0
  23. data/lib/sprockets/eco_template.rb +3 -26
  24. data/lib/sprockets/ejs_processor.rb +31 -0
  25. data/lib/sprockets/ejs_template.rb +3 -25
  26. data/lib/sprockets/encoding_utils.rb +9 -21
  27. data/lib/sprockets/engines.rb +25 -27
  28. data/lib/sprockets/environment.rb +9 -1
  29. data/lib/sprockets/erb_processor.rb +30 -0
  30. data/lib/sprockets/erb_template.rb +3 -20
  31. data/lib/sprockets/file_reader.rb +15 -0
  32. data/lib/sprockets/http_utils.rb +2 -0
  33. data/lib/sprockets/jst_processor.rb +9 -2
  34. data/lib/sprockets/legacy.rb +212 -3
  35. data/lib/sprockets/legacy_tilt_processor.rb +1 -1
  36. data/lib/sprockets/loader.rb +95 -89
  37. data/lib/sprockets/manifest.rb +23 -59
  38. data/lib/sprockets/mime.rb +28 -41
  39. data/lib/sprockets/path_dependency_utils.rb +76 -0
  40. data/lib/sprockets/path_utils.rb +21 -1
  41. data/lib/sprockets/paths.rb +23 -8
  42. data/lib/sprockets/processing.rb +102 -91
  43. data/lib/sprockets/processor_utils.rb +97 -0
  44. data/lib/sprockets/resolve.rb +110 -97
  45. data/lib/sprockets/sass_cache_store.rb +2 -2
  46. data/lib/sprockets/sass_compressor.rb +17 -4
  47. data/lib/sprockets/sass_functions.rb +2 -2
  48. data/lib/sprockets/sass_importer.rb +2 -2
  49. data/lib/sprockets/sass_processor.rb +305 -0
  50. data/lib/sprockets/sass_template.rb +4 -286
  51. data/lib/sprockets/server.rb +1 -13
  52. data/lib/sprockets/transformers.rb +62 -25
  53. data/lib/sprockets/uglifier_compressor.rb +17 -4
  54. data/lib/sprockets/uri_utils.rb +190 -0
  55. data/lib/sprockets/utils.rb +87 -6
  56. data/lib/sprockets/version.rb +1 -1
  57. data/lib/sprockets/yui_compressor.rb +17 -4
  58. metadata +14 -5
  59. data/lib/sprockets/asset_uri.rb +0 -80
  60. data/lib/sprockets/lazy_processor.rb +0 -15
@@ -1,289 +1,7 @@
1
- require 'rack/utils'
2
- require 'sass'
3
- require 'uri'
1
+ require 'sprockets/sass_processor'
4
2
 
5
3
  module Sprockets
6
- # Template engine class for the SASS/SCSS compiler. Depends on the `sass` gem.
7
- #
8
- # For more infomation see:
9
- #
10
- # https://github.com/sass/sass
11
- # https://github.com/rails/sass-rails
12
- #
13
- class SassTemplate
14
- # Internal: Defines default sass syntax to use. Exposed so the ScssTemplate
15
- # may override it.
16
- def self.syntax
17
- :sass
18
- end
19
-
20
- def self.call(*args)
21
- new.call(*args)
22
- end
23
-
24
- # Public: Initialize template with custom options.
25
- #
26
- # options - Hash
27
- # cache_version - String custom cache version. Used to force a cache
28
- # change after code changes are made to Sass Functions.
29
- #
30
- def initialize(options = {}, &block)
31
- @cache_version = options[:cache_version]
32
-
33
- @functions = Module.new do
34
- include Functions
35
- include options[:functions] if options[:functions]
36
- class_eval(&block) if block_given?
37
- end
38
- end
39
-
40
- def call(input)
41
- context = input[:environment].context_class.new(input)
42
-
43
- options = {
44
- filename: input[:filename],
45
- syntax: self.class.syntax,
46
- cache_store: CacheStore.new(input[:cache], @cache_version),
47
- load_paths: input[:environment].paths,
48
- sprockets: {
49
- context: context,
50
- environment: input[:environment],
51
- dependencies: context.metadata[:dependency_paths]
52
- }
53
- }
54
-
55
- engine = ::Sass::Engine.new(input[:data], options)
56
-
57
- css = Utils.module_include(::Sass::Script::Functions, @functions) do
58
- engine.render
59
- end
60
-
61
- # Track all imported files
62
- engine.dependencies.map do |dependency|
63
- context.metadata[:dependency_paths] << dependency.options[:filename]
64
- end
65
-
66
- context.metadata.merge(data: css)
67
- end
68
-
69
- # Public: Functions injected into Sass context during Sprockets evaluation.
70
- #
71
- # This module may be extended to add global functionality to all Sprockets
72
- # Sass environments. Though, scoping your functions to just your environment
73
- # is preferred.
74
- #
75
- # module Sprockets::SassTemplate::Functions
76
- # def asset_path(path, options = {})
77
- # end
78
- # end
79
- #
80
- module Functions
81
- # Public: Generate a url for asset path.
82
- #
83
- # Default implementation is deprecated. Currently defaults to
84
- # Context#asset_path.
85
- #
86
- # Will raise NotImplementedError in the future. Users should provide their
87
- # own base implementation.
88
- #
89
- # Returns a Sass::Script::String.
90
- def asset_path(path, options = {})
91
- path = path.value
92
-
93
- path, _, query, fragment = URI.split(path)[5..8]
94
- path = sprockets_context.asset_path(path, options)
95
- query = "?#{query}" if query
96
- fragment = "##{fragment}" if fragment
97
-
98
- ::Sass::Script::String.new("#{path}#{query}#{fragment}", :string)
99
- end
100
-
101
- # Public: Generate a asset url() link.
102
- #
103
- # path - Sass::Script::String URL path
104
- #
105
- # Returns a Sass::Script::String.
106
- def asset_url(path, options = {})
107
- ::Sass::Script::String.new("url(#{asset_path(path, options).value})")
108
- end
109
-
110
- # Public: Generate url for image path.
111
- #
112
- # path - Sass::Script::String URL path
113
- #
114
- # Returns a Sass::Script::String.
115
- def image_path(path)
116
- asset_path(path, type: :image)
117
- end
118
-
119
- # Public: Generate a image url() link.
120
- #
121
- # path - Sass::Script::String URL path
122
- #
123
- # Returns a Sass::Script::String.
124
- def image_url(path)
125
- asset_url(path, type: :image)
126
- end
127
-
128
- # Public: Generate url for video path.
129
- #
130
- # path - Sass::Script::String URL path
131
- #
132
- # Returns a Sass::Script::String.
133
- def video_path(path)
134
- asset_path(path, type: :video)
135
- end
136
-
137
- # Public: Generate a video url() link.
138
- #
139
- # path - Sass::Script::String URL path
140
- #
141
- # Returns a Sass::Script::String.
142
- def video_url(path)
143
- asset_url(path, type: :video)
144
- end
145
-
146
- # Public: Generate url for audio path.
147
- #
148
- # path - Sass::Script::String URL path
149
- #
150
- # Returns a Sass::Script::String.
151
- def audio_path(path)
152
- asset_path(path, type: :audio)
153
- end
154
-
155
- # Public: Generate a audio url() link.
156
- #
157
- # path - Sass::Script::String URL path
158
- #
159
- # Returns a Sass::Script::String.
160
- def audio_url(path)
161
- asset_url(path, type: :audio)
162
- end
163
-
164
- # Public: Generate url for font path.
165
- #
166
- # path - Sass::Script::String URL path
167
- #
168
- # Returns a Sass::Script::String.
169
- def font_path(path)
170
- asset_path(path, type: :font)
171
- end
172
-
173
- # Public: Generate a font url() link.
174
- #
175
- # path - Sass::Script::String URL path
176
- #
177
- # Returns a Sass::Script::String.
178
- def font_url(path)
179
- asset_url(path, type: :font)
180
- end
181
-
182
- # Public: Generate url for javascript path.
183
- #
184
- # path - Sass::Script::String URL path
185
- #
186
- # Returns a Sass::Script::String.
187
- def javascript_path(path)
188
- asset_path(path, type: :javascript)
189
- end
190
-
191
- # Public: Generate a javascript url() link.
192
- #
193
- # path - Sass::Script::String URL path
194
- #
195
- # Returns a Sass::Script::String.
196
- def javascript_url(path)
197
- asset_url(path, type: :javascript)
198
- end
199
-
200
- # Public: Generate url for stylesheet path.
201
- #
202
- # path - Sass::Script::String URL path
203
- #
204
- # Returns a Sass::Script::String.
205
- def stylesheet_path(path)
206
- asset_path(path, type: :stylesheet)
207
- end
208
-
209
- # Public: Generate a stylesheet url() link.
210
- #
211
- # path - Sass::Script::String URL path
212
- #
213
- # Returns a Sass::Script::String.
214
- def stylesheet_url(path)
215
- asset_url(path, type: :stylesheet)
216
- end
217
-
218
- # Public: Generate a data URI for asset path.
219
- #
220
- # path - Sass::Script::String logical asset path
221
- #
222
- # Returns a Sass::Script::String.
223
- def asset_data_url(path)
224
- if asset = sprockets_environment.find_asset(path.value, accept_encoding: 'base64')
225
- sprockets_dependencies << asset.filename
226
- url = "data:#{asset.content_type};base64,#{Rack::Utils.escape(asset.to_s)}"
227
- ::Sass::Script::String.new("url(" + url + ")")
228
- end
229
- end
230
-
231
- protected
232
- # Public: The Environment.
233
- #
234
- # Returns Sprockets::Environment.
235
- def sprockets_environment
236
- options[:sprockets][:environment]
237
- end
238
-
239
- # Public: Mutatable set dependency paths.
240
- #
241
- # Returns a Set.
242
- def sprockets_dependencies
243
- options[:sprockets][:dependencies]
244
- end
245
-
246
- # Deprecated: Get the Context instance. Use APIs on
247
- # sprockets_environment or sprockets_dependencies directly.
248
- #
249
- # Returns a Context instance.
250
- def sprockets_context
251
- options[:sprockets][:context]
252
- end
253
-
254
- end
255
-
256
- # Internal: Cache wrapper for Sprockets cache adapter.
257
- class CacheStore < ::Sass::CacheStores::Base
258
- VERSION = '1'
259
-
260
- def initialize(cache, version)
261
- @cache, @version = cache, "#{VERSION}/#{version}"
262
- end
263
-
264
- def _store(key, version, sha, contents)
265
- @cache._set("#{@version}/#{version}/#{key}/#{sha}", contents)
266
- end
267
-
268
- def _retrieve(key, version, sha)
269
- @cache._get("#{@version}/#{version}/#{key}/#{sha}")
270
- end
271
-
272
- def path_to(key)
273
- key
274
- end
275
- end
276
- end
277
-
278
- class ScssTemplate < SassTemplate
279
- def self.syntax
280
- :scss
281
- end
282
- end
283
-
284
- # Deprecated: Use Sprockets::SassTemplate::Functions instead.
285
- SassFunctions = SassTemplate::Functions
286
-
287
- # Deprecated: Use Sprockets::SassTemplate::CacheStore instead.
288
- SassCacheStore = SassTemplate::CacheStore
4
+ # Deprecated
5
+ SassTemplate = SassProcessor
6
+ ScssTemplate = ScssProcessor
289
7
  end
@@ -48,7 +48,7 @@ module Sprockets
48
48
 
49
49
  # 2.x/3.x compatibility hack. Just ignore fingerprints on ?body=1 requests.
50
50
  # 3.x/4.x prefers strong validation of fingerprint to body contents, but
51
- # 2.x just ignored it.
51
+ # 2.x just ignored it.
52
52
  if options[:bundle] == false
53
53
  fingerprint = nil
54
54
  end
@@ -63,13 +63,6 @@ module Sprockets
63
63
  if_none_match = env['HTTP_IF_NONE_MATCH'][/^"(\w+)"$/, 1]
64
64
  end
65
65
 
66
- if !if_match && !if_none_match && env['HTTP_ACCEPT_ENCODING']
67
- # Accept-Encoding negotiation is only enabled for non-fingerprinted
68
- # assets. Avoids the "Apache ETag gzip" bug. Just Google it.
69
- # https://issues.apache.org/bugzilla/show_bug.cgi?id=39727
70
- options[:accept_encoding] = env['HTTP_ACCEPT_ENCODING']
71
- end
72
-
73
66
  asset = find_asset(path, options)
74
67
 
75
68
  if asset.nil?
@@ -252,11 +245,6 @@ module Sprockets
252
245
  def headers(env, asset, length)
253
246
  headers = {}
254
247
 
255
- # Set content encoding
256
- if asset.encoding
257
- headers["Content-Encoding"] = asset.encoding
258
- end
259
-
260
248
  # Set content length header
261
249
  headers["Content-Length"] = length.to_s
262
250
 
@@ -1,5 +1,11 @@
1
+ require 'sprockets/http_utils'
2
+ require 'sprockets/processor_utils'
3
+ require 'sprockets/utils'
4
+
1
5
  module Sprockets
2
6
  module Transformers
7
+ include HTTPUtils, ProcessorUtils, Utils
8
+
3
9
  # Public: Two level mapping of a source mime type to a target mime type.
4
10
  #
5
11
  # environment.transformers
@@ -8,17 +14,9 @@ module Sprockets
8
14
  # }
9
15
  # }
10
16
  #
11
- attr_reader :transformers
12
-
13
- # Public: Two level mapping of target mime type to source mime type.
14
- #
15
- # environment.inverted_transformers
16
- # # => { 'application/javascript' => {
17
- # 'text/coffeescript' => ConvertCoffeeScriptToJavaScript
18
- # }
19
- # }
20
- #
21
- attr_reader :inverted_transformers
17
+ def transformers
18
+ config[:transformers]
19
+ end
22
20
 
23
21
  # Public: Register a transformer from and to a mime type.
24
22
  #
@@ -35,12 +33,10 @@ module Sprockets
35
33
  #
36
34
  # Returns nothing.
37
35
  def register_transformer(from, to, proc)
38
- mutate_hash_config(:transformers, from) do |transformers|
36
+ self.config = hash_reassoc(config, :registered_transformers, from) do |transformers|
39
37
  transformers.merge(to => proc)
40
38
  end
41
- mutate_hash_config(:inverted_transformers, to) do |transformers|
42
- transformers.merge(from => proc)
43
- end
39
+ compute_transformers!
44
40
  end
45
41
 
46
42
  # Internal: Resolve target mime type that the source type should be
@@ -79,25 +75,66 @@ module Sprockets
79
75
  accepts = []
80
76
  parsed_accepts.each do |(type, q)|
81
77
  accepts.push([type, q])
82
- inverted_transformers[type].keys.each do |subtype|
78
+ config[:inverted_transformers][type].each do |subtype|
83
79
  accepts.push([subtype, q * 0.8])
84
80
  end
85
81
  end
86
82
  accepts
87
83
  end
88
84
 
89
- # Internal: Find and load transformer by from and to mime type.
85
+ # Internal: Compose multiple transformer steps into a single processor
86
+ # function.
90
87
  #
91
- # from - String mime type
92
- # to - String mime type
88
+ # transformers - Two level Hash of a source mime type to a target mime type
89
+ # types - Array of mime type steps
93
90
  #
94
- # Returns Array of Procs.
95
- def unwrap_transformer(from, to)
96
- if processor = transformers[from][to]
97
- [unwrap_processor(processor)]
98
- else
99
- []
91
+ # Returns Processor.
92
+ def compose_transformers(transformers, types)
93
+ if types.length < 2
94
+ raise ArgumentError, "too few transform types: #{types.inspect}"
95
+ end
96
+
97
+ processors = []
98
+ enum = types.each
99
+
100
+ loop do
101
+ src, dst = enum.next, enum.peek
102
+ unless processor = transformers[src][dst]
103
+ raise ArgumentError, "missing transformer for type: #{src} to #{dst}"
104
+ end
105
+ processors.concat config[:postprocessors][src]
106
+ processors << processor
107
+ processors.concat config[:preprocessors][dst]
108
+ end
109
+
110
+ if processors.size > 1
111
+ compose_processors(*processors.reverse)
112
+ elsif processors.size == 1
113
+ processors.first
100
114
  end
101
115
  end
116
+
117
+ private
118
+ def compute_transformers!
119
+ registered_transformers = self.config[:registered_transformers]
120
+ transformers = Hash.new { {} }
121
+ inverted_transformers = Hash.new { Set.new }
122
+
123
+ registered_transformers.keys.flat_map do |key|
124
+ dfs_paths([key]) { |k| registered_transformers[k].keys }
125
+ end.each do |types|
126
+ src, dst = types.first, types.last
127
+ processor = compose_transformers(registered_transformers, types)
128
+
129
+ transformers[src] = {} unless transformers.key?(src)
130
+ transformers[src][dst] = processor
131
+
132
+ inverted_transformers[dst] = Set.new unless inverted_transformers.key?(dst)
133
+ inverted_transformers[dst] << src
134
+ end
135
+
136
+ self.config = hash_reassoc(config, :transformers) { transformers }
137
+ self.config = hash_reassoc(config, :inverted_transformers) { inverted_transformers }
138
+ end
102
139
  end
103
140
  end