class Sass::Engine

puts output
output = sass_engine.render
sass_engine = Sass::Engine.new(template)
template = File.load(‘stylesheets/sassy.sass’)
new instance and calling render to render the template. For example:
template is done. It can be directly used by the user by creating a
This is the class where all the parsing and processing of the Sass

def self.find_file_to_import(filename, load_paths)

def self.find_file_to_import(filename, load_paths)
  was_sass = false
  original_filename = filename
  if filename[-5..-1] == ".sass"
    filename = filename[0...-5]
    was_sass = true
  elsif filename[-4..-1] == ".css"
    return filename
  end
  new_filename = find_full_path("#{filename}.sass", load_paths)
  if new_filename.nil?
    if was_sass
      raise Exception.new("File to import not found or unreadable: #{original_filename}.")
    else
      return filename + '.css'
    end
  else
    new_filename
  end
end

def self.find_full_path(filename, load_paths)

def self.find_full_path(filename, load_paths)
  load_paths.each do |path|
    ["_#{filename}", filename].each do |name|
      full_path = File.join(path, name)
      if File.readable?(full_path)
        return full_path
      end
    end
  end
  nil
end

def build_tree(index)

def build_tree(index)
  line, tabs = @lines[index]
  index += 1
  @line = index
  node = parse_line(line)
  has_children = has_children?(index, tabs)
  # Node is a symbol if it's non-outputting, like a constant assignment
  unless node.is_a? Tree::Node
    if has_children
      if node == :constant
        raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath constants.", @line + 1)
      elsif node.is_a? Array
        # arrays can either be full of import statements
        # or attributes from mixin includes
        # in either case they shouldn't have children.
        # Need to peek into the array in order to give meaningful errors
        directive_type = (node.first.is_a?(Tree::DirectiveNode) ? "import" : "mixin")
        raise SyntaxError.new("Illegal nesting: Nothing may be nested beneath #{directive_type} directives.", @line + 1)
      end
    end
    index = @line if node == :mixin
    return node, index
  end
  node.line = @line
  if node.is_a? Tree::CommentNode
    while has_children
      line, index = raw_next_line(index)
      node << line
      has_children = has_children?(index, tabs)
    end
    return node, index
  end
  # Resolve multiline rules
  if node.is_a?(Tree::RuleNode)
    if node.continued?
      child, index = build_tree(index) if @lines[old_index = index]
      if @lines[old_index].nil? || has_children?(old_index, tabs) || !child.is_a?(Tree::RuleNode)
        raise SyntaxError.new("Rules can't end in commas.", @line)
      end
      node.add_rules child
    end
    node.children = child.children if child
  end
  while has_children
    child, index = build_tree(index)
    validate_and_append_child(node, child)
    has_children = has_children?(index, tabs)
  end
  return node, index
end

def constants

def constants
  @constants
end

def count_tabs(line)

Counts the tabulation of a line.
def count_tabs(line)
  return nil if line.strip.empty?
  return nil unless spaces = line.index(/[^ ]/)
  if spaces % 2 == 1
      raise SyntaxError.new(<<END.strip, @line)
aces} space#{spaces == 1 ? ' was' : 's were'} used for indentation. Sass must be indented using two spaces.
  elsif line[spaces] == ?\t
    raise SyntaxError.new(<<END.strip, @line)
b character was used for indentation. Sass must be indented using two spaces.
you sure you have soft tabs enabled in your editor?
  end
  spaces / 2
end

def has_children?(index, tabs)

def has_children?(index, tabs)
  next_line = ['//', 0]
  while !next_line.nil? && next_line[0] == '//' && next_line[1] = 0
    next_line = @lines[index]
    index += 1
  end
  next_line && next_line[1] > tabs
end

def import(files)

def import(files)
  nodes = []
  files.split(/,\s*/).each do |filename|
    engine = nil
    begin
      filename = self.class.find_file_to_import(filename, @options[:load_paths])
    rescue Exception => e
      raise SyntaxError.new(e.message, @line)
    end
    if filename =~ /\.css$/
      nodes << Tree::DirectiveNode.new("@import url(#{filename})", @options[:style])
    else
      File.open(filename) do |file|
        new_options = @options.dup
        new_options[:filename] = filename
        engine = Sass::Engine.new(file.read, @options)
      end
      engine.constants.merge! @constants
      engine.mixins.merge! @mixins
      begin
        root = engine.render_to_tree
      rescue Sass::SyntaxError => err
        err.add_backtrace_entry(filename)
        raise err
      end
      root.children.each do |child|
        child.filename = filename
        nodes << child
      end
      @constants = engine.constants
      @mixins = engine.mixins
    end
  end
  nodes
end

def initialize(template, options={})


++
to README.rdoc!
When adding options, remember to add information about them

TODO: Add current options to REFRENCE. Remember :filename!

--

See README.rdoc for available options.
template string when render is called.
Creates a new instace of Sass::Engine that will compile the given
def initialize(template, options={})
  @options = {
    :style => :nested,
    :load_paths => ['.']
  }.merge! options
  @template = template.split(/\r\n|\r|\n/)
  @lines = []
  @constants = {"important" => "!important"}
  @mixins = {}
end

def mixins

def mixins
  @mixins
end

def parse_attribute(line, attribute_regx)

def parse_attribute(line, attribute_regx)
  if @options[:attribute_syntax] == :normal &&
      attribute_regx == ATTRIBUTE_ALTERNATE
    raise SyntaxError.new("Illegal attribute syntax: can't use alternate syntax when :attribute_syntax => :normal is set.")
  elsif @options[:attribute_syntax] == :alternate &&
      attribute_regx == ATTRIBUTE
    raise SyntaxError.new("Illegal attribute syntax: can't use normal syntax when :attribute_syntax => :alternate is set.")
  end
  name, eq, value = line.scan(attribute_regx)[0]
  if name.nil? || value.nil?
    raise SyntaxError.new("Invalid attribute: \"#{line}\".", @line)
  end
  if eq.strip[0] == SCRIPT_CHAR
    value = Sass::Constant.parse(value, @constants, @line).to_s
  end
  Tree::AttrNode.new(name, value, @options[:style])
end

def parse_comment(line)

def parse_comment(line)
  if line[1] == SASS_COMMENT_CHAR
    :comment
  elsif line[1] == CSS_COMMENT_CHAR
    Tree::CommentNode.new(line, @options[:style])
  else
    Tree::RuleNode.new(line, @options[:style])
  end
end

def parse_constant(line)

def parse_constant(line)
  name, op, value = line.scan(Sass::Constant::MATCH)[0]
  unless name && value
    raise SyntaxError.new("Invalid constant: \"#{line}\".", @line)
  end
  constant = Sass::Constant.parse(value, @constants, @line)
  if op == '||='
    @constants[name] ||= constant
  else
    @constants[name] = constant
  end
  :constant
end

def parse_directive(line)

def parse_directive(line)
  directive, value = line[1..-1].split(/\s+/, 2)
  # If value begins with url( or ",
  # it's a CSS @import rule and we don't want to touch it.
  if directive == "import" && value !~ /^(url\(|")/
    import(value)
  else
    Tree::DirectiveNode.new(line, @options[:style])
  end
end

def parse_line(line)

def parse_line(line)
  case line[0]
  when ATTRIBUTE_CHAR
    parse_attribute(line, ATTRIBUTE)
  when Constant::CONSTANT_CHAR
    parse_constant(line)
  when COMMENT_CHAR
    parse_comment(line)
  when DIRECTIVE_CHAR
    parse_directive(line)
  when ESCAPE_CHAR
    Tree::RuleNode.new(line[1..-1], @options[:style])
  when MIXIN_DEFINITION_CHAR
    parse_mixin_definition(line)
  when MIXIN_INCLUDE_CHAR
    if line[1].nil? || line[1] == ?\s
      Tree::RuleNode.new(line, @options[:style])
    else
      parse_mixin_include(line)
    end
  else
    if line =~ ATTRIBUTE_ALTERNATE_MATCHER
      parse_attribute(line, ATTRIBUTE_ALTERNATE)
    else
      Tree::RuleNode.new(line, @options[:style])
    end
  end
end

def parse_mixin_definition(line)

def parse_mixin_definition(line)
  mixin_name = line[1..-1]
  @mixins[mixin_name] =  []
  index = @line
  line, tabs = @lines[index]
  while !line.nil? && tabs > 0
    child, index = build_tree(index)
    validate_and_append_child(@mixins[mixin_name], child)
    line, tabs = @lines[index]
  end
  :mixin
end

def parse_mixin_include(line)

def parse_mixin_include(line)
  mixin_name = line[1..-1]
  unless @mixins.has_key?(mixin_name)
    raise SyntaxError.new("Undefined mixin '#{mixin_name}'.", @line)
  end
  @mixins[mixin_name]
end

def raw_next_line(index)

def raw_next_line(index)
  [@lines[index][0], index + 1]
end

def render

Processes the template and returns the result as a string.
def render
  begin
    render_to_tree.to_s
  rescue SyntaxError => err
    unless err.sass_filename
      err.add_backtrace_entry(@options[:filename])
    end
    raise err
  end
end

def render_to_tree

def render_to_tree
  split_lines
  root = Tree::Node.new(@options[:style])
  index = 0
  while @lines[index]
    old_index = index
    child, index = build_tree(index)
    if child.is_a? Tree::Node
      child.line = old_index + 1
      root << child
    elsif child.is_a? Array
      child.each do |c|
        root << c
      end
    end
  end
  @lines.clear
  root
end

def split_lines

and computes the tabulation of the line.
Readies each line in the template for parsing,
def split_lines
  @line = 0
  old_tabs = nil
  @template.each_with_index do |line, index|
    @line += 1
    tabs = count_tabs(line)
    if line[0] == COMMENT_CHAR && line[1] == SASS_COMMENT_CHAR && tabs == 0
      tabs = old_tabs
    end
    if tabs # if line isn't blank
      raise SyntaxError.new("Indenting at the beginning of the document is illegal.", @line) if old_tabs.nil? && tabs > 0
      if old_tabs && tabs - old_tabs > 1
        raise SyntaxError.new("#{tabs * 2} spaces were used for indentation. Sass must be indented using two spaces.", @line)
      end
      @lines << [line.strip, tabs]
      old_tabs = tabs
    else
      @lines << ['//', old_tabs || 0]
    end
  end
  @line = nil
end

def validate_and_append_child(parent, child)

def validate_and_append_child(parent, child)
  case child
  when :constant
    raise SyntaxError.new("Constants may only be declared at the root of a document.", @line)
  when :mixin
    raise SyntaxError.new("Mixins may only be defined at the root of a document.", @line)
  when Array
    child.each do |c|
      if c.is_a?(Tree::DirectiveNode)
        raise SyntaxError.new("Import directives may only be used at the root of a document.", @line)
      end
      parent << c
    end
  when Tree::Node
    parent << child
  end
end