sprockets 2.2.3 → 2.12.5

Sign up to get free protection for your applications and to get access to all the features.
@@ -53,7 +53,7 @@ module Sprockets
53
53
  # # => 'application'
54
54
  #
55
55
  def logical_path
56
- @logical_path[/^([^.]+)/, 0]
56
+ @logical_path.chomp(File.extname(@logical_path))
57
57
  end
58
58
 
59
59
  # Returns content type of file
@@ -81,7 +81,11 @@ module Sprockets
81
81
  attributes = environment.attributes_for(pathname)
82
82
 
83
83
  if pathname.absolute?
84
- pathname
84
+ if environment.stat(pathname)
85
+ pathname
86
+ else
87
+ raise FileNotFound, "couldn't find file '#{pathname}'"
88
+ end
85
89
 
86
90
  elsif content_type = options[:content_type]
87
91
  content_type = self.content_type if content_type == :self
@@ -101,7 +105,7 @@ module Sprockets
101
105
 
102
106
  raise FileNotFound, "couldn't find file '#{path}'"
103
107
  else
104
- environment.resolve(path, :base_path => self.pathname.dirname, &block)
108
+ environment.resolve(path, {:base_path => self.pathname.dirname}.merge(options), &block)
105
109
  end
106
110
  end
107
111
 
@@ -217,6 +221,56 @@ module Sprockets
217
221
  "data:#{asset.content_type};base64,#{Rack::Utils.escape(base64)}"
218
222
  end
219
223
 
224
+ # Expands logical path to full url to asset.
225
+ #
226
+ # NOTE: This helper is currently not implemented and should be
227
+ # customized by the application. Though, in the future, some
228
+ # basics implemention may be provided with different methods that
229
+ # are required to be overridden.
230
+ def asset_path(path, options = {})
231
+ message = <<-EOS
232
+ Custom asset_path helper is not implemented
233
+
234
+ Extend your environment context with a custom method.
235
+
236
+ environment.context_class.class_eval do
237
+ def asset_path(path, options = {})
238
+ end
239
+ end
240
+ EOS
241
+ raise NotImplementedError, message
242
+ end
243
+
244
+ # Expand logical image asset path.
245
+ def image_path(path)
246
+ asset_path(path, :type => :image)
247
+ end
248
+
249
+ # Expand logical video asset path.
250
+ def video_path(path)
251
+ asset_path(path, :type => :video)
252
+ end
253
+
254
+ # Expand logical audio asset path.
255
+ def audio_path(path)
256
+ asset_path(path, :type => :audio)
257
+ end
258
+
259
+ # Expand logical font asset path.
260
+ def font_path(path)
261
+ asset_path(path, :type => :font)
262
+ end
263
+
264
+ # Expand logical javascript asset path.
265
+ def javascript_path(path)
266
+ asset_path(path, :type => :javascript)
267
+ end
268
+
269
+ # Expand logical stylesheet asset path.
270
+ def stylesheet_path(path)
271
+ asset_path(path, :type => :stylesheet)
272
+ end
273
+
220
274
  private
221
275
  # Annotates exception backtrace with the original template that
222
276
  # the exception was raised in.
@@ -65,7 +65,7 @@ module Sprockets
65
65
  # //= require "foo"
66
66
  #
67
67
  DIRECTIVE_PATTERN = /
68
- ^ [\W]* = \s* (\w+.*?) (\*\/)? $
68
+ ^ \W* = \s* (\w+.*?) (\*\/)? $
69
69
  /x
70
70
 
71
71
  attr_reader :pathname
@@ -92,6 +92,8 @@ module Sprockets
92
92
  @context = context
93
93
 
94
94
  @result = ""
95
+ @result.force_encoding(body.encoding) if body.respond_to?(:encoding)
96
+
95
97
  @has_written_body = false
96
98
 
97
99
  process_directives
@@ -28,12 +28,12 @@ module Sprockets
28
28
  # Sprockets.register_engine '.sass', SassTemplate
29
29
  #
30
30
  module Engines
31
- # Returns an `Array` of `Engine`s registered on the
32
- # `Environment`. If an `ext` argument is supplied, the `Engine`
33
- # register under that extension will be returned.
31
+ # Returns a `Hash` of `Engine`s registered on the `Environment`.
32
+ # If an `ext` argument is supplied, the `Engine` associated with
33
+ # that extension will be returned.
34
34
  #
35
35
  # environment.engines
36
- # # => [CoffeeScriptTemplate, SassTemplate, ...]
36
+ # # => {".coffee" => CoffeeScriptTemplate, ".sass" => SassTemplate, ...}
37
37
  #
38
38
  # environment.engines('.coffee')
39
39
  # # => CoffeeScriptTemplate
@@ -1,9 +1,6 @@
1
1
  require 'sprockets/base'
2
- require 'sprockets/charset_normalizer'
3
2
  require 'sprockets/context'
4
- require 'sprockets/directive_processor'
5
3
  require 'sprockets/index'
6
- require 'sprockets/safety_colons'
7
4
 
8
5
  require 'hike'
9
6
  require 'logger'
@@ -35,24 +32,24 @@ module Sprockets
35
32
  @digest_class = ::Digest::MD5
36
33
  @version = ''
37
34
 
38
- @mime_types = {}
35
+ @mime_types = Sprockets.registered_mime_types
39
36
  @engines = Sprockets.engines
40
- @preprocessors = Hash.new { |h, k| h[k] = [] }
41
- @postprocessors = Hash.new { |h, k| h[k] = [] }
42
- @bundle_processors = Hash.new { |h, k| h[k] = [] }
37
+ @preprocessors = Sprockets.preprocessors
38
+ @postprocessors = Sprockets.postprocessors
39
+ @bundle_processors = Sprockets.bundle_processors
40
+ @compressors = Sprockets.compressors
41
+
42
+ Sprockets.paths.each do |path|
43
+ append_path(path)
44
+ end
43
45
 
44
46
  @engines.each do |ext, klass|
45
47
  add_engine_to_trail(ext, klass)
46
48
  end
47
49
 
48
- register_mime_type 'text/css', '.css'
49
- register_mime_type 'application/javascript', '.js'
50
-
51
- register_preprocessor 'text/css', DirectiveProcessor
52
- register_preprocessor 'application/javascript', DirectiveProcessor
53
-
54
- register_postprocessor 'application/javascript', SafetyColons
55
- register_bundle_processor 'text/css', CharsetNormalizer
50
+ @mime_types.each do |ext, type|
51
+ @trail.append_extension(ext)
52
+ end
56
53
 
57
54
  expire_index!
58
55
 
@@ -7,6 +7,7 @@ module Sprockets
7
7
  class EncodingError < Error; end
8
8
  class FileNotFound < Error; end
9
9
  class FileOutsidePaths < Error; end
10
+ class NotImplementedError < Error; end
10
11
  class UnserializeError < Error; end
11
12
 
12
13
  module EngineError
@@ -31,6 +31,7 @@ module Sprockets
31
31
  @preprocessors = environment.preprocessors
32
32
  @postprocessors = environment.postprocessors
33
33
  @bundle_processors = environment.bundle_processors
34
+ @compressors = environment.compressors
34
35
 
35
36
  # Initialize caches
36
37
  @assets = {}
@@ -2,9 +2,7 @@ require 'tilt'
2
2
 
3
3
  module Sprockets
4
4
  class JstProcessor < Tilt::Template
5
- def self.default_mime_type
6
- 'application/javascript'
7
- end
5
+ self.default_mime_type = 'application/javascript'
8
6
 
9
7
  def self.default_namespace
10
8
  'this.JST'
@@ -18,9 +16,7 @@ module Sprockets
18
16
 
19
17
  def evaluate(scope, locals, &block)
20
18
  <<-JST
21
- (function() {
22
- #{namespace} || (#{namespace} = {});
23
- #{namespace}[#{scope.logical_path.inspect}] = #{indent(data)};
19
+ (function() { #{namespace} || (#{namespace} = {}); #{namespace}[#{scope.logical_path.inspect}] = #{indent(data)};
24
20
  }).call(this);
25
21
  JST
26
22
  end
@@ -1,4 +1,5 @@
1
1
  require 'multi_json'
2
+ require 'securerandom'
2
3
  require 'time'
3
4
 
4
5
  module Sprockets
@@ -18,26 +19,50 @@ module Sprockets
18
19
  # a full path to the manifest json file. The file may or may not
19
20
  # already exist. The dirname of the `path` will be used to write
20
21
  # compiled assets to. Otherwise, if the path is a directory, the
21
- # filename will default to "manifest.json" in that directory.
22
+ # filename will default a random "manifest-123.json" file in that
23
+ # directory.
22
24
  #
23
25
  # Manifest.new(environment, "./public/assets/manifest.json")
24
26
  #
25
- def initialize(environment, path)
26
- @environment = environment
27
+ def initialize(*args)
28
+ if args.first.is_a?(Base) || args.first.nil?
29
+ @environment = args.shift
30
+ end
27
31
 
28
- if File.extname(path) == ""
29
- @dir = File.expand_path(path)
30
- @path = File.join(@dir, 'manifest.json')
31
- else
32
- @path = File.expand_path(path)
33
- @dir = File.dirname(path)
32
+ @dir, @path = args[0], args[1]
33
+
34
+ # Expand paths
35
+ @dir = File.expand_path(@dir) if @dir
36
+ @path = File.expand_path(@path) if @path
37
+
38
+ # If path is given as the second arg
39
+ if @dir && File.extname(@dir) != ""
40
+ @dir, @path = nil, @dir
41
+ end
42
+
43
+ # Default dir to the directory of the path
44
+ @dir ||= File.dirname(@path) if @path
45
+
46
+ # If directory is given w/o path, pick a random manifest.json location
47
+ if @dir && @path.nil?
48
+ # Find the first manifest.json in the directory
49
+ paths = Dir[File.join(@dir, "manifest*.json")]
50
+ if paths.any?
51
+ @path = paths.first
52
+ else
53
+ @path = File.join(@dir, "manifest-#{SecureRandom.hex(16)}.json")
54
+ end
55
+ end
56
+
57
+ unless @dir && @path
58
+ raise ArgumentError, "manifest requires output path"
34
59
  end
35
60
 
36
61
  data = nil
37
62
 
38
63
  begin
39
64
  if File.exist?(@path)
40
- data = MultiJson.decode(File.read(@path))
65
+ data = json_decode(File.read(@path))
41
66
  end
42
67
  rescue MultiJson::DecodeError => e
43
68
  logger.error "#{@path} is invalid: #{e.class} #{e.message}"
@@ -83,14 +108,19 @@ module Sprockets
83
108
  # compile("application.js")
84
109
  #
85
110
  def compile(*args)
111
+ unless environment
112
+ raise Error, "manifest requires environment for compilation"
113
+ end
114
+
86
115
  paths = environment.each_logical_path(*args).to_a +
87
- args.flatten.select { |fn| Pathname.new(fn).absolute? }
116
+ args.flatten.select { |fn| Pathname.new(fn).absolute? if fn.is_a?(String)}
88
117
 
89
118
  paths.each do |path|
90
119
  if asset = find_asset(path)
91
120
  files[asset.digest_path] = {
92
121
  'logical_path' => asset.logical_path,
93
122
  'mtime' => asset.mtime.iso8601,
123
+ 'size' => asset.bytesize,
94
124
  'digest' => asset.digest
95
125
  }
96
126
  assets[asset.logical_path] = asset.digest_path
@@ -102,12 +132,13 @@ module Sprockets
102
132
  else
103
133
  logger.info "Writing #{target}"
104
134
  asset.write_to target
135
+ asset.write_to "#{target}.gz" if asset.is_a?(BundledAsset)
105
136
  end
106
137
 
107
- save
108
- asset
109
138
  end
110
139
  end
140
+ save
141
+ paths
111
142
  end
112
143
 
113
144
  # Removes file from directory and from manifest. `filename` must
@@ -117,6 +148,7 @@ module Sprockets
117
148
  #
118
149
  def remove(filename)
119
150
  path = File.join(dir, filename)
151
+ gzip = "#{path}.gz"
120
152
  logical_path = files[filename]['logical_path']
121
153
 
122
154
  if assets[logical_path] == filename
@@ -125,10 +157,11 @@ module Sprockets
125
157
 
126
158
  files.delete(filename)
127
159
  FileUtils.rm(path) if File.exist?(path)
160
+ FileUtils.rm(gzip) if File.exist?(gzip)
128
161
 
129
162
  save
130
163
 
131
- logger.warn "Removed #{filename}"
164
+ logger.info "Removed #{filename}"
132
165
 
133
166
  nil
134
167
  end
@@ -151,7 +184,7 @@ module Sprockets
151
184
  # Wipe directive
152
185
  def clobber
153
186
  FileUtils.rm_r(@dir) if File.exist?(@dir)
154
- logger.warn "Removed #{@dir}"
187
+ logger.info "Removed #{@dir}"
155
188
  nil
156
189
  end
157
190
 
@@ -177,21 +210,46 @@ module Sprockets
177
210
  ms = benchmark do
178
211
  asset = environment.find_asset(logical_path)
179
212
  end
180
- logger.warn "Compiled #{logical_path} (#{ms}ms)"
213
+ logger.debug "Compiled #{logical_path} (#{ms}ms)"
181
214
  asset
182
215
  end
183
216
 
184
217
  # Persist manfiest back to FS
185
218
  def save
186
- FileUtils.mkdir_p dir
219
+ FileUtils.mkdir_p File.dirname(path)
187
220
  File.open(path, 'w') do |f|
188
- f.write MultiJson.encode(@data)
221
+ f.write json_encode(@data)
189
222
  end
190
223
  end
191
224
 
192
225
  private
226
+ # Feature detect newer MultiJson API
227
+ if MultiJson.respond_to?(:dump)
228
+ def json_decode(obj)
229
+ MultiJson.load(obj)
230
+ end
231
+
232
+ def json_encode(obj)
233
+ MultiJson.dump(obj)
234
+ end
235
+ else
236
+ def json_decode(obj)
237
+ MultiJson.decode(obj)
238
+ end
239
+
240
+ def json_encode(obj)
241
+ MultiJson.encode(obj)
242
+ end
243
+ end
244
+
193
245
  def logger
194
- environment.logger
246
+ if environment
247
+ environment.logger
248
+ else
249
+ logger = Logger.new($stderr)
250
+ logger.level = Logger::FATAL
251
+ logger
252
+ end
195
253
  end
196
254
 
197
255
  def benchmark
@@ -15,6 +15,11 @@ module Sprockets
15
15
  end
16
16
  end
17
17
 
18
+ # Returns a `Hash` of explicitly registered mime types.
19
+ def registered_mime_types
20
+ @mime_types.dup
21
+ end
22
+
18
23
  if {}.respond_to?(:key)
19
24
  def extension_for_mime_type(type)
20
25
  mime_types.key(type)
@@ -41,8 +46,4 @@ module Sprockets
41
46
  end
42
47
  end
43
48
  end
44
-
45
- # Extend Sprockets module to provide global registry
46
- extend Mime
47
- @mime_types = {}
48
49
  end
@@ -1,16 +1,11 @@
1
- require 'sprockets/errors'
2
- require 'pathname'
3
-
4
1
  module Sprockets
5
- # `Trail` is an internal mixin whose public methods are exposed on
6
- # the `Environment` and `Index` classes.
7
- module Trail
2
+ module Paths
8
3
  # Returns `Environment` root.
9
4
  #
10
5
  # All relative paths are expanded with root as its base. To be
11
6
  # useful set this to your applications root directory. (`Rails.root`)
12
7
  def root
13
- trail.root.dup
8
+ @trail.root.dup
14
9
  end
15
10
 
16
11
  # Returns an `Array` of path `String`s.
@@ -21,14 +16,13 @@ module Sprockets
21
16
  # have no affect on the environment. See `append_path`,
22
17
  # `prepend_path`, and `clear_paths`.
23
18
  def paths
24
- trail.paths.dup
19
+ @trail.paths.dup
25
20
  end
26
21
 
27
22
  # Prepend a `path` to the `paths` list.
28
23
  #
29
24
  # Paths at the end of the `Array` have the least priority.
30
25
  def prepend_path(path)
31
- expire_index!
32
26
  @trail.prepend_path(path)
33
27
  end
34
28
 
@@ -36,7 +30,6 @@ module Sprockets
36
30
  #
37
31
  # Paths at the beginning of the `Array` have a higher priority.
38
32
  def append_path(path)
39
- expire_index!
40
33
  @trail.append_path(path)
41
34
  end
42
35
 
@@ -46,7 +39,6 @@ module Sprockets
46
39
  # completely wipe the paths list and reappend them in the order
47
40
  # you want.
48
41
  def clear_paths
49
- expire_index!
50
42
  @trail.paths.dup.each { |path| @trail.remove_path(path) }
51
43
  end
52
44
 
@@ -57,34 +49,10 @@ module Sprockets
57
49
  # # => [".js", ".css", ".coffee", ".sass", ...]
58
50
  #
59
51
  def extensions
60
- trail.extensions.dup
61
- end
62
-
63
- # Finds the expanded real path for a given logical path by
64
- # searching the environment's paths.
65
- #
66
- # resolve("application.js")
67
- # # => "/path/to/app/javascripts/application.js.coffee"
68
- #
69
- # A `FileNotFound` exception is raised if the file does not exist.
70
- def resolve(logical_path, options = {})
71
- # If a block is given, preform an iterable search
72
- if block_given?
73
- args = attributes_for(logical_path).search_paths + [options]
74
- trail.find(*args) do |path|
75
- yield Pathname.new(path)
76
- end
77
- else
78
- resolve(logical_path, options) do |pathname|
79
- return pathname
80
- end
81
- raise FileNotFound, "couldn't find file '#{logical_path}'"
82
- end
52
+ @trail.extensions.dup
83
53
  end
84
54
 
85
55
  protected
86
- def trail
87
- @trail
88
- end
56
+ attr_reader :trail
89
57
  end
90
58
  end