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.
- checksums.yaml +4 -4
- data/lib/sprockets.rb +22 -19
- data/lib/sprockets/asset.rb +24 -12
- data/lib/sprockets/asset_uri.rb +0 -1
- data/lib/sprockets/base.rb +14 -127
- data/lib/sprockets/bundle.rb +9 -2
- data/lib/sprockets/cached_environment.rb +35 -16
- data/lib/sprockets/configuration.rb +19 -18
- data/lib/sprockets/context.rb +41 -20
- data/lib/sprockets/directive_processor.rb +36 -19
- data/lib/sprockets/environment.rb +1 -0
- data/lib/sprockets/legacy.rb +67 -0
- data/lib/sprockets/loader.rb +168 -0
- data/lib/sprockets/mime.rb +1 -4
- data/lib/sprockets/path_digest_utils.rb +47 -0
- data/lib/sprockets/path_utils.rb +22 -0
- data/lib/sprockets/paths.rb +21 -0
- data/lib/sprockets/processing.rb +4 -48
- data/lib/sprockets/resolve.rb +73 -181
- data/lib/sprockets/transformers.rb +36 -2
- data/lib/sprockets/version.rb +1 -1
- metadata +4 -2
data/lib/sprockets/mime.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'sprockets/encoding_utils'
|
2
|
+
require 'sprockets/http_utils'
|
2
3
|
|
3
4
|
module Sprockets
|
4
5
|
module Mime
|
@@ -119,10 +120,6 @@ module Sprockets
|
|
119
120
|
end
|
120
121
|
|
121
122
|
private
|
122
|
-
def read_input(input)
|
123
|
-
read_file(input[:filename], input[:content_type])
|
124
|
-
end
|
125
|
-
|
126
123
|
# Internal: Get a postprocessor to perform the encoding.
|
127
124
|
#
|
128
125
|
# encoding - String encoding.
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'sprockets/digest_utils'
|
2
|
+
require 'sprockets/path_utils'
|
3
|
+
|
4
|
+
module Sprockets
|
5
|
+
# Internal: Crossover of path and digest utilities functions.
|
6
|
+
module PathDigestUtils
|
7
|
+
include DigestUtils, PathUtils
|
8
|
+
|
9
|
+
# Internal: Compute digest for file stat.
|
10
|
+
#
|
11
|
+
# path - String filename
|
12
|
+
# stat - File::Stat
|
13
|
+
#
|
14
|
+
# Returns String digest bytes.
|
15
|
+
def stat_digest(path, stat)
|
16
|
+
if stat.directory?
|
17
|
+
# If its a directive, digest the list of filenames
|
18
|
+
digest_class.digest(self.entries(path).join(','))
|
19
|
+
elsif stat.file?
|
20
|
+
# If its a file, digest the contents
|
21
|
+
digest_class.file(path.to_s).digest
|
22
|
+
else
|
23
|
+
raise TypeError, "stat was not a directory or file: #{stat.ftype}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Internal: Compute digest for path.
|
28
|
+
#
|
29
|
+
# path - String filename or directory path.
|
30
|
+
#
|
31
|
+
# Returns String digest bytes or nil.
|
32
|
+
def file_digest(path)
|
33
|
+
if stat = self.stat(path)
|
34
|
+
self.stat_digest(path, stat)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
# Internal: Compute digest for a set of paths.
|
39
|
+
#
|
40
|
+
# paths - Array of filename or directory paths.
|
41
|
+
#
|
42
|
+
# Returns String digest bytes.
|
43
|
+
def files_digest(paths)
|
44
|
+
self.digest(paths.map { |path| self.file_digest(path) })
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/lib/sprockets/path_utils.rb
CHANGED
@@ -195,6 +195,28 @@ module Sprockets
|
|
195
195
|
nil
|
196
196
|
end
|
197
197
|
|
198
|
+
# Internal: Recursive stat all the files under a directory in alphabetical
|
199
|
+
# order.
|
200
|
+
#
|
201
|
+
# dir - A String directory
|
202
|
+
#
|
203
|
+
# Returns an Enumerator of [path, stat].
|
204
|
+
def stat_sorted_tree(dir, &block)
|
205
|
+
return to_enum(__method__, dir) unless block_given?
|
206
|
+
|
207
|
+
self.stat_directory(dir).sort_by { |path, stat|
|
208
|
+
stat.directory? ? "#{path}/" : path
|
209
|
+
}.each do |path, stat|
|
210
|
+
yield path, stat
|
211
|
+
|
212
|
+
if stat.directory?
|
213
|
+
stat_sorted_tree(path, &block)
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
nil
|
218
|
+
end
|
219
|
+
|
198
220
|
# Internal: Write to a file atomically. Useful for situations where you
|
199
221
|
# don't want other processes or threads to see half-written files.
|
200
222
|
#
|
data/lib/sprockets/paths.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
|
+
require 'sprockets/path_utils'
|
2
|
+
|
1
3
|
module Sprockets
|
2
4
|
module Paths
|
5
|
+
include PathUtils
|
6
|
+
|
3
7
|
# Returns `Environment` root.
|
4
8
|
#
|
5
9
|
# All relative paths are expanded with root as its base. To be
|
@@ -41,5 +45,22 @@ module Sprockets
|
|
41
45
|
paths.clear
|
42
46
|
end
|
43
47
|
end
|
48
|
+
|
49
|
+
# Public: Iterate over every file under all load paths.
|
50
|
+
#
|
51
|
+
# Returns Enumerator if no block is given.
|
52
|
+
def each_file
|
53
|
+
return to_enum(__method__) unless block_given?
|
54
|
+
|
55
|
+
paths.each do |root|
|
56
|
+
stat_tree(root).each do |filename, stat|
|
57
|
+
if stat.file?
|
58
|
+
yield filename
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
nil
|
64
|
+
end
|
44
65
|
end
|
45
66
|
end
|
data/lib/sprockets/processing.rb
CHANGED
@@ -156,61 +156,17 @@ module Sprockets
|
|
156
156
|
end
|
157
157
|
end
|
158
158
|
|
159
|
-
# Internal: Run processors on filename and data.
|
160
|
-
#
|
161
|
-
# Returns Hash.
|
162
|
-
def process(processors, uri, filename, load_path, name, content_type)
|
163
|
-
data, metadata = nil, {}
|
164
|
-
|
165
|
-
input = {
|
166
|
-
environment: self,
|
167
|
-
cache: cache,
|
168
|
-
uri: uri,
|
169
|
-
filename: filename,
|
170
|
-
load_path: load_path,
|
171
|
-
name: name,
|
172
|
-
content_type: content_type,
|
173
|
-
metadata: metadata
|
174
|
-
}
|
175
|
-
|
176
|
-
processors.each do |processor|
|
177
|
-
begin
|
178
|
-
result = processor.call(input.merge(data: data, metadata: metadata))
|
179
|
-
case result
|
180
|
-
when NilClass
|
181
|
-
# noop
|
182
|
-
when Hash
|
183
|
-
data = result[:data] if result.key?(:data)
|
184
|
-
metadata = metadata.merge(result)
|
185
|
-
metadata.delete(:data)
|
186
|
-
when String
|
187
|
-
data = result
|
188
|
-
else
|
189
|
-
raise Error, "invalid processor return type: #{result.class}"
|
190
|
-
end
|
191
|
-
end
|
192
|
-
end
|
193
|
-
|
194
|
-
{
|
195
|
-
source: data,
|
196
|
-
charset: data.encoding.name.downcase,
|
197
|
-
length: data.bytesize,
|
198
|
-
digest: digest(data),
|
199
|
-
metadata: metadata
|
200
|
-
}
|
201
|
-
end
|
202
|
-
|
203
159
|
# Internal: Two dimensional Hash of reducer functions for a given mime type
|
204
160
|
# and asset metadata key.
|
205
161
|
attr_reader :bundle_reducers
|
206
162
|
|
207
|
-
# Public: Register bundle reducer function.
|
163
|
+
# Public: Register bundle metadata reducer function.
|
208
164
|
#
|
209
165
|
# Examples
|
210
166
|
#
|
211
|
-
# Sprockets.
|
167
|
+
# Sprockets.register_bundle_metadata_reducer 'application/javascript', :jshint_errors, [], :+
|
212
168
|
#
|
213
|
-
# Sprockets.
|
169
|
+
# Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, 0 { |total, count|
|
214
170
|
# total + count
|
215
171
|
# }
|
216
172
|
#
|
@@ -220,7 +176,7 @@ module Sprockets
|
|
220
176
|
# block - Proc accepting the memo accumulator and current value
|
221
177
|
#
|
222
178
|
# Returns nothing.
|
223
|
-
def
|
179
|
+
def register_bundle_metadata_reducer(mime_type, key, *args, &block)
|
224
180
|
case args.size
|
225
181
|
when 0
|
226
182
|
reducer = block
|
data/lib/sprockets/resolve.rb
CHANGED
@@ -1,106 +1,57 @@
|
|
1
|
+
require 'sprockets/asset_uri'
|
2
|
+
|
1
3
|
module Sprockets
|
2
4
|
module Resolve
|
3
|
-
# Public:
|
4
|
-
#
|
5
|
-
# Returns Enumerator if no block is given.
|
6
|
-
def each_file
|
7
|
-
return to_enum(__method__) unless block_given?
|
8
|
-
|
9
|
-
paths.each do |root|
|
10
|
-
stat_tree(root).each do |filename, stat|
|
11
|
-
if stat.file?
|
12
|
-
yield filename
|
13
|
-
end
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
nil
|
18
|
-
end
|
19
|
-
|
20
|
-
# Finds the expanded real path for a given logical path by
|
21
|
-
# searching the environment's paths.
|
5
|
+
# Public: Finds the absolute path for a given logical path by searching the
|
6
|
+
# environment's load paths.
|
22
7
|
#
|
23
8
|
# resolve("application.js")
|
24
|
-
# # => "/path/to/app/javascripts/application.js
|
9
|
+
# # => "/path/to/app/javascripts/application.js"
|
10
|
+
#
|
11
|
+
# An accept content type can be given if the logical path doesn't have a
|
12
|
+
# format extension.
|
25
13
|
#
|
26
|
-
#
|
14
|
+
# resolve("application", accept: "application/javascript")
|
15
|
+
# # => "/path/to/app/javascripts/application.js"
|
16
|
+
#
|
17
|
+
# The String path is returned or nil if no results are found.
|
27
18
|
def resolve(path, options = {})
|
28
|
-
|
29
|
-
return filename
|
30
|
-
end
|
31
|
-
|
32
|
-
accept = options[:accept]
|
33
|
-
message = "couldn't find file '#{path}'"
|
34
|
-
message << " with type '#{accept}'" if accept
|
35
|
-
raise FileNotFound, message
|
36
|
-
end
|
19
|
+
logical_name, mime_type, _ = parse_path_extnames(path)
|
37
20
|
|
38
|
-
|
39
|
-
if !self.paths.include?(load_path.to_s)
|
40
|
-
raise FileOutsidePaths, "#{load_path} isn't in paths: #{self.paths.join(', ')}"
|
41
|
-
end
|
21
|
+
paths = options[:load_paths] || self.paths
|
42
22
|
|
43
|
-
|
44
|
-
|
23
|
+
if absolute_path?(path)
|
24
|
+
path = File.expand_path(path)
|
25
|
+
if paths_split(paths, path) && file?(path)
|
26
|
+
if accept = options[:accept]
|
27
|
+
find_best_q_match(accept, [path]) do |candidate, matcher|
|
28
|
+
match_mime_type?(mime_type || "application/octet-stream", matcher)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
path
|
32
|
+
end
|
33
|
+
end
|
34
|
+
else
|
35
|
+
accepts = parse_accept_options(mime_type, options[:accept])
|
36
|
+
filename, _ = resolve_under_paths(paths, logical_name, mime_type, accepts)
|
37
|
+
filename
|
45
38
|
end
|
46
|
-
|
47
|
-
accept = options[:accept]
|
48
|
-
message = "couldn't find file '#{logical_path}' under '#{load_path}'"
|
49
|
-
message << " with type '#{accept}'" if accept
|
50
|
-
raise FileNotFound, message
|
51
39
|
end
|
52
40
|
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
logical_name, mime_type, _ = parse_path_extnames(logical_path)
|
57
|
-
logical_basename = File.basename(logical_name)
|
58
|
-
|
59
|
-
accepts = parse_accept_options(mime_type, options[:accept])
|
60
|
-
|
61
|
-
_resolve_all_under_load_path(load_path, logical_name, logical_basename, accepts, &block)
|
62
|
-
|
63
|
-
nil
|
64
|
-
end
|
65
|
-
|
66
|
-
# Public: Finds the expanded real path for a given logical path by searching
|
67
|
-
# the environment's paths. Includes all matching paths including fallbacks
|
68
|
-
# and shadowed matches.
|
41
|
+
# Public: Find Asset URI for given a logical path by searching the
|
42
|
+
# environment's load paths.
|
69
43
|
#
|
70
|
-
#
|
71
|
-
# # => "
|
44
|
+
# locate("application.js")
|
45
|
+
# # => "file:///path/to/app/javascripts/application.js?content_type=application/javascript"
|
72
46
|
#
|
73
|
-
#
|
74
|
-
#
|
47
|
+
# An accept content type can be given if the logical path doesn't have a
|
48
|
+
# format extension.
|
75
49
|
#
|
76
|
-
#
|
77
|
-
#
|
78
|
-
# end
|
50
|
+
# locate("application", accept: "application/javascript")
|
51
|
+
# # => "file:///path/to/app/javascripts/application.coffee?content_type=application/javascript"
|
79
52
|
#
|
80
|
-
|
81
|
-
|
82
|
-
path = path.to_s
|
83
|
-
|
84
|
-
logical_name, mime_type, _ = parse_path_extnames(path)
|
85
|
-
logical_basename = File.basename(logical_name)
|
86
|
-
|
87
|
-
accepts = parse_accept_options(mime_type, options[:accept])
|
88
|
-
|
89
|
-
self.paths.each do |load_path|
|
90
|
-
_resolve_all_under_load_path(load_path, logical_name, logical_basename, accepts, &block)
|
91
|
-
end
|
92
|
-
|
93
|
-
nil
|
94
|
-
end
|
95
|
-
|
96
|
-
# Experimental: Get transform type for filename
|
97
|
-
def resolve_path_transform_type(filename, accept)
|
98
|
-
mime_type = parse_path_extnames(filename)[1]
|
99
|
-
resolve_transform_type(mime_type, accept)
|
100
|
-
end
|
101
|
-
|
102
|
-
# Experimental
|
103
|
-
def resolve_asset_uri(path, options = {})
|
53
|
+
# The String Asset URI is returned or nil if no results are found.
|
54
|
+
def locate(path, options = {})
|
104
55
|
path = path.to_s
|
105
56
|
accept = options[:accept]
|
106
57
|
skip_bundle = options.key?(:bundle) ? !options[:bundle] : false
|
@@ -108,19 +59,29 @@ module Sprockets
|
|
108
59
|
available_encodings = self.encodings.keys + ['identity']
|
109
60
|
encoding = find_best_q_match(options[:accept_encoding], available_encodings)
|
110
61
|
|
62
|
+
paths = options[:load_paths] || self.paths
|
63
|
+
|
111
64
|
if absolute_path?(path)
|
112
65
|
path = File.expand_path(path)
|
113
|
-
if paths_split(
|
114
|
-
|
115
|
-
|
116
|
-
|
66
|
+
if paths_split(paths, path) && file?(path)
|
67
|
+
mime_type = parse_path_extnames(path)[1]
|
68
|
+
_type = resolve_transform_type(mime_type, accept)
|
69
|
+
if !accept || _type
|
70
|
+
filename = path
|
71
|
+
type = _type
|
72
|
+
end
|
117
73
|
end
|
118
74
|
else
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
75
|
+
logical_name, mime_type, _ = parse_path_extnames(path)
|
76
|
+
parsed_accept = parse_accept_options(mime_type, accept)
|
77
|
+
|
78
|
+
if parsed_accept.empty?
|
79
|
+
return
|
123
80
|
end
|
81
|
+
|
82
|
+
transformed_accepts = expand_transform_accepts(parsed_accept)
|
83
|
+
filename, mime_type = resolve_under_paths(paths, logical_name, mime_type, transformed_accepts)
|
84
|
+
type = resolve_transform_type(mime_type, parsed_accept) if filename
|
124
85
|
end
|
125
86
|
|
126
87
|
if filename
|
@@ -129,58 +90,21 @@ module Sprockets
|
|
129
90
|
end
|
130
91
|
end
|
131
92
|
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
def logical_paths
|
136
|
-
return to_enum(__method__) unless block_given?
|
137
|
-
|
138
|
-
seen = Set.new
|
139
|
-
|
140
|
-
self.paths.each do |load_path|
|
141
|
-
stat_tree(load_path).each do |filename, stat|
|
142
|
-
next unless stat.file?
|
143
|
-
|
144
|
-
path = split_subpath(load_path, filename)
|
145
|
-
path, mime_type, _ = parse_path_extnames(path)
|
146
|
-
path = normalize_logical_path(path)
|
147
|
-
path += mime_types[mime_type][:extensions].first if mime_type
|
93
|
+
protected
|
94
|
+
def resolve_under_paths(paths, logical_name, mime_type, accepts)
|
95
|
+
logical_basename = File.basename(logical_name)
|
148
96
|
|
149
|
-
|
150
|
-
|
151
|
-
|
97
|
+
paths.each do |load_path|
|
98
|
+
candidates = path_matches(load_path, logical_name, logical_basename)
|
99
|
+
candidate = find_best_q_match(accepts, candidates) do |c, matcher|
|
100
|
+
match_mime_type?(c[1] || "application/octet-stream", matcher)
|
152
101
|
end
|
102
|
+
return candidate if candidate
|
153
103
|
end
|
154
|
-
end
|
155
|
-
|
156
|
-
nil
|
157
|
-
end
|
158
|
-
|
159
|
-
# Deprecated: Iterate over all logical paths with a matcher.
|
160
|
-
#
|
161
|
-
# Remove from 4.x.
|
162
|
-
#
|
163
|
-
# args - List of matcher objects.
|
164
|
-
#
|
165
|
-
# Returns Enumerator if no block is given.
|
166
|
-
def each_logical_path(*args, &block)
|
167
|
-
return to_enum(__method__, *args) unless block_given?
|
168
104
|
|
169
|
-
|
170
|
-
logical_paths.each do |a, b|
|
171
|
-
if filters.any? { |f| f.call(a, b) }
|
172
|
-
if block.arity == 2
|
173
|
-
yield a, b
|
174
|
-
else
|
175
|
-
yield a
|
176
|
-
end
|
177
|
-
end
|
105
|
+
nil
|
178
106
|
end
|
179
107
|
|
180
|
-
nil
|
181
|
-
end
|
182
|
-
|
183
|
-
protected
|
184
108
|
def parse_accept_options(mime_type, types)
|
185
109
|
accepts = []
|
186
110
|
accepts += parse_q_values(types) if types
|
@@ -206,52 +130,20 @@ module Sprockets
|
|
206
130
|
path
|
207
131
|
end
|
208
132
|
|
209
|
-
def _resolve_all_under_load_path(load_path, logical_name, logical_basename, accepts, &block)
|
210
|
-
filenames = path_matches(load_path, logical_name, logical_basename)
|
211
|
-
|
212
|
-
matches = []
|
213
|
-
|
214
|
-
# TODO: Cleanup double iteration of accept and filenames
|
215
|
-
|
216
|
-
# Exact mime type match first
|
217
|
-
matches += find_q_matches(accepts, filenames) do |filename, accepted|
|
218
|
-
if !file?(filename)
|
219
|
-
nil
|
220
|
-
elsif accepted == '*/*'
|
221
|
-
filename
|
222
|
-
elsif parse_path_extnames(filename)[1] == accepted
|
223
|
-
filename
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
|
-
# Then transformable match
|
228
|
-
matches += find_q_matches(accepts, filenames) do |filename, accepted|
|
229
|
-
if !file?(filename)
|
230
|
-
nil
|
231
|
-
elsif accepted == '*/*'
|
232
|
-
filename
|
233
|
-
elsif resolve_path_transform_type(filename, accepted)
|
234
|
-
filename
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
matches.uniq.each(&block)
|
239
|
-
end
|
240
|
-
|
241
133
|
def path_matches(load_path, logical_name, logical_basename)
|
242
|
-
|
134
|
+
candidates = []
|
243
135
|
dirname = File.dirname(File.join(load_path, logical_name))
|
244
|
-
dirname_matches(dirname, logical_basename) { |
|
245
|
-
resolve_alternates(load_path, logical_name) { |fn|
|
246
|
-
dirname_matches(File.join(load_path, logical_name), "index") { |
|
247
|
-
|
136
|
+
dirname_matches(dirname, logical_basename) { |candidate| candidates << candidate }
|
137
|
+
resolve_alternates(load_path, logical_name) { |fn| candidates << [fn, parse_path_extnames(fn)[1]] }
|
138
|
+
dirname_matches(File.join(load_path, logical_name), "index") { |candidate| candidates << candidate }
|
139
|
+
candidates.select { |fn, _| file?(fn) }
|
248
140
|
end
|
249
141
|
|
250
142
|
def dirname_matches(dirname, basename)
|
251
143
|
self.entries(dirname).each do |entry|
|
252
|
-
name = parse_path_extnames(entry)
|
144
|
+
name, type, _ = parse_path_extnames(entry)
|
253
145
|
if basename == name
|
254
|
-
yield File.join(dirname, entry)
|
146
|
+
yield [File.join(dirname, entry), type]
|
255
147
|
end
|
256
148
|
end
|
257
149
|
end
|