require 'glue/flexob' require 'glue/configuration' module Glue # A template is a text file with embeded Ruby code. The template # processor converts the original text file to ruby code and # then evaluates this code to produce the result of the # template transformation. module TemplateMixin # Convert a template to actual Ruby code, ready to be # evaluated. # # [+template+] # The template as a String. # # [+buffer+] # The variable to act as a buffer where the ruby code # for this template will be generated. Passed as a| # String. # # [+base_dir+] # The base directory where the templates reside. def compile_template(template, buffer = '@out', base_dir = Dir.pwd) text = template.dup # Strip the xml header! (interracts with the following gsub!) text.gsub!(/<\?xml.*\?>/, "") # Statically include sub-template files. # The target file is included at compile time. # # gmosx: must be xformed before the text.gsub!(/<\?include href=["|'](.*?)["|'](.*)\?>/) do |match| text = File.read("#{base_dir}/#$1") text.gsub!(/<\?xml.*\?>/, '') text.gsub!(/<\/?root(.*?)>/m, ' '); text end # Transform include instructions # must be transformed before the processinc instructions. # Useful to include fragments cached on disk # # gmosx, FIXME: NOT TESTED! test and add caching. # add load_statically_included fixes. text.gsub!(//) do |match| "" end # xform render/inject instructions # must be transformed before the processinc instructions. text.gsub!(//) do |match| "" end text.gsub!(//) do |match| "" end # Remove elements. typically removed by xslt but lets # play it safe. The element is typically added to # template files to make them XHTML valid. text.gsub!(/<(\/)?root>/, '') # Transform the processing instructions, use /, "; #{buffer} << %^") text.gsub!(/<\?r(\s?)/, "^; ") # Transform alternative code tags. # (very useful in xsl stylesheets) text.gsub!(/<\/ruby>/, "; #{buffer} << %^") text.gsub!(//, "^; ") # Also handle erb/asp/jsp style tags. Those tags # *cannot* be used with an xslt stylesheet. text.gsub!(/%>/, "; #{buffer} << %^") text.gsub!(/<%/, "^; ") # Alterative versions of interpolation. # (very useful in xsl stylesheets) # Example: #\my_val\ text.gsub!(/\#\\(.*?)\\/, '#{\1}') # Alternative for entities. # (useful in xsl stylesheets) # Examples: %nbsp;, %rquo; text.gsub!(/%(\S*?);/, '&\1;') # Compile time ruby code. This code is evaluated when # compiling the template and the result injected directly # into the result. Usefull for example to prevaluate # localization. Just use the #[] marker instead of #{}. text.gsub!(/\#\[(.*?)\]/) do |match| eval($1) end text = "#{buffer} << %^" + text + "^" return text end # Evaluate the template. # # [+ruby+] # A String containing the compiled template # code. # # [+binding+] # The evaluation binding for the rendering. def evaluate_template(ruby, the_binding = nil) eval(ruby, the_binding) end # Compile and render the template. def process_template(template, buffer = '@out', the_binding = nil) evaluate_template(compile_template(template, buffer), the_binding) end end # A helper class that provides access to the Template methods # as singleton methods. class Template # The default root directory where template files reside. setting :root, :default => 'public', :doc => 'The default root directory where template files reside' # The default template name. setting :default, :default => 'index', :doc => 'The default template name' # The default template file extension. setting :extension, :default => 'xhtml', :doc => 'The default template file extension' class << self include TemplateMixin alias_method :compile, :compile_template alias_method :transform, :compile_template alias_method :evaluate, :evaluate_template alias_method :process, :process_template end include TemplateMixin # Helper. def render(template) str = '' process_template(template, 'str', binding) return str end end # A Template that reads from files and also # provides a simple but effective caching scheme. # An intuitive binding mechanism provides the # expansion environment. class FileTemplate < Flexob include TemplateMixin @@compiled_template_cache = {} attr_accessor :template_filename def initialize(filename = nil) super @template_filename = filename end def process __out__ = '' unless compiled = @@compiled_template_cache[@template_filename] template = File.read(@template_filename) compiled = compile_template(template, '__out__') @@compiled_template_cache[@template_filename] = compiled end evaluate_template(compiled, binding) return __out__ end end end # * George Moschovitis