class Sprockets::Manifest

def self.compile_match_filter(filter)

Returns a Proc or raise a TypeError.

compile_match_filter("foo/*.js")

compile_match_filter(/application.js/)

})
File.extname(logical_path) == '.js'
compile_match_filter(proc { |logical_path|

passed to logical_paths.select(&proc).
Deprecated: Compile logical path matching filter into a proc that can be
def self.compile_match_filter(filter)
  # If the filter is already a proc, great nothing to do.
  if filter.respond_to?(:call)
    filter
  # If the filter is a regexp, wrap it in a proc that tests it against the
  # logical path.
  elsif filter.is_a?(Regexp)
    proc { |logical_path| filter.match(logical_path) }
  elsif filter.is_a?(String)
    # If its an absolute path, detect the matching full filename
    if PathUtils.absolute_path?(filter)
      proc { |logical_path, filename| filename == filter.to_s }
    else
      # Otherwise do an fnmatch against the logical path.
      proc { |logical_path| File.fnmatch(filter.to_s, logical_path) }
    end
  else
    raise TypeError, "unknown filter type: #{filter.inspect}"
  end
end

def assets


"jquery.js" => "jquery-ae0908555a245f8266f77df5a8edca2e.js" }
{ "application.js" => "application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js",

Logical path (String): Fingerprint path (String)

map to the latest fingerprinted filename.
Returns internal assets mapping. Keys are logical paths which
def assets
  @data['assets'] ||= {}
end

def clean(count = 2, age = 3600)


age=600.
To only keep files created within the last 10 minutes, set count=0 and

To force only 1 backup to be kept, set count=1 and age=0.

Examples

keep the latest version, 2 backups and any created within the past hour.
Cleanup old assets in the compile directory. By default it will
def clean(count = 2, age = 3600)
  asset_versions = files.group_by { |_, attrs| attrs['logical_path'] }
  asset_versions.each do |logical_path, versions|
    current = assets[logical_path]
    versions.reject { |path, _|
      path == current
    }.sort_by { |_, attrs|
      # Sort by timestamp
      Time.parse(attrs['mtime'])
    }.reverse.each_with_index.drop_while { |(_, attrs), index|
      age = [0, Time.now - Time.parse(attrs['mtime'])].max
      # Keep if under age or within the count limit
      age < age || index < count
    }.each { |(path, _), _|
       # Remove old assets
      remove(path)
    }
  end
end

def clobber

Wipe directive
def clobber
  FileUtils.rm_r(directory) if File.exist?(directory)
  logger.info "Removed #{directory}"
  nil
end

def compile(*args)


compile("application.js")

also inserted into the manifest file.
`application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js`. An entry is
fingerprinted filename like
Compile and write asset to directory. The asset is written to a
def compile(*args)
  unless environment
    raise Error, "manifest requires environment for compilation"
  end
  filenames = []
  find(*args) do |asset|
    files[asset.digest_path] = {
      'logical_path' => asset.logical_path,
      'mtime'        => asset.mtime.iso8601,
      'size'         => asset.bytesize,
      'digest'       => asset.hexdigest,
      'integrity'    => asset.integrity
    }
    assets[asset.logical_path] = asset.digest_path
    target = File.join(dir, asset.digest_path)
    if File.exist?(target)
      logger.debug "Skipping #{target}, already exists"
    else
      logger.info "Writing #{target}"
      asset.write_to target
    end
    filenames << asset.filename
  end
  save
  filenames
end

def files


'digest' => "2e8e9a7c6b0aafa0c9bdeec90ea30213" } }
'mtime' => "2011-12-13T21:47:08-06:00",
{ 'logical_path' => "application.js",
{ "application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js" =>

digest: Base64 hex digest (String)
mtime: ISO8601 mtime (String)
logical_path: Logical path (String)
Fingerprint path (String):

which map to an attributes array.
Returns internal file directory listing. Keys are filenames
def files
  @data['files'] ||= {}
end

def filter_logical_paths(*args)

Returns an Enumerator.

files you want to compile.
Deprecated: Filter logical paths in environment. Useful for selecting what
def filter_logical_paths(*args)
  filters = args.flatten.map { |arg| self.class.compile_match_filter(arg) }
  environment.cached.logical_paths.select do |a, b|
    filters.any? { |f| f.call(a, b) }
  end
end

def find(*args)

Returns Enumerator of Assets.

Public: Find all assets matching pattern set in environment.
def find(*args)
  unless environment
    raise Error, "manifest requires environment for compilation"
  end
  return to_enum(__method__, *args) unless block_given?
  filters = args.flatten.map { |arg| self.class.compile_match_filter(arg) }
  environment = self.environment.cached
  environment.logical_paths do |logical_path, filename|
    if filters.any? { |f| f.call(logical_path, filename) }
      environment.find_all_linked_assets(filename) do |asset|
        yield asset
      end
    end
  end
  nil
end

def initialize(*args)


Manifest.new(environment, "./public/assets/manifest.json")

"manifest-123.json" file in that directory.
Otherwise, if the path is a directory, the filename will default a random
dirname of the `filename` will be used to write compiled assets to.
path to the manifest json file. The file may or may not already exist. The
Create new Manifest associated with an `environment`. `filename` is a full
def initialize(*args)
  if args.first.is_a?(Base) || args.first.nil?
    @environment = args.shift
  end
  @directory, @filename = args[0], args[1]
  # Expand paths
  @directory = File.expand_path(@directory) if @directory
  @filename  = File.expand_path(@filename) if @filename
  # If filename is given as the second arg
  if @directory && File.extname(@directory) != ""
    @directory, @filename = nil, @directory
  end
  # Default dir to the directory of the filename
  @directory ||= File.dirname(@filename) if @filename
  # If directory is given w/o filename, pick a random manifest.json location
  if @directory && @filename.nil?
    # Find the first manifest.json in the directory
    filenames = Dir[File.join(@directory, "manifest*.json")]
    if filenames.any?
      @filename = filenames.first
    else
      @filename = File.join(@directory, "manifest-#{SecureRandom.hex(16)}.json")
    end
  end
  unless @directory && @filename
    raise ArgumentError, "manifest requires output filename"
  end
  data = {}
  begin
    if File.exist?(@filename)
      data = json_decode(File.read(@filename))
    end
  rescue JSON::ParserError => e
    logger.error "#{@filename} is invalid: #{e.class} #{e.message}"
  end
  @data = data
end

def json_decode(obj)

def json_decode(obj)
  JSON.parse(obj, create_additions: false)
end

def json_encode(obj)

def json_encode(obj)
  JSON.generate(obj)
end

def logger

def logger
  if environment
    environment.logger
  else
    logger = Logger.new($stderr)
    logger.level = Logger::FATAL
    logger
  end
end

def remove(filename)


manifest.remove("application-2e8e9a7c6b0aafa0c9bdeec90ea30213.js")

be the name with any directory path.
Removes file from directory and from manifest. `filename` must
def remove(filename)
  path = File.join(dir, filename)
  logical_path = files[filename]['logical_path']
  if assets[logical_path] == filename
    assets.delete(logical_path)
  end
  files.delete(filename)
  FileUtils.rm(path) if File.exist?(path)
  save
  logger.info "Removed #{filename}"
  nil
end

def save

Persist manfiest back to FS
def save
  data = json_encode(@data)
  FileUtils.mkdir_p File.dirname(filename)
  PathUtils.atomic_write(filename) do |f|
    f.write(data)
  end
end