# code: # * George Moschovitis # # (c) 2004 Navel, all rights reserved. # $Id: shaders.rb 189 2004-12-13 21:38:05Z gmosx $ module N # = Shader # # The equivalent of a 3d engine shader. In essence it defines a # transformation-pipeline that tansforms the .xhtml files to actual # ruby code ready for evaluation (compilation) by the engine. # # Shaders are equivalend to the render-pipeline filters, ie they # share their folded-filter design. #-- # TODO: pipeline stage mixin to be reused in filters too. #++ # class Shader # the next stage in the Shader pipeline. attr :next_stage def initialize(next_stage = nil) @next_stage = next_stage end # Process the text and optionally update the hash. # The hash is a short, unique representation of the input text, # typically used as a caching key. # def process(hash, text) process_next(hash, text) end # Set the next stage of the pipeline. # def << (next_stage = nil) @next_stage = next_stage return self end # Process the next stage of the pipeline. # def process_next(hash, text) if @next_stage return @next_stage.process(hash, text) else return hash, text end end end # = RubyShader # # Convert the xhtml script to actual Ruby code, ready to be # evaluated. # class RubyShader < N::Shader # Convert the xhtml script to actual Ruby code, ready to be # evaluated. # #-- # Investigate: # perhaps xl:href should be used to be XLink compatible? #++ # def process(hash, text) # strip the xml header! (interracts with the following gsub!) text.gsub!(/<\?xml.*\?>/, "") # statically include sub script files. # The target file is included at compile time. # # gmosx: must be xformed before the # text.gsub!(/<\?include href="(.*?)"(.*)\?>/) { |match| # gmosx: xmm match matches the whole string. # match = overload_path($1) load_statically_included("#$root_dir/#$1") } # xform include instructions # must be transformed before the processinc instructions. text.gsub!(//) { |match| "" } # remove elements. typically removed by xslt but lets # play it safe. text.gsub!(/<(\/)?root>/, '') # runtime ruby code. # xform the processing instructions, use /, "\n@out << %^") text.gsub!(/<\?r(\s?)/, "^\n") # xform alternative code tags (very useful in xsl stylesheets) # text.gsub!(/<\/ruby>/, "\n@out << %^") text.gsub!(//, "^\n") # compile time ruby code. # Usefull for example to prevaluate localization. text.gsub!(/\#\[(.*?)\]/) { |match| eval($1) } text = "@out << %^" + text + "^" process_next(hash, text) end # Loads and statically includes a file. # def load_statically_included(filename) $log.debug "Statically including '#{filename}'" if $DBG text = File.read(filename) text.gsub!(/<\?xml.*\?>/, '') text.gsub!(/<\/?root(.*?)>/m, ' '); return text end end # = XSLTShader # # Apply an XSL transformation to the script code. # There is no need to keep post xsl. I can reuse the same xsl # by calling transform again. # class XSLTShader < N::Shader # The name attr :name # The xslt filename. attr :xsl_filename # The xslt transformer. attr :xslt # Last modified time of the xslt. attr :mtime def initialize(xsl_filename, next_stage = nil) # leave this require here. only inlcude the xslt # library if the project needs it. require "xml/xslt" @name = File.basename(xsl_filename, '.*') @xsl_filename = xsl_filename @xslt = XML::XSLT.new @next_stage = next_stage end # Transform the given text # def process(hash, text) parse_xsl() @xslt.xml = text hash += @name process_next(hash, xslt.serve) end private # Parse the xsl. # def parse_xsl $log.debug "Parsing xsl '#{@xsl_filename}'" if $DBG @mtime = File.mtime(@xsl_filename) @xslt.xsl = File.read(@xsl_filename) end end # = CompressShader # # Compress the inline xhtml. Does not touch the ruby code. # class CompressShader < N::Shader # Compress the inline xhtml. Does not touch the ruby code. # def process(hash, text) text.gsub!(/\@out \<\< \%\^(.*?)\^/m) do |match| c = $1.gsub(/^(\s*)/m, '').squeeze(" \t").tr("\n", '').tr("\t", ' ') "@out << %{#{c}}" end process_next(hash, text) end end end # module