Class: ERB::Compiler

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

Overview

ERB::Compiler

Compiles ERB templates into Ruby code; the compiled code produces the template result when evaluated. ERB::Compiler provides hooks to define how generated output is handled.

Internally ERB does something like this to generate the code returned by ERB#src:

compiler = ERB::Compiler.new('<>')
compiler.pre_cmd    = ["_erbout=''"]
compiler.put_cmd    = "_erbout.concat"
compiler.insert_cmd = "_erbout.concat"
compiler.post_cmd   = ["_erbout"]

code, enc = compiler.compile("Got <%= obj %>!\n")
puts code

Generates:

#coding:UTF-8
_erbout=''; _erbout.concat "Got "; _erbout.concat(( obj ).to_s); _erbout.concat "!\n"; _erbout

By default the output is sent to the print method. For example:

compiler = ERB::Compiler.new('<>')
code, enc = compiler.compile("Got <%= obj %>!\n")
puts code

Generates:

#coding:UTF-8
print "Got "; print(( obj ).to_s); print "!\n"

Evaluation

The compiled code can be used in any context where the names in the code correctly resolve. Using the last example, each of these print ‘Got It!’

Evaluate using a variable:

obj = 'It'
eval code

Evaluate using an input:

mod = Module.new
mod.module_eval %{
  def get(obj)
    #{code}
  end
}
extend mod
get('It')

Evaluate using an accessor:

klass = Class.new Object
klass.class_eval %{
  attr_accessor :obj
  def initialize(obj)
    @obj = obj
  end
  def get_it
    #{code}
  end
}
klass.new('It').get_it

Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.

Defined Under Namespace

Classes: Buffer, PercentLine, Scanner, SimpleScanner, TrimScanner

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(trim_mode) ⇒ Compiler

Construct a new compiler using the trim_mode. See ERB#new for available trim modes.



411
412
413
414
415
416
417
# File 'lib/missing/erb.rb', line 411

def initialize(trim_mode)
  @percent, @trim_mode = prepare_trim_mode(trim_mode)
  @put_cmd = 'print'
  @insert_cmd = @put_cmd
  @pre_cmd = []
  @post_cmd = []
end

Instance Attribute Details

#insert_cmdObject

The command to handle text that is inserted prior to a newline



424
425
426
# File 'lib/missing/erb.rb', line 424

def insert_cmd
  @insert_cmd
end

#percentObject (readonly)

Returns the value of attribute percent.



418
419
420
# File 'lib/missing/erb.rb', line 418

def percent
  @percent
end

#post_cmdObject

An array of commands appended to compiled code



430
431
432
# File 'lib/missing/erb.rb', line 430

def post_cmd
  @post_cmd
end

#pre_cmdObject

An array of commands prepended to compiled code



427
428
429
# File 'lib/missing/erb.rb', line 427

def pre_cmd
  @pre_cmd
end

#put_cmdObject

The command to handle text that ends with a newline



421
422
423
# File 'lib/missing/erb.rb', line 421

def put_cmd
  @put_cmd
end

#trim_modeObject (readonly)

Returns the value of attribute trim_mode.



418
419
420
# File 'lib/missing/erb.rb', line 418

def trim_mode
  @trim_mode
end

Instance Method Details

#compile(s) ⇒ Object

Compiles an ERB template into Ruby code. Returns an array of the code and encoding like [“code”, Encoding].



321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
# File 'lib/missing/erb.rb', line 321

def compile(s)
  out = Buffer.new(self)
  content = ''
  scanner = make_scanner(s)
  scanner.scan do |token|
    next if token.nil?
    next if token == ''
    if scanner.stag.nil?
      case token
      when PercentLine
        out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
        content = ''
        out.push(token.to_s)
        out.cr
      when :cr
        out.cr
      when '<%', '<%=', '<%#'
        scanner.stag = token
        out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
        content = ''
      when "\n"
        content << "\n"
        out.push("#{@put_cmd} #{content_dump(content)}")
        content = ''
      when '<%%'
        content << '<%'
      else
        content << token
      end
    else
      case token
      when '%>'
        case scanner.stag
        when '<%'
          if content[-1] == ?\n
            content.chop!
            out.push(content)
            out.cr
          else
            out.push(content)
          end
        when '<%='
          out.push("#{@insert_cmd}((#{content}).to_s)")
        when '<%#'
          # out.push("# #{content_dump(content)}")
        end
        scanner.stag = nil
        content = ''
      when '%%>'
        content << '%>'
      else
        content << token
      end
    end
  end
  out.push("#{@put_cmd} #{content_dump(content)}") if content.size > 0
  out.close
  return out.script
end

#content_dump(s) ⇒ Object

:nodoc:



310
311
312
313
314
315
316
317
# File 'lib/missing/erb.rb', line 310

def content_dump(s) # :nodoc:
  n = s.count("\n")
  if n > 0
    s.dump + "\n" * n
  else
    s.dump
  end
end

#make_scanner(src) ⇒ Object

:nodoc:



405
406
407
# File 'lib/missing/erb.rb', line 405

def make_scanner(src) # :nodoc:
  Scanner.make_scanner(src, @trim_mode, @percent)
end

#prepare_trim_mode(mode) ⇒ Object

:nodoc:



381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
# File 'lib/missing/erb.rb', line 381

def prepare_trim_mode(mode) # :nodoc:
  case mode
  when 1
    return [false, '>']
  when 2
    return [false, '<>']
  when 0
    return [false, nil]
  when String
    perc = mode.include?('%')
    if mode.include?('-')
      return [perc, '-']
    elsif mode.include?('<>')
      return [perc, '<>']
    elsif mode.include?('>')
      return [perc, '>']
    else
      [perc, nil]
    end
  else
    return [false, nil]
  end
end