lib/tilt.rb in tilt-1.0.1 vs lib/tilt.rb in tilt-1.1
- old
+ new
@@ -1,9 +1,9 @@
require 'digest/md5'
module Tilt
- VERSION = '1.0.1'
+ VERSION = '1.1'
@template_mappings = {}
# Hash of template path pattern => template implementation class mappings.
def self.mappings
@@ -57,11 +57,11 @@
def __tilt__
end
end
# Base class for template implementations. Subclasses must implement
- # the #prepare method and one of the #evaluate or #evaluate_source
+ # the #prepare method and one of the #evaluate or #precompiled_template
# methods.
class Template
# Template source; loaded from a file or given directly.
attr_reader :data
@@ -280,17 +280,22 @@
"__tilt_#{digest}"
end
def compile_template_method(method_name, locals)
source, offset = precompiled(locals)
- offset += 1
- CompileSite.module_eval <<-RUBY, eval_file, line - offset
+ offset += 5
+ CompileSite.class_eval <<-RUBY, eval_file, line - offset
def #{method_name}(locals)
- #{source}
+ Thread.current[:tilt_vars] = [self, locals]
+ class << self
+ this, locals = Thread.current[:tilt_vars]
+ this.instance_eval do
+ #{source}
+ end
+ end
end
RUBY
-
ObjectSpace.define_finalizer self,
Template.compiled_template_method_remover(CompileSite, method_name)
end
def self.compiled_template_method_remover(site, method_name)
@@ -304,10 +309,31 @@
rescue NameError
# method was already removed (ruby >= 1.9)
end
end
end
+
+ # Special case Ruby 1.9.1's broken yield.
+ #
+ # http://github.com/rtomayko/tilt/commit/20c01a5
+ # http://redmine.ruby-lang.org/issues/show/3601
+ #
+ # Remove when 1.9.2 dominates 1.9.1 installs in the wild.
+ if RUBY_VERSION =~ /^1.9.1/
+ undef compile_template_method
+ def compile_template_method(method_name, locals)
+ source, offset = precompiled(locals)
+ offset += 1
+ CompileSite.module_eval <<-RUBY, eval_file, line - offset
+ def #{method_name}(locals)
+ #{source}
+ end
+ RUBY
+ ObjectSpace.define_finalizer self,
+ Template.compiled_template_method_remover(CompileSite, method_name)
+ end
+ end
end
# 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):
@@ -526,15 +552,23 @@
@output ||= @engine.render
end
private
def sass_options
- options.merge(:filename => eval_file, :line => line)
+ options.merge(:filename => eval_file, :line => line, :syntax => :sass)
end
end
register 'sass', SassTemplate
+ # Sass's new .scss type template implementation.
+ class ScssTemplate < SassTemplate
+ private
+ def sass_options
+ options.merge(:filename => eval_file, :line => line, :syntax => :scss)
+ end
+ end
+ register 'scss', ScssTemplate
# Lessscss template implementation. See:
# http://lesscss.org/
#
# Less templates do not support object scopes, locals, or yield.
@@ -553,10 +587,69 @@
end
end
register 'less', LessTemplate
+ # CoffeeScript template implementation. See:
+ # http://coffeescript.org/
+ #
+ # CoffeeScript templates do not support object scopes, locals, or yield.
+ class CoffeeScriptTemplate < Template
+ @@default_no_wrap = false
+
+ def self.default_no_wrap
+ @@default_no_wrap
+ end
+
+ def self.default_no_wrap=(value)
+ @@default_no_wrap = value
+ end
+
+ def initialize_engine
+ return if defined? ::CoffeeScript
+ require_template_library 'coffee_script'
+ end
+
+ def prepare
+ @no_wrap = options.key?(:no_wrap) ? options[:no_wrap] :
+ self.class.default_no_wrap
+ end
+
+ def evaluate(scope, locals, &block)
+ @output ||= CoffeeScript.compile(data, :no_wrap => @no_wrap)
+ end
+ end
+ register 'coffee', CoffeeScriptTemplate
+
+
+ # Nokogiri template implementation. See:
+ # http://nokogiri.org/
+ class NokogiriTemplate < Template
+ def initialize_engine
+ return if defined?(::Nokogiri)
+ require_template_library 'nokogiri'
+ end
+
+ def prepare; end
+
+ def evaluate(scope, locals, &block)
+ xml = ::Nokogiri::XML::Builder.new
+ if data.respond_to?(:to_str)
+ locals[:xml] = xml
+ super(scope, locals, &block)
+ elsif data.kind_of?(Proc)
+ data.call(xml)
+ end
+ xml.to_xml
+ end
+
+ def precompiled_template(locals)
+ data.to_str
+ end
+ end
+ register 'nokogiri', NokogiriTemplate
+
# Builder template implementation. See:
# http://builder.rubyforge.org/
class BuilderTemplate < Template
def initialize_engine
return if defined?(::Builder)
@@ -727,6 +820,49 @@
parser = Radius::Parser.new(context, options)
parser.parse(data)
end
end
register 'radius', RadiusTemplate
+
+
+ # Markaby
+ # http://github.com/markaby/markaby
+ class MarkabyTemplate < Template
+ def self.builder_class
+ @builder_class ||= Class.new(Markaby::Builder) do
+ def __capture_markaby_tilt__(&block)
+ __run_markaby_tilt__ do
+ text capture(&block)
+ end
+ end
+ end
+ end
+
+ def initialize_engine
+ return if defined? ::Markaby
+ require_template_library 'markaby'
+ end
+
+ def prepare
+ end
+
+ def evaluate(scope, locals, &block)
+ builder = self.class.builder_class.new({}, scope)
+ builder.locals = locals
+
+ if block
+ builder.instance_eval <<-CODE, __FILE__, __LINE__
+ def __run_markaby_tilt__
+ #{data}
+ end
+ CODE
+
+ builder.__capture_markaby_tilt__(&block)
+ else
+ builder.instance_eval(data, __FILE__, __LINE__)
+ end
+
+ builder.to_s
+ end
+ end
+ register 'mab', MarkabyTemplate
end