Class | Tenjin::Template |
In: |
lib/tenjin.rb
|
Parent: | Object |
template class
ex. file ‘example.rbhtml‘
<html> <body> <h1>${@title}</h1> <ul> <?rb i = 0 ?> <?rb for item in @items ?> <?rb i += 1 ?> <li>#{i} : ${item}</li> <?rb end ?> </ul> </body> </html>
ex. convertion
require 'tenjin' template = Tenjin::Template.new('example.rbhtml') print template.script ## or # template = Tenjin::Template.new() # print template.convert_file('example.rbhtml') ## or # template = Tenjin::Template.new() # fname = 'example.rbhtml' # print template.convert(File.read(fname), fname) # filename is optional
ex. evaluation
context = {:title=>'Tenjin Example', :items=>['foo', 'bar', 'baz'] } output = template.render(context) ## or # context = Tenjin::Context(:title=>'Tenjin Example', :items=>['foo','bar','baz']) # output = template.render(context) ## or # output = template.render(:title=>'Tenjin Example', :items=>['foo','bar','baz']) print output
ESCAPE_FUNCTION | = | 'escape' |
STMT_PATTERN | = | self.compile_stmt_pattern('rb') |
args | [RW] | |
escapefunc | [RW] | |
filename | [RW] | |
initbuf | [RW] | |
newline | [RW] | |
script | [RW] | |
timestamp | [RW] |
initializer of Template class.
options:
:escapefunc : | function name to escape value (default ‘escape’) |
:preamble : | preamble such as "_buf = ’’" (default nil) |
:postamble : | postamble such as "_buf.to_s" (default nil) |
# File lib/tenjin.rb, line 327 def initialize(filename=nil, options={}) if filename.is_a?(Hash) options = filename filename = nil end @filename = filename @escapefunc = options[:escapefunc] || ESCAPE_FUNCTION @preamble = options[:preamble] == true ? "_buf = #{init_buf_expr()}; " : options[:preamble] @postamble = options[:postamble] == true ? "_buf.to_s" : options[:postamble] @args = nil # or array of argument names convert_file(filename) if filename end
# File lib/tenjin.rb, line 381 def self.compile_stmt_pattern(pi) return /<\?#{pi}( |\t|\r?\n)(.*?) ?\?>([ \t]*\r?\n)?/m end
convert string into ruby code
# File lib/tenjin.rb, line 349 def convert(input, filename=nil) @input = input @filename = filename @proc = nil pos = input.index(?\n) if pos && input[pos-1] == ?\r @newline = "\r\n" @newlinestr = '\\r\\n' else @newline = "\n" @newlinestr = '\\n' end before_convert() parse_stmts(input) after_convert() return @script end
add expression code
# File lib/tenjin.rb, line 587 def add_expr(code, flag_escape=nil) return if !code || code.empty? @script << (flag_escape ? "\#{#{@escapefunc}((#{code}).to_s)}" : "\#{#{code}}") end
add text string
# File lib/tenjin.rb, line 569 def add_text(text, encode_newline=false) return unless text && !text.empty? if encode_newline && text[-1] == ?\n text.chomp! @script << escape_str(text) << @newlinestr else @script << escape_str(text) end end
escape ’\’ and ’`’ into ’\\’ and ’\`’
# File lib/tenjin.rb, line 580 def escape_str(str) str.gsub!(/[`\\]/, '\\\\\&') str.gsub!(/\r\n/, "\\r\r\n") if @newline == "\r\n" return str end
# File lib/tenjin.rb, line 454 def expr_pattern #return /([\#$])\{(.*?)\}/ return /(\$)\{(.*?)\}/m #return /\$\{.*?\}/ end
ex. get_expr_and_escapeflag(’$’, ‘item[:name]’) => ‘item[:name]’, true
# File lib/tenjin.rb, line 461 def get_expr_and_escapeflag(matched) return matched[2], matched[1] == '$' end
parse expressions (’#{…}’ and ’${…}’)
# File lib/tenjin.rb, line 466 def parse_exprs(input) return if !input or input.empty? pos = 0 start_text_part() input.scan(expr_pattern()) do m = Regexp.last_match text = input[pos, m.begin(0) - pos] pos = m.end(0) expr, flag_escape = get_expr_and_escapeflag(m) #m = Regexp.last_match #start = m.begin(0) #stop = m.end(0) #text = input[pos, start - pos] #expr = input[start+2, stop-start-3] #pos = stop add_text(text) add_expr(expr, flag_escape) end rest = $' || input #if !rest || rest.empty? # @script << '`; ' #elsif rest[-1] == ?\n # rest.chomp! # @script << escape_str(rest) << @newlinestr << '`' << @newline #else # @script << escape_str(rest) << '`; ' #end flag_newline = input[-1] == ?\n add_text(rest, true) stop_text_part() @script << (flag_newline ? @newline : '; ') end
parse statements (’<?rb … ?>’)
# File lib/tenjin.rb, line 392 def parse_stmts(input) return unless input is_bol = true prev_rspace = nil pos = 0 input.scan(stmt_pattern()) do |mspace, code, rspace| m = Regexp.last_match text = input[pos, m.begin(0) - pos] pos = m.end(0) ## detect spaces at beginning of line lspace = nil if rspace.nil? # nothing elsif text.empty? lspace = "" if is_bol elsif text[-1] == ?\n lspace = "" else rindex = text.rindex(?\n) if rindex s = text[rindex+1..-1] if s =~ /\A[ \t]*\z/ lspace = s text = text[0..rindex] #text[rindex+1..-1] = '' end else if is_bol && text =~ /\A[ \t]*\z/ lspace = text text = nil #lspace = text.dup #text[0..-1] = '' end end end is_bol = rspace ? true : false ## text.insert(0, prev_rspace) if prev_rspace parse_exprs(text) code.insert(0, mspace) if mspace != ' ' if lspace assert if rspace.nil? code.insert(0, lspace) code << rspace #add_stmt(code) prev_rspace = nil else code << ';' unless code[-1] == ?\n #add_stmt(code) prev_rspace = rspace end if code code = statement_hook(code) add_stmt(code) end end #rest = $' || input rest = pos > 0 ? input[pos..-1] : input rest.insert(0, prev_rspace) if prev_rspace parse_exprs(rest) if rest && !rest.empty? end
expand macros and parse ’#@ARGS’ in a statement.
# File lib/tenjin.rb, line 500 def statement_hook(stmt) ## macro expantion #macro_pattern = /\A\s*(\w+)\((.*?)\);?(\s*)\z/ #if macro_pattern =~ stmt # name = $1; arg = $2; rspace = $3 # handler = get_macro_handler(name) # ret = handler ? handler.call(arg) + $3 : stmt # return ret #end ## arguments declaration if @args.nil? args_pattern = /\A *\#@ARGS([ \t]+(.*?))?(\s*)\z/ # if args_pattern =~ stmt @args = [] declares = '' rspace = $3 if $2 for s in $2.split(/,/) arg = s.strip() next if s.empty? arg =~ /\A[a-zA-Z_]\w*\z/ or raise ArgumentError.new("#{arg}: invalid template argument.") @args << arg declares << " #{arg} = @#{arg};" end end declares << rspace return declares end end ## return stmt end