sprockets 2.2.3 → 2.12.5

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.
@@ -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