30 lines implementation of eRuby

Hi all,

Do you like eRuby? Do you want to customize ERB?

The following is 30 lines implementation of eRuby.
This will help you to get your own eRuby implementation.

class TinyEruby

  def initialize(input=nil)
    @src = convert(input) if input
  end

  attr_reader :src

  def convert(input)
    src = "_buf = '';"       # preamble
    input.scan(/(.*?)<%(=)?(.*?)%>/m) do |text, ch, code|
      src << " _buf << '#{escape_text(text)}';" unless text.empty?
      src << (ch == '=' ? " _buf << (#{code}).to_s" : code) << ';'
    end
    rest = $' || input
    src << " _buf << '#{escape_text(rest)}';" unless rest.empty?
    src << "\n_buf.to_s\n"   # postamble
    return src
  end

  def escape_text(text)
    return text.gsub!(/['\\]/, '\\\\\&') || text
  end

  def result(_binding=TOPLEVEL_BINDING)
    eval @src, _binding
  end

end

Usage of TinyEruby is the same as ERB.

The above code may be slow in some cases, because long pattern
matching (‘(.*?)’ and $1) in convert() is not fast.
You can improve performance of TinyEruby to avoid long matching.

 ...
  def convert(input)
    src = "_buf = '';"       # preamble
    pos = 0
    input.scan(/<%(=)?(.*?)%>/m) do |ch, code|
      match = Regexp.last_match
      len   = match.begin(0) - pos
      text  = input[pos, len]
      pos   = match.end(0)
      src << " _buf << '#{escape_text(text)}';" unless text.empty?
      src << (ch == '=' ? " _buf << (#{code}).to_s" : code) << ';'
    end
    rest = $' || input
    src << " _buf << '#{escape_text(rest)}';" unless rest.empty?
    src << "\n_buf.to_s\n"   # postamble
    return src
  end
  ...

These codes are released in public domain. You can use it freely.
See
http://www.kuwata-lab.com/support/2007/10/09/30-lines-implementation-of-eruby/
for details.