class Erubi::Engine
def add_code(code)
def add_code(code) @src << code @src << ';' unless code[RANGE_LAST] == "\n" end
def add_text(text)
def add_text(text) @src << " #{@bufvar} << '" << text.gsub(/['\\]/, '\\\\\&') << "';" unless text.empty? end
def initialize(input, properties={})
:preamble :: The preamble for the template, by default initializes up the buffer variable.
:postable :: the postamble for the template, by default returns the resulting source code.
:outvar :: Same as bufvar, with lower priority.
:freeze :: Whether to enable frozen string literals in the resulting source code.
:filename :: The filename for the template.
:escape_html :: Same as :escape, with lower priority.
:escape :: Whether to make <%= escape by default, and <%== not escape by default.
:escapefunc :: The function to use for escaping, as a string (default: ::Erubi.h).
:bufvar :: The variable name to use for the buffer variable, as a string.
Initialize a new Erubi::Engine. Options:
def initialize(input, properties={}) escape = properties.fetch(:escape){properties.fetch(:escape_html, false)} trim = properties[:trim] != false @filename = properties[:filename] @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf" preamble = properties[:preamble] || "#{bufvar} = String.new;" postamble = properties[:postamble] || "#{bufvar}.to_s\n" @src = src = String.new src << "# frozen_string_literal: true\n" if properties[:freeze] 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(/<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m) 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 ? true : false add_text(text) if text && !text.empty? if ch == '=' rspace = nil if tailch && !tailch.empty? add_text(lspace) if lspace if ((indicator == '=') ^ escape) src << " #{bufvar} << (" << code << ').to_s;' else src << " #{bufvar} << #{escapefunc}((" << code << '));' end add_text(rspace) if rspace elsif ch == '#' n = code.count("\n") + (rspace ? 1 : 0) if trim add_code("\n" * n) else add_text(lspace) if lspace add_code("\n" * n) add_text(rspace) if rspace end elsif ch == '%' add_text("#{lspace}#{prefix||='<%'}#{code}#{tailch}#{postfix||='%>'}#{rspace}") else if trim add_code("#{lspace}#{code}#{rspace}") else add_text(lspace) if lspace add_code(code) add_text(rspace) if rspace end end end rest = pos == 0 ? input : input[pos..-1] add_text(rest) src << "\n" unless src[RANGE_LAST] == "\n" src << postamble freeze end