class Erubi::Engine
:nocov:
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 91 def initialize(input, properties={}) 92 @escape = escape = properties.fetch(:escape){properties.fetch(:escape_html, false)} 93 trim = properties[:trim] != false 94 @filename = properties[:filename] 95 @bufvar = bufvar = properties[:bufvar] || properties[:outvar] || "_buf" 96 bufval = properties[:bufval] || '::String.new' 97 regexp = properties[:regexp] || DEFAULT_REGEXP 98 literal_prefix = properties[:literal_prefix] || '<%' 99 literal_postfix = properties[:literal_postfix] || '%>' 100 preamble = properties[:preamble] || "#{bufvar} = #{bufval};" 101 postamble = properties[:postamble] || "#{bufvar}.to_s\n" 102 @chain_appends = properties[:chain_appends] 103 @text_end = if properties.fetch(:freeze_template_literals, FREEZE_TEMPLATE_LITERALS) 104 "'.freeze" 105 else 106 "'" 107 end 108 109 @buffer_on_stack = false 110 @src = src = properties[:src] || String.new 111 src << "# frozen_string_literal: true\n" if properties[:freeze] 112 if properties[:ensure] 113 src << "begin; __original_outvar = #{bufvar}" 114 if SKIP_DEFINED_FOR_INSTANCE_VARIABLE && /\A@[^@]/ =~ bufvar 115 src << "; " 116 else 117 src << " if defined?(#{bufvar}); " 118 end 119 end 120 121 unless @escapefunc = properties[:escapefunc] 122 if escape 123 @escapefunc = '__erubi.h' 124 src << "__erubi = ::Erubi; " 125 else 126 @escapefunc = '::Erubi.h' 127 end 128 end 129 130 src << preamble 131 132 pos = 0 133 is_bol = true 134 input.scan(regexp) do |indicator, code, tailch, rspace| 135 match = Regexp.last_match 136 len = match.begin(0) - pos 137 text = input[pos, len] 138 pos = match.end(0) 139 ch = indicator ? indicator[RANGE_FIRST] : nil 140 141 lspace = nil 142 143 unless ch == '=' 144 if text.empty? 145 lspace = "" if is_bol 146 elsif text[RANGE_LAST] == "\n" 147 lspace = "" 148 else 149 rindex = text.rindex("\n") 150 if rindex 151 range = rindex+1..-1 152 s = text[range] 153 if /\A[ \t]*\z/.send(MATCH_METHOD, s) 154 lspace = s 155 text[range] = '' 156 end 157 else 158 if is_bol && /\A[ \t]*\z/.send(MATCH_METHOD, text) 159 lspace = text 160 text = '' 161 end 162 end 163 end 164 end 165 166 is_bol = rspace 167 add_text(text) 168 case ch 169 when '=' 170 rspace = nil if tailch && !tailch.empty? 171 add_expression(indicator, code) 172 add_text(rspace) if rspace 173 when nil, '-' 174 if trim && lspace && rspace 175 add_code("#{lspace}#{code}#{rspace}") 176 else 177 add_text(lspace) if lspace 178 add_code(code) 179 add_text(rspace) if rspace 180 end 181 when '#' 182 n = code.count("\n") + (rspace ? 1 : 0) 183 if trim && lspace && rspace 184 add_code("\n" * n) 185 else 186 add_text(lspace) if lspace 187 add_code("\n" * n) 188 add_text(rspace) if rspace 189 end 190 when '%' 191 add_text("#{lspace}#{literal_prefix}#{code}#{tailch}#{literal_postfix}#{rspace}") 192 else 193 handle(indicator, code, tailch, rspace, lspace) 194 end 195 end 196 rest = pos == 0 ? input : input[pos..-1] 197 add_text(rest) 198 199 src << "\n" unless src[RANGE_LAST] == "\n" 200 add_postamble(postamble) 201 src << "; ensure\n " << bufvar << " = __original_outvar\nend\n" if properties[:ensure] 202 src.freeze 203 freeze 204 end
Private Instance Methods
Add ruby code to the template
# File lib/erubi.rb 223 def add_code(code) 224 terminate_expression 225 @src << code 226 @src << ';' unless code[RANGE_LAST] == "\n" 227 @buffer_on_stack = false 228 end
Add the given ruby expression result to the template, escaping it based on the indicator given and escape flag.
# File lib/erubi.rb 232 def add_expression(indicator, code) 233 if ((indicator == '=') ^ @escape) 234 add_expression_result(code) 235 else 236 add_expression_result_escaped(code) 237 end 238 end
Add the result of Ruby expression to the template
# File lib/erubi.rb 241 def add_expression_result(code) 242 with_buffer{@src << ' << (' << code << ').to_s'} 243 end
Add the escaped result of Ruby expression to the template
# File lib/erubi.rb 246 def add_expression_result_escaped(code) 247 with_buffer{@src << ' << ' << @escapefunc << '((' << code << '))'} 248 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 252 def add_postamble(postamble) 253 terminate_expression 254 @src << postamble 255 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 210 def add_text(text) 211 return if text.empty? 212 213 if text.frozen? 214 text = text.gsub(/['\\]/, '\\\\\&') 215 else 216 text.gsub!(/['\\]/, '\\\\\&') 217 end 218 219 with_buffer{@src << " << '" << text << @text_end} 220 end
Raise an exception, as the base engine class does not support handling other indicators.
# File lib/erubi.rb 258 def handle(indicator, code, tailch, rspace, lspace) 259 raise ArgumentError, "Invalid indicator: #{indicator}" 260 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 286 def terminate_expression 287 @src << '; ' if @chain_appends 288 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 268 def with_buffer 269 if @chain_appends 270 unless @buffer_on_stack 271 @src << '; ' << @bufvar 272 end 273 yield 274 @buffer_on_stack = true 275 else 276 @src << ' ' << @bufvar 277 yield 278 @src << ';' 279 end 280 end