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.
custom directives or invent your own directive syntax.
the processor to do whatever you’d like. You could add your own
coupled to Sprockets. This makes it possible to disable or modify
The Processor is implemented as a ‘Tilt::Template` and is loosely
*/
*= 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 compat?

Checks if Sprockets 1.x compat mode enabled
def compat?
  @compat
end

def constants

compat mode is on.
constants.yml was present. This is only available if
Sprockets 1.x allowed for constant interpolation if a
def constants
  if compat?
    pathname = Pathname.new(context.root_path).join("constants.yml")
    stat(pathname) ? YAML.load_file(pathname) : {}
  else
    {}
  end
end

def directives


[[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 directives
  @directives ||= header.lines.each_with_index.map { |line, index|
    if directive = line[DIRECTIVE_PATTERN, 1]
      name, *args = Shellwords.shellwords(directive)
      if respond_to?("process_#{name}_directive")
        [index + 1, name, *args]
      end
    end
  }.compact
end

def each_entry(root, &block)

def each_entry(root, &block)
  context.environment.each_entry(root, &block)
end

def entries(path)

def entries(path)
  context.environment.entries(path)
end

def evaluate(context, locals, &block)

for the complete API.
access the environment and append to the bundle. See `Context`
`context` is a `Context` instance with methods that allow you to

Implemented for Tilt#render.
def evaluate(context, locals, &block)
  @context = context
  @result = ""
  @has_written_body = false
  process_directives
  process_source
  @result
end

def prepare

def prepare
  @pathname = Pathname.new(file)
  @header = data[HEADER_PATTERN, 0] || ""
  @body   = $' || data
  # Ensure body ends in a new line
  @body  += "\n" if @body != "" && @body !~ /\n\Z/m
  @included_pathnames = []
  @compat             = false
end

def process_compat_directive


//= compat

file in both Sprockets 1 and 2.
Makes it possible to use the same JavaScript source

Enable Sprockets 1.x compat mode.
def process_compat_directive
  @compat = true
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)
  context.depend_on_asset(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)
  context.depend_on(path)
end

def process_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["#{pathname.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.each do |line_number, name, *args|
    context.__LINE__ = line_number
    send("process_#{name}_directive", *args)
    context.__LINE__ = nil
  end
end

def process_include_directive(path)


//= include "header"

has been required.
inserts the contents of the dependency even if it already
The `include` directive works similar to `require` but
def process_include_directive(path)
  pathname = context.resolve(path)
  context.depend_on_asset(pathname)
  included_pathnames << pathname
end

def process_provide_directive(path)

not permitted.
Mutating the path when an asset is being built is
`provide` is stubbed out for Sprockets 1.x compat.
def process_provide_directive(path)
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)
  if @compat
    if path =~ /<([^>]+)>/
      path = $1
    else
      path = "./#{path}" unless relative?(path)
    end
  end
  context.require_asset(path)
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 = ".")
  if relative?(path)
    root = pathname.dirname.join(path).expand_path
    unless (stats = stat(root)) && stats.directory?
      raise ArgumentError, "require_tree argument must be a directory"
    end
    context.depend_on(root)
    entries(root).each do |pathname|
      pathname = root.join(pathname)
      if pathname.to_s == self.file
        next
      elsif context.asset_requirable?(pathname)
        context.require_asset(pathname)
      end
    end
  else
    # The path must be relative and start with a `./`.
    raise ArgumentError, "require_directory argument must be a relative path"
  end
end

def process_require_self_directive


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

before other dependencies are loaded.
index file to contain global styles that need to be defined
directives. Useful in CSS files, where it's common for the
inserted before any subsequent `require` or `include`
`require_self` causes the body of the current file to be
def process_require_self_directive
  if @has_written_body
    raise ArgumentError, "require_self can only be called once per source file"
  end
  context.require_asset(pathname)
  process_source
  included_pathnames.clear
  @has_written_body = true
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 = ".")
  if relative?(path)
    root = pathname.dirname.join(path).expand_path
    unless (stats = stat(root)) && stats.directory?
      raise ArgumentError, "require_tree argument must be a directory"
    end
    context.depend_on(root)
    each_entry(root) do |pathname|
      if pathname.to_s == self.file
        next
      elsif stat(pathname).directory?
        context.depend_on(pathname)
      elsif context.asset_requirable?(pathname)
        context.require_asset(pathname)
      end
    end
  else
    # The path must be relative and start with a `./`.
    raise ArgumentError, "require_tree argument must be a relative path"
  end
end

def process_source

def process_source
  unless @has_written_body || processed_header.empty?
    @result << processed_header << "\n"
  end
  included_pathnames.each do |pathname|
    @result << context.evaluate(pathname)
  end
  unless @has_written_body
    @result << body
  end
  if compat? && constants.any?
    @result.gsub!(/<%=(.*?)%>/) { constants[$1.strip] }
  end
end

def processed_header

Returns the header String with any directives stripped.
def processed_header
  lineno = 0
  @processed_header ||= header.lines.reject { |line|
    lineno += 1
    directives.assoc(lineno)
  }.join.chomp
end

def processed_source

Returns the source String with any directives stripped.
def processed_source
  @processed_source ||= processed_header + body
end

def relative?(path)

def relative?(path)
  path =~ /^\.($|\.?\/)/
end

def stat(path)

def stat(path)
  context.environment.stat(path)
end