mirror of
https://github.com/sinatra/sinatra
synced 2023-03-27 23:18:01 -04:00
Upgrade Tilt to 0.4
This commit is contained in:
parent
20f6d0a156
commit
f6aaadf082
1 changed files with 141 additions and 26 deletions
|
@ -1,5 +1,5 @@
|
|||
module Tilt
|
||||
VERSION = '0.3'
|
||||
VERSION = '0.4'
|
||||
|
||||
@template_mappings = {}
|
||||
|
||||
|
@ -67,6 +67,9 @@ module Tilt
|
|||
# default, template data is read from the file specified. When a block
|
||||
# is given, it should read template data and return as a String. When
|
||||
# file is nil, a block is required.
|
||||
#
|
||||
# The #initialize_engine method is called if this is the very first
|
||||
# time this template subclass has been initialized.
|
||||
def initialize(file=nil, line=1, options={}, &block)
|
||||
raise ArgumentError, "file or block required" if file.nil? && block.nil?
|
||||
options, line = line, 1 if line.is_a?(Hash)
|
||||
|
@ -74,8 +77,22 @@ module Tilt
|
|||
@line = line || 1
|
||||
@options = options || {}
|
||||
@reader = block || lambda { |t| File.read(file) }
|
||||
|
||||
if !self.class.engine_initialized
|
||||
initialize_engine
|
||||
self.class.engine_initialized = true
|
||||
end
|
||||
end
|
||||
|
||||
# Called once and only once for each template subclass the first time
|
||||
# the template class is initialized. This should be used to require the
|
||||
# underlying template library and perform any initial setup.
|
||||
def initialize_engine
|
||||
end
|
||||
@engine_initialized = false
|
||||
class << self ; attr_accessor :engine_initialized ; end
|
||||
|
||||
|
||||
# Load template source and compile the template. The template is
|
||||
# loaded and compiled the first time this method is called; subsequent
|
||||
# calls are no-ops.
|
||||
|
@ -150,14 +167,19 @@ module Tilt
|
|||
end
|
||||
end
|
||||
|
||||
# Extremely simple template cache implementation.
|
||||
# Extremely simple template cache implementation. Calling applications
|
||||
# create a Tilt::Cache instance and use #fetch with any set of hashable
|
||||
# arguments (such as those to Tilt.new):
|
||||
# cache = Tilt::Cache.new
|
||||
# cache.fetch(path, line, options) { Tilt.new(path, line, options) }
|
||||
#
|
||||
# Subsequent invocations return the already compiled template object.
|
||||
class Cache
|
||||
def initialize
|
||||
@cache = {}
|
||||
end
|
||||
|
||||
def fetch(*key)
|
||||
key = key.map { |part| part.to_s }.join(":")
|
||||
@cache[key] ||= yield
|
||||
end
|
||||
|
||||
|
@ -187,8 +209,11 @@ module Tilt
|
|||
# ERB template implementation. See:
|
||||
# http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
|
||||
class ERBTemplate < Template
|
||||
def initialize_engine
|
||||
require_template_library 'erb' unless defined? ::ERB
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'erb' unless defined?(::ERB)
|
||||
@engine = ::ERB.new(data, options[:safe], options[:trim], '@_out_buf')
|
||||
end
|
||||
|
||||
|
@ -229,11 +254,25 @@ module Tilt
|
|||
# Erubis template implementation. See:
|
||||
# http://www.kuwata-lab.com/erubis/
|
||||
class ErubisTemplate < ERBTemplate
|
||||
def initialize_engine
|
||||
require_template_library 'erubis' unless defined? ::Erubis
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'erubis' unless defined?(::Erubis)
|
||||
Erubis::Eruby.class_eval(%Q{def add_preamble(src) src << "@_out_buf = _buf = '';" end})
|
||||
@engine = ::Erubis::Eruby.new(data, options)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Erubis doesn't have ERB's line-off-by-one under 1.9 problem. Override
|
||||
# and adjust back.
|
||||
if RUBY_VERSION >= '1.9.0'
|
||||
def local_assignment_code(locals)
|
||||
source, offset = super
|
||||
[source, offset - 1]
|
||||
end
|
||||
end
|
||||
end
|
||||
register 'erubis', ErubisTemplate
|
||||
|
||||
|
@ -241,8 +280,11 @@ module Tilt
|
|||
# Haml template implementation. See:
|
||||
# http://haml.hamptoncatlin.com/
|
||||
class HamlTemplate < Template
|
||||
def initialize_engine
|
||||
require_template_library 'haml' unless defined? ::Haml::Engine
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'haml' unless defined?(::Haml::Engine)
|
||||
@engine = ::Haml::Engine.new(data, haml_options)
|
||||
end
|
||||
|
||||
|
@ -263,8 +305,11 @@ module Tilt
|
|||
#
|
||||
# Sass templates do not support object scopes, locals, or yield.
|
||||
class SassTemplate < Template
|
||||
def initialize_engine
|
||||
require_template_library 'sass' unless defined? ::Sass::Engine
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'sass' unless defined?(::Sass::Engine)
|
||||
@engine = ::Sass::Engine.new(data, sass_options)
|
||||
end
|
||||
|
||||
|
@ -283,10 +328,13 @@ module Tilt
|
|||
# Builder template implementation. See:
|
||||
# http://builder.rubyforge.org/
|
||||
class BuilderTemplate < Template
|
||||
def compile!
|
||||
def initialize_engine
|
||||
require_template_library 'builder' unless defined?(::Builder)
|
||||
end
|
||||
|
||||
def compile!
|
||||
end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
xml = ::Builder::XmlMarkup.new(:indent => 2)
|
||||
if data.respond_to?(:to_str)
|
||||
|
@ -308,29 +356,57 @@ module Tilt
|
|||
# Liquid template implementation. See:
|
||||
# http://liquid.rubyforge.org/
|
||||
#
|
||||
# LiquidTemplate does not support scopes or yield blocks.
|
||||
# Liquid is designed to be a *safe* template system and threfore
|
||||
# does not provide direct access to execuatable scopes. In order to
|
||||
# support a +scope+, the +scope+ must be able to represent itself
|
||||
# as a hash by responding to #to_h. If the +scope+ does not respond
|
||||
# to #to_h it will be ignored.
|
||||
#
|
||||
# LiquidTemplate does not support yield blocks.
|
||||
#
|
||||
# It's suggested that your program require 'liquid' at load
|
||||
# time when using this template engine.
|
||||
class LiquidTemplate < Template
|
||||
def initialize_engine
|
||||
require_template_library 'liquid' unless defined? ::Liquid::Template
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'liquid' unless defined?(::Liquid::Template)
|
||||
@engine = ::Liquid::Template.parse(data)
|
||||
end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
locals = locals.inject({}) { |hash,(k,v)| hash[k.to_s] = v ; hash }
|
||||
locals = locals.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
|
||||
if scope.respond_to?(:to_h)
|
||||
scope = scope.to_h.inject({}){ |h,(k,v)| h[k.to_s] = v ; h }
|
||||
locals = scope.merge(locals)
|
||||
end
|
||||
# TODO: Is it possible to lazy yield ?
|
||||
locals['yield'] = block.nil? ? '' : yield
|
||||
locals['content'] = block.nil? ? '' : yield
|
||||
@engine.render(locals)
|
||||
end
|
||||
end
|
||||
register 'liquid', LiquidTemplate
|
||||
|
||||
|
||||
# Discount Markdown implementation.
|
||||
# Discount Markdown implementation. See:
|
||||
# http://github.com/rtomayko/rdiscount
|
||||
#
|
||||
# RDiscount is a simple text filter. It does not support +scope+ or
|
||||
# +locals+. The +:smart+ and +:filter_html+ options may be set true
|
||||
# to enable those flags on the underlying RDiscount object.
|
||||
class RDiscountTemplate < Template
|
||||
def flags
|
||||
[:smart, :filter_html].select { |flag| options[flag] }
|
||||
end
|
||||
|
||||
def initialize_engine
|
||||
require_template_library 'rdiscount' unless defined? ::RDiscount
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'rdiscount' unless defined?(::RDiscount)
|
||||
@engine = RDiscount.new(data)
|
||||
@engine = RDiscount.new(data, *flags)
|
||||
end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
|
@ -338,9 +414,28 @@ module Tilt
|
|||
end
|
||||
end
|
||||
register 'markdown', RDiscountTemplate
|
||||
register 'mkd', RDiscountTemplate
|
||||
register 'md', RDiscountTemplate
|
||||
|
||||
|
||||
# RedCloth implementation. See:
|
||||
# http://redcloth.org/
|
||||
class RedClothTemplate < Template
|
||||
def initialize_engine
|
||||
require_template_library 'redcloth' unless defined? ::RedCloth
|
||||
end
|
||||
|
||||
def compile!
|
||||
@engine = RedCloth.new(data)
|
||||
end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
@engine.to_html
|
||||
end
|
||||
end
|
||||
register 'textile', RedClothTemplate
|
||||
|
||||
|
||||
# Mustache is written and maintained by Chris Wanstrath. See:
|
||||
# http://github.com/defunkt/mustache
|
||||
#
|
||||
|
@ -350,17 +445,13 @@ module Tilt
|
|||
class MustacheTemplate < Template
|
||||
attr_reader :engine
|
||||
|
||||
# Locates and compiles the Mustache object used to create new views. The
|
||||
def initialize_engine
|
||||
require_template_library 'mustache' unless defined? ::Mustache
|
||||
end
|
||||
|
||||
def compile!
|
||||
require_template_library 'mustache' unless defined?(::Mustache)
|
||||
|
||||
# Set the Mustache view namespace if we can
|
||||
Mustache.view_namespace = options[:namespace]
|
||||
|
||||
# Figure out which Mustache class to use.
|
||||
@engine = options[:view] || Mustache.view_class(name)
|
||||
|
||||
# set options on the view class
|
||||
options.each do |key, value|
|
||||
next if %w[view namespace mustaches].include?(key.to_s)
|
||||
@engine.send("#{key}=", value) if @engine.respond_to? "#{key}="
|
||||
|
@ -368,20 +459,19 @@ module Tilt
|
|||
end
|
||||
|
||||
def evaluate(scope=nil, locals={}, &block)
|
||||
# Create a new instance for playing with
|
||||
instance = @engine.new
|
||||
|
||||
# Copy instance variables from scope to the view
|
||||
# copy instance variables from scope to the view
|
||||
scope.instance_variables.each do |name|
|
||||
instance.instance_variable_set(name, scope.instance_variable_get(name))
|
||||
end
|
||||
|
||||
# Locals get added to the view's context
|
||||
# locals get added to the view's context
|
||||
locals.each do |local, value|
|
||||
instance[local] = value
|
||||
end
|
||||
|
||||
# If we're passed a block it's a subview. Sticking it in yield
|
||||
# if we're passed a block it's a subview. Sticking it in yield
|
||||
# lets us use {{yield}} in layout.html to render the actual page.
|
||||
instance[:yield] = block.call if block
|
||||
|
||||
|
@ -391,4 +481,29 @@ module Tilt
|
|||
end
|
||||
end
|
||||
register 'mustache', MustacheTemplate
|
||||
|
||||
# RDoc template. See:
|
||||
# http://rdoc.rubyforge.org/
|
||||
#
|
||||
# It's suggested that your program require 'rdoc/markup' and
|
||||
# 'rdoc/markup/to_html' at load time when using this template
|
||||
# engine.
|
||||
class RDocTemplate < Template
|
||||
def initialize_engine
|
||||
unless defined?(::RDoc::Markup)
|
||||
require_template_library 'rdoc/markup'
|
||||
require_template_library 'rdoc/markup/to_html'
|
||||
end
|
||||
end
|
||||
|
||||
def compile!
|
||||
markup = RDoc::Markup::ToHtml.new
|
||||
@engine = markup.convert(data)
|
||||
end
|
||||
|
||||
def evaluate(scope, locals, &block)
|
||||
@engine.to_s
|
||||
end
|
||||
end
|
||||
register 'rdoc', RDocTemplate
|
||||
end
|
||||
|
|
Loading…
Reference in a new issue