sprockets 2.0.5 → 2.1.0.beta
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of sprockets might be problematic. Click here for more details.
- data/lib/sprockets.rb +44 -12
- data/lib/sprockets/asset.rb +114 -68
- data/lib/sprockets/asset_attributes.rb +1 -34
- data/lib/sprockets/base.rb +97 -16
- data/lib/sprockets/bundled_asset.rb +32 -211
- data/lib/sprockets/cache/file_store.rb +2 -11
- data/lib/sprockets/caching.rb +11 -42
- data/lib/sprockets/context.rb +7 -5
- data/lib/sprockets/engines.rb +0 -24
- data/lib/sprockets/environment.rb +5 -11
- data/lib/sprockets/errors.rb +1 -0
- data/lib/sprockets/index.rb +31 -15
- data/lib/sprockets/processed_asset.rb +148 -0
- data/lib/sprockets/server.rb +22 -13
- data/lib/sprockets/static_asset.rb +2 -33
- data/lib/sprockets/trail.rb +0 -24
- data/lib/sprockets/version.rb +1 -1
- metadata +181 -147
- checksums.yaml +0 -7
- data/lib/sprockets/digest.rb +0 -67
data/lib/sprockets.rb
CHANGED
@@ -1,31 +1,63 @@
|
|
1
1
|
require 'sprockets/version'
|
2
2
|
|
3
3
|
module Sprockets
|
4
|
-
|
4
|
+
# Environment
|
5
|
+
autoload :Base, "sprockets/base"
|
6
|
+
autoload :Engines, "sprockets/engines"
|
7
|
+
autoload :Environment, "sprockets/environment"
|
8
|
+
autoload :Index, "sprockets/index"
|
9
|
+
|
10
|
+
# Assets
|
5
11
|
autoload :Asset, "sprockets/asset"
|
6
|
-
autoload :AssetAttributes, "sprockets/asset_attributes"
|
7
12
|
autoload :BundledAsset, "sprockets/bundled_asset"
|
13
|
+
autoload :ProcessedAsset, "sprockets/processed_asset"
|
14
|
+
autoload :StaticAsset, "sprockets/static_asset"
|
15
|
+
|
16
|
+
# Processing
|
8
17
|
autoload :CharsetNormalizer, "sprockets/charset_normalizer"
|
9
|
-
autoload :CircularDependencyError, "sprockets/errors"
|
10
|
-
autoload :ContentTypeMismatch, "sprockets/errors"
|
11
18
|
autoload :Context, "sprockets/context"
|
12
19
|
autoload :DirectiveProcessor, "sprockets/directive_processor"
|
13
20
|
autoload :EcoTemplate, "sprockets/eco_template"
|
14
21
|
autoload :EjsTemplate, "sprockets/ejs_template"
|
22
|
+
autoload :JstProcessor, "sprockets/jst_processor"
|
23
|
+
autoload :Processor, "sprockets/processor"
|
24
|
+
autoload :SafetyColons, "sprockets/safety_colons"
|
25
|
+
|
26
|
+
# Internal utilities
|
27
|
+
autoload :ArgumentError, "sprockets/errors"
|
28
|
+
autoload :AssetAttributes, "sprockets/asset_attributes"
|
29
|
+
autoload :CircularDependencyError, "sprockets/errors"
|
30
|
+
autoload :ContentTypeMismatch, "sprockets/errors"
|
15
31
|
autoload :EngineError, "sprockets/errors"
|
16
|
-
autoload :Engines, "sprockets/engines"
|
17
|
-
autoload :Environment, "sprockets/environment"
|
18
32
|
autoload :Error, "sprockets/errors"
|
19
33
|
autoload :FileNotFound, "sprockets/errors"
|
20
|
-
autoload :Index, "sprockets/index"
|
21
|
-
autoload :JstProcessor, "sprockets/jst_processor"
|
22
|
-
autoload :Processing, "sprockets/processing"
|
23
|
-
autoload :Processor, "sprockets/processor"
|
24
|
-
autoload :Server, "sprockets/server"
|
25
|
-
autoload :StaticAsset, "sprockets/static_asset"
|
26
34
|
autoload :Utils, "sprockets/utils"
|
27
35
|
|
28
36
|
module Cache
|
29
37
|
autoload :FileStore, "sprockets/cache/file_store"
|
30
38
|
end
|
39
|
+
|
40
|
+
# Extend Sprockets module to provide global registry
|
41
|
+
extend Engines
|
42
|
+
@engines = {}
|
43
|
+
|
44
|
+
# Cherry pick the default Tilt engines that make sense for
|
45
|
+
# Sprockets. We don't need ones that only generate html like HAML.
|
46
|
+
|
47
|
+
# Mmm, CoffeeScript
|
48
|
+
register_engine '.coffee', Tilt::CoffeeScriptTemplate
|
49
|
+
|
50
|
+
# JST engines
|
51
|
+
register_engine '.jst', JstProcessor
|
52
|
+
register_engine '.eco', EcoTemplate
|
53
|
+
register_engine '.ejs', EjsTemplate
|
54
|
+
|
55
|
+
# CSS engines
|
56
|
+
register_engine '.less', Tilt::LessTemplate
|
57
|
+
register_engine '.sass', Tilt::SassTemplate
|
58
|
+
register_engine '.scss', Tilt::ScssTemplate
|
59
|
+
|
60
|
+
# Other
|
61
|
+
register_engine '.erb', Tilt::ERBTemplate
|
62
|
+
register_engine '.str', Tilt::StringTemplate
|
31
63
|
end
|
data/lib/sprockets/asset.rb
CHANGED
@@ -1,90 +1,79 @@
|
|
1
1
|
require 'time'
|
2
|
+
require 'set'
|
2
3
|
|
3
4
|
module Sprockets
|
4
5
|
# `Asset` is the base class for `BundledAsset` and `StaticAsset`.
|
5
6
|
class Asset
|
6
7
|
# Internal initializer to load `Asset` from serialized `Hash`.
|
7
8
|
def self.from_hash(environment, hash)
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
return unless hash.is_a?(Hash)
|
10
|
+
|
11
|
+
klass = case hash['class']
|
12
|
+
when 'BundledAsset'
|
13
|
+
BundledAsset
|
14
|
+
when 'ProcessedAsset'
|
15
|
+
ProcessedAsset
|
16
|
+
when 'StaticAsset'
|
17
|
+
StaticAsset
|
18
|
+
else
|
19
|
+
nil
|
20
|
+
end
|
12
21
|
|
13
|
-
|
14
|
-
|
15
|
-
|
22
|
+
if klass
|
23
|
+
asset = klass.allocate
|
24
|
+
asset.init_with(environment, hash)
|
25
|
+
asset
|
26
|
+
end
|
27
|
+
rescue UnserializeError
|
28
|
+
nil
|
16
29
|
end
|
17
30
|
|
18
|
-
attr_reader :
|
19
|
-
attr_reader :
|
31
|
+
attr_reader :logical_path, :pathname
|
32
|
+
attr_reader :content_type, :mtime, :length, :digest
|
20
33
|
|
21
34
|
def initialize(environment, logical_path, pathname)
|
22
|
-
@
|
35
|
+
@root = environment.root
|
23
36
|
@logical_path = logical_path.to_s
|
24
37
|
@pathname = Pathname.new(pathname)
|
25
|
-
@
|
38
|
+
@content_type = environment.content_type_of(pathname)
|
39
|
+
@mtime = environment.stat(pathname).mtime
|
40
|
+
@length = environment.stat(pathname).size
|
41
|
+
@digest = environment.file_digest(pathname).hexdigest
|
26
42
|
end
|
27
43
|
|
28
44
|
# Initialize `Asset` from serialized `Hash`.
|
29
45
|
def init_with(environment, coder)
|
30
|
-
@
|
31
|
-
@pathname = @mtime = @length = nil
|
46
|
+
@root = environment.root
|
32
47
|
|
33
|
-
|
34
|
-
|
35
|
-
|
48
|
+
@logical_path = coder['logical_path']
|
49
|
+
@content_type = coder['content_type']
|
50
|
+
@digest = coder['digest']
|
36
51
|
|
37
|
-
if
|
52
|
+
if pathname = coder['pathname']
|
38
53
|
# Expand `$root` placeholder and wrapper string in a `Pathname`
|
39
|
-
@pathname = Pathname.new(expand_root_path(
|
54
|
+
@pathname = Pathname.new(expand_root_path(pathname))
|
40
55
|
end
|
41
56
|
|
42
|
-
if
|
57
|
+
if mtime = coder['mtime']
|
43
58
|
# Parse time string
|
44
|
-
@mtime = Time.parse(
|
59
|
+
@mtime = Time.parse(mtime)
|
45
60
|
end
|
46
61
|
|
47
|
-
if
|
62
|
+
if length = coder['length']
|
48
63
|
# Convert length to an `Integer`
|
49
|
-
@length = Integer(
|
64
|
+
@length = Integer(length)
|
50
65
|
end
|
51
66
|
end
|
52
67
|
|
53
68
|
# Copy serialized attributes to the coder object
|
54
69
|
def encode_with(coder)
|
55
|
-
coder['class']
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
else
|
63
|
-
value.to_s
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
coder['pathname'] = relativize_root_path(coder['pathname'])
|
68
|
-
end
|
69
|
-
|
70
|
-
# Returns `Content-Type` from pathname.
|
71
|
-
def content_type
|
72
|
-
@content_type ||= environment.content_type_of(pathname)
|
73
|
-
end
|
74
|
-
|
75
|
-
# Get mtime at the time the `Asset` is built.
|
76
|
-
def mtime
|
77
|
-
@mtime ||= environment.stat(pathname).mtime
|
78
|
-
end
|
79
|
-
|
80
|
-
# Get length at the time the `Asset` is built.
|
81
|
-
def length
|
82
|
-
@length ||= environment.stat(pathname).size
|
83
|
-
end
|
84
|
-
|
85
|
-
# Get content digest at the time the `Asset` is built.
|
86
|
-
def digest
|
87
|
-
@digest ||= environment.file_digest(pathname).hexdigest
|
70
|
+
coder['class'] = self.class.name.sub(/Sprockets::/, '')
|
71
|
+
coder['logical_path'] = logical_path
|
72
|
+
coder['pathname'] = relativize_root_path(pathname).to_s
|
73
|
+
coder['content_type'] = content_type
|
74
|
+
coder['mtime'] = mtime.iso8601
|
75
|
+
coder['length'] = length
|
76
|
+
coder['digest'] = digest
|
88
77
|
end
|
89
78
|
|
90
79
|
# Return logical path with digest spliced in.
|
@@ -92,7 +81,7 @@ module Sprockets
|
|
92
81
|
# "foo/bar-37b51d194a7513e45b56f6524f2d51f2.js"
|
93
82
|
#
|
94
83
|
def digest_path
|
95
|
-
|
84
|
+
logical_path.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
|
96
85
|
end
|
97
86
|
|
98
87
|
# Return an `Array` of `Asset` files that are declared dependencies.
|
@@ -111,6 +100,16 @@ module Sprockets
|
|
111
100
|
[self]
|
112
101
|
end
|
113
102
|
|
103
|
+
# `body` is aliased to source by default if it can't have any dependencies.
|
104
|
+
def body
|
105
|
+
source
|
106
|
+
end
|
107
|
+
|
108
|
+
# Return `String` of concatenated source.
|
109
|
+
def to_s
|
110
|
+
source
|
111
|
+
end
|
112
|
+
|
114
113
|
# Add enumerator to allow `Asset` instances to be used as Rack
|
115
114
|
# compatible body objects.
|
116
115
|
def each
|
@@ -121,18 +120,47 @@ module Sprockets
|
|
121
120
|
# digest to the inmemory model.
|
122
121
|
#
|
123
122
|
# Used to test if cached models need to be rebuilt.
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
!stale?
|
123
|
+
def fresh?(environment)
|
124
|
+
# Check current mtime and digest
|
125
|
+
dependency_fresh?(environment, self)
|
128
126
|
end
|
129
127
|
|
130
128
|
# Checks if Asset is stale by comparing the actual mtime and
|
131
129
|
# digest to the inmemory model.
|
132
130
|
#
|
133
131
|
# Subclass must override `fresh?` or `stale?`.
|
134
|
-
def stale?
|
135
|
-
!fresh?
|
132
|
+
def stale?(environment)
|
133
|
+
!fresh?(environment)
|
134
|
+
end
|
135
|
+
|
136
|
+
# Save asset to disk.
|
137
|
+
def write_to(filename, options = {})
|
138
|
+
# Gzip contents if filename has '.gz'
|
139
|
+
options[:compress] ||= File.extname(filename) == '.gz'
|
140
|
+
|
141
|
+
File.open("#{filename}+", 'wb') do |f|
|
142
|
+
if options[:compress]
|
143
|
+
# Run contents through `Zlib`
|
144
|
+
gz = Zlib::GzipWriter.new(f, Zlib::BEST_COMPRESSION)
|
145
|
+
gz.write to_s
|
146
|
+
gz.close
|
147
|
+
else
|
148
|
+
# Write out as is
|
149
|
+
f.write to_s
|
150
|
+
f.close
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Atomic write
|
155
|
+
FileUtils.mv("#{filename}+", filename)
|
156
|
+
|
157
|
+
# Set mtime correctly
|
158
|
+
File.utime(mtime, mtime, filename)
|
159
|
+
|
160
|
+
nil
|
161
|
+
ensure
|
162
|
+
# Ensure tmp file gets cleaned up
|
163
|
+
FileUtils.rm("#{filename}+") if File.exist?("#{filename}+")
|
136
164
|
end
|
137
165
|
|
138
166
|
# Pretty inspect
|
@@ -144,29 +172,47 @@ module Sprockets
|
|
144
172
|
">"
|
145
173
|
end
|
146
174
|
|
175
|
+
def hash
|
176
|
+
digest.hash
|
177
|
+
end
|
178
|
+
|
147
179
|
# Assets are equal if they share the same path, mtime and digest.
|
148
180
|
def eql?(other)
|
149
181
|
other.class == self.class &&
|
150
|
-
other.
|
182
|
+
other.logical_path == self.logical_path &&
|
151
183
|
other.mtime.to_i == self.mtime.to_i &&
|
152
184
|
other.digest == self.digest
|
153
185
|
end
|
154
186
|
alias_method :==, :eql?
|
155
187
|
|
156
188
|
protected
|
189
|
+
# Internal: String paths that are marked as dependencies after processing.
|
190
|
+
#
|
191
|
+
# Default to an empty `Array`.
|
192
|
+
def dependency_paths
|
193
|
+
@dependency_paths ||= []
|
194
|
+
end
|
195
|
+
|
196
|
+
# Internal: `ProccessedAsset`s that are required after processing.
|
197
|
+
#
|
198
|
+
# Default to an empty `Array`.
|
199
|
+
def required_assets
|
200
|
+
@required_assets ||= []
|
201
|
+
end
|
202
|
+
|
157
203
|
# Get pathname with its root stripped.
|
158
204
|
def relative_pathname
|
159
|
-
Pathname.new(relativize_root_path(pathname))
|
205
|
+
@relative_pathname ||= Pathname.new(relativize_root_path(pathname))
|
160
206
|
end
|
161
207
|
|
162
208
|
# Replace `$root` placeholder with actual environment root.
|
163
209
|
def expand_root_path(path)
|
164
|
-
|
210
|
+
path.to_s.sub(/^\$root/, @root)
|
165
211
|
end
|
166
212
|
|
167
213
|
# Replace actual environment root with `$root` placeholder.
|
168
214
|
def relativize_root_path(path)
|
169
|
-
|
215
|
+
path.to_s.sub(/^#{Regexp.escape(@root)}/, '$root')
|
170
216
|
end
|
171
217
|
|
172
218
|
# Check if dependency is fresh.
|
@@ -175,8 +221,8 @@ module Sprockets
|
|
175
221
|
#
|
176
222
|
# A `Hash` is used rather than other `Asset` object because we
|
177
223
|
# want to test non-asset files and directories.
|
178
|
-
def dependency_fresh?(dep
|
179
|
-
path, mtime, hexdigest = dep.
|
224
|
+
def dependency_fresh?(environment, dep)
|
225
|
+
path, mtime, hexdigest = dep.pathname.to_s, dep.mtime, dep.digest
|
180
226
|
|
181
227
|
stat = environment.stat(path)
|
182
228
|
|
@@ -13,16 +13,6 @@ module Sprockets
|
|
13
13
|
@pathname = path.is_a?(Pathname) ? path : Pathname.new(path.to_s)
|
14
14
|
end
|
15
15
|
|
16
|
-
# Replaces `$root` placeholder with actual environment root.
|
17
|
-
def expand_root
|
18
|
-
pathname.to_s.sub(/^\$root/, environment.root)
|
19
|
-
end
|
20
|
-
|
21
|
-
# Replaces environment root with `$root` placeholder.
|
22
|
-
def relativize_root
|
23
|
-
pathname.to_s.sub(/^#{Regexp.escape(environment.root)}/, '$root')
|
24
|
-
end
|
25
|
-
|
26
16
|
# Returns paths search the load path for.
|
27
17
|
def search_paths
|
28
18
|
paths = [pathname.to_s]
|
@@ -42,9 +32,8 @@ module Sprockets
|
|
42
32
|
# shaddowed in the path, but is required relatively, its logical
|
43
33
|
# path will be incorrect.
|
44
34
|
def logical_path
|
45
|
-
raise ArgumentError unless pathname.absolute?
|
46
|
-
|
47
35
|
if root_path = environment.paths.detect { |path| pathname.to_s[path] }
|
36
|
+
path = pathname.to_s.sub("#{root_path}/", '')
|
48
37
|
path = pathname.relative_path_from(Pathname.new(root_path)).to_s
|
49
38
|
path = engine_extensions.inject(path) { |p, ext| p.sub(ext, '') }
|
50
39
|
path = "#{path}#{engine_format_extension}" unless format_extension
|
@@ -114,28 +103,6 @@ module Sprockets
|
|
114
103
|
end
|
115
104
|
end
|
116
105
|
|
117
|
-
# Gets digest fingerprint.
|
118
|
-
#
|
119
|
-
# "foo-0aa2105d29558f3eb790d411d7d8fb66.js"
|
120
|
-
# # => "0aa2105d29558f3eb790d411d7d8fb66"
|
121
|
-
#
|
122
|
-
def path_fingerprint
|
123
|
-
pathname.basename(extensions.join).to_s =~ /-([0-9a-f]{7,40})$/ ? $1 : nil
|
124
|
-
end
|
125
|
-
|
126
|
-
# Injects digest fingerprint into path.
|
127
|
-
#
|
128
|
-
# "foo.js"
|
129
|
-
# # => "foo-0aa2105d29558f3eb790d411d7d8fb66.js"
|
130
|
-
#
|
131
|
-
def path_with_fingerprint(digest)
|
132
|
-
if old_digest = path_fingerprint
|
133
|
-
pathname.sub(old_digest, digest).to_s
|
134
|
-
else
|
135
|
-
pathname.to_s.sub(/\.(\w+)$/) { |ext| "-#{digest}#{ext}" }
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
106
|
private
|
140
107
|
# Returns implicit engine content type.
|
141
108
|
#
|
data/lib/sprockets/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'sprockets/asset_attributes'
|
2
2
|
require 'sprockets/bundled_asset'
|
3
3
|
require 'sprockets/caching'
|
4
|
-
require 'sprockets/
|
4
|
+
require 'sprockets/processed_asset'
|
5
5
|
require 'sprockets/processing'
|
6
6
|
require 'sprockets/server'
|
7
7
|
require 'sprockets/static_asset'
|
@@ -11,9 +11,66 @@ require 'pathname'
|
|
11
11
|
module Sprockets
|
12
12
|
# `Base` class for `Environment` and `Index`.
|
13
13
|
class Base
|
14
|
-
include Digest
|
15
14
|
include Caching, Processing, Server, Trail
|
16
15
|
|
16
|
+
# Returns a `Digest` implementation class.
|
17
|
+
#
|
18
|
+
# Defaults to `Digest::MD5`.
|
19
|
+
attr_reader :digest_class
|
20
|
+
|
21
|
+
# Assign a `Digest` implementation class. This maybe any Ruby
|
22
|
+
# `Digest::` implementation such as `Digest::MD5` or
|
23
|
+
# `Digest::SHA1`.
|
24
|
+
#
|
25
|
+
# environment.digest_class = Digest::SHA1
|
26
|
+
#
|
27
|
+
def digest_class=(klass)
|
28
|
+
expire_index!
|
29
|
+
@digest_class = klass
|
30
|
+
end
|
31
|
+
|
32
|
+
# The `Environment#version` is a custom value used for manually
|
33
|
+
# expiring all asset caches.
|
34
|
+
#
|
35
|
+
# Sprockets is able to track most file and directory changes and
|
36
|
+
# will take care of expiring the cache for you. However, its
|
37
|
+
# impossible to know when any custom helpers change that you mix
|
38
|
+
# into the `Context`.
|
39
|
+
#
|
40
|
+
# It would be wise to increment this value anytime you make a
|
41
|
+
# configuration change to the `Environment` object.
|
42
|
+
attr_reader :version
|
43
|
+
|
44
|
+
# Assign an environment version.
|
45
|
+
#
|
46
|
+
# environment.version = '2.0'
|
47
|
+
#
|
48
|
+
def version=(version)
|
49
|
+
expire_index!
|
50
|
+
@version = version
|
51
|
+
end
|
52
|
+
|
53
|
+
# Returns a `Digest` instance for the `Environment`.
|
54
|
+
#
|
55
|
+
# This value serves two purposes. If two `Environment`s have the
|
56
|
+
# same digest value they can be treated as equal. This is more
|
57
|
+
# useful for comparing environment states between processes rather
|
58
|
+
# than in the same. Two equal `Environment`s can share the same
|
59
|
+
# cached assets.
|
60
|
+
#
|
61
|
+
# The value also provides a seed digest for all `Asset`
|
62
|
+
# digests. Any change in the environment digest will affect all of
|
63
|
+
# its assets.
|
64
|
+
def digest
|
65
|
+
# Compute the initial digest using the implementation class. The
|
66
|
+
# Sprockets release version and custom environment version are
|
67
|
+
# mixed in. So any new releases will affect all your assets.
|
68
|
+
@digest ||= digest_class.new.update(VERSION).update(version.to_s)
|
69
|
+
|
70
|
+
# Returned a dupped copy so the caller can safely mutate it with `.update`
|
71
|
+
@digest.dup
|
72
|
+
end
|
73
|
+
|
17
74
|
# Get and set `Logger` instance.
|
18
75
|
attr_accessor :logger
|
19
76
|
|
@@ -63,14 +120,10 @@ module Sprockets
|
|
63
120
|
# Read and compute digest of filename.
|
64
121
|
#
|
65
122
|
# Subclasses may cache this method.
|
66
|
-
def file_digest(path
|
123
|
+
def file_digest(path)
|
67
124
|
if stat = self.stat(path)
|
68
|
-
# `data` maybe provided
|
69
|
-
if data
|
70
|
-
digest.update(data)
|
71
|
-
|
72
125
|
# If its a file, digest the contents
|
73
|
-
|
126
|
+
if stat.file?
|
74
127
|
digest.file(path.to_s)
|
75
128
|
|
76
129
|
# If its a directive, digest the list of filenames
|
@@ -93,13 +146,21 @@ module Sprockets
|
|
93
146
|
|
94
147
|
# Find asset by logical path or expanded path.
|
95
148
|
def find_asset(path, options = {})
|
96
|
-
|
149
|
+
logical_path = path
|
150
|
+
pathname = Pathname.new(path)
|
97
151
|
|
98
|
-
if pathname.
|
99
|
-
|
152
|
+
if pathname.to_s =~ /^\//
|
153
|
+
return unless stat(pathname)
|
154
|
+
logical_path = attributes_for(pathname).logical_path
|
100
155
|
else
|
101
|
-
|
156
|
+
begin
|
157
|
+
pathname = resolve(logical_path)
|
158
|
+
rescue FileNotFound
|
159
|
+
return nil
|
160
|
+
end
|
102
161
|
end
|
162
|
+
|
163
|
+
build_asset(logical_path, pathname, options)
|
103
164
|
end
|
104
165
|
|
105
166
|
# Preferred `find_asset` shorthand.
|
@@ -172,15 +233,35 @@ module Sprockets
|
|
172
233
|
def build_asset(logical_path, pathname, options)
|
173
234
|
pathname = Pathname.new(pathname)
|
174
235
|
|
175
|
-
return unless stat(pathname)
|
176
|
-
|
177
236
|
# If there are any processors to run on the pathname, use
|
178
237
|
# `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.
|
179
238
|
if attributes_for(pathname).processors.any?
|
180
|
-
|
239
|
+
if options[:bundle] == false
|
240
|
+
circular_call_protection(pathname.to_s) do
|
241
|
+
ProcessedAsset.new(index, logical_path, pathname)
|
242
|
+
end
|
243
|
+
else
|
244
|
+
BundledAsset.new(index, logical_path, pathname)
|
245
|
+
end
|
181
246
|
else
|
182
|
-
StaticAsset.new(
|
247
|
+
StaticAsset.new(index, logical_path, pathname)
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
def cache_key_for(path, options)
|
252
|
+
"#{path}:#{options[:bundle] ? '1' : '0'}"
|
253
|
+
end
|
254
|
+
|
255
|
+
def circular_call_protection(path)
|
256
|
+
reset = Thread.current[:sprockets_circular_calls].nil?
|
257
|
+
calls = Thread.current[:sprockets_circular_calls] ||= Set.new
|
258
|
+
if calls.include?(path)
|
259
|
+
raise CircularDependencyError, "#{path} has already been required"
|
183
260
|
end
|
261
|
+
calls << path
|
262
|
+
yield
|
263
|
+
ensure
|
264
|
+
Thread.current[:sprockets_circular_calls] = nil if reset
|
184
265
|
end
|
185
266
|
end
|
186
267
|
end
|