class ERB::Compiler
:nodoc:
Good! See also ERB#def_method, ERB#def_module, and ERB#def_class.
klass.new(‘It’).get_it
}
end
#{code}
def get_it
end
@obj = obj
def initialize(obj)
attr_accessor :obj
klass.class_eval %{
klass = Class.new Object
Evaluate using an accessor:
get(‘It’)
extend mod
}
end
#{code}
def get(obj)
mod.module_eval %{
mod = Module.new
Evaluate using an input:
eval code
obj = ‘It’
Evaluate using a variable:
correctly resolve. Using the last example, each of these print ‘Got It!’
The compiled code can be used in any context where the names in the code
== Evaluation
print “Got ”.freeze; print(( obj ).to_s); print “!n”.freeze
#coding:UTF-8
Generates:
puts code
code, enc = compiler.compile(“Got <%= obj %>!n”)
compiler = ERB::Compiler.new(‘<>’)
By default the output is sent to the print method. For example:
_erbout=+”; _erbout.<< “Got ”.freeze; _erbout.<<(( obj ).to_s); _erbout.<< “!n”.freeze; _erbout
#coding:UTF-8
Generates:
puts code
code, enc = compiler.compile(“Got <%= obj %>!n”)
compiler.post_cmd = [“_erbout”]
compiler.insert_cmd = “_erbout.<<”
compiler.put_cmd = “_erbout.<<”
compiler.pre_cmd = [“_erbout=+””]
compiler = ERB::Compiler.new(‘<>’)
ERB#src:
Internally ERB does something like this to generate the code returned by
generated output is handled.
template result when evaluated. ERB::Compiler provides hooks to define how
Compiles ERB templates into Ruby code; the compiled code produces the
ERB::Compiler
–
frozen_string_literal: true
def add_insert_cmd(out, content)
def add_insert_cmd(out, content) out.push("#{@insert_cmd}((#{content}).to_s)") end
def add_put_cmd(out, content)
def add_put_cmd(out, content) out.push("#{@put_cmd} #{content.dump}.freeze#{"\n" * content.count("\n")}") end
def compile(s)
Compiles an ERB template into Ruby code. Returns an array of the code
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
def compile_content(stag, out)
def compile_content(stag, out) case stag when '<%' if content[-1] == ?\n content.chop! out.push(content) out.cr else out.push(content) end when '<%=' add_insert_cmd(out, content) when '<%#' out.push("\n" * content.count("\n")) # only adjust lineno end end
def compile_etag(etag, out, scanner)
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
def compile_stag(stag, out, scanner)
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
def detect_magic_comment(s, enc = nil)
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].*?)\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
def initialize(trim_mode)
Construct a new compiler using the trim_mode. See ERB::new for available
def initialize(trim_mode) @percent, @trim_mode = prepare_trim_mode(trim_mode) @put_cmd = 'print' @insert_cmd = @put_cmd @pre_cmd = [] @post_cmd = [] end
def make_scanner(src) # :nodoc:
def make_scanner(src) # :nodoc: Scanner.make_scanner(src, @trim_mode, @percent) end
def prepare_trim_mode(mode) # :nodoc:
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
def warn_invalid_trim_mode(mode, uplevel:)
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 + WARNING_UPLEVEL end