Class: Sprockets::DirectiveProcessor

Inherits:
Tilt::Template
  • Object
show all
Defined in:
lib/sprockets/directive_processor.rb

Overview

The ‘DirectiveProcessor` is responsible for parsing and evaluating directive comments in a source file.

A directive comment starts with a comment prefix, followed by an “=”, then the directive name, then any arguments.

// JavaScript
//= require "foo"

# CoffeeScript
#= require "bar"

/* CSS
 *= require "baz"
 */

The Processor is implemented as a ‘Tilt::Template` and is loosely coupled to Sprockets. This makes it possible to disable or modify the processor to do whatever you’d like. You could add your own custom directives or invent your own directive syntax.

‘Environment#processors` includes `DirectiveProcessor` by default.

To remove the processor entirely:

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

Then inject your own preprocessor:

env.register_processor('text/css', MyProcessor)

Constant Summary collapse

HEADER_PATTERN =

Directives will only be picked up if they are in the header of the source file. C style (/* */), JavaScript (//), and Ruby (#) comments are supported.

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

/
  \A (
    (?m:\s*) (
      (\/\* (?m:.*?) \*\/) |
      (\#\#\# (?m:.*?) \#\#\#) |
      (\/\/ .* \n?)+ |
      (\# .* \n?)+
    )
  )+
/x
DIRECTIVE_PATTERN =

Directives are denoted by a ‘=` followed by the name, then argument list.

A few different styles are allowed:

// =require foo
//= require foo
//= require "foo"
/
  ^ \W* = \s* (\w+.*?) (\*\/)? $
/x

Instance Attribute Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



72
73
74
# File 'lib/sprockets/directive_processor.rb', line 72

def body
  @body
end

#headerObject (readonly)

Returns the value of attribute header.



72
73
74
# File 'lib/sprockets/directive_processor.rb', line 72

def header
  @header
end

#pathnameObject (readonly)

Returns the value of attribute pathname.



71
72
73
# File 'lib/sprockets/directive_processor.rb', line 71

def pathname
  @pathname
end

Instance Method Details

#directivesObject

Returns an Array of directive structures. Each structure is an Array with the line number as the first element, the directive name as the second element, followed by any arguments.

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


127
128
129
130
131
132
133
134
135
136
# File 'lib/sprockets/directive_processor.rb', line 127

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", true)
        [index + 1, name, *args]
      end
    end
  }.compact
end

#evaluate(context, locals, &block) ⇒ Object

Implemented for Tilt#render.

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



91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/sprockets/directive_processor.rb', line 91

def evaluate(context, locals, &block)
  @context = context

  @result = ""
  @result.force_encoding(body.encoding) if body.respond_to?(:encoding)

  @has_written_body = false

  process_directives
  process_source

  @result
end

#prepareObject



74
75
76
77
78
79
80
81
82
83
84
# File 'lib/sprockets/directive_processor.rb', line 74

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

#processed_headerObject

Returns the header String with any directives stripped.



106
107
108
109
110
111
112
113
# File 'lib/sprockets/directive_processor.rb', line 106

def processed_header
  lineno = 0
  @processed_header ||= header.lines.map { |line|
    lineno += 1
    # Replace directive line with a clean break
    directives.assoc(lineno) ? "\n" : line
  }.join.chomp
end

#processed_sourceObject

Returns the source String with any directives stripped.



116
117
118
# File 'lib/sprockets/directive_processor.rb', line 116

def processed_source
  @processed_source ||= processed_header + body
end