Class: ERB::Compiler
Relationships & Source Files | |
Namespace Children | |
Classes:
| |
Inherits: | Object |
Defined in: | lib/erb.rb |
Overview
Compiles ERB templates into Ruby code; the compiled code produces the template result when evaluated. Compiler
provides hooks to define how generated output is handled.
Internally ERB does something like this to generate the code returned by #src:
compiler = ERB::Compiler.new('<>')
compiler.pre_cmd = ["_erbout=+''"]
compiler.put_cmd = "_erbout.<<"
compiler.insert_cmd = "_erbout.<<"
compiler.post_cmd = ["_erbout"]
code, enc = compiler.compile("Got <%= obj %>!\n")
puts code
Generates:
#coding:UTF-8
_erbout=+''; _erbout.<< "Got ".freeze; _erbout.<<(( obj ).to_s); _erbout.<< "!\n".freeze; _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 ".freeze; print(( obj ).to_s); print "!\n".freeze
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 #def_method, #def_module, and #def_class.
Class Method Summary
-
.new(trim_mode) ⇒ Compiler
constructor
Construct a new compiler using the trim_mode.
Instance Attribute Summary
-
#insert_cmd
rw
The command to handle text that is inserted prior to a newline.
- #percent readonly
-
#post_cmd
rw
An array of commands appended to compiled code.
-
#pre_cmd
rw
An array of commands prepended to compiled code.
-
#put_cmd
rw
The command to handle text that ends with a newline.
- #trim_mode readonly
-
#content
rw
private
A buffered text in #compile
Instance Method Summary
- #add_insert_cmd(out, content)
- #add_put_cmd(out, content)
-
#compile(s)
Compiles an
::ERB
template into Ruby code. - #compile_content(stag, out)
- #compile_etag(etag, out, scanner)
- #compile_stag(stag, out, scanner)
- #make_scanner(src)
- #prepare_trim_mode(mode)
- #detect_magic_comment(s, enc = nil) private
- #warn_invalid_trim_mode(mode, uplevel:) private
Constructor Details
.new(trim_mode) ⇒ Compiler
Construct a new compiler using the trim_mode. See ERB.new for available trim modes.
# File 'lib/erb.rb', line 694
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
#content (rw, private)
A buffered text in #compile
# File 'lib/erb.rb', line 718
attr_accessor :content
#insert_cmd (rw)
The command to handle text that is inserted prior to a newline
# File 'lib/erb.rb', line 707
attr_accessor :insert_cmd
#percent (readonly)
[ GitHub ]# File 'lib/erb.rb', line 701
attr_reader :percent, :trim_mode
#post_cmd (rw)
An array of commands appended to compiled code
# File 'lib/erb.rb', line 713
attr_accessor :post_cmd
#pre_cmd (rw)
An array of commands prepended to compiled code
# File 'lib/erb.rb', line 710
attr_accessor :pre_cmd
#put_cmd (rw)
The command to handle text that ends with a newline
# File 'lib/erb.rb', line 704
attr_accessor :put_cmd
#trim_mode (readonly)
[ GitHub ]# File 'lib/erb.rb', line 701
attr_reader :percent, :trim_mode
Instance Method Details
#add_insert_cmd(out, content)
[ GitHub ]#add_put_cmd(out, content)
[ GitHub ]#compile(s)
Compiles an ::ERB
template into Ruby code. Returns an array of the code and encoding like [“code”, Encoding].
# File 'lib/erb.rb', line 582
def compile(s) enc = s.encoding raise ArgumentError, "#{enc} is not ASCII compatible" if enc.dummy? s = s.b # see String#b magic_comment = detect_magic_comment(s, enc) out = Buffer.new(self, *magic_comment) self.content = +'' scanner = make_scanner(s) scanner.scan do |token| next if token.nil? next if token == '' if scanner.stag.nil? compile_stag(token, out, scanner) else compile_etag(token, out, scanner) end end add_put_cmd(out, content) if content.size > 0 out.close return out.script, *magic_comment end
#compile_content(stag, out)
[ GitHub ]#compile_etag(etag, out, scanner)
[ GitHub ]# File 'lib/erb.rb', line 629
def compile_etag(etag, out, scanner) case etag when '%>' compile_content(scanner.stag, out) scanner.stag = nil self.content = +'' when '%%>' content << '%>' else content << etag end end
#compile_stag(stag, out, scanner)
[ GitHub ]# File 'lib/erb.rb', line 605
def compile_stag(stag, out, scanner) case stag when PercentLine add_put_cmd(out, content) if content.size > 0 self.content = +'' out.push(stag.to_s) out.cr when :cr out.cr when '<%', '<%=', '<%#' scanner.stag = stag add_put_cmd(out, content) if content.size > 0 self.content = +'' when "\n" content << "\n" add_put_cmd(out, content) self.content = +'' when '<%%' content << '<%' else content << stag end end
#detect_magic_comment(s, enc = nil) (private)
[ GitHub ]# File 'lib/erb.rb', line 720
def detect_magic_comment(s, enc = nil) re = @percent ? /\G(?:<%#(.*)%>|%#(.*)\n)/ : /\G<%#(.*)%>/ frozen = nil s.scan(re) do comment = $+ comment = $1 if comment[/-\*-\s*(.*?)\s*-*-$/] case comment when %r"coding\s*[=:]\s*([[:alnum:]\-_]+)" enc = Encoding.find($1.sub(/-(?:mac|dos|unix)/i, '')) when %r"frozen[-_]string[-_]literal\s*:\s*([[:alnum:]]+)" frozen = $1 end end return enc, frozen end
#make_scanner(src)
[ GitHub ]# File 'lib/erb.rb', line 688
def make_scanner(src) # :nodoc: Scanner.make_scanner(src, @trim_mode, @percent) end
#prepare_trim_mode(mode)
[ GitHub ]# File 'lib/erb.rb', line 659
def prepare_trim_mode(mode) # :nodoc: case mode when 1 return [false, '>'] when 2 return [false, '<>'] when 0, nil return [false, nil] when String unless mode.match?(/\A(%|-|>|<>){1,2}\z/) warn_invalid_trim_mode(mode, uplevel: 5) end perc = mode.include?('%') if mode.include?('-') return [perc, '-'] elsif mode.include?('<>') return [perc, '<>'] elsif mode.include?('>') return [perc, '>'] else [perc, nil] end else warn_invalid_trim_mode(mode, uplevel: 5) return [false, nil] end end
#warn_invalid_trim_mode(mode, uplevel:) (private)
[ GitHub ]# File 'lib/erb.rb', line 736
def warn_invalid_trim_mode(mode, uplevel:) warn "Invalid ERB trim mode: #{mode.inspect} (trim_mode: nil, 0, 1, 2, or String composed of '%' and/or '-', '>', '<>')", uplevel: uplevel + 1 end