Class: Erubi::Engine

Inherits:
Object
  • Object
show all
Defined in:
lib/erubi.rb

Direct Known Subclasses

CaptureEndEngine

Constant Summary collapse

DEFAULT_REGEXP =

The default regular expression used for scanning.

/<%(={1,2}|-|\#|%)?(.*?)([-=])?%>([ \t]*\r?\n)?/m

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(input, properties = {}) ⇒ Engine

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 to false 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.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/erubi.rb', line 94

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

Instance Attribute Details

#bufvarObject (readonly)

The variable name used for the buffer variable.



65
66
67
# File 'lib/erubi.rb', line 65

def bufvar
  @bufvar
end

#filenameObject (readonly)

The filename of the template, if one was given.



62
63
64
# File 'lib/erubi.rb', line 62

def filename
  @filename
end

#srcObject (readonly)

The frozen ruby source code generated from the template, which can be evaled.



59
60
61
# File 'lib/erubi.rb', line 59

def src
  @src
end