Class: Sprockets::Base

Inherits:
Object
  • Object
show all
Includes:
Caching, Compressing, Engines, Mime, Paths, Processing, Server
Defined in:
lib/sprockets/base.rb

Overview

`Base` class for `Environment` and `Index`.

Direct Known Subclasses

Environment, Index

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Caching

#cache_get, #cache_set

Methods included from Paths

#extensions, #paths, #root

Methods included from Mime

#encoding_for_mime_type, #extension_for_mime_type, #mime_types, #registered_mime_types

Methods included from Processing

#bundle_processors, #format_extensions, #postprocessors, #preprocessors, #processors, #register_processor, #unregister_processor

Methods included from Compressing

#compressors, #css_compressor, #css_compressor=, #js_compressor, #js_compressor=, #register_compressor

Methods included from Engines

#engine_extensions, #engines

Methods included from Server

#call

Instance Attribute Details

#cacheObject

Get persistent cache store


89
90
91
# File 'lib/sprockets/base.rb', line 89

def cache
  @cache
end

#context_classObject (readonly)

Get `Context` class.

This class maybe mutated and mixed in with custom helpers.

environment.context_class.instance_eval do
  include MyHelpers
  def asset_url; end
end

86
87
88
# File 'lib/sprockets/base.rb', line 86

def context_class
  @context_class
end

#default_external_encodingObject

Define `default_external_encoding` accessor on 1.9. Defaults to UTF-8.


217
218
219
# File 'lib/sprockets/base.rb', line 217

def default_external_encoding
  @default_external_encoding
end

#digest_classObject

Returns a `Digest` implementation class.

Defaults to `Digest::MD5`.


19
20
21
# File 'lib/sprockets/base.rb', line 19

def digest_class
  @digest_class
end

#loggerObject

Get and set `Logger` instance.


75
76
77
# File 'lib/sprockets/base.rb', line 75

def logger
  @logger
end

#versionObject

The `Environment#version` is a custom value used for manually expiring all asset caches.

Sprockets is able to track most file and directory changes and will take care of expiring the cache for you. However, its impossible to know when any custom helpers change that you mix into the `Context`.

It would be wise to increment this value anytime you make a configuration change to the `Environment` object.


42
43
44
# File 'lib/sprockets/base.rb', line 42

def version
  @version
end

Instance Method Details

#[](*args) ⇒ Object

Preferred `find_asset` shorthand.

environment['application.js']

294
295
296
# File 'lib/sprockets/base.rb', line 294

def [](*args)
  find_asset(*args)
end

#append_path(path) ⇒ Object


107
108
109
110
111
# File 'lib/sprockets/base.rb', line 107

def append_path(path)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#attributes_for(path) ⇒ Object

Internal. Return a `AssetAttributes` for `path`.


252
253
254
# File 'lib/sprockets/base.rb', line 252

def attributes_for(path)
  AssetAttributes.new(self, path)
end

#clear_pathsObject


113
114
115
116
117
# File 'lib/sprockets/base.rb', line 113

def clear_paths
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#content_type_of(path) ⇒ Object

Internal. Return content type of `path`.


257
258
259
# File 'lib/sprockets/base.rb', line 257

def content_type_of(path)
  attributes_for(path).content_type
end

#digestObject

Returns a `Digest` instance for the `Environment`.

This value serves two purposes. If two `Environment`s have the same digest value they can be treated as equal. This is more useful for comparing environment states between processes rather than in the same. Two equal `Environment`s can share the same cached assets.

The value also provides a seed digest for all `Asset` digests. Any change in the environment digest will affect all of its assets.


64
65
66
67
68
69
70
71
72
# File 'lib/sprockets/base.rb', line 64

def digest
  # Compute the initial digest using the implementation class. The
  # Sprockets release version and custom environment version are
  # mixed in. So any new releases will affect all your assets.
  @digest ||= digest_class.new.update(VERSION).update(version.to_s)

  # Returned a dupped copy so the caller can safely mutate it with `.update`
  @digest.dup
end

#each_entry(root, &block) ⇒ Object


298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/sprockets/base.rb', line 298

def each_entry(root, &block)
  return to_enum(__method__, root) unless block_given?
  root = Pathname.new(root) unless root.is_a?(Pathname)

  paths = []
  entries(root).sort.each do |filename|
    path = root.join(filename)
    paths << path

    if stat(path).directory?
      each_entry(path) do |subpath|
        paths << subpath
      end
    end
  end

  paths.sort_by(&:to_s).each(&block)

  nil
end

#each_fileObject


319
320
321
322
323
324
325
326
327
328
329
# File 'lib/sprockets/base.rb', line 319

def each_file
  return to_enum(__method__) unless block_given?
  paths.each do |root|
    each_entry(root) do |path|
      if !stat(path).directory?
        yield path
      end
    end
  end
  nil
end

#each_logical_path(*args, &block) ⇒ Object


331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
# File 'lib/sprockets/base.rb', line 331

def each_logical_path(*args, &block)
  return to_enum(__method__, *args) unless block_given?
  filters = args.flatten
  files = {}
  each_file do |filename|
    if logical_path = logical_path_for_filename(filename, filters)
      unless files[logical_path]
        if block.arity == 2
          yield logical_path, filename.to_s
        else
          yield logical_path
        end
      end

      files[logical_path] = true
    end
  end
  nil
end

#entries(pathname) ⇒ Object

Works like `Dir.entries`.

Subclasses may cache this method.


223
224
225
# File 'lib/sprockets/base.rb', line 223

def entries(pathname)
  @trail.entries(pathname)
end

#file_digest(path) ⇒ Object

Read and compute digest of filename.

Subclasses may cache this method.


237
238
239
240
241
242
243
244
245
246
247
248
249
# File 'lib/sprockets/base.rb', line 237

def file_digest(path)
  if stat = self.stat(path)
    # If its a file, digest the contents
    if stat.file?
      digest.file(path.to_s)

    # If its a directive, digest the list of filenames
    elsif stat.directory?
      contents = self.entries(path).join(',')
      digest.update(contents)
    end
  end
end

#find_asset(path, options = {}) ⇒ Object

Find asset by logical path or expanded path.


262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
# File 'lib/sprockets/base.rb', line 262

def find_asset(path, options = {})
  logical_path = path
  pathname     = Pathname.new(path).cleanpath

  if pathname.absolute?
    return unless stat(pathname)
    logical_path = attributes_for(pathname).logical_path
  else
    begin
      pathname = resolve(logical_path)

      # If logical path is missing a mime type extension, append
      # the absolute path extname so it has one.
      #
      # Ensures some consistency between finding "foo/bar" vs
      # "foo/bar.js".
      if File.extname(logical_path) == ""
        expanded_logical_path = attributes_for(pathname).logical_path
        logical_path += File.extname(expanded_logical_path)
      end
    rescue FileNotFound
      return nil
    end
  end

  build_asset(logical_path, pathname, options)
end

#indexObject

Return an `Index`. Must be implemented by the subclass.


210
211
212
# File 'lib/sprockets/base.rb', line 210

def index
  raise NotImplementedError
end

#inspectObject

Pretty inspect


352
353
354
355
356
357
358
# File 'lib/sprockets/base.rb', line 352

def inspect
  "#<#{self.class}:0x#{object_id.to_s(16)} " +
    "root=#{root.to_s.inspect}, " +
    "paths=#{paths.inspect}, " +
    "digest=#{digest.to_s.inspect}" +
    ">"
end

#prepend_path(path) ⇒ Object


101
102
103
104
105
# File 'lib/sprockets/base.rb', line 101

def prepend_path(path)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#register_bundle_processor(mime_type, klass, &block) ⇒ Object


197
198
199
200
201
# File 'lib/sprockets/base.rb', line 197

def register_bundle_processor(mime_type, klass, &block)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#register_engine(ext, klass) ⇒ Object

Registers a new Engine `klass` for `ext`.


166
167
168
169
170
171
# File 'lib/sprockets/base.rb', line 166

def register_engine(ext, klass)
  # Overrides the global behavior to expire the index
  expire_index!
  add_engine_to_trail(ext, klass)
  super
end

#register_mime_type(mime_type, ext) ⇒ Object

Register a new mime type.


158
159
160
161
162
163
# File 'lib/sprockets/base.rb', line 158

def register_mime_type(mime_type, ext)
  # Overrides the global behavior to expire the index
  expire_index!
  @trail.append_extension(ext)
  super
end

#register_postprocessor(mime_type, klass, &block) ⇒ Object


185
186
187
188
189
# File 'lib/sprockets/base.rb', line 185

def register_postprocessor(mime_type, klass, &block)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#register_preprocessor(mime_type, klass, &block) ⇒ Object


173
174
175
176
177
# File 'lib/sprockets/base.rb', line 173

def register_preprocessor(mime_type, klass, &block)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#resolve(logical_path, options = {}) ⇒ Object

Finds the expanded real path for a given logical path by searching the environment's paths.

resolve("application.js")
# => "/path/to/app/javascripts/application.js.coffee"

A `FileNotFound` exception is raised if the file does not exist.


126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
# File 'lib/sprockets/base.rb', line 126

def resolve(logical_path, options = {})
  # If a block is given, preform an iterable search
  if block_given?
    args = attributes_for(logical_path).search_paths + [options]
    @trail.find(*args) do |path|
      pathname = Pathname.new(path)
      if %w( .bower.json bower.json component.json ).include?(pathname.basename.to_s)
        bower = json_decode(pathname.read)
        case bower['main']
        when String
          yield pathname.dirname.join(bower['main'])
        when Array
          extname = File.extname(logical_path)
          bower['main'].each do |fn|
            if extname == "" || extname == File.extname(fn)
              yield pathname.dirname.join(fn)
            end
          end
        end
      else
        yield pathname
      end
    end
  else
    resolve(logical_path, options) do |pathname|
      return pathname
    end
    raise FileNotFound, "couldn't find file '#{logical_path}'"
  end
end

#stat(path) ⇒ Object

Works like `File.stat`.

Subclasses may cache this method.


230
231
232
# File 'lib/sprockets/base.rb', line 230

def stat(path)
  @trail.stat(path)
end

#unregister_bundle_processor(mime_type, klass) ⇒ Object


203
204
205
206
207
# File 'lib/sprockets/base.rb', line 203

def unregister_bundle_processor(mime_type, klass)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#unregister_postprocessor(mime_type, klass) ⇒ Object


191
192
193
194
195
# File 'lib/sprockets/base.rb', line 191

def unregister_postprocessor(mime_type, klass)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end

#unregister_preprocessor(mime_type, klass) ⇒ Object


179
180
181
182
183
# File 'lib/sprockets/base.rb', line 179

def unregister_preprocessor(mime_type, klass)
  # Overrides the global behavior to expire the index
  expire_index!
  super
end