sprockets 3.0.0.beta.3 → 3.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -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
|
14
|
-
@version
|
15
|
-
@digest_class
|
16
|
-
@context_class
|
17
|
-
@root
|
18
|
-
@paths
|
19
|
-
@mime_types
|
20
|
-
@mime_exts
|
21
|
-
@encodings
|
22
|
-
@engines
|
23
|
-
@engine_mime_types
|
24
|
-
@transformers
|
25
|
-
@
|
26
|
-
@
|
27
|
-
@
|
28
|
-
@
|
29
|
-
@
|
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
|
-
#
|
56
|
+
# Public: Returns a `Digest` implementation class.
|
56
57
|
#
|
57
58
|
# Defaults to `Digest::SHA256`.
|
58
59
|
attr_reader :digest_class
|
data/lib/sprockets/context.rb
CHANGED
@@ -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
|
-
|
82
|
-
|
114
|
+
_resolve(:resolve, path, options)
|
115
|
+
end
|
83
116
|
|
84
|
-
|
85
|
-
|
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.
|
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
|
-
|
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
|
-
|
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.
|
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 <<
|
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
|
239
|
-
|
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
|
-
|
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.
|
270
|
-
required <<
|
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
|
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.
|
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 <<
|
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.
|
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
|
348
|
-
|
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.
|
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.
|
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
|
data/lib/sprockets/legacy.rb
CHANGED
@@ -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
|