Class: TemplatePage

Inherits:
Object
  • Object
show all
Defined in:
lib/rdoc/template.rb

Overview

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)

Defined Under Namespace

Classes: Context, LineReader

Instance Method Summary collapse

Constructor Details

#initialize(*templates) ⇒ TemplatePage

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



132
133
134
135
136
137
138
# File 'lib/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

Instance Method Details

#expand_line(line) ⇒ Object

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



201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/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) ⇒ Object

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



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/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) ⇒ Object

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)



144
145
146
147
# File 'lib/rdoc/template.rb', line 144

def write_html_on(op, value_hash)
  @context = Context.new
  op << substitute_into(@lines, value_hash).tr("\000", '\\')
end