module Roda::RodaPlugins::Assets::ClassMethods

def _compile_assets(type)

all asset groups under the given type.
Internals of compile_assets, handling recursive calls for loading
def _compile_assets(type)
  type, *dirs = type if type.is_a?(Array)
  dirs ||= []
  files = assets_opts[type]
  dirs.each{|d| files = files[d]}
  case files
  when Hash
    files.each_key{|dir| _compile_assets([type] + dirs + [dir])}
  else
    files = Array(files)
    compile_assets_files(files, type, dirs) unless files.empty?
  end
end

def _compiled_assets_initial_hash

The initial hash to use to store compiled asset metadata.
def _compiled_assets_initial_hash
  {}
end

def _precompiled_asset_metadata(file)

The precompiled asset metadata stored in the given file
def _precompiled_asset_metadata(file)
  (opts[:json_parser] || ::JSON.method(:parse)).call(::File.read(file))
end

def asset_digest(content)

want to use a unique value.
a different digest type or to return a static string if you don't
SHA256 hash of the content. This method can be overridden to use
Return a unique id for the given content. By default, uses the
def asset_digest(content)
  algo = assets_opts[:sri] || :sha256
  digest = begin
    require 'openssl'
    ::OpenSSL::Digest
  # :nocov:
  rescue LoadError
    require 'digest/sha2'
    ::Digest
  # :nocov:
  end
  digest.const_get(algo.to_s.upcase).hexdigest(content)
end

def assets_opts

Return the assets options for this class.
def assets_opts
  opts[:assets]
end

def compile_assets(type=nil)

compile assets for the given asset group.
can specify an array of types (e.g. [:css, :frontend]) to
is given, compile both the :css and :js asset types. You
Compile options for the given asset type. If no asset_type
def compile_assets(type=nil)
  require 'fileutils'
  unless assets_opts[:compiled]
    opts[:assets] = assets_opts.merge(:compiled => _compiled_assets_initial_hash).freeze
  end
  if type == nil
    _compile_assets(:css)
    _compile_assets(:js)
  else
    _compile_assets(type)
  end
  if precompile_file = assets_opts[:precompiled]
    require 'json'
    ::FileUtils.mkdir_p(File.dirname(precompile_file))
    tmp_file = "#{precompile_file}.tmp"
    ::File.open(tmp_file, 'wb'){|f| f.write((opts[:json_serializer] || :to_json.to_proc).call(assets_opts[:compiled]))}
    ::File.rename(tmp_file, precompile_file)
  end
  assets_opts[:compiled]
end

def compile_assets_files(files, type, dirs)

are files in an asset group.
file. Dirs should be an array of asset group names, if these
Compile each array of files for the given type into a single
def compile_assets_files(files, type, dirs)
  dirs = nil if dirs && dirs.empty?
  o = assets_opts
  app = allocate
  content = files.map do |file|
    file = "#{dirs.join('/')}/#{file}" if dirs && o[:group_subdirs]
    file = "#{o[:"#{type}_path"]}#{file}"
    app.read_asset_file(file, type)
  end.join("\n")
  unless o[:concat_only]
    content = compress_asset(content, type)
  end
  suffix = ".#{dirs.join('.')}" if dirs
  key = "#{type}#{suffix}"
  unique_id = o[:compiled][key] = asset_digest(content)
  path = "#{o[:"compiled_#{type}_path"]}#{suffix}.#{unique_id}.#{type}"
  ::FileUtils.mkdir_p(File.dirname(path))
  ::File.open(path, 'wb'){|f| f.write(content)}
  if o[:gzip]
    require 'zlib'
    Zlib::GzipWriter.open("#{path}.gz") do |gz|
      gz.write(content)
    end
  end
  nil
end

def compress_asset(content, type)

configured compressor, or trying the supported compressors.
Compress the given content for the given type by using the
def compress_asset(content, type)
  case compressor = assets_opts[:"#{type}_compressor"]
  when :none
    return content
  when nil
    # default, try different compressors
  else
    # Allow calling private compress methods
    return send("compress_#{type}_#{compressor}", content)
  end
  compressors = if type == :js
    [:yui, :closure, :uglifier, :minjs]
  else
    [:yui]
  end
  compressors.each do |comp|
    begin
    # Allow calling private compress methods
      if c = send("compress_#{type}_#{comp}", content)
        return c
      end
    rescue LoadError, CompressorNotFound
    end
  end
  content
end

def compress_css_yui(content)

Compress the CSS using YUI Compressor, requires java runtime
def compress_css_yui(content)
  compress_yui(content, :compress_css)
end

def compress_js_closure(content)

Compress the JS using Google Closure Compiler, requires java runtime
def compress_js_closure(content)
  require 'closure-compiler'
  begin
    ::Closure::Compiler.new.compile(content)
  rescue ::Closure::Error => e
    raise CompressorNotFound, "#{e.class}: #{e.message}", e.backtrace
  end
end

def compress_js_minjs(content)

Compress the JS using MinJS, a pure ruby compressor
def compress_js_minjs(content)
  require 'minjs'
  Minjs::Compressor::Compressor.new(:debug => false).compress(content).to_js
end

def compress_js_uglifier(content)

Compress the JS using Uglifier, requires javascript runtime
def compress_js_uglifier(content)
  begin
    require 'uglifier'
  rescue => e
    # :nocov:
    raise CompressorNotFound, "#{e.class}: #{e.message}", e.backtrace
    # :nocov:
  end
  Uglifier.compile(content)
end

def compress_js_yui(content)

Compress the CSS using YUI Compressor, requires java runtime
def compress_js_yui(content)
  compress_yui(content, :compress_js)
end

def compress_yui(content, meth)

Compress the CSS/JS using YUI Compressor, requires java runtime
def compress_yui(content, meth)
  require 'yuicompressor'
  ::YUICompressor.public_send(meth, content, :munge => true)
rescue ::Errno::ENOENT => e
  raise CompressorNotFound, "#{e.class}: #{e.message}", e.backtrace
end