class Sprockets::DirectiveProcessor


env.register_processor(‘text/css’, MyProcessor)
Then inject your own preprocessor:
env.unregister_processor(‘application/javascript’, Sprockets::DirectiveProcessor)
env.unregister_processor(‘text/css’, Sprockets::DirectiveProcessor)
To remove the processor entirely:
‘Environment#processors` includes `DirectiveProcessor` by default.
directive syntax.
you’d like. You could add your own custom directives or invent your own
This makes it possible to disable or modify the processor to do whatever
*/
*= require “baz”
/* CSS
#= require “bar”
# CoffeeScript
//= require “foo”
// JavaScript
then the directive name, then any arguments.
A directive comment starts with a comment prefix, followed by an “=”,
directive comments in a source file.
The ‘DirectiveProcessor` is responsible for parsing and evaluating

def self.call(input)

def self.call(input)
  instance.call(input)
end

def self.instance

def self.instance
  @instance ||= new(
    # Deprecated: Default to C and Ruby comment styles
    comments: ["//", ["/*", "*/"]] + ["#", ["###", "###"]]
  )
end

def _call(input)

def _call(input)
  @environment  = input[:environment]
  @uri          = input[:uri]
  @filename     = input[:filename]
  @dirname      = File.dirname(@filename)
  @content_type = input[:content_type]
  @required     = Set.new(input[:metadata][:required])
  @stubbed      = Set.new(input[:metadata][:stubbed])
  @links        = Set.new(input[:metadata][:links])
  @dependencies = Set.new(input[:metadata][:dependencies])
  data, directives = process_source(input[:data])
  process_directives(directives)
  { data: data,
    required: @required,
    stubbed: @stubbed,
    links: @links,
    dependencies: @dependencies }
end

def call(input)

def call(input)
  dup._call(input)
end

def compile_header_pattern(comments)

of code will not be processed.
Directives in comments after the first non-whitespace line

Ruby (#) comments are supported.
of the source file. C style (/* */), JavaScript (//), and
Directives will only be picked up if they are in the header
def compile_header_pattern(comments)
  re = comments.map { |c|
    case c
    when String
      "(?:#{Regexp.escape(c)}.*\\n?)+"
    when Array
      "(?:#{Regexp.escape(c[0])}(?m:.*?)#{Regexp.escape(c[1])})"
    else
      raise TypeError, "unknown comment type: #{c.class}"
    end
  }.join("|")
  Regexp.compile("\\A(?:(?m:\\s*)(?:#{re}))+")
end

def expand_accept_shorthand(accept)

def expand_accept_shorthand(accept)
  if accept.nil?
    nil
  elsif accept.include?("/")
    accept
  elsif accept.start_with?(".")
    @environment.mime_exts[accept]
  else
    @environment.mime_exts[".#{accept}"]
  end
end

def expand_relative_dirname(directive, path)

def expand_relative_dirname(directive, path)
  if @environment.relative_path?(path)
    path = File.expand_path(path, @dirname)
    stat = @environment.stat(path)
    if stat && stat.directory?
      path
    else
      raise ArgumentError, "#{directive} argument must be a directory"
    end
  else
    # The path must be relative and start with a `./`.
    raise ArgumentError, "#{directive} argument must be a relative path"
  end
end

def extract_directives(header)


[[1, "require", "foo"], [2, "require", "bar"]]

arguments.
directive name as the second element, followed by any
is an Array with the line number as the first element, the
Returns an Array of directive structures. Each structure
def extract_directives(header)
  processed_header = ""
  directives = []
  header.lines.each_with_index do |line, index|
    if directive = line[DIRECTIVE_PATTERN, 1]
      name, *args = Shellwords.shellwords(directive)
      if respond_to?("process_#{name}_directive", true)
        directives << [index + 1, name, *args]
        # Replace directive line with a clean break
        line = "\n"
      end
    end
    processed_header << line
  end
  return processed_header.chomp, directives
end

def initialize(options = {})

def initialize(options = {})
  @header_pattern = compile_header_pattern(Array(options[:comments]))
end

def link_paths(paths, deps, accept)

def link_paths(paths, deps, accept)
  resolve_paths(paths, deps, accept: accept) do |uri|
    @links << load(uri).uri
  end
end

def load(uri)

def load(uri)
  asset = @environment.load(uri)
  @dependencies.merge(asset.metadata[:dependencies])
  asset
end

def process_depend_on_asset_directive(path)


//= depend_on_asset "bar.js"

Unlike `depend_on`, the path must be a requirable asset.

source file.
invalid the asset dependency will invalidate the cache our the
This is used for caching purposes. Any changes that would

it.
Allows you to state a dependency on an asset without including
def process_depend_on_asset_directive(path)
  load(resolve(path))
end

def process_depend_on_directive(path)


//= depend_on "foo.png"

in contents from another file.
This is useful if you are using ERB and File.read to pull

source file.
the dependency file will invalidate the cache of the
This is used for caching purposes. Any changes made to

including it.
Allows you to state a dependency on a file without
def process_depend_on_directive(path)
  resolve(path)
end

def process_directives(directives)


env.register_processor('text/css', DirectiveProcessor)
env.unregister_processor('text/css', Sprockets::DirectiveProcessor)

Replace the current processor on the environment with your own:

end
end
end
require(filename)
Dir["#{dirname}/#{glob}"].sort.each do |filename|
def process_require_glob_directive
class DirectiveProcessor < Sprockets::DirectiveProcessor

`process_require_glob_directive`.
`Sprockets::DirectiveProcessor`, then add a method called
To implement a custom directive called `require_glob`, subclass

processor.
automatically be available. This makes it easy to extend the
Any directive method matching `process_*_directive` will
Gathers comment directives in the source and processes them.
def process_directives(directives)
  directives.each do |line_number, name, *args|
    begin
      send("process_#{name}_directive", *args)
    rescue Exception => e
      e.set_backtrace(["#{@filename}:#{line_number}"] + e.backtrace)
      raise e
    end
  end
end

def process_link_directive(path)


/*= link "logo.png" */

current.
bundle. Any linked assets will automatically be compiled along with the
The `path` must be a valid asset and should not already be part of the

Declares a linked dependency on the target asset.
def process_link_directive(path)
  @links << load(resolve(path)).uri
end

def process_link_directory_directive(path = ".", accept = nil)


//= link_directory "./scripts" .js

extension or content type in these cases
Use caution when linking against JS or CSS assets. Include an explicit

//= link_directory "./fonts"

nested directories.
directory. It's similar to `path/*` since it does not follow
`link_directory` links all the files inside a single
def process_link_directory_directive(path = ".", accept = nil)
  path = expand_relative_dirname(:link_directory, path)
  accept = expand_accept_shorthand(accept)
  link_paths(*@environment.stat_directory_with_dependencies(path), accept)
end

def process_link_tree_directive(path = ".", accept = nil)


//= link_tree "./styles" .css

extension or content type in these cases
Use caution when linking against JS or CSS assets. Include an explicit

//= link_tree "./images"

Its glob equivalent is `path/**/*`.
`link_tree` links all the nested files in a directory.
def process_link_tree_directive(path = ".", accept = nil)
  path = expand_relative_dirname(:link_tree, path)
  accept = expand_accept_shorthand(accept)
  link_paths(*@environment.stat_sorted_tree_with_dependencies(path), accept)
end

def process_require_directive(path)


//= require "./bar"

path:
Relative paths work too. Use a leading `./` to denote a relative

//= require "foo"

assumes you are requiring another ".js".
Extensions are optional. If your source file is ".js", it

//= require "foo.js"

`require` works with files in the environment path:

and ensures its only loaded once before the source file.
It provides a way to declare a dependency on a file in your path
The `require` directive functions similar to Ruby's own `require`.
def process_require_directive(path)
  @required << resolve(path, accept: @content_type, pipeline: :self)
end

def process_require_directory_directive(path = ".")


//= require_directory "./javascripts"

nested directories.
directory. It's similar to `path/*` since it does not follow
`require_directory` requires all the files inside a single
def process_require_directory_directive(path = ".")
  path = expand_relative_dirname(:require_directory, path)
  require_paths(*@environment.stat_directory_with_dependencies(path))
end

def process_require_self_directive


*/
*= require_tree .
*= require_self
/*= require "reset"

be defined before other dependencies are loaded.
it's common for the index file to contain global styles that need to
before any subsequent `require` directives. Useful in CSS files, where
`require_self` causes the body of the current file to be inserted
def process_require_self_directive
  if @required.include?(@uri)
    raise ArgumentError, "require_self can only be called once per source file"
  end
  @required << @uri
end

def process_require_tree_directive(path = ".")


//= require_tree "./public"

Its glob equivalent is `path/**/*`.
`require_tree` requires all the nested files in a directory.
def process_require_tree_directive(path = ".")
  path = expand_relative_dirname(:require_tree, path)
  require_paths(*@environment.stat_sorted_tree_with_dependencies(path))
end

def process_source(source)

def process_source(source)
  header = source[@header_pattern, 0] || ""
  body   = $' || source
  header, directives = extract_directives(header)
  data = ""
  data.force_encoding(body.encoding)
  data << header << "\n" unless header.empty?
  data << body
  # Ensure body ends in a new line
  data << "\n" if data.length > 0 && data[-1] != "\n"
  return data, directives
end

def process_stub_directive(path)


//= stub "jquery"

can't be brought back by any other `require`.
be part of the bundle. Once stubbed, it is blacklisted and
The `path` must be a valid asset and may or may not already

Allows dependency to be excluded from the asset bundle.
def process_stub_directive(path)
  @stubbed << resolve(path, accept: @content_type, pipeline: :self)
end

def require_paths(paths, deps)

def require_paths(paths, deps)
  resolve_paths(paths, deps, accept: @content_type, pipeline: :self) do |uri|
    @required << uri
  end
end

def resolve(path, options = {})

def resolve(path, options = {})
  # Prevent absolute paths in directives
  if @environment.absolute_path?(path)
    raise FileOutsidePaths, "can't require absolute file: #{path}"
  end
  uri, deps = @environment.resolve!(path, options.merge(base_path: @dirname))
  @dependencies.merge(deps)
  uri
end

def resolve_paths(paths, deps, options = {})

def resolve_paths(paths, deps, options = {})
  @dependencies.merge(deps)
  paths.each do |subpath, stat|
    next if subpath == @filename || stat.directory?
    uri, deps = @environment.resolve(subpath, options.merge(compat: false))
    @dependencies.merge(deps)
    yield uri if uri
  end
end