class Erubi::Engine
Constants
- DEFAULT_REGEXP
The default regular expression used for scanning.
Attributes
The variable name used for the buffer variable.
The filename of the template, if one was given.
The frozen ruby source code generated from the template, which can be evaled.
Public Class Methods
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.
:chain_appends
-
Whether to chain <tt><<</t> calls to the buffer variable. Offers better performance, but can cause issues when the buffer variable is reassigned during template rendering (default
false
). :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 add a
frozen_string_literal: true
magic comment at the top of the resulting source code. Note this may cause problems if you are wrapping the resulting source code in other code, because the magic comment only has an effect at the beginning of the file, and having the magic comment later in the file can trigger warnings. :freeze_template_literals
-
Whether to suffix all literal strings for template code with
.freeze
(default:true
on Ruby 2.1+,false
on Ruby 2.0 and older). Can be set tofalse
on Ruby 2.3+ when frozen string literals are enabled in order to improve performance. :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, line 93 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] || DEFAULT_REGEXP literal_prefix = properties[:literal_prefix] || '<%' literal_postfix = properties[:literal_postfix] || '%>' preamble = properties[:preamble] || "#{bufvar} = #{bufval};" postamble = properties[:postamble] || "#{bufvar}.to_s\n" @chain_appends = properties[:chain_appends] @text_end = if properties.fetch(:freeze_template_literals, FREEZE_TEMPLATE_LITERALS) "'.freeze" else "'" end @buffer_on_stack = false @src = src = properties[:src] || String.new src << "# frozen_string_literal: true\n" if properties[:freeze] if properties[:ensure] src << "begin; __original_outvar = #{bufvar}" if SKIP_DEFINED_FOR_INSTANCE_VARIABLE && /\A@[^@]/ =~ bufvar src << "; " else src << " if defined?(#{bufvar}); " end end 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 /\A[ \t]*\z/.send(MATCH_METHOD, s) lspace = s text[range] = '' end else if is_bol && /\A[ \t]*\z/.send(MATCH_METHOD, text) lspace = text text = '' end end end end is_bol = rspace add_text(text) case ch when '=' rspace = nil if tailch && !tailch.empty? add_expression(indicator, code) add_text(rspace) if 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 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}#{literal_prefix}#{code}#{tailch}#{literal_postfix}#{rspace}") 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 ruby code to the template
# File lib/erubi.rb, line 225 def add_code(code) terminate_expression @src << code @src << ';' unless code[RANGE_LAST] == "\n" @buffer_on_stack = false end
Add the given ruby expression result to the template, escaping it based on the indicator given and escape flag.
# File lib/erubi.rb, line 234 def add_expression(indicator, code) if ((indicator == '=') ^ @escape) add_expression_result(code) else add_expression_result_escaped(code) end end
Add the result of Ruby expression to the template
# File lib/erubi.rb, line 243 def add_expression_result(code) with_buffer{@src << ' << (' << code << ').to_s'} end
Add the escaped result of Ruby expression to the template
# File lib/erubi.rb, line 248 def add_expression_result_escaped(code) with_buffer{@src << ' << ' << @escapefunc << '((' << code << '))'} end
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 254 def add_postamble(postamble) terminate_expression @src << postamble end
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, line 212 def add_text(text) return if text.empty? if text.frozen? text = text.gsub(/['\\]/, '\\\\\&') else text.gsub!(/['\\]/, '\\\\\&') end with_buffer{@src << " << '" << text << @text_end} end
Raise an exception, as the base engine class does not support handling other indicators.
# File lib/erubi.rb, line 260 def handle(indicator, code, tailch, rspace, lspace) raise ArgumentError, "Invalid indicator: #{indicator}" end
Make sure that any current expression has been terminated. The default is to terminate all expressions, but when the chain_appends option is used, expressions may not be terminated.
# File lib/erubi.rb, line 288 def terminate_expression @src << '; ' if @chain_appends end
Make sure the buffer variable is the target of the next append before yielding to the block. Mark that the buffer is the target of the next append after the block executes.
This method should only be called if the block will result in code where << will append to the bufvar.
# File lib/erubi.rb, line 270 def with_buffer if @chain_appends unless @buffer_on_stack @src << '; ' << @bufvar end yield @buffer_on_stack = true else @src << ' ' << @bufvar yield @src << ';' end end