module Sprockets::Loader

def fetch_asset_from_dependency_cache(uri, filename, limit = 3)

def fetch_asset_from_dependency_cache(uri, filename, limit = 3)
  key = ['asset-uri-cache-dependencies', VERSION, uri, file_digest(filename)]
  history = cache.get(key) || []
  history.each_with_index do |deps, index|
    if asset = yield(deps)
      cache.set(key, history.rotate!(index)) if index > 0
      return asset
    end
  end
  asset = yield
  deps = asset[:metadata][:dependencies]
  cache.set(key, history.unshift(deps).take(limit))
  asset
end

def load(uri)

Returns Asset.

uri - AssetURI

Public: Load Asset by AssetURI.
def load(uri)
  filename, params = parse_asset_uri(uri)
  if params.key?(:id)
    asset = cache.fetch(['asset-uri', uri]) do
      load_asset_by_id_uri(uri, filename, params)
    end
  else
    asset = fetch_asset_from_dependency_cache(uri, filename) do |paths|
      if paths
        digest = digest(resolve_dependencies(paths))
        if id_uri = cache.get(['asset-uri-digest', VERSION, uri, digest], true)
          cache.get(['asset-uri', VERSION, id_uri], true)
        end
      else
        load_asset_by_uri(uri, filename, params)
      end
    end
  end
  Asset.new(self, asset)
end

def load_asset_by_id_uri(uri, filename, params)

def load_asset_by_id_uri(uri, filename, params)
  # Internal assertion, should be routed through load_asset_by_uri
  unless id = params.delete(:id)
    raise ArgumentError, "expected uri to have an id: #{uri}"
  end
  uri = build_asset_uri(filename, params)
  asset = load_asset_by_uri(uri, filename, params)
  if id && asset[:id] != id
    raise VersionNotFound, "could not find specified id: #{id}"
  end
  asset
end

def load_asset_by_uri(uri, filename, params)

def load_asset_by_uri(uri, filename, params)
  # Internal assertion, should be routed through load_asset_by_id_uri
  if params.key?(:id)
    raise ArgumentError, "expected uri to have no id: #{uri}"
  end
  unless file?(filename)
    raise FileNotFound, "could not find file: #{filename}"
  end
  load_path, logical_path = paths_split(self.paths, filename)
  unless load_path
    raise FileOutsidePaths, "#{filename} is no longer under a load path: #{self.paths.join(', ')}"
  end
  logical_path, file_type, engine_extnames = parse_path_extnames(logical_path)
  logical_path = normalize_logical_path(logical_path)
  name = logical_path
  if type = params[:type]
    logical_path += mime_types[type][:extensions].first
  end
  if type != file_type && !transformers[file_type][type]
    raise ConversionError, "could not convert #{file_type.inspect} to #{type.inspect}"
  end
  skip_bundle = params[:skip_bundle]
  processors = processors_for(type, file_type, engine_extnames, skip_bundle)
  processors_dep_uri = build_processors_uri(type, file_type, engine_extnames, skip_bundle)
  dependencies = self.dependencies + [processors_dep_uri]
  # Read into memory and process if theres a processor pipeline
  if processors.any?
    result = call_processors(processors, {
      environment: self,
      cache: self.cache,
      uri: uri,
      filename: filename,
      load_path: load_path,
      name: name,
      content_type: type,
      metadata: { dependencies: dependencies }
    })
    source = result.delete(:data)
    metadata = result.merge!(
      charset: source.encoding.name.downcase,
      digest: digest(source),
      length: source.bytesize
    )
  else
    metadata = {
      digest: file_digest(filename),
      length: self.stat(filename).size,
      dependencies: dependencies
    }
  end
  asset = {
    uri: uri,
    load_path: load_path,
    filename: filename,
    name: name,
    logical_path: logical_path,
    content_type: type,
    source: source,
    metadata: metadata,
    integrity: integrity_uri(metadata[:digest], type),
    dependencies_digest: digest(resolve_dependencies(metadata[:dependencies]))
  }
  asset[:id]  = pack_hexdigest(digest(asset))
  asset[:uri] = build_asset_uri(filename, params.merge(id: asset[:id]))
  # Deprecated: Avoid tracking Asset mtime
  asset[:mtime] = metadata[:dependencies].map { |u|
    if u.start_with?("file-digest:")
      s = self.stat(parse_file_digest_uri(u))
      s ? s.mtime.to_i : 0
    else
      0
    end
  }.max
  cache.set(['asset-uri', VERSION, asset[:uri]], asset, true)
  cache.set(['asset-uri-digest', VERSION, uri, asset[:dependencies_digest]], asset[:uri], true)
  asset
end