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