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 (default '::String.new').

: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.

:literal_prefix

The prefix to output when using escaped tag delimiters (default '<%').

:literal_postfix

The postfix to output when using escaped tag delimiters (default '%>').

: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 the buffer variable.

:regexp

The regexp to use for scanning.

:src

The initial value to use for the source code, an empty string by default.

:trim

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

    # File lib/erubi.rb
 74 def initialize(input, properties={})
 75   @escape = escape = properties.fetch(:escape){properties.fetch(:escape_html, false)}
 76   trim       = properties[:trim] != false
 77   @filename  = properties[:filename]
 78   @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf"
 79   bufval = properties[:bufval] || '::String.new'
 80   regexp = properties[:regexp] || /<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m
 81   literal_prefix = properties[:literal_prefix] || '<%'
 82   literal_postfix = properties[:literal_postfix] || '%>'
 83   preamble   = properties[:preamble] || "#{bufvar} = #{bufval};"
 84   postamble  = properties[:postamble] || "#{bufvar}.to_s\n"
 85 
 86   @src = src = properties[:src] || String.new
 87   src << "# frozen_string_literal: true\n" if properties[:freeze]
 88   src << "begin; __original_outvar = #{bufvar} if defined?(#{bufvar}); " if properties[:ensure]
 89 
 90   unless @escapefunc = properties[:escapefunc]
 91     if escape
 92       @escapefunc = '__erubi.h'
 93       src << "__erubi = ::Erubi;"
 94     else
 95       @escapefunc = '::Erubi.h'
 96     end
 97   end
 98 
 99   src << preamble
100 
101   pos = 0
102   is_bol = true
103   input.scan(regexp) do |indicator, code, tailch, rspace|
104     match = Regexp.last_match
105     len  = match.begin(0) - pos
106     text = input[pos, len]
107     pos  = match.end(0)
108     ch   = indicator ? indicator[RANGE_FIRST] : nil
109 
110     lspace = nil
111 
112     unless ch == '='
113       if text.empty?
114         lspace = "" if is_bol
115       elsif text[RANGE_LAST] == "\n"
116         lspace = ""
117       else
118         rindex = text.rindex("\n")
119         if rindex
120           range = rindex+1..-1
121           s = text[range]
122           if /\A[ \t]*\z/.send(MATCH_METHOD, s)
123             lspace = s
124             text[range] = ''
125           end
126         else
127           if is_bol && /\A[ \t]*\z/.send(MATCH_METHOD, text)
128             lspace = text
129             text = ''
130           end
131         end
132       end
133     end
134 
135     is_bol = rspace
136     add_text(text)
137     case ch
138     when '='
139       rspace = nil if tailch && !tailch.empty?
140       add_expression(indicator, code)
141       add_text(rspace) if rspace
142     when nil, '-'
143       if trim && lspace && rspace
144         add_code("#{lspace}#{code}#{rspace}")
145       else
146         add_text(lspace) if lspace
147         add_code(code)
148         add_text(rspace) if rspace
149       end
150     when '#'
151       n = code.count("\n") + (rspace ? 1 : 0)
152       if trim && lspace && rspace
153         add_code("\n" * n)
154       else
155         add_text(lspace) if lspace
156         add_code("\n" * n)
157         add_text(rspace) if rspace
158       end
159     when '%'
160       add_text("#{lspace}#{literal_prefix}#{code}#{tailch}#{literal_postfix}#{rspace}")
161     else
162       handle(indicator, code, tailch, rspace, lspace)
163     end
164   end
165   rest = pos == 0 ? input : input[pos..-1]
166   add_text(rest)
167 
168   src << "\n" unless src[RANGE_LAST] == "\n"
169   add_postamble(postamble)
170   src << "; ensure\n  " << bufvar << " = __original_outvar\nend\n" if properties[:ensure]
171   src.freeze
172   freeze
173 end

Private Instance Methods

add_code(code) click to toggle source

Add ruby code to the template

    # File lib/erubi.rb
191 def add_code(code)
192   @src << code
193   @src << ';' unless code[RANGE_LAST] == "\n"
194 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
198 def add_expression(indicator, code)
199   if ((indicator == '=') ^ @escape)
200     add_expression_result(code)
201   else
202     add_expression_result_escaped(code)
203   end
204 end
add_expression_result(code) click to toggle source

Add the result of Ruby expression to the template

    # File lib/erubi.rb
207 def add_expression_result(code)
208   @src << ' ' << @bufvar << ' << (' << code << ').to_s;'
209 end
add_expression_result_escaped(code) click to toggle source

Add the escaped result of Ruby expression to the template

    # File lib/erubi.rb
212 def add_expression_result_escaped(code)
213   @src << ' ' << @bufvar << ' << ' << @escapefunc << '((' << code << '));'
214 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
218 def add_postamble(postamble)
219   src << postamble
220 end
add_text(text) click to toggle source

Add raw text to the template. Modifies argument if argument is mutable as a memory optimization. Must be called with a string, cannot be called with nil (Rails’s subclass depends on it).

    # File lib/erubi.rb
179 def add_text(text)
180   return if text.empty?
181 
182   if text.frozen?
183     text = text.gsub(/['\\]/, '\\\\\&')
184   else
185     text.gsub!(/['\\]/, '\\\\\&')
186   end
187   @src << " " << @bufvar << " << '" << text << TEXT_END
188 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
223 def handle(indicator, code, tailch, rspace, lspace)
224   raise ArgumentError, "Invalid indicator: #{indicator}"
225 end