module Sprockets::ProcessorUtils

def call_processor(processor, input)

Returns a Hash with :data and other processor metadata key/values.

input - Hash of input data to pass to processor
processor - Processor callables

Public: Invoke processor.
def call_processor(processor, input)
  metadata = (input[:metadata] || {}).dup
  metadata[:data] = input[:data]
  case result = processor.call({data: "", metadata: {}}.merge(input))
  when NilClass
    metadata
  when Hash
    metadata.merge(result)
  when String
    metadata.merge(data: result)
  else
    raise TypeError, "invalid processor return type: #{result.class}"
  end
end

def call_processors(processors, input)

Returns a Hash with :data and other processor metadata key/values.

input - Hash of input data to pass to each processor
processors - Array of processor callables

bundle.call(uglify.call(coffee.call(input)))

Think about:
The right to left order processing mirrors standard function composition.

Public: Invoke list of processors in right to left order.
def call_processors(processors, input)
  data = input[:data] || ""
  metadata = (input[:metadata] || {}).dup
  processors.reverse_each do |processor|
    result = call_processor(processor, input.merge(data: data, metadata: metadata))
    data = result.delete(:data)
    metadata.merge!(result)
  end
  metadata.merge(data: data)
end

def compose_processors(*processors)

Returns a composed Proc.

processors - Array of processors callables

Public: Compose processors in right to left order.
def compose_processors(*processors)
  CompositeProcessor.create processors
end

def processor_cache_key(processor)

Returns JSON serializable key or nil.

processor - Processor function

Internal: Get processor defined cached key.
def processor_cache_key(processor)
  processor.cache_key if processor.respond_to?(:cache_key)
end

def processors_cache_keys(processors)

Returns Array of JSON serializable keys.

processors - Array of processor functions

Internal: Get combined cache keys for set of processors.
def processors_cache_keys(processors)
  processors.map { |processor| processor_cache_key(processor) }
end

def valid_processor_metadata_value?(value)

Returns true if class is in whitelist otherwise false.

value - Any Object

Internal: Validate object is in validate metadata whitelist.
def valid_processor_metadata_value?(value)
  if VALID_METADATA_VALUE_TYPES_HASH[value.class]
    true
  elsif VALID_METADATA_COMPOUND_TYPES_HASH[value.class]
    value.all? { |v| valid_processor_metadata_value?(v) }
  else
    false
  end
end

def validate_processor_result!(result)

Returns result or raises a TypeError.

result - Metadata Hash returned from call_processors

raise a friendly user error message.
Internal: Validate returned result of calling a processor pipeline and
def validate_processor_result!(result)
  if !result.instance_of?(Hash)
    raise TypeError, "processor metadata result was expected to be a Hash, but was #{result.class}"
  end
  if !result[:data].instance_of?(String)
    raise TypeError, "processor :data was expected to be a String, but as #{result[:data].class}"
  end
  result.each do |key, value|
    if !key.instance_of?(Symbol)
      raise TypeError, "processor metadata[#{key.inspect}] expected to be a Symbol"
    end
    if !valid_processor_metadata_value?(value)
      raise TypeError, "processor metadata[:#{key}] returned a complex type: #{value.inspect}\n" +
        "Only #{VALID_METADATA_TYPES.to_a.join(", ")} maybe used."
    end
  end
  result
end