# class Erubi::Engine

### Attributes

bufvar[R]

The variable name used for the buffer variable.

filename[R]

The filename of the template, if one was given.

src[R]

The frozen ruby source code generated from the template, which can be evaled.

### Public Class Methods

new(input, properties={}) click to toggle source

Initialize a new Erubi::Engine. Options:

:bufval

  The value to use for the buffer variable, as a string.

:bufvar

  The variable name to use for the buffer variable, as a string.

:ensure

  Wrap the template in a begin/ensure block restoring the previous value of bufvar.

:escapefunc

  The function to use for escaping, as a string (default: Erubi.h).

:escape

  Whether to make <%= escape by default, and <%== not escape by default.

:escape_html

  Same as :escape, with lower priority.

:filename

  The filename for the template.

:freeze

  Whether to enable frozen string literals in the resulting source code.

:outvar

  Same as bufvar, with lower priority.

:postamble

  The postamble for the template, by default returns the resulting source code.

:preamble

  The preamble for the template, by default initializes up the buffer variable.

:regexp

  The regexp to use for scanning.

:src

  The initial value to use for the source code

:trim

  Whether to trim leading and trailing whitespace, true by default.

    # File lib/erubi.rb, line 67
    def initialize(input, properties={})
      @escape = escape = properties.fetch(:escape){properties.fetch(:escape_html, false)}
      trim       = properties[:trim] != false
      @filename  = properties[:filename]
      @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf"
      bufval = properties[:bufval] || 'String.new'
      regexp = properties[:regexp] || /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
      preamble   = properties[:preamble] || "#{bufvar} = #{bufval};"
      postamble  = properties[:postamble] || "#{bufvar}.to_s\n"

      @src = src = properties[:src] || String.new
      src << "# frozen_string_literal: true\n" if properties[:freeze]
      src << "begin; __original_outvar = #{bufvar} if defined?(#{bufvar}); " if properties[:ensure]

      unless @escapefunc = properties[:escapefunc]
        if escape
          @escapefunc = '__erubi.h'
          src << "__erubi = ::Erubi;"
        else
          @escapefunc = '::Erubi.h'
        end
      end

      src << preamble

      pos = 0
      is_bol = true
      input.scan(regexp) do |indicator, code, tailch, rspace|
        match = Regexp.last_match
        len  = match.begin(0) - pos
        text = input[pos, len]
        pos  = match.end(0)
        ch   = indicator ? indicator[RANGE_FIRST] : nil

        lspace = nil

        unless ch == '='
          if text.empty?
            lspace = "" if is_bol
          elsif text[RANGE_LAST] == "\n"
            lspace = ""
          else
            rindex = text.rindex("\n")
            if rindex
              range = rindex+1..-1
              s = text[range]
              if s =~ /\A[ \t]*\z/
                lspace = s
                text[range] = ''
              end
            else
              if is_bol && text =~ /\A[ \t]*\z/
                lspace = text.dup
                text[RANGE_ALL] = ''
              end
            end
          end
        end

        is_bol = rspace
        add_text(text) if text && !text.empty?
        case ch
        when '='
          rspace = nil if tailch && !tailch.empty?
          add_text(lspace) if lspace
          add_expression(indicator, code)
          add_text(rspace) if rspace
        when '#'
          n = code.count("\n") + (rspace ? 1 : 0)
          if trim && lspace && rspace
            add_code("\n" * n)
          else
            add_text(lspace) if lspace
            add_code("\n" * n)
            add_text(rspace) if rspace
          end
        when '%'
          add_text("#{lspace}#{prefix||='<%'}#{code}#{tailch}#{postfix||='%>'}#{rspace}")
        when nil, '-'
          if trim && lspace && rspace
            add_code("#{lspace}#{code}#{rspace}")
          else
            add_text(lspace) if lspace
            add_code(code)
            add_text(rspace) if rspace
          end
        else
          handle(indicator, code, tailch, rspace, lspace)
        end
      end
      rest = pos == 0 ? input : input[pos..-1]
      add_text(rest)

      src << "\n" unless src[RANGE_LAST] == "\n"
      add_postamble(postamble)
      src << "; ensure\n  #{bufvar} = __original_outvar\nend\n" if properties[:ensure]
      src.freeze
      freeze
    end

### Private Instance Methods

add_code(code) click to toggle source

Add ruby code to the template

    # File lib/erubi.rb, line 175
    def add_code(code)
      @src << code
      @src << ';' unless code[RANGE_LAST] == "\n"
    end

add_expression(indicator, code) click to toggle source

Add the given ruby expression result to the template, escaping it based on the indicator given and escape flag.

    # File lib/erubi.rb, line 182
    def add_expression(indicator, code)
      if ((indicator == '=') ^ @escape)
        add_expression_result(code)
      else
        add_expression_result_escaped(code)
      end
    end

add_expression_result(code) click to toggle source

Add the result of Ruby expression to the template

    # File lib/erubi.rb, line 191
    def add_expression_result(code)
      @src << " #{@bufvar} << (" << code << ').to_s;'
    end

add_expression_result_escaped(code) click to toggle source

Add the escaped result of Ruby expression to the template

    # File lib/erubi.rb, line 196
    def add_expression_result_escaped(code)
      @src << " #{@bufvar} << #{@escapefunc}((" << code << '));'
    end

add_postamble(postamble) click to toggle source

Add the given postamble to the src. Can be overridden in subclasses to make additional changes to src that depend on the current state.

    # File lib/erubi.rb, line 202
    def add_postamble(postamble)
      src << postamble
    end

add_text(text) click to toggle source

Add raw text to the template

    # File lib/erubi.rb, line 170
    def add_text(text)
      @src << " #{@bufvar} << '" << text.gsub(/['\\]/, '\\\\\&') << TEXT_END unless text.empty?
    end

handle(indicator, code, tailch, rspace, lspace) click to toggle source

Raise an exception, as the base engine class does not support handling other indicators.

    # File lib/erubi.rb, line 207
    def handle(indicator, code, tailch, rspace, lspace)
      raise ArgumentError, "Invalid indicator: #{indicator}"
    end