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

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 (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)