sprockets 2.12.5 → 3.0.0.beta.1

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.

Files changed (62) hide show
  1. checksums.yaml +5 -5
  2. data/LICENSE +2 -2
  3. data/README.md +61 -34
  4. data/lib/rake/sprocketstask.rb +5 -4
  5. data/lib/sprockets.rb +123 -85
  6. data/lib/sprockets/asset.rb +161 -200
  7. data/lib/sprockets/asset_uri.rb +64 -0
  8. data/lib/sprockets/base.rb +138 -373
  9. data/lib/sprockets/bower.rb +56 -0
  10. data/lib/sprockets/bundle.rb +32 -0
  11. data/lib/sprockets/cache.rb +220 -0
  12. data/lib/sprockets/cache/file_store.rb +145 -13
  13. data/lib/sprockets/cache/memory_store.rb +66 -0
  14. data/lib/sprockets/cache/null_store.rb +46 -0
  15. data/lib/sprockets/cached_environment.rb +103 -0
  16. data/lib/sprockets/closure_compressor.rb +30 -12
  17. data/lib/sprockets/coffee_script_template.rb +23 -0
  18. data/lib/sprockets/compressing.rb +20 -25
  19. data/lib/sprockets/configuration.rb +95 -0
  20. data/lib/sprockets/context.rb +68 -131
  21. data/lib/sprockets/directive_processor.rb +138 -179
  22. data/lib/sprockets/eco_template.rb +10 -19
  23. data/lib/sprockets/ejs_template.rb +10 -19
  24. data/lib/sprockets/encoding_utils.rb +246 -0
  25. data/lib/sprockets/engines.rb +40 -29
  26. data/lib/sprockets/environment.rb +10 -66
  27. data/lib/sprockets/erb_template.rb +23 -0
  28. data/lib/sprockets/errors.rb +5 -13
  29. data/lib/sprockets/http_utils.rb +97 -0
  30. data/lib/sprockets/jst_processor.rb +28 -15
  31. data/lib/sprockets/lazy_processor.rb +15 -0
  32. data/lib/sprockets/legacy.rb +23 -0
  33. data/lib/sprockets/legacy_proc_processor.rb +35 -0
  34. data/lib/sprockets/legacy_tilt_processor.rb +29 -0
  35. data/lib/sprockets/manifest.rb +128 -99
  36. data/lib/sprockets/mime.rb +114 -33
  37. data/lib/sprockets/path_utils.rb +179 -0
  38. data/lib/sprockets/paths.rb +13 -26
  39. data/lib/sprockets/processing.rb +198 -107
  40. data/lib/sprockets/resolve.rb +289 -0
  41. data/lib/sprockets/sass_compressor.rb +36 -17
  42. data/lib/sprockets/sass_template.rb +269 -46
  43. data/lib/sprockets/server.rb +113 -83
  44. data/lib/sprockets/transformers.rb +69 -0
  45. data/lib/sprockets/uglifier_compressor.rb +36 -15
  46. data/lib/sprockets/utils.rb +161 -44
  47. data/lib/sprockets/version.rb +1 -1
  48. data/lib/sprockets/yui_compressor.rb +37 -12
  49. metadata +64 -106
  50. data/lib/sprockets/asset_attributes.rb +0 -137
  51. data/lib/sprockets/bundled_asset.rb +0 -78
  52. data/lib/sprockets/caching.rb +0 -96
  53. data/lib/sprockets/charset_normalizer.rb +0 -41
  54. data/lib/sprockets/index.rb +0 -100
  55. data/lib/sprockets/processed_asset.rb +0 -152
  56. data/lib/sprockets/processor.rb +0 -32
  57. data/lib/sprockets/safety_colons.rb +0 -28
  58. data/lib/sprockets/sass_cache_store.rb +0 -29
  59. data/lib/sprockets/sass_functions.rb +0 -70
  60. data/lib/sprockets/sass_importer.rb +0 -30
  61. data/lib/sprockets/scss_template.rb +0 -13
  62. data/lib/sprockets/static_asset.rb +0 -60
@@ -1,15 +1,13 @@
1
- require 'base64'
2
- require 'rack/utils'
3
- require 'sprockets/errors'
4
- require 'sprockets/utils'
5
1
  require 'pathname'
2
+ require 'rack/utils'
6
3
  require 'set'
4
+ require 'sprockets/errors'
7
5
 
8
6
  module Sprockets
9
- # `Context` provides helper methods to all `Tilt` processors. They
10
- # are typically accessed by ERB templates. You can mix in custom
11
- # helpers by injecting them into `Environment#context_class`. Do not
12
- # mix them into `Context` directly.
7
+ # Deprecated: `Context` provides helper methods to all `Template` processors.
8
+ # They are typically accessed by ERB templates. You can mix in custom helpers
9
+ # by injecting them into `Environment#context_class`. Do not mix them into
10
+ # `Context` directly.
13
11
  #
14
12
  # environment.context_class.class_eval do
15
13
  # include MyHelper
@@ -21,49 +19,52 @@ module Sprockets
21
19
  # The `Context` also collects dependencies declared by
22
20
  # assets. See `DirectiveProcessor` for an example of this.
23
21
  class Context
24
- attr_reader :environment, :pathname
25
- attr_reader :_required_paths, :_stubbed_assets
26
- attr_reader :_dependency_paths, :_dependency_assets
27
- attr_writer :__LINE__
22
+ attr_reader :environment, :filename, :pathname
28
23
 
29
- def initialize(environment, logical_path, pathname)
30
- @environment = environment
31
- @logical_path = logical_path
32
- @pathname = pathname
33
- @__LINE__ = nil
24
+ def initialize(input)
25
+ @environment = input[:environment]
26
+ @metadata = input[:metadata]
27
+ @load_path = input[:load_path]
28
+ @logical_path = input[:name]
29
+ @filename = input[:filename]
30
+ @dirname = File.dirname(@filename)
31
+ @pathname = Pathname.new(@filename)
32
+ @content_type = input[:content_type]
34
33
 
35
- @_required_paths = []
36
- @_stubbed_assets = Set.new
37
- @_dependency_paths = Set.new
38
- @_dependency_assets = Set.new([pathname.to_s])
34
+ @required = Set.new(@metadata[:required])
35
+ @stubbed = Set.new(@metadata[:stubbed])
36
+ @links = Set.new(@metadata[:links])
37
+ @dependency_paths = Set.new(@metadata[:dependency_paths])
38
+ end
39
+
40
+ def metadata
41
+ { required: @required,
42
+ stubbed: @stubbed,
43
+ links: @links,
44
+ dependency_paths: @dependency_paths }
39
45
  end
40
46
 
41
47
  # Returns the environment path that contains the file.
42
48
  #
43
49
  # If `app/javascripts` and `app/stylesheets` are in your path, and
44
- # current file is `app/javascripts/foo/bar.js`, `root_path` would
50
+ # current file is `app/javascripts/foo/bar.js`, `load_path` would
45
51
  # return `app/javascripts`.
46
- def root_path
47
- environment.paths.detect { |path| pathname.to_s[path] }
48
- end
52
+ attr_reader :load_path
53
+ alias_method :root_path, :load_path
49
54
 
50
55
  # Returns logical path without any file extensions.
51
56
  #
52
57
  # 'app/javascripts/application.js'
53
58
  # # => 'application'
54
59
  #
55
- def logical_path
56
- @logical_path.chomp(File.extname(@logical_path))
57
- end
60
+ attr_reader :logical_path
58
61
 
59
62
  # Returns content type of file
60
63
  #
61
64
  # 'application/javascript'
62
65
  # 'text/css'
63
66
  #
64
- def content_type
65
- environment.content_type_of(pathname)
66
- end
67
+ attr_reader :content_type
67
68
 
68
69
  # Given a logical path, `resolve` will find and return the fully
69
70
  # expanded path. Relative paths will also be resolved. An optional
@@ -76,36 +77,21 @@ module Sprockets
76
77
  # resolve("./bar.js")
77
78
  # # => "/path/to/app/javascripts/bar.js"
78
79
  #
79
- def resolve(path, options = {}, &block)
80
- pathname = Pathname.new(path)
81
- attributes = environment.attributes_for(pathname)
80
+ def resolve(path, options = {})
81
+ options[:content_type] = self.content_type if options[:content_type] == :self
82
+ options[:accept] = options.delete(:content_type)
82
83
 
83
- if pathname.absolute?
84
- if environment.stat(pathname)
85
- pathname
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)
86
90
  else
87
- raise FileNotFound, "couldn't find file '#{pathname}'"
91
+ raise FileOutsidePaths, "#{path} isn't under path: #{load_path}"
88
92
  end
89
-
90
- elsif content_type = options[:content_type]
91
- content_type = self.content_type if content_type == :self
92
-
93
- if attributes.format_extension
94
- if content_type != attributes.content_type
95
- raise ContentTypeMismatch, "#{path} is " +
96
- "'#{attributes.content_type}', not '#{content_type}'"
97
- end
98
- end
99
-
100
- resolve(path) do |candidate|
101
- if self.content_type == environment.content_type_of(candidate)
102
- return candidate
103
- end
104
- end
105
-
106
- raise FileNotFound, "couldn't find file '#{path}'"
107
93
  else
108
- environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
94
+ environment.resolve(path, options)
109
95
  end
110
96
  end
111
97
 
@@ -116,7 +102,7 @@ module Sprockets
116
102
  # the dependency file with invalidate the cache of the
117
103
  # source file.
118
104
  def depend_on(path)
119
- @_dependency_paths << resolve(path).to_s
105
+ @dependency_paths << resolve(path).to_s
120
106
  nil
121
107
  end
122
108
 
@@ -128,8 +114,9 @@ module Sprockets
128
114
  # file. Unlike `depend_on`, this will include recursively include
129
115
  # the target asset's dependencies.
130
116
  def depend_on_asset(path)
131
- filename = resolve(path).to_s
132
- @_dependency_assets << filename
117
+ if asset = @environment.find_asset(resolve(path))
118
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
119
+ end
133
120
  nil
134
121
  end
135
122
 
@@ -143,9 +130,8 @@ module Sprockets
143
130
  # <%= require_asset "#{framework}.js" %>
144
131
  #
145
132
  def require_asset(path)
146
- pathname = resolve(path, :content_type => :self)
147
- depend_on_asset(pathname)
148
- @_required_paths << pathname.to_s
133
+ filename = resolve(path, accept: @content_type)
134
+ @required << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
149
135
  nil
150
136
  end
151
137
 
@@ -153,55 +139,22 @@ module Sprockets
153
139
  # `path` must be an asset which may or may not already be included
154
140
  # in the bundle.
155
141
  def stub_asset(path)
156
- @_stubbed_assets << resolve(path, :content_type => :self).to_s
142
+ filename = resolve(path, accept: @content_type)
143
+ @stubbed << @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
157
144
  nil
158
145
  end
159
146
 
160
- # Tests if target path is able to be safely required into the
161
- # current concatenation.
162
- def asset_requirable?(path)
163
- pathname = resolve(path)
164
- content_type = environment.content_type_of(pathname)
165
- stat = environment.stat(path)
166
- return false unless stat && stat.file?
167
- self.content_type.nil? || self.content_type == content_type
168
- end
169
-
170
- # Reads `path` and runs processors on the file.
171
- #
172
- # This allows you to capture the result of an asset and include it
173
- # directly in another.
147
+ # `link_asset` declares an external dependency on an asset without directly
148
+ # including it. The target asset is returned from this function making it
149
+ # easy to construct a link to it.
174
150
  #
175
- # <%= evaluate "bar.js" %>
176
- #
177
- def evaluate(path, options = {})
178
- pathname = resolve(path)
179
- attributes = environment.attributes_for(pathname)
180
- processors = options[:processors] || attributes.processors
181
-
182
- if options[:data]
183
- result = options[:data]
184
- else
185
- if environment.respond_to?(:default_external_encoding)
186
- mime_type = environment.mime_types(pathname.extname)
187
- encoding = environment.encoding_for_mime_type(mime_type)
188
- result = Sprockets::Utils.read_unicode(pathname, encoding)
189
- else
190
- result = Sprockets::Utils.read_unicode(pathname)
191
- end
192
- end
193
-
194
- processors.each do |processor|
195
- begin
196
- template = processor.new(pathname.to_s) { result }
197
- result = template.render(self, {})
198
- rescue Exception => e
199
- annotate_exception! e
200
- raise
201
- end
151
+ # Returns an Asset or nil.
152
+ def link_asset(path)
153
+ if asset = @environment.find_asset(resolve(path))
154
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
155
+ @links << asset.uri
202
156
  end
203
-
204
- result
157
+ asset
205
158
  end
206
159
 
207
160
  # Returns a Base64-encoded `data:` URI with the contents of the
@@ -216,9 +169,8 @@ module Sprockets
216
169
  #
217
170
  def asset_data_uri(path)
218
171
  depend_on_asset(path)
219
- asset = environment.find_asset(path)
220
- base64 = Base64.encode64(asset.to_s).gsub(/\s+/, "")
221
- "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
172
+ asset = environment.find_asset(path, accept_encoding: 'base64')
173
+ "data:#{asset.content_type};base64,#{Rack::Utils.escape(asset.to_s)}"
222
174
  end
223
175
 
224
176
  # Expands logical path to full url to asset.
@@ -243,47 +195,32 @@ Extend your environment context with a custom method.
243
195
 
244
196
  # Expand logical image asset path.
245
197
  def image_path(path)
246
- asset_path(path, :type => :image)
198
+ asset_path(path, type: :image)
247
199
  end
248
200
 
249
201
  # Expand logical video asset path.
250
202
  def video_path(path)
251
- asset_path(path, :type => :video)
203
+ asset_path(path, type: :video)
252
204
  end
253
205
 
254
206
  # Expand logical audio asset path.
255
207
  def audio_path(path)
256
- asset_path(path, :type => :audio)
208
+ asset_path(path, type: :audio)
257
209
  end
258
210
 
259
211
  # Expand logical font asset path.
260
212
  def font_path(path)
261
- asset_path(path, :type => :font)
213
+ asset_path(path, type: :font)
262
214
  end
263
215
 
264
216
  # Expand logical javascript asset path.
265
217
  def javascript_path(path)
266
- asset_path(path, :type => :javascript)
218
+ asset_path(path, type: :javascript)
267
219
  end
268
220
 
269
221
  # Expand logical stylesheet asset path.
270
222
  def stylesheet_path(path)
271
- asset_path(path, :type => :stylesheet)
223
+ asset_path(path, type: :stylesheet)
272
224
  end
273
-
274
- private
275
- # Annotates exception backtrace with the original template that
276
- # the exception was raised in.
277
- def annotate_exception!(exception)
278
- location = pathname.to_s
279
- location << ":#{@__LINE__}" if @__LINE__
280
-
281
- exception.extend(Sprockets::EngineError)
282
- exception.sprockets_annotation = " (in #{location})"
283
- end
284
-
285
- def logger
286
- environment.logger
287
- end
288
225
  end
289
226
  end
@@ -1,7 +1,5 @@
1
- require 'pathname'
1
+ require 'set'
2
2
  require 'shellwords'
3
- require 'tilt'
4
- require 'yaml'
5
3
 
6
4
  module Sprockets
7
5
  # The `DirectiveProcessor` is responsible for parsing and evaluating
@@ -20,10 +18,9 @@ module Sprockets
20
18
  # *= require "baz"
21
19
  # */
22
20
  #
23
- # The Processor is implemented as a `Tilt::Template` and is loosely
24
- # coupled to Sprockets. This makes it possible to disable or modify
25
- # the processor to do whatever you'd like. You could add your own
26
- # custom directives or invent your own directive syntax.
21
+ # This makes it possible to disable or modify the processor to do whatever
22
+ # you'd like. You could add your own custom directives or invent your own
23
+ # directive syntax.
27
24
  #
28
25
  # `Environment#processors` includes `DirectiveProcessor` by default.
29
26
  #
@@ -36,7 +33,9 @@ module Sprockets
36
33
  #
37
34
  # env.register_processor('text/css', MyProcessor)
38
35
  #
39
- class DirectiveProcessor < Tilt::Template
36
+ class DirectiveProcessor
37
+ VERSION = '1'
38
+
40
39
  # Directives will only be picked up if they are in the header
41
40
  # of the source file. C style (/* */), JavaScript (//), and
42
41
  # Ruby (#) comments are supported.
@@ -68,76 +67,82 @@ module Sprockets
68
67
  ^ \W* = \s* (\w+.*?) (\*\/)? $
69
68
  /x
70
69
 
71
- attr_reader :pathname
72
- attr_reader :header, :body
70
+ def self.call(input)
71
+ new.call(input)
72
+ end
73
73
 
74
- def prepare
75
- @pathname = Pathname.new(file)
74
+ def call(input)
75
+ @environment = input[:environment]
76
+ @uri = input[:uri]
77
+ @load_path = input[:load_path]
78
+ @filename = input[:filename]
79
+ @dirname = File.dirname(@filename)
80
+ @content_type = input[:content_type]
81
+
82
+ data = input[:data]
83
+ cache_key = ['DirectiveProcessor', VERSION, data]
84
+ result = input[:cache].fetch(cache_key) do
85
+ process_source(data)
86
+ end
76
87
 
77
- @header = data[HEADER_PATTERN, 0] || ""
78
- @body = $' || data
79
- # Ensure body ends in a new line
80
- @body += "\n" if @body != "" && @body !~ /\n\Z/m
88
+ data, directives = result.values_at(:data, :directives)
81
89
 
82
- @included_pathnames = []
83
- @compat = false
84
- end
90
+ @required = Set.new(input[:metadata][:required])
91
+ @stubbed = Set.new(input[:metadata][:stubbed])
92
+ @links = Set.new(input[:metadata][:links])
93
+ @dependency_paths = Set.new(input[:metadata][:dependency_paths])
85
94
 
86
- # Implemented for Tilt#render.
87
- #
88
- # `context` is a `Context` instance with methods that allow you to
89
- # access the environment and append to the bundle. See `Context`
90
- # for the complete API.
91
- def evaluate(context, locals, &block)
92
- @context = context
95
+ process_directives(directives)
93
96
 
94
- @result = ""
95
- @result.force_encoding(body.encoding) if body.respond_to?(:encoding)
97
+ { data: data,
98
+ required: @required,
99
+ stubbed: @stubbed,
100
+ links: @links,
101
+ dependency_paths: @dependency_paths }
102
+ end
96
103
 
97
- @has_written_body = false
104
+ protected
105
+ def process_source(source)
106
+ header = source[HEADER_PATTERN, 0] || ""
107
+ body = $' || source
98
108
 
99
- process_directives
100
- process_source
109
+ header, directives = extract_directives(header)
101
110
 
102
- @result
103
- end
111
+ data = ""
112
+ data.force_encoding(body.encoding)
113
+ data << header << "\n" unless header.empty?
114
+ data << body
115
+ # Ensure body ends in a new line
116
+ data << "\n" if data.length > 0 && data[-1] != "\n"
104
117
 
105
- # Returns the header String with any directives stripped.
106
- def processed_header
107
- lineno = 0
108
- @processed_header ||= header.lines.map { |line|
109
- lineno += 1
110
- # Replace directive line with a clean break
111
- directives.assoc(lineno) ? "\n" : line
112
- }.join.chomp
113
- end
118
+ { data: data, directives: directives }
119
+ end
114
120
 
115
- # Returns the source String with any directives stripped.
116
- def processed_source
117
- @processed_source ||= processed_header + body
118
- end
121
+ # Returns an Array of directive structures. Each structure
122
+ # is an Array with the line number as the first element, the
123
+ # directive name as the second element, followed by any
124
+ # arguments.
125
+ #
126
+ # [[1, "require", "foo"], [2, "require", "bar"]]
127
+ #
128
+ def extract_directives(header)
129
+ processed_header = ""
130
+ directives = []
119
131
 
120
- # Returns an Array of directive structures. Each structure
121
- # is an Array with the line number as the first element, the
122
- # directive name as the second element, followed by any
123
- # arguments.
124
- #
125
- # [[1, "require", "foo"], [2, "require", "bar"]]
126
- #
127
- def directives
128
- @directives ||= header.lines.each_with_index.map { |line, index|
129
- if directive = line[DIRECTIVE_PATTERN, 1]
130
- name, *args = Shellwords.shellwords(directive)
131
- if respond_to?("process_#{name}_directive", true)
132
- [index + 1, name, *args]
132
+ header.lines.each_with_index do |line, index|
133
+ if directive = line[DIRECTIVE_PATTERN, 1]
134
+ name, *args = Shellwords.shellwords(directive)
135
+ if respond_to?("process_#{name}_directive", true)
136
+ directives << [index + 1, name, *args]
137
+ # Replace directive line with a clean break
138
+ line = "\n"
139
+ end
133
140
  end
141
+ processed_header << line
134
142
  end
135
- }.compact
136
- end
137
143
 
138
- protected
139
- attr_reader :included_pathnames
140
- attr_reader :context
144
+ return processed_header.chomp, directives
145
+ end
141
146
 
142
147
  # Gathers comment directives in the source and processes them.
143
148
  # Any directive method matching `process_*_directive` will
@@ -150,7 +155,7 @@ module Sprockets
150
155
  #
151
156
  # class DirectiveProcessor < Sprockets::DirectiveProcessor
152
157
  # def process_require_glob_directive
153
- # Dir["#{pathname.dirname}/#{glob}"].sort.each do |filename|
158
+ # Dir["#{dirname}/#{glob}"].sort.each do |filename|
154
159
  # require(filename)
155
160
  # end
156
161
  # end
@@ -161,29 +166,14 @@ module Sprockets
161
166
  # env.unregister_processor('text/css', Sprockets::DirectiveProcessor)
162
167
  # env.register_processor('text/css', DirectiveProcessor)
163
168
  #
164
- def process_directives
169
+ def process_directives(directives)
165
170
  directives.each do |line_number, name, *args|
166
- context.__LINE__ = line_number
167
- send("process_#{name}_directive", *args)
168
- context.__LINE__ = nil
169
- end
170
- end
171
-
172
- def process_source
173
- unless @has_written_body || processed_header.empty?
174
- @result << processed_header << "\n"
175
- end
176
-
177
- included_pathnames.each do |pathname|
178
- @result << context.evaluate(pathname)
179
- end
180
-
181
- unless @has_written_body
182
- @result << body
183
- end
184
-
185
- if compat? && constants.any?
186
- @result.gsub!(/<%=(.*?)%>/) { constants[$1.strip] }
171
+ begin
172
+ send("process_#{name}_directive", *args)
173
+ rescue Exception => e
174
+ e.set_backtrace(["#{@filename}:#{line_number}"] + e.backtrace)
175
+ raise e
176
+ end
187
177
  end
188
178
  end
189
179
 
@@ -206,22 +196,13 @@ module Sprockets
206
196
  # //= require "./bar"
207
197
  #
208
198
  def process_require_directive(path)
209
- if @compat
210
- if path =~ /<([^>]+)>/
211
- path = $1
212
- else
213
- path = "./#{path}" unless relative?(path)
214
- end
215
- end
216
-
217
- context.require_asset(path)
199
+ @required << resolve_uri(path)
218
200
  end
219
201
 
220
- # `require_self` causes the body of the current file to be
221
- # inserted before any subsequent `require` or `include`
222
- # directives. Useful in CSS files, where it's common for the
223
- # index file to contain global styles that need to be defined
224
- # before other dependencies are loaded.
202
+ # `require_self` causes the body of the current file to be inserted
203
+ # before any subsequent `require` directives. Useful in CSS files, where
204
+ # it's common for the index file to contain global styles that need to
205
+ # be defined before other dependencies are loaded.
225
206
  #
226
207
  # /*= require "reset"
227
208
  # *= require_self
@@ -229,26 +210,10 @@ module Sprockets
229
210
  # */
230
211
  #
231
212
  def process_require_self_directive
232
- if @has_written_body
213
+ if @required.include?(@uri)
233
214
  raise ArgumentError, "require_self can only be called once per source file"
234
215
  end
235
-
236
- context.require_asset(pathname)
237
- process_source
238
- included_pathnames.clear
239
- @has_written_body = true
240
- end
241
-
242
- # The `include` directive works similar to `require` but
243
- # inserts the contents of the dependency even if it already
244
- # has been required.
245
- #
246
- # //= include "header"
247
- #
248
- def process_include_directive(path)
249
- pathname = context.resolve(path)
250
- context.depend_on_asset(pathname)
251
- included_pathnames << pathname
216
+ @required << @uri
252
217
  end
253
218
 
254
219
  # `require_directory` requires all the files inside a single
@@ -258,21 +223,20 @@ module Sprockets
258
223
  # //= require_directory "./javascripts"
259
224
  #
260
225
  def process_require_directory_directive(path = ".")
261
- if relative?(path)
262
- root = pathname.dirname.join(path).expand_path
226
+ if @environment.relative_path?(path)
227
+ root = expand_relative_path(path)
263
228
 
264
- unless (stats = stat(root)) && stats.directory?
229
+ unless (stats = @environment.stat(root)) && stats.directory?
265
230
  raise ArgumentError, "require_directory argument must be a directory"
266
231
  end
267
232
 
268
- context.depend_on(root)
233
+ @dependency_paths << root
269
234
 
270
- entries(root).each do |pathname|
271
- pathname = root.join(pathname)
272
- if pathname.to_s == self.file
235
+ @environment.stat_directory(root).each do |subpath, stat|
236
+ if subpath == @filename
273
237
  next
274
- elsif context.asset_requirable?(pathname)
275
- context.require_asset(pathname)
238
+ elsif @environment.resolve_path_transform_type(subpath, @content_type)
239
+ @required << @environment.resolve_asset_uri(subpath, accept: @content_type, bundle: false)
276
240
  end
277
241
  end
278
242
  else
@@ -287,24 +251,28 @@ module Sprockets
287
251
  # //= require_tree "./public"
288
252
  #
289
253
  def process_require_tree_directive(path = ".")
290
- if relative?(path)
291
- root = pathname.dirname.join(path).expand_path
254
+ if @environment.relative_path?(path)
255
+ root = expand_relative_path(path)
292
256
 
293
- unless (stats = stat(root)) && stats.directory?
257
+ unless (stats = @environment.stat(root)) && stats.directory?
294
258
  raise ArgumentError, "require_tree argument must be a directory"
295
259
  end
296
260
 
297
- context.depend_on(root)
261
+ @dependency_paths << root
298
262
 
299
- each_entry(root) do |pathname|
300
- if pathname.to_s == self.file
263
+ required = []
264
+ @environment.stat_tree(root).each do |subpath, stat|
265
+ if subpath == @filename
301
266
  next
302
- elsif stat(pathname).directory?
303
- context.depend_on(pathname)
304
- elsif context.asset_requirable?(pathname)
305
- context.require_asset(pathname)
267
+ elsif stat.directory?
268
+ @dependency_paths << subpath
269
+ elsif @environment.resolve_path_transform_type(subpath, @content_type)
270
+ required << subpath
306
271
  end
307
272
  end
273
+ required.sort_by(&:to_s).each do |subpath|
274
+ @required << @environment.resolve_asset_uri(subpath, accept: @content_type, bundle: false)
275
+ end
308
276
  else
309
277
  # The path must be relative and start with a `./`.
310
278
  raise ArgumentError, "require_tree argument must be a relative path"
@@ -324,7 +292,7 @@ module Sprockets
324
292
  # //= depend_on "foo.png"
325
293
  #
326
294
  def process_depend_on_directive(path)
327
- context.depend_on(path)
295
+ @dependency_paths << resolve(path, accept: "#{@content_type}, */*")
328
296
  end
329
297
 
330
298
  # Allows you to state a dependency on an asset without including
@@ -339,7 +307,9 @@ module Sprockets
339
307
  # //= depend_on_asset "bar.js"
340
308
  #
341
309
  def process_depend_on_asset_directive(path)
342
- context.depend_on_asset(path)
310
+ if asset = @environment.find_asset(resolve(path, accept: "#{@content_type}, */*"))
311
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
312
+ end
343
313
  end
344
314
 
345
315
  # Allows dependency to be excluded from the asset bundle.
@@ -351,58 +321,47 @@ module Sprockets
351
321
  # //= stub "jquery"
352
322
  #
353
323
  def process_stub_directive(path)
354
- context.stub_asset(path)
324
+ @stubbed << resolve_uri(path)
355
325
  end
356
326
 
357
- # Enable Sprockets 1.x compat mode.
327
+ # Declares a linked dependency on the target asset.
358
328
  #
359
- # Makes it possible to use the same JavaScript source
360
- # file in both Sprockets 1 and 2.
329
+ # The `path` must be a valid asset and should not already be part of the
330
+ # bundle. Any linked assets will automatically be compiled along with the
331
+ # current.
361
332
  #
362
- # //= compat
333
+ # /*= link "logo.png" */
363
334
  #
364
- def process_compat_directive
365
- @compat = true
366
- end
367
-
368
- # Checks if Sprockets 1.x compat mode enabled
369
- def compat?
370
- @compat
371
- end
372
-
373
- # Sprockets 1.x allowed for constant interpolation if a
374
- # constants.yml was present. This is only available if
375
- # compat mode is on.
376
- def constants
377
- if compat?
378
- pathname = Pathname.new(context.root_path).join("constants.yml")
379
- stat(pathname) ? YAML.load_file(pathname) : {}
380
- else
381
- {}
335
+ def process_link_directive(path)
336
+ if asset = @environment.find_asset(resolve(path, accept: "#{@content_type}, */*"))
337
+ @dependency_paths.merge(asset.metadata[:dependency_paths])
338
+ @links << asset.uri
382
339
  end
383
340
  end
384
341
 
385
- # `provide` is stubbed out for Sprockets 1.x compat.
386
- # Mutating the path when an asset is being built is
387
- # not permitted.
388
- def process_provide_directive(path)
389
- end
390
-
391
342
  private
392
- def relative?(path)
393
- path =~ /^\.($|\.?\/)/
343
+ def expand_relative_path(path)
344
+ File.expand_path(path, @dirname)
394
345
  end
395
346
 
396
- def stat(path)
397
- context.environment.stat(path)
347
+ def resolve_uri(path)
348
+ filename = resolve(path, accept: @content_type)
349
+ @environment.resolve_asset_uri(filename, accept: @content_type, bundle: false)
398
350
  end
399
351
 
400
- def entries(path)
401
- context.environment.entries(path)
402
- end
403
-
404
- def each_entry(root, &block)
405
- context.environment.each_entry(root, &block)
352
+ def resolve(path, options = {})
353
+ if @environment.absolute_path?(path)
354
+ raise FileOutsidePaths, "can't require absolute file: #{path}"
355
+ elsif @environment.relative_path?(path)
356
+ path = expand_relative_path(path)
357
+ if logical_path = @environment.split_subpath(@load_path, path)
358
+ @environment.resolve_in_load_path(@load_path, logical_path, options)
359
+ else
360
+ raise FileOutsidePaths, "#{path} isn't under path: #{@load_path}"
361
+ end
362
+ else
363
+ @environment.resolve(path, options)
364
+ end
406
365
  end
407
366
  end
408
367
  end