#!/usr/bin/ruby #Given partial HTML files in the pages directory, generate full XHTML files in the htdocs directory. #Each page is given a title corresponding to its directory (in reverse, since browsers often truncate later bits). #A menu parallels the directory structure. Optionally, a file linktitle may be placed in a directory to change the link text in the menu. #htdocs/site.css is set to the stylesheet. #Finally, these pages are surrounded by the usual XHTML incantations. #Where are the input and output files given the web path? class Setup def initialize(in_root, out_root) @in_root = with_slash(in_root) @out_root = with_slash(out_root) end def in_fs(web_path) @in_root + web_path end def out_fs(web_path) @out_root + web_path end private def with_slash(str) str[-1] == "/" ? str : (str + "/") end end #One node in the directory tree. class Directory #Web path attr_reader :path #Basename of path attr_reader :base #Text of link to use. Equal to base unless overridden by a linktitle file. attr_reader :linktitle #Subdirectories, also Directory objects. attr_reader :dirs #HTML documents in this directory, as defined by ending with .html attr_reader :pages def initialize(setup, parent, path) @setup = setup @parent = parent @path = path @nesting = path.count('/') in_fs = @setup.in_fs(path) @base = File.basename(path) @linktitle = @base @pages=[] @dirs=[] Dir.foreach(in_fs) do |entry| if entry == "." or entry == ".." next elsif entry[-5..-1] == ".html" @pages << entry elsif File::Stat.new(in_fs + entry).directory? @dirs << Directory.new(@setup, self, @path + entry + '/') elsif entry == "linktitle" @linktitle = File.new(in_fs + entry).read.chomp else $stderr.puts "Extra file #{path + entry}" end end @dirs.sort! { |a,b| a.linktitle <=> b.linktitle } @pages.sort! $stderr.puts "Missing index.html in #{path}" unless @pages.include?("index.html") #Memoisation table for menu function @menu_cache = {} end def menu(depth, child) cache_key = [depth, child] ret = @menu_cache[cache_key] return ret if ret @menu_cache[cache_key] = if @parent @parent.menu(depth + 1, self) else "