require 'sprockets/engines'
require 'sprockets/lazy_processor'
require 'sprockets/legacy_proc_processor'
require 'sprockets/legacy_tilt_processor'
require 'sprockets/mime'
require 'sprockets/utils'
module Sprockets
# `Processing` is an internal mixin whose public methods are exposed on
# the `Environment` and `CachedEnvironment` classes.
module Processing
# Preprocessors are ran before Postprocessors and Engine
# processors.
attr_reader :preprocessors
# Internal: Find and load preprocessors by mime type.
#
# mime_type - String MIME type.
#
# Returns Array of Procs.
def unwrap_preprocessors(mime_type)
preprocessors[mime_type].map do |processor|
unwrap_processor(processor)
end
end
# Postprocessors are ran after Preprocessors and Engine processors.
attr_reader :postprocessors
# Internal: Find and load postprocessors by mime type.
#
# mime_type - String MIME type.
#
# Returns Array of Procs.
def unwrap_postprocessors(mime_type)
postprocessors[mime_type].map do |processor|
unwrap_processor(processor)
end
end
# Registers a new Preprocessor `klass` for `mime_type`.
#
# register_preprocessor 'text/css', Sprockets::DirectiveProcessor
#
# A block can be passed for to create a shorthand processor.
#
# register_preprocessor 'text/css', :my_processor do |context, data|
# data.gsub(...)
# end
#
def register_preprocessor(mime_type, klass, &block)
mutate_hash_config(:preprocessors, mime_type) do |processors|
processors.push(wrap_processor(klass, block))
processors
end
end
# Registers a new Postprocessor `klass` for `mime_type`.
#
# register_postprocessor 'application/javascript', Sprockets::DirectiveProcessor
#
# A block can be passed for to create a shorthand processor.
#
# register_postprocessor 'application/javascript', :my_processor do |context, data|
# data.gsub(...)
# end
#
def register_postprocessor(mime_type, klass, proc = nil, &block)
proc ||= block
mutate_hash_config(:postprocessors, mime_type) do |processors|
processors.push(wrap_processor(klass, proc))
processors
end
end
# Remove Preprocessor `klass` for `mime_type`.
#
# unregister_preprocessor 'text/css', Sprockets::DirectiveProcessor
#
def unregister_preprocessor(mime_type, klass)
if klass.is_a?(String) || klass.is_a?(Symbol)
klass = preprocessors[mime_type].detect { |cls|
cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})"
}
end
mutate_hash_config(:preprocessors, mime_type) do |processors|
processors.delete(klass)
processors
end
end
# Remove Postprocessor `klass` for `mime_type`.
#
# unregister_postprocessor 'text/css', Sprockets::DirectiveProcessor
#
def unregister_postprocessor(mime_type, klass)
if klass.is_a?(String) || klass.is_a?(Symbol)
klass = postprocessors[mime_type].detect { |cls|
cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})"
}
end
mutate_hash_config(:postprocessors, mime_type) do |processors|
processors.delete(klass)
processors
end
end
# Bundle Processors are ran on concatenated assets rather than
# individual files.
attr_reader :bundle_processors
# Internal: Find and load bundle processors by mime type.
#
# mime_type - String MIME type.
#
# Returns Array of Procs.
def unwrap_bundle_processors(mime_type)
bundle_processors[mime_type].map do |processor|
unwrap_processor(processor)
end
end
# Registers a new Bundle Processor `klass` for `mime_type`.
#
# register_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
#
# A block can be passed for to create a shorthand processor.
#
# register_bundle_processor 'application/javascript', :my_processor do |context, data|
# data.gsub(...)
# end
#
def register_bundle_processor(mime_type, klass, &block)
mutate_hash_config(:bundle_processors, mime_type) do |processors|
processors.push(wrap_processor(klass, block))
processors
end
end
# Remove Bundle Processor `klass` for `mime_type`.
#
# unregister_bundle_processor 'application/javascript', Sprockets::DirectiveProcessor
#
def unregister_bundle_processor(mime_type, klass)
if klass.is_a?(String) || klass.is_a?(Symbol)
klass = bundle_processors[mime_type].detect { |cls|
cls.respond_to?(:name) && cls.name == "Sprockets::LegacyProcProcessor (#{klass})"
}
end
mutate_hash_config(:bundle_processors, mime_type) do |processors|
processors.delete(klass)
processors
end
end
# Internal: Two dimensional Hash of reducer functions for a given mime type
# and asset metadata key.
attr_reader :bundle_reducers
# Public: Register bundle metadata reducer function.
#
# Examples
#
# Sprockets.register_bundle_metadata_reducer 'application/javascript', :jshint_errors, [], :+
#
# Sprockets.register_bundle_metadata_reducer 'text/css', :selector_count, 0 { |total, count|
# total + count
# }
#
# mime_type - String MIME Type. Use '*/*' applies to all types.
# key - Symbol metadata key
# initial - Initial memo to pass to the reduce funciton (default: nil)
# block - Proc accepting the memo accumulator and current value
#
# Returns nothing.
def register_bundle_metadata_reducer(mime_type, key, *args, &block)
case args.size
when 0
reducer = block
when 1
if block_given?
initial = args[0]
reducer = block
else
initial = nil
reducer = args[0].to_proc
end
when 2
initial = args[0]
reducer = args[1].to_proc
else
raise ArgumentError, "wrong number of arguments (#{args.size} for 0..2)"
end
mutate_hash_config(:bundle_reducers, mime_type) do |reducers|
reducers.merge(key => [initial, reducer])
end
end
# Internal: Gather all bundle reducer functions for MIME type.
#
# mime_type - String MIME type
#
# Returns an Array of [initial, reducer_proc] pairs.
def unwrap_bundle_reducers(mime_type)
self.bundle_reducers['*/*'].merge(self.bundle_reducers[mime_type])
end
# Internal: Run bundle reducers on set of Assets producing a reduced
# metadata Hash.
#
# assets - Array of Assets
# reducers - Array of [initial, reducer_proc] pairs
#
# Returns reduced asset metadata Hash.
def process_bundle_reducers(assets, reducers)
initial = {}
reducers.each do |k, (v, _)|
initial[k] = v if v
end
assets.reduce(initial) do |h, asset|
reducers.each do |k, (_, block)|
value = k == :data ? asset.source : asset.metadata[k]
h[k] = h.key?(k) ? block.call(h[k], value) : value
end
h
end
end
private
def wrap_processor(klass, proc)
if !proc
if klass.class == Sprockets::LazyProcessor || klass.respond_to?(:call)
klass
else
LegacyTiltProcessor.new(klass)
end
elsif proc.respond_to?(:arity) && proc.arity == 2
LegacyProcProcessor.new(klass.to_s, proc)
else
proc
end
end
def unwrap_processor(processor)
processor.respond_to?(:unwrap) ? processor.unwrap : processor
end
end
end