lib/temple/engines/erb.rb



require 'erb'

module Temple
  module Engines
    # An engine which works in-place for ERB:
    # 
    #   require 'temple'
    #   
    #   template = Temple::Engine::ERB.new("<%= 1 + 1 %>")
    #   template.result # => "2"
    class ERB < ::ERB
      OriginalERB = ::ERB
      Optimizers = [Filters::StaticMerger.new, Filters::DynamicInliner.new]
      
      # The optional _filename_ argument passed to Kernel#eval when the ERB
      # code is run
      attr_accessor :filename
      
      # The Ruby code generated by ERB
      attr_reader :src
      
      # The sexp generated by Temple
      attr_reader :sexp
      
      # The optimized sexp generated by Temple
      attr_reader :optimized_sexp
      
      # Sets the ERB constant to Temple::Engine::ERB
      # 
      # Example:
      # 
      #   require 'temple'
      #   Temple::Engine::ERB.rock!
      #   ERB == Temple::Engine::ERB
      def self.rock!
        Object.send(:remove_const, :ERB)
        Object.send(:const_set, :ERB, self)
      end
      
      # Sets the ERB constant back to regular ERB
      # 
      # Example:
      # 
      #   require 'temple'
      #   original_erb = ERB
      #   Temple::Engine::ERB.rock!
      #   ERB.suck!
      #   ERB == original_erb
      
      def self.suck!
        Object.send(:remove_const, :ERB)
        Object.send(:const_set, :ERB, OriginalERB)
      end
      
      def initialize(str, safe_level = nil, trim_mode = nil, eoutvar = '_erbout', options = {})
        @safe_level = safe_level
        @trim_mode = trim_mode
        @parser = Parsers::ERB.new(:trim_mode => @trim_mode)
        
        @generator = options[:generator] || Core::ArrayBuffer
        
        if @generator.is_a?(Class)
          @generator = @generator.new(:buffer => eoutvar)
        end
        
        @sexp = @parser.compile(str)
        @optimized_sexp = Optimizers.inject(@sexp) { |m, e| e.compile(m) }
        @src = @generator.compile(@optimized_sexp)
        
        if str.respond_to?(:encoding)
          @enc = detect_magic_comment(str) || str.encoding
          @src.insert(0, "#coding:#{@enc}\n")
          @src << ".force_encoding(__ENCODING__)"
        end
      end
      
      def percent?
        @trim_mode.is_a?(String) and @trim_mode.include?("%")
      end
      
      def detect_magic_comment(s)
        if /\A<%#(.*)%>/ =~ s or (percent? and /\A%#(.*)/ =~ s)
  	      comment = $1
  	      comment = $1 if comment[/-\*-\s*(.*?)\s*-*-$/]
  	      if %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" =~ comment
  	        enc = $1.sub(/-(?:mac|dos|unix)/i, '')
  	        enc = Encoding.find(enc)
  	      end
        end
      end
    end
  end
end