lib/jekyll/assets/proxy.rb
# Frozen-string-literal: true
# Copyright: 2012 - 2020 - ISC License
# Encoding: utf-8
require 'digest'
module Jekyll
module Assets
class Proxy < Extensible
attr_reader :file
class Deleted < StandardError
def initialize(obj)
super "#{obj} violated a contract and " \
'deleted your proxy file'
end
end
# --
# @param [Hash] args the args.
# @param [Sprockets::Asset] asset the asset.
# @param [String] type the assets content_type
# @param [Env] env the environment.
# Run all your proxies on assets.
# @return [Sprockets::Asset]
# --
def self.proxy(asset, args:, ctx:)
env = ctx.registers[:site].sprockets
return asset if (proxies = proxies_for(asset: asset, args: args)).empty?
key = digest(args)
out = env.cache.fetch(key) do
file = copy(asset, args: args, ctx: ctx)
proxies.each do |o|
obj = o.new(file, {
args: args,
asset: asset,
ctx: ctx
})
o = obj.process
file = o if o.is_a?(Pathutil) && file != o
raise Deleted, o unless file.exist?
end
file
end
env.find_asset!(out)
end
# --
def self.proxies_for(asset:, args:)
Proxy.inherited.select do |o|
o.for?({
type: asset.content_type,
args: args,
})
end
end
# --
# Copy the asset to the proxied directory.
# @note this is done so we do not directly alter.
# @param [Sprockets::Asset] asset the current asset.
# @param [Env] env the environment.
# @param [Hash] args the args.
# @return [Pathutil]
# --
def self.copy(asset, ctx:, args:)
env = ctx.registers[:site].sprockets
path = env.in_cache_dir('proxied')
extname = File.extname(args[:argv1])
out = Pathutil.new(path).join(digest(args))
.sub_ext(extname)
unless out.file?
out.dirname.mkdir_p
Pathutil.new(asset.filename).cp(
out
)
end
out
end
def self.digest(args)
Digest::SHA256.hexdigest(args.to_h.inspect)[0, 6]
end
# --
# @return [Symbol] the argument key.
# Allows you to tell the proxier which args are yours.
# @note we will not run your proxy if the argkey doen't match.
# @param [Symbol] key the key.
# --
def self.args_key(key = nil)
key.nil? ? @key : @key = key
end
# --
# Return a list of proxy keys.
# This allows you to select their values from args.
# @return [Array<Symbol>]
# --
def self.keys
inherited.map(&:arg_keys).flatten
end
# --
def initialize(file, **kwd)
super(**kwd)
@file = file
end
end
end
end
Jekyll::Assets::Hook.register :env, :after_init do
append_path(
in_cache_dir(
'proxied'
)
)
end