Class: TemplatePage

Class | TemplatePage
In: | rdoc/template.rb
Parent: | Object

Cheap-n-cheerful HTML page template system. You create a template containing:

- variable names between percent signs (`%fred%`)
- blocks of repeating stuff:

        START:key
          ... stuff
        END:key

You feed the code a hash. For simple variables, the values are resolved directly from the hash. For blocks, the hash entry corresponding to `key` will be an array of hashes. The block will be generated once for each entry. Blocks can be nested arbitrarily deeply.

The template may also contain

      IF:key
        ... stuff
      ENDIF:key

stuff will only be included in the output if the corresponding key is set in the value hash.

Usage: Given a set of templates `T1, T2,` etc

               values = { "name" => "Dave", state => "TX" }

               t = TemplatePage.new(T1, T2, T3)
               File.open(name, "w") {|f| t.write_html_on(f, values)}
            or
               res = ''
               t.write_html_on(res, values)

### Methods

expand_line new substitute_into write_html_on

### Classes and Modules

Class TemplatePage::Context
Class TemplatePage::LineReader

### Public Class methods

new(*templates)

`templates` is an array of strings containing the templates. We start at the first, and substitute in subsequent ones where the string `!INCLUDE!` occurs. For example, we could have the overall page template containing

      <html><body>
        <h1>Master</h1>
        !INCLUDE!
      </bost></html>

and substitute subpages in to it by passing [master, sub_page]. This gives us a cheap way of framing pages

[Source]

    # File rdoc/template.rb, line 132
      def initialize(*templates)
        result = "!INCLUDE!"
        templates.each do |content|
          result.sub!(/!INCLUDE!/, content)
        end
        @lines = LineReader.new(result.split($/))
      end

### Public Instance methods

expand_line(line)

Given an individual line, we look for %xxx% constructs and HREF:ref:name: constructs, substituting for each.

[Source]

    # File rdoc/template.rb, line 201
      def expand_line(line)
        # Generate a cross reference if a reference is given,
        # otherwise just fill in the name part

        line.gsub!(/HREF:(\w+?):(\w+?):/) {
          ref = @context.lookup($1)
          name = @context.find_scalar($2)

          if ref and !ref.kind_of?(Array)
            "<a href=\"#{ref}\">#{name}</a>"
          else
            name
          end
        }

        # Substitute in values for %xxx% constructs.  This is made complex
        # because the replacement string may contain characters that are
        # meaningful to the regexp (like \1)

        line = line.gsub(/%([a-zA-Z]\w*)%/) {
          val = @context.find_scalar($1)
          val.tr('\\', "\000")
        }

        line
      rescue Exception => e
        $stderr.puts "Error in template: #{e}"
        $stderr.puts "Original line: #{line}"
        exit
      end

substitute_into(lines, values)

Substitute a set of key/value pairs into the given template. Keys with scalar values have them substituted directly into the page. Those with array values invoke `substitute_array` (below), which examples a block of the template once for each row in the array.

This routine also copes with the `IF:` key directive, removing chunks of the template if the corresponding key does not appear in the hash, and the START: directive, which loops its contents for each value in an array

[Source]

    # File rdoc/template.rb, line 161
      def substitute_into(lines, values)
        @context.push(values)
        skip_to = nil
        result = []

        while line = lines.read

          case line

          when /^IF:(\w+)/
            lines.read_up_to(/^ENDIF:#$1/) unless @context.lookup($1)

        when /^IFNOT:(\w+)/
            lines.read_up_to(/^ENDIF:#$1/) if @context.lookup($1)

          when /^ENDIF:/
            ;

          when /^START:(\w+)/
            tag = $1
            body = lines.read_up_to(/^END:#{tag}/)
            inner_values = @context.lookup(tag)
            raise "unknown tag: #{tag}" unless inner_values
            raise "not array: #{tag}"   unless inner_values.kind_of?(Array)
            inner_values.each do |vals|
              result << substitute_into(body.dup, vals)
            end
          else
            result << expand_line(line.dup)
          end
        end

        @context.pop

        result.join("\n")
      end

write_html_on(op, value_hash)

Render the templates into HTML, storing the result on `op` using the method `<<`. The `value_hash` contains key/value pairs used to drive the substitution (as described above)

[Source]

    # File rdoc/template.rb, line 144
      def write_html_on(op, value_hash)
        @context = Context.new
        op << substitute_into(@lines, value_hash).tr("\000", '\\')
      end

[Validate]