sprockets 3.0.0.beta.8 → 3.0.0.beta.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +7 -6
  3. data/lib/sprockets.rb +39 -15
  4. data/lib/sprockets/autoload.rb +11 -0
  5. data/lib/sprockets/autoload/closure.rb +7 -0
  6. data/lib/sprockets/autoload/coffee_script.rb +7 -0
  7. data/lib/sprockets/autoload/eco.rb +7 -0
  8. data/lib/sprockets/autoload/ejs.rb +7 -0
  9. data/lib/sprockets/autoload/sass.rb +7 -0
  10. data/lib/sprockets/autoload/uglifier.rb +7 -0
  11. data/lib/sprockets/autoload/yui.rb +7 -0
  12. data/lib/sprockets/bundle.rb +33 -3
  13. data/lib/sprockets/cache.rb +15 -6
  14. data/lib/sprockets/closure_compressor.rb +3 -5
  15. data/lib/sprockets/coffee_script_processor.rb +2 -5
  16. data/lib/sprockets/compressing.rb +2 -2
  17. data/lib/sprockets/context.rb +2 -2
  18. data/lib/sprockets/dependencies.rb +1 -1
  19. data/lib/sprockets/directive_processor.rb +3 -3
  20. data/lib/sprockets/eco_processor.rb +2 -4
  21. data/lib/sprockets/ejs_processor.rb +1 -3
  22. data/lib/sprockets/engines.rb +1 -1
  23. data/lib/sprockets/http_utils.rb +17 -1
  24. data/lib/sprockets/legacy.rb +3 -2
  25. data/lib/sprockets/loader.rb +11 -8
  26. data/lib/sprockets/manifest.rb +27 -17
  27. data/lib/sprockets/manifest_utils.rb +45 -0
  28. data/lib/sprockets/mime.rb +10 -7
  29. data/lib/sprockets/paths.rb +2 -2
  30. data/lib/sprockets/processing.rb +35 -52
  31. data/lib/sprockets/processor_utils.rb +34 -28
  32. data/lib/sprockets/resolve.rb +35 -25
  33. data/lib/sprockets/sass_cache_store.rb +29 -2
  34. data/lib/sprockets/sass_compressor.rb +3 -5
  35. data/lib/sprockets/sass_processor.rb +11 -32
  36. data/lib/sprockets/server.rb +4 -4
  37. data/lib/sprockets/transformers.rb +1 -1
  38. data/lib/sprockets/uglifier_compressor.rb +3 -5
  39. data/lib/sprockets/uri_utils.rb +3 -3
  40. data/lib/sprockets/version.rb +1 -1
  41. data/lib/sprockets/yui_compressor.rb +3 -5
  42. metadata +12 -4
  43. data/lib/sprockets/autoload_processor.rb +0 -48
@@ -1,5 +1,3 @@
1
- require 'eco'
2
-
3
1
  module Sprockets
4
2
  # Processor engine class for the Eco compiler. Depends on the `eco` gem.
5
3
  #
@@ -12,7 +10,7 @@ module Sprockets
12
10
  VERSION = '1'
13
11
 
14
12
  def self.cache_key
15
- @cache_key ||= [name, ::Eco::Source::VERSION, VERSION].freeze
13
+ @cache_key ||= [name, Autoload::Eco::Source::VERSION, VERSION].freeze
16
14
  end
17
15
 
18
16
  # Compile template data with Eco compiler.
@@ -25,7 +23,7 @@ module Sprockets
25
23
  def self.call(input)
26
24
  data = input[:data]
27
25
  input[:cache].fetch(cache_key + [data]) do
28
- ::Eco.compile(data)
26
+ Autoload::Eco.compile(data)
29
27
  end
30
28
  end
31
29
  end
@@ -1,5 +1,3 @@
1
- require 'ejs'
2
-
3
1
  module Sprockets
4
2
  # Processor engine class for the EJS compiler. Depends on the `ejs` gem.
5
3
  #
@@ -24,7 +22,7 @@ module Sprockets
24
22
  def self.call(input)
25
23
  data = input[:data]
26
24
  input[:cache].fetch(cache_key + [data]) do
27
- ::EJS.compile(data)
25
+ Autoload::EJS.compile(data)
28
26
  end
29
27
  end
30
28
  end
@@ -53,7 +53,7 @@ module Sprockets
53
53
  def register_engine(ext, klass, options = {})
54
54
  ext = Sprockets::Utils.normalize_extension(ext)
55
55
 
56
- if klass.class == Sprockets::AutoloadProcessor || klass.respond_to?(:call)
56
+ if klass.respond_to?(:call)
57
57
  processor = klass
58
58
  self.config = hash_reassoc(config, :engines) do |engines|
59
59
  engines.merge(ext => klass)
@@ -4,7 +4,7 @@ module Sprockets
4
4
  module HTTPUtils
5
5
  extend self
6
6
 
7
- # Internal: Test mime type against mime range.
7
+ # Public: Test mime type against mime range.
8
8
  #
9
9
  # match_mime_type?('text/html', 'text/*') => true
10
10
  # match_mime_type?('text/plain', '*') => true
@@ -18,6 +18,22 @@ module Sprockets
18
18
  (m1 == '*' || v1 == m1) && (m2.nil? || m2 == '*' || m2 == v2)
19
19
  end
20
20
 
21
+ # Public: Return values from Hash where the key matches the mime type.
22
+ #
23
+ # hash - Hash of String matcher keys to Object values
24
+ # mime_type - String mime type
25
+ #
26
+ # Returns Array of Object values.
27
+ def match_mime_type_keys(hash, mime_type)
28
+ type, subtype = mime_type.split('/', 2)
29
+ [
30
+ hash["*"],
31
+ hash["*/*"],
32
+ hash["#{type}/*"],
33
+ hash["#{type}/#{subtype}"]
34
+ ].compact
35
+ end
36
+
21
37
  # Internal: Parse Accept header quality values.
22
38
  #
23
39
  # Adapted from Rack::Utils#q_values.
@@ -7,6 +7,7 @@ require 'sprockets/manifest'
7
7
  require 'sprockets/resolve'
8
8
 
9
9
  module Sprockets
10
+ autoload :CoffeeScriptTemplate, 'sprockets/coffee_script_template'
10
11
  autoload :EcoTemplate, 'sprockets/eco_template'
11
12
  autoload :EjsTemplate, 'sprockets/ejs_template'
12
13
  autoload :ERBTemplate, 'sprockets/erb_template'
@@ -100,12 +101,12 @@ module Sprockets
100
101
 
101
102
  seen = Set.new
102
103
 
103
- self.paths.each do |load_path|
104
+ paths.each do |load_path|
104
105
  stat_tree(load_path).each do |filename, stat|
105
106
  next unless stat.file?
106
107
 
107
108
  path = split_subpath(load_path, filename)
108
- path, mime_type, _ = parse_path_extnames(path)
109
+ path, mime_type, _, _ = parse_path_extnames(path)
109
110
  path = normalize_logical_path(path)
110
111
  path += mime_types[mime_type][:extensions].first if mime_type
111
112
 
@@ -71,29 +71,32 @@ module Sprockets
71
71
  raise FileNotFound, "could not find file: #{filename}"
72
72
  end
73
73
 
74
- load_path, logical_path = paths_split(self.paths, filename)
74
+ load_path, logical_path = paths_split(config[:paths], filename)
75
75
 
76
76
  unless load_path
77
77
  raise FileOutsidePaths, "#{filename} is no longer under a load path: #{self.paths.join(', ')}"
78
78
  end
79
79
 
80
- logical_path, file_type, engine_extnames = parse_path_extnames(logical_path)
80
+ logical_path, file_type, engine_extnames, _ = parse_path_extnames(logical_path)
81
81
  logical_path = normalize_logical_path(logical_path)
82
82
  name = logical_path
83
83
 
84
+ if pipeline = params[:pipeline]
85
+ logical_path += ".#{pipeline}"
86
+ end
87
+
84
88
  if type = params[:type]
85
- logical_path += mime_types[type][:extensions].first
89
+ logical_path += config[:mime_types][type][:extensions].first
86
90
  end
87
91
 
88
- if type != file_type && !transformers[file_type][type]
92
+ if type != file_type && !config[:transformers][file_type][type]
89
93
  raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}"
90
94
  end
91
95
 
92
- skip_bundle = params[:skip_bundle]
93
- processors = processors_for(type, file_type, engine_extnames, skip_bundle)
96
+ processors = processors_for(type, file_type, engine_extnames, pipeline)
94
97
 
95
- processors_dep_uri = build_processors_uri(type, file_type, engine_extnames, skip_bundle)
96
- dependencies = self.dependencies + [processors_dep_uri]
98
+ processors_dep_uri = build_processors_uri(type, file_type, engine_extnames, pipeline)
99
+ dependencies = config[:dependencies] + [processors_dep_uri]
97
100
 
98
101
  # Read into memory and process if theres a processor pipeline
99
102
  if processors.any?
@@ -1,6 +1,6 @@
1
1
  require 'json'
2
- require 'securerandom'
3
2
  require 'time'
3
+ require 'sprockets/manifest_utils'
4
4
 
5
5
  module Sprockets
6
6
  # The Manifest logs the contents of assets compiled to a single directory. It
@@ -13,13 +13,15 @@ module Sprockets
13
13
  # that don't have sprockets loaded. See `#assets` and `#files` for more
14
14
  # infomation about the structure.
15
15
  class Manifest
16
+ include ManifestUtils
17
+
16
18
  attr_reader :environment
17
19
 
18
20
  # Create new Manifest associated with an `environment`. `filename` is a full
19
21
  # path to the manifest json file. The file may or may not already exist. The
20
22
  # dirname of the `filename` will be used to write compiled assets to.
21
23
  # Otherwise, if the path is a directory, the filename will default a random
22
- # "manifest-123.json" file in that directory.
24
+ # ".sprockets-manifest-*.json" file in that directory.
23
25
  #
24
26
  # Manifest.new(environment, "./public/assets/manifest.json")
25
27
  #
@@ -30,6 +32,9 @@ module Sprockets
30
32
 
31
33
  @directory, @filename = args[0], args[1]
32
34
 
35
+ # Whether the manifest file is using the old manifest-*.json naming convention
36
+ @legacy_manifest = false
37
+
33
38
  # Expand paths
34
39
  @directory = File.expand_path(@directory) if @directory
35
40
  @filename = File.expand_path(@filename) if @filename
@@ -42,14 +47,14 @@ module Sprockets
42
47
  # Default dir to the directory of the filename
43
48
  @directory ||= File.dirname(@filename) if @filename
44
49
 
45
- # If directory is given w/o filename, pick a random manifest.json location
50
+ # If directory is given w/o filename, pick a random manifest location
51
+ @rename_filename = nil
46
52
  if @directory && @filename.nil?
47
- # Find the first manifest.json in the directory
48
- filenames = Dir[File.join(@directory, "manifest*.json")]
49
- if filenames.any?
50
- @filename = filenames.first
51
- else
52
- @filename = File.join(@directory, "manifest-#{SecureRandom.hex(16)}.json")
53
+ @filename = find_directory_manifest(@directory)
54
+
55
+ # If legacy manifest name autodetected, mark to rename on save
56
+ if File.basename(@filename).start_with?("manifest")
57
+ @rename_filename = File.join(@directory, generate_manifest_path)
53
58
  end
54
59
  end
55
60
 
@@ -232,15 +237,20 @@ module Sprockets
232
237
  nil
233
238
  end
234
239
 
235
- protected
236
- # Persist manfiest back to FS
237
- def save
238
- data = json_encode(@data)
239
- FileUtils.mkdir_p File.dirname(filename)
240
- PathUtils.atomic_write(filename) do |f|
241
- f.write(data)
242
- end
240
+ # Persist manfiest back to FS
241
+ def save
242
+ if @rename_filename
243
+ FileUtils.mv(@filename, @rename_filename)
244
+ @filename = @rename_filename
245
+ @rename_filename = nil
246
+ end
247
+
248
+ data = json_encode(@data)
249
+ FileUtils.mkdir_p File.dirname(@filename)
250
+ PathUtils.atomic_write(@filename) do |f|
251
+ f.write(data)
243
252
  end
253
+ end
244
254
 
245
255
  private
246
256
  def json_decode(obj)
@@ -0,0 +1,45 @@
1
+ require 'securerandom'
2
+
3
+ module Sprockets
4
+ # Public: Manifest utilities.
5
+ module ManifestUtils
6
+ extend self
7
+
8
+ MANIFEST_RE = /^\.sprockets-manifest-[0-9a-f]{32}.json$/
9
+ LEGACY_MANIFEST_RE = /^manifest(-[0-9a-f]{32})?.json$/
10
+
11
+ # Public: Generate a new random manifest path.
12
+ #
13
+ # Manifests are not intended to be accessed publicly, but typically live
14
+ # alongside public assets for convenience. To avoid being served, the
15
+ # filename is prefixed with a "." which is usually hidden by web servers
16
+ # like Apache. To help in other environments that may not control this,
17
+ # a random hex string is appended to the filename to prevent people from
18
+ # guessing the location. If directory indexes are enabled on the server,
19
+ # all bets are off.
20
+ #
21
+ # Return String path.
22
+ def generate_manifest_path
23
+ ".sprockets-manifest-#{SecureRandom.hex(16)}.json"
24
+ end
25
+
26
+ # Public: Find or pick a new manifest filename for target build directory.
27
+ #
28
+ # dirname - String dirname
29
+ #
30
+ # Examples
31
+ #
32
+ # find_directory_manifest("/app/public/assets")
33
+ # # => "/app/public/assets/.sprockets-manifest-abc123.json"
34
+ #
35
+ # Returns String filename.
36
+ def find_directory_manifest(dirname)
37
+ entries = File.directory?(dirname) ? Dir.entries(dirname) : []
38
+ entry = entries.find { |e| e =~ MANIFEST_RE } ||
39
+ # Deprecated: Will be removed in 4.x
40
+ entries.find { |e| e =~ LEGACY_MANIFEST_RE } ||
41
+ generate_manifest_path
42
+ File.join(dirname, entry)
43
+ end
44
+ end
45
+ end
@@ -81,7 +81,7 @@ module Sprockets
81
81
  #
82
82
  # Returns Proc detector or nil if none is available.
83
83
  def mime_type_charset_detecter(mime_type)
84
- if type = mime_types[mime_type]
84
+ if type = config[:mime_types][mime_type]
85
85
  if detect = type[:charset]
86
86
  return detect
87
87
  end
@@ -109,12 +109,15 @@ module Sprockets
109
109
  def compute_extname_map
110
110
  graph = {}
111
111
 
112
- ([[nil, nil]] + mime_exts.to_a).each do |format_extname, format_type|
113
- 3.times do |n|
114
- engines.keys.permutation(n).each do |engine_extnames|
115
- key = "#{format_extname}#{engine_extnames.join}"
116
- type = format_type || engine_mime_types[engine_extnames.first]
117
- graph[key] = {type: type, engines: engine_extnames}
112
+ ([nil] + pipelines.keys.map(&:to_s)).each do |pipeline|
113
+ pipeline_extname = ".#{pipeline}" if pipeline
114
+ ([[nil, nil]] + config[:mime_exts].to_a).each do |format_extname, format_type|
115
+ 3.times do |n|
116
+ config[:engines].keys.permutation(n).each do |engine_extnames|
117
+ key = "#{pipeline_extname}#{format_extname}#{engine_extnames.join}"
118
+ type = format_type || config[:engine_mime_types][engine_extnames.first]
119
+ graph[key] = {type: type, engines: engine_extnames, pipeline: pipeline}
120
+ end
118
121
  end
119
122
  end
120
123
  end
@@ -35,7 +35,7 @@ module Sprockets
35
35
  # Paths at the end of the `Array` have the least priority.
36
36
  def prepend_path(path)
37
37
  self.config = hash_reassoc(config, :paths) do |paths|
38
- path = File.expand_path(path, root).freeze
38
+ path = File.expand_path(path, config[:root]).freeze
39
39
  paths.unshift(path)
40
40
  end
41
41
  end
@@ -45,7 +45,7 @@ module Sprockets
45
45
  # Paths at the beginning of the `Array` have a higher priority.
46
46
  def append_path(path)
47
47
  self.config = hash_reassoc(config, :paths) do |paths|
48
- path = File.expand_path(path, root).freeze
48
+ path = File.expand_path(path, config[:root]).freeze
49
49
  paths.push(path)
50
50
  end
51
51
  end
@@ -12,6 +12,18 @@ module Sprockets
12
12
  module Processing
13
13
  include ProcessorUtils, URIUtils, Utils
14
14
 
15
+ def pipelines
16
+ config[:pipelines]
17
+ end
18
+
19
+ def register_pipeline(name, proc = nil, &block)
20
+ proc ||= block
21
+
22
+ self.config = hash_reassoc(config, :pipelines) do |pipelines|
23
+ pipelines.merge(name.to_sym => proc)
24
+ end
25
+ end
26
+
15
27
  # Preprocessors are ran before Postprocessors and Engine
16
28
  # processors.
17
29
  def preprocessors
@@ -98,12 +110,6 @@ module Sprockets
98
110
  unregister_config_processor(:bundle_processors, *args)
99
111
  end
100
112
 
101
- # Internal: Two dimensional Hash of reducer functions for a given mime type
102
- # and asset metadata key.
103
- def bundle_reducers
104
- config[:bundle_reducers]
105
- end
106
-
107
113
  # Public: Register bundle metadata reducer function.
108
114
  #
109
115
  # Examples
@@ -144,74 +150,51 @@ module Sprockets
144
150
  end
145
151
  end
146
152
 
147
- # Internal: Gather all bundle reducer functions for MIME type.
148
- #
149
- # mime_type - String MIME type
150
- #
151
- # Returns an Array of [initial, reducer_proc] pairs.
152
- def load_bundle_reducers(mime_type)
153
- self.bundle_reducers['*/*'].merge(self.bundle_reducers[mime_type])
154
- end
155
-
156
- # Internal: Run bundle reducers on set of Assets producing a reduced
157
- # metadata Hash.
158
- #
159
- # assets - Array of Assets
160
- # reducers - Array of [initial, reducer_proc] pairs
161
- #
162
- # Returns reduced asset metadata Hash.
163
- def process_bundle_reducers(assets, reducers)
164
- initial = {}
165
- reducers.each do |k, (v, _)|
166
- initial[k] = v if v
167
- end
168
-
169
- assets.reduce(initial) do |h, asset|
170
- reducers.each do |k, (_, block)|
171
- value = k == :data ? asset.source : asset.metadata[k]
172
- h[k] = h.key?(k) ? block.call(h[k], value) : value
173
- end
174
- h
175
- end
176
- end
177
-
178
153
  protected
179
154
  def resolve_processors_cache_key_uri(uri)
180
155
  params = parse_uri_query_params(uri[11..-1])
181
156
  params[:engine_extnames] = params[:engines] ? params[:engines].split(',') : []
182
- processors = processors_for(params[:type], params[:file_type], params[:engine_extnames], params[:skip_bundle])
157
+ processors = processors_for(params[:type], params[:file_type], params[:engine_extnames], params[:pipeline])
183
158
  processors_cache_keys(processors)
184
159
  end
185
160
 
186
- def build_processors_uri(type, file_type, engine_extnames, skip_bundle)
161
+ def build_processors_uri(type, file_type, engine_extnames, pipeline)
187
162
  engines = engine_extnames.join(',') if engine_extnames.any?
188
163
  query = encode_uri_query_params(
189
164
  type: type,
190
165
  file_type: file_type,
191
166
  engines: engines,
192
- skip_bundle: skip_bundle
167
+ pipeline: pipeline
193
168
  )
194
169
  "processors:#{query}"
195
170
  end
196
171
 
197
- def processors_for(type, file_type, engine_extnames, skip_bundle)
198
- processors = []
199
-
200
- bundled_processors = skip_bundle ? [] : config[:bundle_processors][type]
172
+ def processors_for(type, file_type, engine_extnames, pipeline)
173
+ pipeline ||= :default
174
+ config[:pipelines][pipeline.to_sym].call(self, type, file_type, engine_extnames)
175
+ end
201
176
 
177
+ def default_processors_for(type, file_type, engine_extnames)
178
+ bundled_processors = config[:bundle_processors][type]
202
179
  if bundled_processors.any?
203
- processors.concat bundled_processors
180
+ bundled_processors
204
181
  else
205
- processors.concat config[:postprocessors][type]
182
+ self_processors_for(type, file_type, engine_extnames)
183
+ end
184
+ end
206
185
 
207
- if type != file_type && processor = transformers[file_type][type]
208
- processors << processor
209
- end
186
+ def self_processors_for(type, file_type, engine_extnames)
187
+ processors = []
188
+
189
+ processors.concat config[:postprocessors][type]
210
190
 
211
- processors.concat engine_extnames.map { |ext| engines[ext] }
212
- processors.concat config[:preprocessors][file_type]
191
+ if type != file_type && processor = config[:transformers][file_type][type]
192
+ processors << processor
213
193
  end
214
194
 
195
+ processors.concat engine_extnames.map { |ext| engines[ext] }
196
+ processors.concat config[:preprocessors][file_type]
197
+
215
198
  if processors.any? || mime_type_charset_detecter(type)
216
199
  processors << FileReader
217
200
  end
@@ -249,7 +232,7 @@ module Sprockets
249
232
 
250
233
  def wrap_processor(klass, proc)
251
234
  if !proc
252
- if klass.class == Sprockets::AutoloadProcessor || klass.respond_to?(:call)
235
+ if klass.respond_to?(:call)
253
236
  klass
254
237
  else
255
238
  LegacyTiltProcessor.new(klass)