module Sinatra::Templates

def builder(template=nil, options={}, locals={}, &block)

def builder(template=nil, options={}, locals={}, &block)
  require_warn('Builder') unless defined?(::Builder)
  options, template = template, nil if template.is_a?(Hash)
  template = lambda { block } if template.nil?
  render :builder, template, options, locals
end

def erb(template, options={}, locals={})

def erb(template, options={}, locals={})
  require_warn('ERB') unless defined?(::ERB)
  render :erb, template, options, locals
end

def haml(template, options={}, locals={})

def haml(template, options={}, locals={})
  require_warn('Haml') unless defined?(::Haml::Engine)
  render :haml, template, options, locals
end

def lookup_layout(engine, template, views_dir)

def lookup_layout(engine, template, views_dir)
  lookup_template(engine, template, views_dir)
rescue Errno::ENOENT
  nil
end

def lookup_template(engine, template, views_dir, filename = nil, line = nil)

def lookup_template(engine, template, views_dir, filename = nil, line = nil)
  case template
  when Symbol
    if cached = self.class.templates[template]
      lookup_template(engine, cached[:template], views_dir, cached[:filename], cached[:line])
    else
      path = ::File.join(views_dir, "#{template}.#{engine}")
      [ ::File.read(path), path, 1 ]
    end
  when Proc
    filename, line = self.class.caller_locations.first if filename.nil?
    [ template.call, filename, line.to_i ]
  when String
    filename, line = self.class.caller_locations.first if filename.nil?
    [ template, filename, line.to_i ]
  else
    raise ArgumentError
  end
end

def render(engine, template, options={}, locals={})

def render(engine, template, options={}, locals={})
  # merge app-level options
  options = self.class.send(engine).merge(options) if self.class.respond_to?(engine)
  # extract generic options
  layout = options.delete(:layout)
  layout = :layout if layout.nil? || layout == true
  views = options.delete(:views) || self.class.views || "./views"
  locals = options.delete(:locals) || locals || {}
  # render template
  data, options[:filename], options[:line] = lookup_template(engine, template, views)
  output = __send__("render_#{engine}", template, data, options, locals)
  # render layout
  if layout
    data, options[:filename], options[:line] = lookup_layout(engine, layout, views)
    if data
      output = __send__("render_#{engine}", layout, data, options, locals) { output }
    end
  end
  output
end

def render_builder(template, data, options, locals, &block)

def render_builder(template, data, options, locals, &block)
  options = { :indent => 2 }.merge(options)
  filename = options.delete(:filename) || '<BUILDER>'
  line = options.delete(:line) || 1
  xml = ::Builder::XmlMarkup.new(options)
  if data.respond_to?(:to_str)
    eval data.to_str, binding, filename, line
  elsif data.kind_of?(Proc)
    data.call(xml)
  end
  xml.target!
end

def render_erb(template, data, options, locals, &block)

def render_erb(template, data, options, locals, &block)
  original_out_buf = defined?(@_out_buf) && @_out_buf
  data = data.call if data.kind_of? Proc
  instance = ::ERB.new(data, nil, nil, '@_out_buf')
  locals_assigns = locals.to_a.collect { |k,v| "#{k} = locals[:#{k}]" }
  filename = options.delete(:filename) || '(__ERB__)'
  line = options.delete(:line) || 1
  line -= 1 if instance.src =~ /^#coding:/
  render_binding = binding
  eval locals_assigns.join("\n"), render_binding
  eval instance.src, render_binding, filename, line
  @_out_buf, result = original_out_buf, @_out_buf
  result
end

def render_haml(template, data, options, locals, &block)

def render_haml(template, data, options, locals, &block)
  ::Haml::Engine.new(data, options).render(self, locals, &block)
end

def render_sass(template, data, options, locals, &block)

def render_sass(template, data, options, locals, &block)
  ::Sass::Engine.new(data, options).render
end

def require_warn(engine)

def require_warn(engine)
  warn "Auto-require of #{engine} is deprecated; add require '#{engine}' to your app."
  require engine.downcase
end

def sass(template, options={}, locals={})

def sass(template, options={}, locals={})
  require_warn('Sass') unless defined?(::Sass::Engine)
  options[:layout] = false
  render :sass, template, options, locals
end