sprockets 3.0.0.beta.3 → 3.0.0.beta.4

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.
@@ -10,23 +10,24 @@ module Sprockets
10
10
  include Paths, Mime, Engines, Transformers, Processing, Compressing
11
11
 
12
12
  def initialize_configuration(parent)
13
- @logger = parent.logger
14
- @version = parent.version
15
- @digest_class = parent.digest_class
16
- @context_class = Class.new(parent.context_class)
17
- @root = parent.root
18
- @paths = parent.paths
19
- @mime_types = parent.mime_types
20
- @mime_exts = parent.mime_exts
21
- @encodings = parent.encodings
22
- @engines = parent.engines
23
- @engine_mime_types = parent.engine_mime_types
24
- @transformers = parent.transformers
25
- @preprocessors = parent.preprocessors
26
- @postprocessors = parent.postprocessors
27
- @bundle_reducers = parent.bundle_reducers
28
- @bundle_processors = parent.bundle_processors
29
- @compressors = parent.compressors
13
+ @logger = parent.logger
14
+ @version = parent.version
15
+ @digest_class = parent.digest_class
16
+ @context_class = Class.new(parent.context_class)
17
+ @root = parent.root
18
+ @paths = parent.paths
19
+ @mime_types = parent.mime_types
20
+ @mime_exts = parent.mime_exts
21
+ @encodings = parent.encodings
22
+ @engines = parent.engines
23
+ @engine_mime_types = parent.engine_mime_types
24
+ @transformers = parent.transformers
25
+ @inverted_transformers = parent.inverted_transformers
26
+ @preprocessors = parent.preprocessors
27
+ @postprocessors = parent.postprocessors
28
+ @bundle_reducers = parent.bundle_reducers
29
+ @bundle_processors = parent.bundle_processors
30
+ @compressors = parent.compressors
30
31
  end
31
32
 
32
33
  # Get and set `Logger` instance.
@@ -52,7 +53,7 @@ module Sprockets
52
53
  mutate_config(:version) { version.dup }
53
54
  end
54
55
 
55
- # Deprecated: Returns a `Digest` implementation class.
56
+ # Public: Returns a `Digest` implementation class.
56
57
  #
57
58
  # Defaults to `Digest::SHA256`.
58
59
  attr_reader :digest_class
@@ -66,6 +66,39 @@ module Sprockets
66
66
  #
67
67
  attr_reader :content_type
68
68
 
69
+ # Internal
70
+ def _resolve(method, path, options = {})
71
+ options[:content_type] = self.content_type if options[:content_type] == :self
72
+ options[:accept] = options.delete(:content_type)
73
+
74
+ if environment.absolute_path?(path)
75
+ filename = path
76
+ elsif environment.relative_path?(path)
77
+ path = File.expand_path(path, @dirname)
78
+ if logical_path = @environment.split_subpath(load_path, path)
79
+ if filename = environment.send(method, logical_path, options.merge(load_paths: [load_path]))
80
+ accept = options[:accept]
81
+ message = "couldn't find file '#{logical_path}' under '#{load_path}'"
82
+ message << " with type '#{accept}'" if accept
83
+ raise FileNotFound, message
84
+ end
85
+ else
86
+ raise FileOutsidePaths, "#{path} isn't under path: #{load_path}"
87
+ end
88
+ else
89
+ filename = environment.send(method, path, options)
90
+ end
91
+
92
+ if filename
93
+ filename
94
+ else
95
+ accept = options[:accept]
96
+ message = "couldn't find file '#{path}'"
97
+ message << " with type '#{accept}'" if accept
98
+ raise FileNotFound, message
99
+ end
100
+ end
101
+
69
102
  # Given a logical path, `resolve` will find and return the fully
70
103
  # expanded path. Relative paths will also be resolved. An optional
71
104
  # `:content_type` restriction can be supplied to restrict the
@@ -78,21 +111,11 @@ module Sprockets
78
111
  # # => "/path/to/app/javascripts/bar.js"
79
112
  #
80
113
  def resolve(path, options = {})
81
- options[:content_type] = self.content_type if options[:content_type] == :self
82
- options[:accept] = options.delete(:content_type)
114
+ _resolve(:resolve, path, options)
115
+ end
83
116
 
84
- if environment.absolute_path?(path)
85
- path
86
- elsif environment.relative_path?(path)
87
- path = File.expand_path(path, @dirname)
88
- if logical_path = @environment.split_subpath(load_path, path)
89
- environment.resolve_in_load_path(load_path, logical_path, options)
90
- else
91
- raise FileOutsidePaths, "#{path} isn't under path: #{load_path}"
92
- end
93
- else
94
- environment.resolve(path, options)
95
- end
117
+ def locate(path, options = {})
118
+ _resolve(:locate, path, options)
96
119
  end
97
120
 
98
121
  # `depend_on` allows you to state a dependency on a file without
@@ -114,7 +137,7 @@ module Sprockets
114
137
  # file. Unlike `depend_on`, this will include recursively include
115
138
  # the target asset's dependencies.
116
139
  def depend_on_asset(path)
117
- if asset = @environment.find_asset(resolve(path))
140
+ if asset = @environment.load(locate(path))
118
141
  @dependency_paths.merge(asset.metadata[:dependency_paths])
119
142
  end
120
143
  nil
@@ -130,8 +153,7 @@ module Sprockets
130
153
  # <%= require_asset "#{framework}.js" %>
131
154
  #
132
155
  def require_asset(path)
133
- filename = resolve(path, accept: @content_type)
134
- @required << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
156
+ @required << locate(path, accept: @content_type, bundle: false)
135
157
  nil
136
158
  end
137
159
 
@@ -139,8 +161,7 @@ module Sprockets
139
161
  # `path` must be an asset which may or may not already be included
140
162
  # in the bundle.
141
163
  def stub_asset(path)
142
- filename = resolve(path, accept: @content_type)
143
- @stubbed << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
164
+ @stubbed << @environment.locate(path, accept: @content_type, bundle: false)
144
165
  nil
145
166
  end
146
167
 
@@ -150,7 +171,7 @@ module Sprockets
150
171
  #
151
172
  # Returns an Asset or nil.
152
173
  def link_asset(path)
153
- if asset = @environment.find_asset(resolve(path))
174
+ if asset = @environment.load(locate(path))
154
175
  @dependency_paths.merge(asset.metadata[:dependency_paths])
155
176
  @links << asset.uri
156
177
  end
@@ -196,7 +196,7 @@ module Sprockets
196
196
  # //= require "./bar"
197
197
  #
198
198
  def process_require_directive(path)
199
- @required << resolve_uri(path)
199
+ @required << locate(path, accept: @content_type, bundle: false)
200
200
  end
201
201
 
202
202
  # `require_self` causes the body of the current file to be inserted
@@ -235,8 +235,10 @@ module Sprockets
235
235
  @environment.stat_directory(root).each do |subpath, stat|
236
236
  if subpath == @filename
237
237
  next
238
- elsif @environment.resolve_path_transform_type(subpath, @content_type)
239
- @required << @environment.resolve_asset_uri(subpath, accept: @content_type, bundle: false)
238
+ elsif stat.directory?
239
+ next
240
+ elsif uri = @environment.locate(subpath, accept: @content_type, bundle: false)
241
+ @required << uri
240
242
  end
241
243
  end
242
244
  else
@@ -260,19 +262,15 @@ module Sprockets
260
262
 
261
263
  @dependency_paths << root
262
264
 
263
- required = []
264
- @environment.stat_tree(root).each do |subpath, stat|
265
+ @environment.stat_sorted_tree(root).each do |subpath, stat|
265
266
  if subpath == @filename
266
267
  next
267
268
  elsif stat.directory?
268
269
  @dependency_paths << subpath
269
- elsif @environment.resolve_path_transform_type(subpath, @content_type)
270
- required << subpath
270
+ elsif uri = @environment.locate(subpath, accept: @content_type, bundle: false)
271
+ @required << uri
271
272
  end
272
273
  end
273
- required.sort_by(&:to_s).each do |subpath|
274
- @required << @environment.resolve_asset_uri(subpath, accept: @content_type, bundle: false)
275
- end
276
274
  else
277
275
  # The path must be relative and start with a `./`.
278
276
  raise ArgumentError, "require_tree argument must be a relative path"
@@ -292,7 +290,7 @@ module Sprockets
292
290
  # //= depend_on "foo.png"
293
291
  #
294
292
  def process_depend_on_directive(path)
295
- @dependency_paths << resolve(path, accept: "#{@content_type}, */*")
293
+ @dependency_paths << resolve(path)
296
294
  end
297
295
 
298
296
  # Allows you to state a dependency on an asset without including
@@ -307,7 +305,7 @@ module Sprockets
307
305
  # //= depend_on_asset "bar.js"
308
306
  #
309
307
  def process_depend_on_asset_directive(path)
310
- if asset = @environment.find_asset(resolve(path, accept: "#{@content_type}, */*"))
308
+ if asset = @environment.load(locate(path))
311
309
  @dependency_paths.merge(asset.metadata[:dependency_paths])
312
310
  end
313
311
  end
@@ -321,7 +319,7 @@ module Sprockets
321
319
  # //= stub "jquery"
322
320
  #
323
321
  def process_stub_directive(path)
324
- @stubbed << resolve_uri(path)
322
+ @stubbed << locate(path, accept: @content_type, bundle: false)
325
323
  end
326
324
 
327
325
  # Declares a linked dependency on the target asset.
@@ -333,7 +331,7 @@ module Sprockets
333
331
  # /*= link "logo.png" */
334
332
  #
335
333
  def process_link_directive(path)
336
- if asset = @environment.find_asset(resolve(path, accept: "#{@content_type}, */*"))
334
+ if asset = @environment.load(locate(path))
337
335
  @dependency_paths.merge(asset.metadata[:dependency_paths])
338
336
  @links << asset.uri
339
337
  end
@@ -344,23 +342,42 @@ module Sprockets
344
342
  File.expand_path(path, @dirname)
345
343
  end
346
344
 
347
- def resolve_uri(path)
348
- filename = resolve(path, accept: @content_type)
349
- @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
345
+ def locate(path, options = {})
346
+ _resolve(:locate, path, options)
350
347
  end
351
348
 
352
349
  def resolve(path, options = {})
350
+ _resolve(:resolve, path, options)
351
+ end
352
+
353
+ def _resolve(method, path, options = {})
353
354
  if @environment.absolute_path?(path)
354
355
  raise FileOutsidePaths, "can't require absolute file: #{path}"
355
356
  elsif @environment.relative_path?(path)
356
357
  path = expand_relative_path(path)
357
358
  if logical_path = @environment.split_subpath(@load_path, path)
358
- @environment.resolve_in_load_path(@load_path, logical_path, options)
359
+ if filename = @environment.send(method, logical_path, options.merge(load_paths: [@load_path]))
360
+ filename
361
+ else
362
+ accept = options[:accept]
363
+ message = "couldn't find file '#{logical_path}' under '#{@load_path}'"
364
+ message << " with type '#{accept}'" if accept
365
+ raise FileNotFound, message
366
+ end
359
367
  else
360
368
  raise FileOutsidePaths, "#{path} isn't under path: #{@load_path}"
361
369
  end
362
370
  else
363
- @environment.resolve(path, options)
371
+ filename = @environment.send(method, path, options)
372
+ end
373
+
374
+ if filename
375
+ filename
376
+ else
377
+ accept = options[:accept]
378
+ message = "couldn't find file '#{path}'"
379
+ message << " with type '#{accept}'" if accept
380
+ raise FileNotFound, message
364
381
  end
365
382
  end
366
383
  end
@@ -1,4 +1,5 @@
1
1
  require 'sprockets/base'
2
+ require 'sprockets/cache/memory_store'
2
3
  require 'sprockets/cached_environment'
3
4
 
4
5
  module Sprockets
@@ -1,5 +1,58 @@
1
+ require 'sprockets/manifest'
2
+
1
3
  module Sprockets
2
4
  module Legacy
5
+ # Deprecated: Iterate over all logical paths with a matcher.
6
+ #
7
+ # Remove from 4.x.
8
+ #
9
+ # args - List of matcher objects.
10
+ #
11
+ # Returns Enumerator if no block is given.
12
+ def each_logical_path(*args, &block)
13
+ return to_enum(__method__, *args) unless block_given?
14
+
15
+ filters = args.flatten.map { |arg| Manifest.compile_match_filter(arg) }
16
+ logical_paths.each do |a, b|
17
+ if filters.any? { |f| f.call(a, b) }
18
+ if block.arity == 2
19
+ yield a, b
20
+ else
21
+ yield a
22
+ end
23
+ end
24
+ end
25
+
26
+ nil
27
+ end
28
+
29
+ # Deprecated: Enumerate over all logical paths in the environment.
30
+ #
31
+ # Returns an Enumerator of [logical_path, filename].
32
+ def logical_paths
33
+ return to_enum(__method__) unless block_given?
34
+
35
+ seen = Set.new
36
+
37
+ self.paths.each do |load_path|
38
+ stat_tree(load_path).each do |filename, stat|
39
+ next unless stat.file?
40
+
41
+ path = split_subpath(load_path, filename)
42
+ path, mime_type, _ = parse_path_extnames(path)
43
+ path = normalize_logical_path(path)
44
+ path += mime_types[mime_type][:extensions].first if mime_type
45
+
46
+ if !seen.include?(path)
47
+ yield path, filename
48
+ seen << path
49
+ end
50
+ end
51
+ end
52
+
53
+ nil
54
+ end
55
+
3
56
  private
4
57
  # Deprecated: Seriously.
5
58
  def matches_filter(filters, logical_path, filename)
@@ -19,5 +72,19 @@ module Sprockets
19
72
  end
20
73
  end
21
74
  end
75
+
76
+ # URI.unescape is deprecated on 1.9. We need to use URI::Parser
77
+ # if its available.
78
+ if defined? URI::DEFAULT_PARSER
79
+ def unescape(str)
80
+ str = URI::DEFAULT_PARSER.unescape(str)
81
+ str.force_encoding(Encoding.default_internal) if Encoding.default_internal
82
+ str
83
+ end
84
+ else
85
+ def unescape(str)
86
+ URI.unescape(str)
87
+ end
88
+ end
22
89
  end
23
90
  end
@@ -0,0 +1,168 @@
1
+ require 'sprockets/asset_uri'
2
+ require 'sprockets/asset'
3
+ require 'sprockets/digest_utils'
4
+ require 'sprockets/engines'
5
+ require 'sprockets/errors'
6
+ require 'sprockets/mime'
7
+ require 'sprockets/path_utils'
8
+ require 'sprockets/processing'
9
+ require 'sprockets/resolve'
10
+ require 'sprockets/transformers'
11
+
12
+ module Sprockets
13
+ # The loader phase takes a asset URI location and returns a constructed Asset
14
+ # object.
15
+ module Loader
16
+ include DigestUtils, Engines, Mime, PathUtils, Processing, Resolve, Transformers
17
+
18
+ # Public: Load Asset by AssetURI.
19
+ #
20
+ # uri - AssetURI
21
+ #
22
+ # Returns Asset.
23
+ def load(uri)
24
+ _, params = AssetURI.parse(uri)
25
+ asset = params.key?(:id) ?
26
+ load_asset_by_id_uri(uri) :
27
+ load_asset_by_uri(uri)
28
+ Asset.new(self, asset)
29
+ end
30
+
31
+ private
32
+ def load_asset_by_id_uri(uri)
33
+ path, params = AssetURI.parse(uri)
34
+
35
+ # Internal assertion, should be routed through load_asset_by_uri
36
+ unless id = params.delete(:id)
37
+ raise ArgumentError, "expected uri to have an id: #{uri}"
38
+ end
39
+
40
+ asset = load_asset_by_uri(AssetURI.build(path, params))
41
+
42
+ if id && asset[:id] != id
43
+ raise VersionNotFound, "could not find specified id: #{id}"
44
+ end
45
+
46
+ asset
47
+ end
48
+
49
+ def load_asset_by_uri(uri)
50
+ filename, params = AssetURI.parse(uri)
51
+
52
+ # Internal assertion, should be routed through load_asset_by_id_uri
53
+ if params.key?(:id)
54
+ raise ArgumentError, "expected uri to have no id: #{uri}"
55
+ end
56
+
57
+ unless file?(filename)
58
+ raise FileNotFound, "could not find file: #{filename}"
59
+ end
60
+
61
+
62
+ type = params[:type]
63
+ load_path, logical_path = paths_split(self.paths, filename)
64
+
65
+ unless load_path
66
+ raise FileOutsidePaths, "#{filename} is no longer under a load path: #{self.paths.join(', ')}"
67
+ end
68
+
69
+ logical_path, file_type, engine_extnames = parse_path_extnames(logical_path)
70
+ logical_path = normalize_logical_path(logical_path)
71
+
72
+ asset = {
73
+ uri: uri,
74
+ load_path: load_path,
75
+ filename: filename,
76
+ name: logical_path,
77
+ logical_path: logical_path
78
+ }
79
+
80
+ if type
81
+ asset[:content_type] = type
82
+ asset[:logical_path] += mime_types[type][:extensions].first
83
+ end
84
+
85
+ if type != file_type
86
+ transformers = unwrap_transformer(file_type, type)
87
+ unless transformers.any?
88
+ raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}"
89
+ end
90
+ else
91
+ transformers = []
92
+ end
93
+
94
+ processed_processors = unwrap_preprocessors(file_type) +
95
+ unwrap_engines(engine_extnames).reverse +
96
+ transformers +
97
+ unwrap_postprocessors(type)
98
+
99
+ bundled_processors = params[:skip_bundle] ? [] : unwrap_bundle_processors(type)
100
+
101
+ processors = bundled_processors.any? ? bundled_processors : processed_processors
102
+ processors += unwrap_encoding_processors(params[:encoding])
103
+
104
+ # Read into memory and process if theres a processor pipeline or the
105
+ # content type is text.
106
+ if processors.any? || mime_type_charset_detecter(type)
107
+ data = read_file(asset[:filename], asset[:content_type])
108
+ metadata = {}
109
+
110
+ input = {
111
+ environment: self,
112
+ cache: self.cache,
113
+ uri: asset[:uri],
114
+ filename: asset[:filename],
115
+ load_path: asset[:load_path],
116
+ name: asset[:name],
117
+ content_type: asset[:content_type],
118
+ metadata: metadata
119
+ }
120
+
121
+ processors.each do |processor|
122
+ begin
123
+ result = processor.call(input.merge(data: data, metadata: metadata))
124
+ case result
125
+ when NilClass
126
+ # noop
127
+ when Hash
128
+ data = result[:data] if result.key?(:data)
129
+ metadata = metadata.merge(result)
130
+ metadata.delete(:data)
131
+ when String
132
+ data = result
133
+ else
134
+ raise Error, "invalid processor return type: #{result.class}"
135
+ end
136
+ end
137
+ end
138
+
139
+ asset[:source] = data
140
+ asset[:metadata] = metadata.merge(
141
+ charset: data.encoding.name.downcase,
142
+ digest: digest(data),
143
+ length: data.bytesize
144
+ )
145
+ else
146
+ asset[:metadata] = {
147
+ encoding: Encoding::BINARY,
148
+ digest: file_digest(asset[:filename]),
149
+ length: self.stat(asset[:filename]).size
150
+ }
151
+ end
152
+
153
+ metadata = asset[:metadata]
154
+ metadata[:dependency_paths] = Set.new(metadata[:dependency_paths]).merge([asset[:filename]])
155
+ metadata[:dependency_sources_digest] = files_digest(metadata[:dependency_paths])
156
+
157
+ asset[:integrity] = integrity_uri(asset[:metadata][:digest], asset[:content_type])
158
+
159
+ asset[:id] = pack_hexdigest(digest(asset))
160
+ asset[:uri] = AssetURI.build(filename, params.merge(id: asset[:id]))
161
+
162
+ # Deprecated: Avoid tracking Asset mtime
163
+ asset[:mtime] = metadata[:dependency_paths].map { |p| stat(p).mtime.to_i }.max
164
+
165
+ asset
166
+ end
167
+ end
168
+ end