lib/temple/core.rb
module Temple # == The Core Abstraction # # The core abstraction is what every template evetually should be compiled # to. Currently it consists of four essential and two convenient types: # multi, static, dynamic, block, newline and capture. # # When compiling, there's two different strings we'll have to think about. # First we have the generated code. This is what your engine (from Temple's # point of view) spits out. If you construct this carefully enough, you can # make exceptions report correct line numbers, which is very convenient. # # Then there's the result. This is what your engine (from the user's point # of view) spits out. It's what happens if you evaluate the generated code. # # === [:multi, *sexp] # # Multi is what glues everything together. It's simply a sexp which combines # several others sexps: # # [:multi, # [:static, "Hello "], # [:dynamic, "@world"]] # # === [:static, string] # # Static indicates that the given string should be appended to the result. # # Example: # # [:static, "Hello World"] # # is the same as: # _buf << "Hello World" # # [:static, "Hello \n World"] # # is the same as # _buf << "Hello\nWorld" # # === [:dynamic, ruby] # # Dynamic indicates that the given Ruby code should be evaluated and then # appended to the result. # # The Ruby code must be a complete expression in the sense that you can pass # it to eval() and it would not raise SyntaxError. # # === [:block, ruby] # # Block indicates that the given Ruby code should be evaluated, and may # change the control flow. Any \n causes a newline in the generated code. # # === [:newline] # # Newline causes a newline in the generated code, but not in the result. # # === [:capture, variable_name, sexp] # # Evaluates the Sexp using the rules above, but instead of appending to the # result, it sets the content to the variable given. # # Example: # # [:multi, # [:static, "Some content"], # [:capture, "foo", [:static, "More content"]], # [:dynamic, "foo.downcase"]] # # is the same as: # _buf << "Some content" # foo = "More content" # _buf << foo.downcase module Core # Implements an array buffer. # # _buf = [] # _buf << "static" # _buf << dynamic # block do # _buf << "more static" # end # _buf.join class ArrayBuffer < Generator def preamble; buffer " = []" end def postamble; buffer ".join" end def on_static(text) to_ruby(text) end def on_dynamic(code) code end def on_block(code) code end end # Just like ArrayBuffer, but doesn't call #join on the array. class Array < ArrayBuffer def postamble; buffer; end end # Implements a string buffer. # # _buf = '' # _buf << "static" # _buf << dynamic.to_s # block do # _buf << "more static" # end # _buf class StringBuffer < ArrayBuffer def preamble; buffer " = ''" end def postamble; buffer end def on_dynamic(code) if @options[:check_literal] && Utils.literal_string?(code) code else "(#{code}).to_s" end end end end end