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