In: |
tangerine.rb
|
Parent: | String |
Tangerine — A general-purpose templating system Copyright (C) 2004 Christian Neukirchen <purl.org/net/chneukirchen>
Licensed under the same terms as Ruby itself.
VERSION | = | "0.3.1" |
Version information |
code | [R] | The generated code. |
taglib | [RW] | The tag library being used. |
Indent the string to depth, only subsequent lines.
# File tangerine.rb, line 19 19: def self.indent(depth, string) 20: string.gsub(/\n^/, "\n" + ' '*depth) 21: end
Create, parse and compile a new Tangerine template given in template.
# File tangerine.rb, line 24 24: def initialize(template, taglib=nil) 25: super template 26: 27: @taglib = taglib 28: 29: @uid = (@@uid += 1) 30: @code = "" 31: 32: generate_header 33: generate_code 34: generate_footer 35: compile 36: end
Compile generated code into a Proc.
# File tangerine.rb, line 147 147: def compile 148: begin 149: @template = eval @code, nil, "(tangerine)", 1 150: rescue SyntaxError 151: raise 152: "Internal error during compilation. Please submit a bugreport.\n" << $! 153: end 154: end
Return a string to be appended to string in order to return code that performs output escaping.
# File tangerine.rb, line 40 40: def escaper 41: "" 42: end
Expand the template for object by calling given methods and inline code.
# File tangerine.rb, line 45 45: def expand(object) 46: begin 47: @template.call object 48: rescue => exception 49: raise exception.exception("During template expansion:\n" << 50: " #{exception}\n" << 51: " #{Tangerine.indent 4, exception.backtrace.join("\n")}\n") 52: end 53: end
Parse the template and generate appropriate output code.
# File tangerine.rb, line 66 66: def generate_code 67: @cursor = 0 68: @mark = 0 69: 70: while @cursor = index(',,', @cursor) 71: # Skip second comma. 72: skip 73: 74: # Do comma escaping? 75: if peek == ?, 76: skip while peek && peek == ?, 77: emit_text selection 78: @mark = @cursor 79: next 80: else 81: emit_text selection 82: end 83: 84: # Skip comment? 85: if peek == ?# 86: @mark = @cursor = index("\n", @cursor) + 1 87: emit_code "\n" # Keep lineno uptodate. 88: next 89: end 90: 91: # Initialize local variables. 92: method = "" 93: resolve = false 94: indent = get_indentation 95: escape = get_escape 96: 97: case peek 98: when ?@ 99: # Use taglib ... 100: skip 101: resolve = true 102: tag = get_tag 103: raise 'Tag not resolvable: foo' unless @taglib 104: expansion = @taglib.resolve(tag) 105: when ?( 106: # ... or instance_eval ... 107: skip 108: method = read_to '('[0], ')'[0] 109: when ?[ 110: # Use instance_eval + refhack 111: skip 112: method = "self" + read_to('['[0], ']'[0]) 113: else 114: # ... or send? 115: method = get_tag 116: end 117: 118: # Read block? 119: block = read_block 120: 121: skip 122: 123: if resolve 124: emit_code "#{result_variable} = " + self.class.new(expansion, @taglib).code + ".call(#{object_variable}); "; 125: elsif method =~ /^[\w_]+[!?]?$/ 126: emit_code "#{result_variable} = #{object_variable}.#{method}; " 127: else 128: emit_code "#{result_variable} = #{object_variable}.instance_eval(#{method.dump}); " 129: end 130: 131: if block 132: emit_code "#{template_variable} = " + self.class.new(block).code 133: emit_code "; #{indent}(#{result_variable} && [*#{result_variable}].map { |d| #{text_variable} << #{template_variable}.call(d) }).to_s#{escape}); " 134: else 135: emit_code "#{text_variable} << #{indent}#{result_variable}.to_s#{escape}); " 136: end 137: 138: @mark = @cursor 139: end 140: 141: @cursor = -1 if @cursor.nil? 142: 143: emit_text selection_to_end 144: end
Emit the code footer.
# File tangerine.rb, line 61 61: def generate_footer 62: emit_code "#{text_variable} }" 63: end