class Sprockets::Base

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

def [](*args)


environment['application.js']

Preferred `find_asset` shorthand.
def [](*args)
  find_asset(*args)
end

def attributes_for(path)

Internal. Return a `AssetAttributes` for `path`.
def attributes_for(path)
  AssetAttributes.new(self, path)
end

def build_asset(logical_path, pathname, options)

def build_asset(logical_path, pathname, options)
  pathname = Pathname.new(pathname)
  # If there are any processors to run on the pathname, use
  # `BundledAsset`. Otherwise use `StaticAsset` and treat is as binary.
  if attributes_for(pathname).processors.any?
    if options[:bundle] == false
      circular_call_protection(pathname.to_s) do
        ProcessedAsset.new(index, logical_path, pathname)
      end
    else
      BundledAsset.new(index, logical_path, pathname)
    end
  else
    StaticAsset.new(index, logical_path, pathname)
  end
end

def cache=(cache)

`[key]`/`[key]=value`, `read(key)`/`write(key, value)`.
setters. Either `get(key)`/`set(key, value)`,
The cache store must implement a pair of getters and

Set persistent cache store
def cache=(cache)
  expire_index!
  @cache = cache
end

def cache_key_for(path, options)

def cache_key_for(path, options)
  "#{path}:#{options[:bundle] ? '1' : '0'}"
end

def circular_call_protection(path)

def circular_call_protection(path)
  reset = Thread.current[:sprockets_circular_calls].nil?
  calls = Thread.current[:sprockets_circular_calls] ||= Set.new
  if calls.include?(path)
    raise CircularDependencyError, "#{path} has already been required"
  end
  calls << path
  yield
ensure
  Thread.current[:sprockets_circular_calls] = nil if reset
end

def content_type_of(path)

Internal. Return content type of `path`.
def content_type_of(path)
  attributes_for(path).content_type
end

def digest

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

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

Returns a `Digest` instance for the `Environment`.
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

def digest_class=(klass)


environment.digest_class = Digest::SHA1

`Digest::SHA1`.
`Digest::` implementation such as `Digest::MD5` or
Assign a `Digest` implementation class. This maybe any Ruby
def digest_class=(klass)
  expire_index!
  @digest_class = klass
end

def each_entry(root, &block)

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

def each_file

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

def each_logical_path(*args)

def each_logical_path(*args)
  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)
      yield logical_path unless files[logical_path]
      files[logical_path] = true
    end
  end
  nil
end

def entries(pathname)

Subclasses may cache this method.

Works like `Dir.entries`.
def entries(pathname)
  trail.entries(pathname)
end

def expire_index!

Clear index after mutating state. Must be implemented by the subclass.
def expire_index!
  raise NotImplementedError
end

def file_digest(path)

Subclasses may cache this method.

Read and compute digest of filename.
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

def find_asset(path, options = {})

Find asset by logical path or expanded path.
def find_asset(path, options = {})
  logical_path = path
  pathname     = Pathname.new(path)
  if pathname.absolute?
    return unless stat(pathname)
    logical_path = attributes_for(pathname).logical_path
  else
    begin
      pathname = resolve(logical_path)
    rescue FileNotFound
      return nil
    end
  end
  build_asset(logical_path, pathname, options)
end

def index

Return an `Index`. Must be implemented by the subclass.
def index
  raise NotImplementedError
end

def inspect

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

def logical_path_for_filename(filename, filters)

def logical_path_for_filename(filename, filters)
  logical_path = attributes_for(filename).logical_path.to_s
  if matches_filter(filters, logical_path)
    return logical_path
  end
  # If filename is an index file, retest with alias
  if File.basename(logical_path)[/[^\.]+/, 0] == 'index'
    path = logical_path.sub(/\/index\./, '.')
    if matches_filter(filters, path)
      return path
    end
  end
  nil
end

def matches_filter(filters, filename)

def matches_filter(filters, filename)
  return true if filters.empty?
  filters.any? do |filter|
    if filter.is_a?(Regexp)
      filter.match(filename)
    elsif filter.respond_to?(:call)
      filter.call(filename)
    else
      File.fnmatch(filter.to_s, filename)
    end
  end
end

def stat(path)

Subclasses may cache this method.

Works like `File.stat`.
def stat(path)
  trail.stat(path)
end

def version=(version)


environment.version = '2.0'

Assign an environment version.
def version=(version)
  expire_index!
  @version = version
end