2011年12月01日

日記スクリプト改修

このBlogを作成するのに使用しているHTMLパーサースクリプトを改修しました。元々、パースするスクリプトがあったのですが、Ruby1.8で実装しており、Ruby1.9にした際に使用できなくなったため、変換エンジンの部分を除いて全て一から書き直しました。残業まみれの日常だと、遅々としてプログラムが進みませんでした。

スクリプト本体

#!/usr/local/bin/ruby --encoding=UTF-8
# -*- encoding: utf-8 -*-

# スクリプト名:myDiary.rb
SCRIPT_NAME = "myDiary.rb"
#Version:2.1
SCRIPT_VERSION = "2.1"
#更新履歴
#2009/08/01:ver1.0 日記スクリプト作成
#2009/08/05:ver1.1 Amazoneアフィリエイト対応
#2011/11/20:ver2.0 Ruby1.9系対応、変換エンジン更新、編集フォームCGI化
#2011/12/01:ver2.1 RSS2.0対応

#== 本文パース規則
#=== 段落
#通常の本文は、特に書式をしていせずに書くことで表示する。
#<p>タグによる段落分けは空行で識別を行なっている。
#<br>タグによる段落内の改行は、改行コードをそのまま<br>タグに変換しているため、単純に入力に改行をするだけで表示することができる。
#==== サンプル(変換前)
# 本文の入力は、書式していをせずに入力
# 改行タグの挿入は改行文字を段落内で見つけた場合に挿入する。
#
# 本文の段落分けは、空行を挟むことで可能。
#==== サンプル(変換後)
# <p>
# 本文の入力は、書式していをせずに入力
# <br>
# 改行タグの挿入は改行文字を段落内で見つけた場合に挿入する。
# </p>
# <p>
# 本文の段落分けは、空行を挟むことで可能。
# </p>
#=== 見出し
#見出しは「!」を行頭につけることで作成することができる。見出しはh2からh6まで指定が可能。
#==== サンプル(変換前)
# !見出し1
# !!見出し2
#==== サンプル(変換後)
# <h2>見出し1</h2>
# <h3>見出し2</h3>
#=== プレーンテキスト
#プレーンテキストは「?」が行頭に登場してから、次に「?」が行頭に登場するまでを<pre>タグで囲む。
#==== サンプル(変換前)
# ?
# プレーンテキストは
# 「?」を行頭につけることで表示出来る。
# ?
#==== サンプル(変換後)
# <pre>プレーンテキストは
# 「?」を行頭につけることで表示出来る。</pre>
#=== HTML文書
#明示的にHTML文章を書きたい場合は、行頭を「<」とすると、次の空行を見つけるまでパース処理をキャンセルする。
#=== 特殊文字のキャンセル
#「!」、「?」、「<」で始まる通常の本文を書きたい場合は、行頭に空白文字を一文字入れることで特殊文字をエスケープすることができる。
class README 
end

require "cgi"
require "pathname"
require "erb"
require "date"
require "time"
require "fileutils"
CGI::MAX_MULTIPART_COUNT = 512 #:nodoc: cgi.rbの受け取れるパラーメタを128個から512個にする。
CGI::MAX_MULTIPART_LENGTH = 512*1024*1024 #:nodoc: cgi.rbが受け取れる最大サイズを128MBから512MBにする。

#== 概要
#設定値を格納する。
class CONFIG
  #(Pathname)HTMLを出力した際の、トップのURL。
  BASE_URL = Pathname.new("http://blog.psyche.gaso.jpn.org")
  #(Pathname)テンポラリファイルを作成するディレクトリ。
  TMP_DIR = Pathname.new("./tmp").realpath
  #(Pathname)データファイルが保存されているディレクトリ。
  DATA_DIR = Pathname.new("./data").realpath
  #(pathname)HTMLデータを保存するディレクトリ。
  HTML_DIR = Pathname.new("./html").realpath
  #(pathname)スクリプトが置かれているディレクトリ。
  SCRIPT_DIR = Pathname.new("./").realpath
  #(pathname)HTML書き出し時にHTML_DIRにコピーするディレクトリ。
  COPY_DIR = Pathname.new("./data/files").realpath
  #(string)ステータスファイル名。
  STATUS_FILE_NAME = "status.txt"
  #(string)画像の一時保存ディレクトリ名。
  IMG_TMP_DIR_NAME = "img"
  #(string)HTML出力するトップページのファイル名。
  TOP_FILE_NAME = "index.html"
  #(string)HTML出力するタグ一覧のファイル名。
  ALL_TAG_LIST_FILE_NAME = "tag_list.html"
  #(sting)HTML出力するエントリー一覧のファイル名。
  ENTRY_LIST_FILE_NAME = "entry_list.html"
  #(string)RSS出力するパス。
  RSS_FILE_NAME = "index.rdf"
  #(string)置換文字列リストを保存するファイル名。
  REPLACE_STR_FILE_NAME = "replace_str.dat"
  #(string)サイトのタイトル。
  TITLE = "意伝子発信器"
  #(string)サイトの説明。
  DESCRIPTION = "いずれ消え行く無駄な情報を、密やかに発信する装置。つまり日記。"
  #(int)RSS出力する記事の数。
  RSS_ITEM_MAX = 10
  #(pathname)HTML出力で使用するトップページのテンプレートファイル。
  TEMPLATE_FILE_HTML_TOP = Pathname.new("./template/top.html").realpath
  #(pathname)HTML出力で使用する各日記ページのテンプレートファイル。
  TEMPLATE_FILE_HTML_ENTRY = Pathname.new("./template/entry.html").realpath
  #(pathname)HTML出力で使用する日記リストページのテンプレートファイル。
  TEMPLATE_FILE_HTML_ENTRY_LIST = Pathname.new("./template/entry_list.html").realpath
  #(pathname)HTML出力で使用するタグ一覧ページのテンプレートファイル。
  TEMPLATE_FILE_HTML_TAG = Pathname.new("./template/tag.html").realpath
  #(Pathname)CGIモードで使用するリストページのテンプレートファイル。
  TEMPLATE_FILE_CGI_LIST = Pathname.new("./template/cgi_list.html").realpath
  #(Pathname)CGIモードで使用する編集ページのテンプレートファイル。
  TEMPLATE_FILE_CGI_EDIT = Pathname.new("./template/cgi_edit.html").realpath
  #(pathnaem)CGIモードで使用する待機ページのテンプレートファイル。
  TEMPLATE_FILE_CGI_WAIT = Pathname.new("./template/cgi_wait.html").realpath
  #オリジナル画像の幅
  IMG_WIDTH = 1440
  #オリジナル画像の高さ。
  IMG_HEIGHT = 1440
  #オリジナル画像の品質
  IMG_QUALITY = 95
  #サムネイルの幅。
  THUMB_WIDTH = 300
  #サムネイルの高さ。
  THUMB_HEIGHT = 300
  #サムネイルの品質
  THUMB_QUALITY = 80
  #正方形サムネイルの一辺のサイズ。
  SQUARE_THUMB_SIZE = 70
  #正方形サムネイルの角を丸める大きさ。
  SQUARE_THUMB_R_SIZE = 10
  #画像ファイル(原寸)のファイル名につけるプレフィックス。
  PREFIX_IMG_ORIGINAL = "image_"
  #画像ファイル(サムネイル)のファイル名につけるプレフィックス。
  PREFIX_IMG_THUMB = "thumb_"
  #画像ファイル(正方形サムネイル)のファイル名につけるプレフィックス。
  PREFIX_IMG_THUMB_SQUARE = "thumb_square_"
  #サムネイルの拡張子。
  THUMB_EXTNAME = ".jpg"
  #デバッグモード
  DEBUG = false
  #デバッグモードの時に出力するログファイル。
  LOG_FILE = "/tmp/log.txt" 
end

#== 概要
#ステータス情報を処理する。
class Status
  #=== 概要
  #ステータス情報を出力する。
  #出力した時間を追加して出力する。
  #=== 引数
  #[(string)message] 出力するメッセージ。
  def self.write(message)
    path = CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME
    time = Time.now.strftime("%Y/%m/%d %H:%M:%S").to_s 
    status = path.read if path.file?
    open(path.to_s, "w"){|file|
      file.write("[" + time + "]" + message.to_s + $/)
      file.write(status)
    }
  end

  #=== 概要
  #ステータス情報を削除する。
  def self.delete
    path = CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME
    while path.file?
      path.delete 
      sleep(1)
    end
  end
end

#== 概要
#デバッグ用のメッセージを出力する。
class Debug
  #=== 概要
  #デバッグ用のメッセージを出力する。
  #出力時に日時を追記する。
  #=== 引数
  #[(string)message] 出力メッセージ。
  def Debug.print(message)
    return nil if !CONFIG::DEBUG
    time = Time.now.strftime("%Y/%m/%d %H:%M:%S").to_s 
    File.open(CONFIG::LOG_FILE, "a+", 0770){|file| file.write("[" + time + "]" + message.to_s + $/)}
  end
end

#== 概要
#日記作成プログラム。
#cgi.param["mode"][0]で受け取ったパラメータを元に、各機能を呼び出す。
#== モード
#[wait] upload, edit, convert, rebuildなどのサーバサイドでの処理が行われる際に、ユーザーに待機させるモード。CONFIG::STATUS_FILE_NAMEが存在すると、自動的にこのモードになる。
#[create] 日記を新しく作成する。作成後、新しく作成したページをeditモードで開く。
#[update] 日記編集ページで日記を更新するモード。更新後はeditモードで編集中のページを開く。
#[edit] 日記編集モード。編集ページを開く。
#[delete] 日記削除モード。日記を削除する。削除後はlistモードで開く。
#[upload] 画像アップロードモード。画像アップロード後は、editモードで編集中のページを開く。
#[convert] 日記変換モード。全てのHTMLデータを変換する。
#[rebuild] 日記再変換モード。全てのHTMLデータと画像データの変換を行う。
#[preview] 未実装。
#[list] 日記一覧を表示するモード。この一覧ページから、edit, create, convert, rebuildが呼び出される。
class MyDiary
  #=== 概要
  #MyDiaryの初期化。
  def initialize
    html = ""
    mode = ""

    if ARGV.length > 1 and ARGV[0]=="debug"
      mode = ARGV[1]
    else
      cgi = CGI.new
      mode = cgi.params["mode"][0]
    end
    mode = "wait" if (CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME).file?

    Debug.print("mode=" + mode.to_s)
    case mode
    when "create"
      date = cgi.params["date"][0]
      html = create_entry(date)
    when "update"
      path = Pathname.new(cgi.params["path"][0]).realpath
      title = cgi.params["title"][0].to_s
      tags = cgi.params["tags"][0].to_s
      text = cgi.params["text"][0].to_s
      html = update_edit_entry(path, title, tags, text)
    when "edit"
      path = Pathname.new(cgi.params["path"][0]).realpath
      html = edit_entry(path)
    when "delete"
      path = Pathname.new(cgi.params["path"][0]).realpath
      html = delete_entry(path)
    when "upload"
      path = Pathname.new(cgi.params["path"][0].read).realpath
      files = cgi.params["files"]
      html = upload_img(path, files)
    when "convert"
      html = convert_html
    when "rebuild"
      html = rebuild
    when "preview"
    when "add_replace"
      search_str = cgi.params["search_str"][0].to_s
      replace_str = cgi.params["replace_str"][0].to_s
      add_replace_str(search_str, replace_str)
      html = make_listview
    when "del_replace" 
      search_str = cgi.params["search_str"][0].to_s
      del_replace_str(search_str)
      html = make_listview
    when "wait"
      status_path = CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME
      entry_path = nil
      begin
        entry_path = Pathname.new(cgi.params["path"][0]).realpath
      rescue
        entry_path = ""
      end
      html = show_wait_page(status_path, entry_path)
    else
      html = make_listview
    end

    output_page(html)
  end

  #=== 概要
  #日記本文を置換する文字列セットを追加する。
  #文字列セットはファイルに出力される。
  #重複する文字列は上書きされる。
  #=== 引数
  #[(string)search_str] 検索する文字列。(置換前文字列)
  #[(string)replace_str] 置換する文字列。(置換後文字列)
  def add_replace_str(search_str, replace_str)
    replace = Replace.new(CONFIG::DATA_DIR + CONFIG::REPLACE_STR_FILE_NAME)
    replace.add_str(search_str, replace_str)
  end

  #=== 概要
  #日記本文を置換する文字列セットから文字列を削除する。
  #=== 引数
  #[(string)search_str] 検索する文字列。(置換前文字列)
  def del_replace_str(search_str)
    replace = Replace.new(CONFIG::DATA_DIR + CONFIG::REPLACE_STR_FILE_NAME)
    replace.del_str(search_str)
  end

  #=== 概要
  #生成済みのHTMLデータとサムネイルを全て削除した後、日記データと画像を全て変換する。
  #変換処理はバックグラウンドで行われる。
  #日記一覧ページのHTMLデータを戻り値として返す。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def rebuild
    Status.write("画像変換開始")
    fork{
      pid = fork{
        #HTMLディレクトリ内を削除
        CONFIG::HTML_DIR.each_entry{|path|
          next if path.to_s=="." || path.to_s==".."
	  path = CONFIG::HTML_DIR + path.to_s
	  if path.directory?
	    path.each_entry{|file|
              next if file.to_s=="." || file.to_s==".."
	      (path + file.to_s).delete
	    }
	  end
	  path.delete
	}
	#画像の変換
	CONFIG::DATA_DIR.each_entry{|path|
	  next if !(CONFIG::DATA_DIR+path.to_s).file? || path.to_s=="." || path.to_s==".."
          (CONFIG::HTML_DIR+path.basename(".*").to_s).mkdir(0770)
	  convert_image(CONFIG::DATA_DIR+path.to_s){|index,file|
            Status.write("画像変換(#{path.basename(".*").to_s}:#{index.to_s}) #{file.to_s}")
	  }
	}
	#日記データの変換
	convert_html
      }
      watch_process(pid)
    }
    page_maker=WaitPageMaker.new(CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME, "")
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_WAIT)
    return html
  end

  #=== 概要
  #* 日記をデータからHTMLに変換する。
  #* RSSを出力する。
  #* CONFIG::COPY_DIRをCONFIG::HTML_DIR以下にコピーする。
  #* 変換処理はバックグラウンドで行われる。
  #* 日記一覧ページのHTMLデータを戻り値として返す。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def convert_html
    Debug.print("HTML変換START")
    Status.write("HTML変換開始")
    fork{
      pid = fork{
        #各日記ページを処理
	entries = Entries.new
	tags = Tags.new
	top_page = TopPageMaker.new
	entries.each{|entry|
	  tags.add(entry)
	  entry_page = EntryPageMaker.new(entry)
	  top_page.add_page(entry_page)
	  html = entry_page.bind_template(CONFIG::TEMPLATE_FILE_HTML_ENTRY)
	  write_page(CONFIG::HTML_DIR + (entry.path.basename(".*").to_s + ".html"), html)
          Status.write("ENTRY変換 #{entry.to_s}")
	}

	#日記一覧ページを処理
	entry_list_page = EntryListPageMaker.new(entries)
	html = entry_list_page.bind_template(CONFIG::TEMPLATE_FILE_HTML_ENTRY_LIST)
	write_page(CONFIG::HTML_DIR + CONFIG::ENTRY_LIST_FILE_NAME, html)

        #タグページを処理
        tags.each{|tag|
	  tag_page = TagPageMaker.new(tag)
	  html = tag_page.bind_template(CONFIG::TEMPLATE_FILE_HTML_TAG)
	  write_page(CONFIG::HTML_DIR + (tag.name.to_s + ".html"), html)
          Status.write("TAG変換 #{tag.name.to_s}")
        }
	#タグ一覧ページを処理
	tag_page = TagPageMaker.new(tags)
	html = tag_page.bind_template(CONFIG::TEMPLATE_FILE_HTML_TAG)
	write_page(CONFIG::HTML_DIR + CONFIG::ALL_TAG_LIST_FILE_NAME, html)

	#Topページを処理
	top_page.add_page(tag_page)
	html = top_page.bind_template(CONFIG::TEMPLATE_FILE_HTML_TOP)
	write_page(CONFIG::HTML_DIR + CONFIG::TOP_FILE_NAME, html)

	#RSSを処理
	make_rss(entries)


	#ディレクトリコピー
	FileUtils.cp_r(CONFIG::COPY_DIR.to_s, CONFIG::HTML_DIR.to_s,{:remove_destination => true})

	Debug.print("HTML変換END")
      }
      watch_process(pid)
    }

    page_maker=WaitPageMaker.new(CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME, "")
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_WAIT)
    return html
  end

  #=== 概要
  #プロセスの監視を行う。
  #監視プロセスが終了後、ステータス情報とTMPディレクトリの削除を行う。
  def watch_process(pid)
    fork{
      text = `ps #{pid.to_s} | grep #{pid.to_s}`
      while !(text=="")
        text = `ps #{pid.to_s} | grep #{pid.to_s}`
        Debug.print("プロセス監視中 " + pid.to_s)
	sleep(1)
      end
      Status.delete
      clear_tmp_dir
      Debug.print("プロセス監視終了 " + pid.to_s)
    }
  end

  #=== 概要
  #バックグラウンドで処理が行われているときに、待機ページを表示させる。
  #待機ページは一定時間でリロードを繰り返し、処理終了後に元のページに戻る。
  #=== 引数
  #[(pathname)status_path] ステータス情報ファイルのパス。
  #[(pathname)entry_path] 日記ファイル。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def show_wait_page(status_path, entry_path)
    page_maker = WaitPageMaker.new(status_path, entry_path)
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_WAIT)
    return html
  end

  #=== 概要
  #新しい日記を作成する。
  #日記の作成日時を元に、日記データの保存ファイル名を作成する。
  #重複する場合を想定して日付の末尾に1から始まる連番を振る。
  #日記を作成後、日記一覧ページのHTMLデータを戻り値として返す。
  #=== 引数
  #[(string)date] 日記の作成日時。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def create_entry(date)
    path = CONFIG::DATA_DIR + date.to_s
    i = 1
    while (path.dirname + (path.basename(".txt").to_s + "-" + i.to_s + ".txt")).exist?
      i += 1
    end
    path = path.dirname + (path.basename(".txt").to_s + "-" + i.to_s + ".txt")
    page_maker = EditPageMaker.new
    page_maker.write_entry(path, "", "", "")
    page_maker.read_entry(path)
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_EDIT)
    return html
  end

  #=== 概要
  #編集中の日記データを保存する。
  #保存後は編集ページのHTMLデータを返す。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  #[(string)title] 日記タイトル。
  #[(string)tags] タグ。
  #[(string)text] 日記本文。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def update_edit_entry(path, title, tags, text)
    page_maker = EditPageMaker.new
    page_maker.write_entry(path, title, tags, text)
    page_maker.read_entry(path)
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_EDIT)
    return html
  end

  #=== 概要
  #日記の編集を行う。
  #日記のタイトル、タグ、本文と、画像のアップロードを行うフォームを表示する。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def edit_entry(path)
    page_maker = EditPageMaker.new
    page_maker.read_entry(path)
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_EDIT)
    return html
  end

  #=== 概要
  #日記を削除する。CONFIG::DATA_DIRとCONFIG::HTML_DIRに作成された日記ファイルと画像フォルダを削除する。
  #削除後、日記一覧ページのHTMLデータを戻り値として返す。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def delete_entry(path)
    dir_path = path.dirname + path.basename(".txt").to_s
    if dir_path.directory?
      dir_path.each_entry{|file|
        f = dir_path + file
        next if f.directory?
        f.delete
      }
      dir_path.delete
    end

    html_path = CONFIG::HTML_DIR + path.basename(".txt").to_s
    if html_path.directory?
      html_path.each_entry{|file|
        f = html_path + file
        next if f.directory?
        f.delete
      }
      html_path.delete
    end
    html_file = CONFIG::HTML_DIR + path.basename("")
    html_file.delete if html_file.file?

    path.delete

    page_maker = ListPageMaker.new
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_LIST)
    return html
  end

  #=== 概要
  #画像データをアップロードしサムネイルの作成を行う。
  #CONFIG::TMP_DIRのクリアを行い、ブラウザからの画像データを一時保管を行う。
  #サムネイル作成やファイルコピーを行うimage_converメソッドをデーモンとして起動する。
  #編集ページのHTMLデータを戻り値として返す。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  #[(Array[File])files] cgiで取得したファイル。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def upload_img(path, files)
    clear_tmp_dir
    img_tmp_dir = CONFIG::TMP_DIR + CONFIG::IMG_TMP_DIR_NAME
    FileUtils.mkdir(img_tmp_dir.to_s,{:mode => 0770})

    files.each{|file|
      tmp_file = img_tmp_dir + file.original_filename
      tmp_file.open("w+", 0770){|f|
        f.write file.read
      }
    }

    Status.write("画像変換開始 " + path.basename(".txt").to_s)
    #別プロセスで処理を行う。
    fork{
      pid = fork{
        html_path = CONFIG::HTML_DIR + path.basename(".txt")
	if html_path.directory?
	  html_path.each_entry{|file|
	    next if file.to_s=="." || file.to_s==".."
	    (html_path + file.to_s).delete
	  }
	  html_path.delete
	end
        FileUtils.mkdir(html_path.to_s, {:mode => 0770})

        data_path = CONFIG::DATA_DIR + path.basename(".txt")
        FileUtils.mkdir(data_path.to_s, {:mode => 0770}) if !data_path.directory?

        img_tmp_path = CONFIG::TMP_DIR + CONFIG::IMG_TMP_DIR_NAME
        img_tmp_path.each_entry{|file|
          img_file = img_tmp_path + file.to_s
          next if img_file.directory?
          next if !(img_file.extname.downcase == ".jpg" || img_file.extname.downcase == ".png") 
          FileUtils.copy(img_file.to_s, data_path.to_s, {:preserve => true})
        }

        convert_image(path){|index, file|
          Status.write("画像変換(#{path.basename(".*").to_s}:#{index.to_s}) #{file.to_s}")
	}
      }
      watch_process(pid)
    }

    page_maker = WaitPageMaker.new(CONFIG::TMP_DIR + CONFIG::STATUS_FILE_NAME, path)
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_WAIT)
    
    return html
  end

  #=== 概要
  #日記一覧のHTMLを作成する。
  #=== 戻り値
  #[(string)]HTMLデータ。
  def make_listview
    page_maker = ListPageMaker.new
    html = page_maker.bind_template(CONFIG::TEMPLATE_FILE_CGI_LIST)
    return html
  end

  #=== 概要
  #TMP_DIR内のファイルを再帰的に全て削除する。
  def clear_tmp_dir
    CONFIG::TMP_DIR.entries.each{|path|
      next if path.to_s==".." or path.to_s=="."
      tmp_path = CONFIG::TMP_DIR + path.to_s
      FileUtils.rm_rf(tmp_path.to_s)
    }
  end

  #=== 概要
  #DATAディレクトリに保存されているjpgとpngからサムネイルを作成し、HTMLデータのディレクトリに保存する。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  #=== yield
  #[convert_image{|index, file|}] (int)indexと(pathname)fileの値を引数としてブロックを評価する。処理が完了した際に評価される。
  def convert_image(path)
    html_path = CONFIG::HTML_DIR + path.basename(".txt")
    data_path = CONFIG::DATA_DIR + path.basename(".txt")

    if data_path.directory?
      index = 0
      data_path.entries.sort.each{|file|
        next if file.to_s=="." || file.to_s==".." 
        original_path = data_path + file.to_s
        img_path = html_path + (CONFIG::PREFIX_IMG_ORIGINAL + index.to_s + ".jpg")
        thumb_path = html_path + (CONFIG::PREFIX_IMG_THUMB + index.to_s + CONFIG::THUMB_EXTNAME)
        square_path = html_path + (CONFIG::PREFIX_IMG_THUMB_SQUARE + index.to_s + CONFIG::THUMB_EXTNAME)
        #ImageConverter.convert_image_format(original_path, img_path)
        ImageConverter.make_img(original_path, img_path, CONFIG::IMG_WIDTH, CONFIG::IMG_HEIGHT, CONFIG::IMG_QUALITY)
        ImageConverter.make_img(original_path, thumb_path, CONFIG::THUMB_WIDTH, CONFIG::THUMB_HEIGHT, CONFIG::THUMB_QUALITY)
        ImageConverter.make_square_img(original_path, square_path, CONFIG::SQUARE_THUMB_SIZE, CONFIG::SQUARE_THUMB_R_SIZE)
        index += 1
	
	yield(index, file)
    }
    end
  end

  #=== 概要
  #RSSを出力する。
  #=== 引数
  #[(Entries)entries] 日記の集合。
  def make_rss(entries)
    i = 0
    rss =  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
    rss << "<rss version=\"2.0\""
    rss << "  xmlns:dc=\"http://purl.org/dc/elements/1.1/\""
    rss << "  xmlns:sy=\"http://purl.org/rss/1.0/modules/syndication/\""
    rss << "  xmlns:admin=\"http://webns.net/mvcb/\""
    rss << "  xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">"

    rss << "<channel>"
    rss << "<title>#{CONFIG::TITLE}</title>"
    rss << "<link>#{(CONFIG::BASE_URL + CONFIG::RSS_FILE_NAME).to_s}</link>"
    rss << "<description>#{CONFIG::DESCRIPTION}</description>"
    rss << "<dc:language>ja</dc:language>"
    entries.each{|entry|
      break if i > CONFIG::RSS_ITEM_MAX
      break if i >= entries.length

      date = Time.parse(DateTime.strptime("#{entry.date}+9", "%Y%m%d%Z").to_s).rfc822.to_s
      rss << "<item>"
      rss << "<title>#{entry.title}</title>"
      rss << "<link>#{(CONFIG::BASE_URL + (entry.path.basename(".*").to_s + ".html")).to_s}</link>"
      rss << "<pubDate>#{date}</pubDate>"
      rss << "</item>"
      i = i + 1
    }
    rss << "</channel>"
    rss << "</rss>"

    write_page(CONFIG::HTML_DIR + CONFIG::RSS_FILE_NAME, rss)
  end

  #=== 概要
  #HTMLページを出力する。
  #=== 引数
  #[(pathname)path] 書き出すパス。
  #[(string)html] HTMLデータ。
  def write_page(path, html)
    path.open("w+", 0777){|file|
      file.write(html)
    }
  end

  #=== 概要
  #webページを出力する。
  #出力する際に、ヘッダー情報を付加して出力を行う。
  #=== 引数
  #[(string)html] 出力するHTMLデータを格納した文字列。
  def output_page(html)
    puts "Content-Type: text/html\n\n"
    puts html
  end
end

#== 概要
#画像を変換するクラス。
class ImageConverter
  #=== 概要
  #画像形式を変換する。変換可能な画像形式の種類はRMagick(ImageMagick)による。
  #=== 引数
  #[(pathname)original_img_path] 元画像のパス。
  #[(pathname)output_img_path] 変換後の画像パス。拡張子の画像形式に変換して出力する。
  def self.convert_image_format(original_img_path, output_img_path)
    begin
      info = `/usr/local/bin/identify #{original_img_path.to_s}`
      type = info.split[1]
      width = info.split[2].split("x")[0]
      height = info.split[2].split("x")[1]
 
      `/usr/local/bin/convert -define #{type}:size=#{width}x#{height} -quality 95 #{original_img_path.to_s} #{output_img_path.to_s}`
    rescue => err
      Debug.print("Error ImageConverter path=" + original_img_path.to_s)
      Debug.print("ErrMes=" + err.to_s)
    end
  end

  #=== 概要
  #縮小画像を作成する。
  #=== 引数
  #[(pathname)img_path] 元画像のパス。
  #[(pathname)thumb_path] 出力するサムネイルのパス。拡張子の画像形式に変換して出力する。
  #[(int)img_width] 出力する画像の幅の長さ。
  #[(int)img_height] 出力する画像の高さの長さ。
  #[(int)quality] 変換後の画像の品質。
  def self.make_img(img_path, thumb_path, img_width, img_height, quality)
    begin
      info = `/usr/local/bin/identify #{img_path.to_s}`
      type = info.split[1]
      width = info.split[2].split("x")[0].to_f
      height = info.split[2].split("x")[1].to_f
      if width > img_width || height > img_height
        `/usr/local/bin/convert -define #{type}:size=#{width.to_s}x#{height.to_s} -resize #{img_width.to_s}x#{img_height.to_s} -quality #{quality.to_s} #{img_path.to_s} #{thumb_path.to_s}`
      else
        `/usr/local/bin/convert -define #{type}:size=#{width.to_s}x#{height.to_s} -quality #{quality.to_s} #{img_path.to_s} #{thumb_path.to_s}`
      end
    rescue => err
      Debug.print("Error ImageConverter path=" + original_img_path.to_s)
      Debug.print("ErrMes=" + err.to_s)
    end
  end

  #=== 概要
  #正方形のサムネイルを作成する。画像の角を丸める処理を行う。
  #=== 引数
  #[(pathname)img_path] 元画像のパス。
  #[(pathname)thumb_path] 出力するサムネイルのパス。拡張子の画像形式に変換して出力する。
  #[(int)size] 出力する正方形サムネイルの一辺の長さ。
  #[(int)r_size] 角を丸める大きさ。
  def self.make_square_img(img_path, thumb_path, size, r_size)
    begin
      info = `/usr/local/bin/identify #{img_path.to_s}`
      type = info.split[1]
      width = info.split[2].split("x")[0].to_f
      height = info.split[2].split("x")[1].to_f
      resize = ((width / height)*size).ceil
      resize = ((height / width)*size).ceil if width < height
 
      `/usr/local/bin/convert -define #{type}:size=#{width.to_s}x#{height.to_s} -resize #{resize.to_s} -gravity center -crop #{size.to_s}x#{size.to_s}+0+0 -quality 80 #{img_path.to_s} #{thumb_path.to_s}`
    rescue => err
      Debug.print("Error ImageConverter path=" + img_path.to_s)
      Debug.print("ErrMes=" + err.to_s)
    end
  end
end

#== 概要
#CGI動作時にページを生成するクラスの基底クラス。
class PageMaker
  #=== 概要
  #テンプレートを適用しHTMLデータを作成する。
  #=== 引数
  #[(pathname)template_file] 適用するテンプレートファイル。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def bind_template(template_file)
    template = template_file.open("r"){|f| f.read}
    erb = ERB.new(template)
    html = erb.result(binding)
    return html
  end
end

#== 概要
#待機ページを生成する。
#一定間隔でリロードを繰り返す動作をする。
class WaitPageMaker < PageMaker
  #=== 概要
  #WaitPageMakerの初期化
  #=== 引数
  #[(pathname)status_path] ステータス情報ファイル。
  #[(pathname)enrty_path] 日記のパス。nilや""を指定した場合はcgiモードをlistにし、リストページを再読み込みする。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def initialize(status_path, entry_path)
    status = ""
    status = status_path.readlines if status_path.file?
    @status_info = make_status_info(status)
    @reload_script = make_reload_script(entry_path)
  end

  private
  #=== 概要
  #ステータス情報をステータスファイルから読み込んで出力する。
  #=== 引数
  #[(string)tatus] ステータス情報。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_status_info(status)
    html = "<pre>"
    status.each{|text|
      html << text.chomp + $/
    }
    html << "</pre>"
    return html
  end

  #=== 概要
  #自動でページをリロードするスクリプトを出力する。
  #日記のパスで指定した編集ページを再読み込みしようとする。
  #=== 引数
  #[(pathname)enrty_path] 日記のパス。nilや""を指定した場合はcgiモードをlistにし、リストページを再読み込みする。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_reload_script(entry_path)
    html =  "<script type='text/javascript'>"
    html << "  setTimeout('document.send.submit()',2000);" 
    html << "</script>"
    html << "<form name='send' method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
    html << "  <intpu type='submit'>"
    if entry_path.to_s=="" || entry_path.to_s==nil
      html << "  <input type='hidden' name='mode' value='list'>"
    else
      html << "  <input type='hidden' name='mode' value='edit'>"
      html << "  <input type='hidden' name='path' value='" + entry_path.to_s + "'>"
    end
    html << "</form>"
    return html
  end
end

#== 概要
#日記の編集ページを生成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@edit_form%>] 日記編集用の入力欄。
#[<%=@edit_date%>] 編集中の日記の日付。
#[<%=@upload_form%>] 画像アップロードボタン。
#[<%=@update_time%>] 日記編集ページの更新時間。
#[<%=@thumb_icon%>] サムネイル。サムネイルが一枚もない場合は、"画像なし"が出力される。
class EditPageMaker < PageMaker
  #=== 概要
  #EditPageMakerの初期化。
  def initialize
    @edit_form = nil
    @edit_date = nil
    @upload_form = nil
    @thumb_icon = nil
    @update_time = Time.now.to_s
  end

  #=== 概要
  #ファイルに日記データを書き込む。
  #=== 引数
  #[(pathname)path] 書きこむ日記ファイル。
  #[(string)title] 日記タイトル。
  #[(string)tags] タグ。
  #[(string)text] 日記本文。
  def write_entry(path, title, tags, text)
    path.open("w+", 0770){|file|
      file.write(title + $/)
      file.write(tags + $/)
      file.write(text)
    }
    @update_time = Time.now.to_s
  end

  #=== 概要
  #ファイルから日記データを読み込む。
  #=== 引数
  #[(pathname)path] 読み込む日記ファイル。
  def read_entry(path)
    entry = path.readlines
    @edit_form = make_edit_form(entry, path)
    @edit_date = path.basename(".txt").to_s
    @upload_form = make_upload_form(path)
    @thumb_icon = make_thumb_list(path)
    @update_time = Time.now.to_s
  end

  private
  #=== 概要
  #サムネイルの画像一覧を作成する。
  #=== 引数
  #[(pathname)path] 読み込む日記ファイル。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_thumb_list(path)
    html_path = CONFIG::HTML_DIR + path.basename(".txt")

    html = "<div id='thumb'>"
    begin
      html_path.entries.each_with_index{|thumb, index|
	next if thumb.directory? || !thumb.to_s.include?(CONFIG::PREFIX_IMG_ORIGINAL)
	img_path = html_path + thumb.basename.to_s
        filename = thumb.basename(".*").to_s
        index = filename.delete(CONFIG::PREFIX_IMG_ORIGINAL)
        thumb_path = html_path + (CONFIG::PREFIX_IMG_THUMB_SQUARE+index+CONFIG::THUMB_EXTNAME)
        html << "#{index.to_s}<a target='./blank' href='#{img_path.relative_path_from(CONFIG::SCRIPT_DIR)}'><img name='#{index.to_s}' data-path='<%=@img[:thumb][#{index.to_s}]%>' src='#{thumb_path.relative_path_from(CONFIG::SCRIPT_DIR).to_s}'></a> "
      }
    rescue
      html << "<p>画像なし</p>"
    end
    html << "</div>"
    html << "<script type='text/javascript'>"
    html << "$(function(){"
    html << "  $('div#thumb img').bind('contextmenu', function(){"
    html << "    var path=$(this).data('path');"
    html << "    insertText(path);"
    html << "    return false;"
    html << "  });"
    html << "});"

    html << "function insertText(text){"
    html << "  var o = $('#area').get(0);"
    html << "  o.focus();"
    html << "  var s = o.value;"
    html << "  var p = o.selectionStart;"
    html << "  var np = p + text.length;"
    html << "  o.value = s.substr(0, p) + text + s.substr(p);"
    html << "  o.setSelectionRange(np, np);"
    html << "};"
    html << "</script>"
    return html
  end

  #=== 概要
  #ファイルをアップトードするフォームを作成する。
  #javascriptで、ファイルが未選択の時は、アップロードボタンを押せないようにする。
  #=== 引数
  #[(pathname)path] 読み込む日記ファイル。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_upload_form(path)
    html = "<script type='text/javascript'>"
    html << "function onFilesSelected(){"
    html << "  var files = document.getElementById(\"fileSelectButton\").files;"
    html << "  if(files.length >= 0){"
    html << "    $(\"input#fileUploadButton\").removeAttr(\"disabled\");"
    html << "  }else{"
    html << "    $(\"input#fileUploadButton\").attr(\"disabled\",\"\");"
    html << "  }"
    html << "};"
    html << "</script>"
    html << "<form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}' enctype='multipart/form-data'>"
    html << "<input id='fileUploadButton' type='submit' name='mode' value='upload' disabled><input type='file' id='fileSelectButton' name='files' multiple onchange='onFilesSelected()'>"
    html << "<input type='hidden' name='path' value='#{path.to_s}'>"
    html << "</form>"
    return html
  end

  #=== 概要
  #編集フォームを作成する。
  #=== 引数
  #[(Array[string])entry] ファイルから読み込んだ日記データ。
  #[(pathname)path] 編集する日記データのパス。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_edit_form(entry, path)
    title = make_title_textbox(entry)
    tags = make_tags_textbox(entry)
    text = make_text_textarea(entry)
    html = "<form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
    html << "<dl>"
    html << "<dt>タイトル</dt>"
    html << "<dd>#{title}</dd>"
    html << "<dt>タグ</dt>"
    html << "<dd>#{tags}</dd>"
    html << "<dt>本文</dt>"
    html << "<dd>#{text}</dd>"
    html << "<dt>処理</dt>"
    html << "<dd>"
    html << "<input type='submit' name='mode' value='update'>"
    html << "<input type='submit' name='mode' value='delete' onclick=\"return confirm('delete ok?')\">"
    html << "<input type='submit' name='mode' value='list'>"
    html << "</dd>" 
    html << "</dl>"
    html << "<input type='hidden' name='path' value='#{path.to_s}'>"
    html << "</form>"
    return html
  end

  #=== 概要
  #日記タイトルを編集するテキストボックスを作成する。
  #=== 引数
  #[(Array[string])entry] ファイルから読み込んだ日記データ。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_title_textbox(entry)
    title = ""
    if entry.length > 0 && entry[0]!=$/
      title = entry[0].chomp
    end
    html = "<input class='text' type='text' name='title' value='" + title + "'>"
    return html
  end

  #=== 概要
  #日記のタグ情報を編集するテキストボックスを作成する。
  #=== 引数
  #[(Array[string])entry] ファイルから読み込んだ日記データ。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_tags_textbox(entry)
    tags = ""
    if entry.length > 1 && entry[1]!=$/
      tags = entry[1].chomp
    end
    html = "<input class='text' type='text' name='tags' value='" + tags + "'>"
    return html
  end

  #=== 概要
  #日記本文を編集するテキストエリアを作成する。
  #=== 引数
  #[(Array[string])entry] ファイルから読み込んだ日記データ。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_text_textarea(entry)
    text = ""
    if entry.length > 2 && entry[2]!=$/
      entry.each_with_index{|line, index|
        next if index == 0 || index == 1
        text << line
      }
    end
    html = "<textarea id='area' name='text'>"
    html << text
    html << "</textarea>"
    return html
  end
end

#== 概要
#CGI動作時に日記一覧ページを生成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@num_entries%>] 日記のエントリー数。
#[<%=@entry_list%>] 日記一覧(編集・削除ボタン付き)。
#[<%=@create_entry%>] 新しく日記を作成するフォーム。
#[<%=@convert_html%>] 日記をHTMLに変換するボタン。
#[<%=@create_replace%>] 新しく日記本文を置換する文字列を登録するフォーム。
#[<%=@replace_list%>] 置換文字列の一覧(削除ボタン付き)。
class ListPageMaker < PageMaker
  #=== 概要
  #ListPageMakerの初期化。
  def initialize
    entries = Array.new
    entries = get_entries
    @entry_list = make_entry_list(entries)
    @num_entries = entries.length
    @create_entry = make_create_entry_form
    @convert_html = make_html_convert_button
    @create_replace = make_create_replace_form
    @replace_list = make_html_replace_list
  end

  private
  #=== 概要
  #置換文字列の一覧を作成する。
  #各置換文字列に、削除ボタンを作成する。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_html_replace_list
    html =  "<dl>"
    replace = Replace.new(CONFIG::DATA_DIR + CONFIG::REPLACE_STR_FILE_NAME)
    replace.replace_hash.keys.reverse.each{|key|
      html << "<dt><form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
      html << "<input type='hidden' name='search_str' value='#{key.to_s}'>"
      html << "<input type='submit' name='mode' value='del_replace'>"
      html << ERB::Util.h(key.to_s)
      html << "</form></dt>"
      html << "<dd>#{ERB::Util.h(replace.replace_hash[key.intern].to_s)}</dd>"
    }
    html << "</dl>"
    return html
  end

  #=== 概要
  #日記本文を置換する文字列を登録するフォームを作成する。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_create_replace_form
    html =  "<form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
    html << "search str:<input type='text' name='search_str' class='replace'>"
    html << "<br>"
    html << "replace str:<input type='text' name='replace_str' class='replace'>"
    html << "<br>"
    html << "<input type='submit' name='mode' value='add_replace'>"
    html << "</form>"
  end

  #=== 概要
  #日記をHTMLに変換するボタンを作成する。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_html_convert_button
    html = "<form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
    html << "<input type='submit' name='mode' value='convert'>"
    html << "<input type='submit' name='mode' value='rebuild'>"
    html << "</form>"
    return html
  end

  #=== 概要
  #新しく日記を作成する。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_create_entry_form
    html = "<form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}'>"
    html << "<input type='text' name='date' value='" + Time.now.strftime("%Y%m%d").to_s + "'>"
    html << "<input type='submit' name='mode' value='create'>"
    html << "</form>"
    return html
  end

  #=== 概要
  #日記データのファイル一覧から各日記の編集ページへのリンクを作成する。
  #=== 引数
  #[(Array[pathname])entries] 日記データのファイル一覧。
  #=== 戻り値
  #[string] HTMLデータ。
  def make_entry_list(entries)
    html = "<ul>"
    entries.each{|entry|
      html << "<li><form method='post' action='myDiary.rb?#{Time.now.tv_sec.to_s}' enctype='multipart/form-data'>"
      html << "<input type='hidden' name='path' value='" + entry.to_s + "'>"
      html << "<input type='submit' name='mode' value='edit'>"
      html << entry.basename(".txt").to_s
      html << " : "
      html << (CONFIG::DATA_DIR + entry.to_s).readlines[0]
      html << "</form></li>"
    }
    html << "</ul>"
    return html
  end

  #=== 概要
  #データフォルダ内にある日記データのファイル一覧を取得する。
  #ファイル一覧は最新日付順で並べられる。
  #=== 戻り値
  #[Array(pathname)] 日記データのファイル一覧。
  def get_entries
    entries = Array.new
    CONFIG::DATA_DIR.each_entry{|path|
      data_path = CONFIG::DATA_DIR + path
      next if data_path.directory? || data_path.extname!=".txt"
      entries << data_path
    }
    return entries.sort{|a,b| b.to_s <=> a.to_s}
  end
end

#== 概要
#日記のトップページを作成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@entries[index].path%>] EntryPageMakerのテンプレートが全て使用できる。 
#[<%=@tag.tag_list%>] TagPageMakerのテンプレートが全て使用できる。
class TopPageMaker < PageMaker
  #=== 概要
  #TopPageMakerの初期化。
  def initialize
    @pages = Array.new
    @tag = nil
  end

  #=== 概要
  #ページ配列への参照の定義。
  #=== 引数
  #[(int)index] 配列のインデックス。
  #=== 戻り値
  #[(EntryPageMaker)] ページ。
  def [](index)
    return @pages[index]
  end

  #=== 概要
  #日記ページを追加する。
  #=== 引数
  #[(EntryPageMaker || TagPageMaker)page] 日記ページ。
  def add_page(page)
    @pages << page if page.class.to_s=="EntryPageMaker"
    @tag = page if page.class.to_s=="TagPageMaker"
  end
end

#== 概要
#エントリー一覧のページを作成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@num%>] エントリーの総数。
#[<%=@entry_list%>] エントリー一覧のリスト。
class EntryListPageMaker < PageMaker
  #=== 概要
  #EntryListPageMakerの初期化。
  #=== 引数
  #[(Entries)entries] 日記の集合。
  def initialize(entries)
    @num = entries.length.to_s
    @entry_list = make_entry_list(entries)
  end

  private
  #=== 概要
  #全てのエントリーのリストを作成する。
  #=== 引数
  #[(Entries)entries] エントリー。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_entry_list(entries)
    html = "<ul class='entry'>"
    entries.each{|entry|
      year = entry.date[0,4]
      month = entry.date[4,2]
      day = entry.date[6,2]

      html << "<li>"
      html << "#{year}年#{month}月#{day}日 "
      html << "<a href='#{ERB::Util.h(entry.path.basename(".*"))}.html'>#{entry.title}</a>"
      html << "</li>"
    }
    html << "</ul>"
    return html
  end
end

#== 概要
#タグ一覧のページを作成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@tag_name%>] タグの名前。
#[<%=@tag_list%>] タグ一覧のリスト、又はタグを含むエントリーのリスト。
class TagPageMaker < PageMaker
  #タグの名前
  attr_reader :tag_name
  #タグ一覧のリスト、又はタグを含むエントリーのリスト。
  attr_reader :tag_list

  #=== 概要
  #TagPageMakerの初期化。
  #Tagオブジェクトで初期化を行うと、そのタグのエントリーリストを作成する。
  #Tagsオブジェクトで初期化を行うと、タグのリストを作成する。
  #=== 引数
  #[(Tag又はTags)tag] タグ。
  def initialize(tag)
    if tag.class.to_s == "Tag"
      @tag_name = tag.name
      @tag_list = make_list(tag)
    elsif tag.class.to_s == "Tags"
      @tag_name = "タグ一覧"
      @tag_list = make_tag_list(tag)
    end
  end

  private
  #=== 概要
  #全てのタグの一覧のリストを作成する。
  #=== 引数
  #[(Tags)tags] 全てのタグ。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_tag_list(tags)
    html = "<ul class='tag'>"
    tags.each{|tag|
      html << "<li>"
      html << "<a href='#{ERB::Util.h(tag.name)}.html'>#{tag.name}</a> (#{tag.entries.size.to_s})"
      html << "</li>"
    }
    html << "</ul>"
    return html
  end

  #=== 概要
  #タグを含むエントリーのリストを作成する。
  #=== 引数
  #[(Tag)tag] タグ。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_list(tag)
    html = "<ul class='tag'>"
    tag.entries.each{|entry|
      year = entry.date[0,4]
      month = entry.date[4,2]
      day = entry.date[6,2]

      html << "<li>"
      html << "#{year}年#{month}月#{day}日 "
      html << "<a href='#{ERB::Util.h(entry.path.basename(".*").to_s)}.html'>#{entry.title}</a>"
      html << "</li>"
    }
    html << "</ul>"
    return html
  end
end

#== 概要
#日記ページを作成するクラス。
#== 継承
#PageMaker
#== テンプレート
#[<%=@title%>] タイトル。
#[<%=@date%>] 日付。
#[<%=@tags%>] タグページへのリンク。
#[<%=@img%>] 画像へのリンクとサムネイル。<%=@img[:thumb][0]%>で1番目の画像のサムネイルとリンクのHTMLを返す。:thumbを:squareに変更すると、サムネイルを正方形にする。
#[<%=@text%>] 日記本文。
#[<%=@next_entry%>] 次のエントリーへのリンク。
#[<%=@prev_entry%>] 前のエントリーへのリンク。
#[<%=@permalink%>] エントリーへの絶対リンク。
class EntryPageMaker < PageMaker
  #[(string)] タイトル。
  attr_reader :title
  #[(string)] 日付。
  attr_reader :date
  #[(string)] タグページへのリンク。
  attr_reader :tags
  #[(string)] 画像へのリンクとサムネイル。<%=@img[:thumb][0]%>で1番目の画像のサムネイルとリンクのHTMLを返す。:thumbを:squareに変更すると、サムネイルを正方形にする。
  attr_reader :img
  #[(string)] 日記本文。
  attr_reader :text
  #[(string)] 次のエントリーへのリンク。
  attr_reader :next_entry
  #[(string)] 前のエントリーへのリンク。
  attr_reader :prev_entry
  #[(string)] エントリーへの絶対リンク。
  attr_reader :permalink

  #=== 概要
  #EntryPageMakerの初期化。
  #=== 引数
  #[(Entry)entry] 日記。
  def initialize(entry)
    @title = entry.title
    @date = entry.date
    @tags = make_link_tags(entry.tags)
    @img = make_link_img(entry.images)
    @text = ERB.new(parse_text(entry.text)).result(binding)
    @next_entry = make_link_next_entry(entry)
    @prev_entry = make_link_prev_entry(entry)
    @permalink = make_link_permalink(entry)
  end

  #=== 概要
  #エントリーへの絶対リンクを作成する。
  #=== 引数
  #[(Entry)entry] 日記
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_link_permalink(entry)
    path = entry.permalink.relative_path_from(CONFIG::HTML_DIR)
    html = "<a href='#{path.to_s}'>#{entry.title}</a>"
    return html
  end

  private
  #=== 概要
  #次のエントリーへのリンクを作成する。
  #=== 引数
  #[(Entry)entry] 日記
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_link_next_entry(entry)
    html = "Next"
    if entry.next_entry.class.to_s=="Pathname"
      path=entry.next_entry.relative_path_from(CONFIG::HTML_DIR)
      html = "<a href='#{path.to_s}'>Next</a>"
    end
    return html
  end

  private
  #=== 概要
  #前のエントリーへのリンクを作成する。
  #=== 引数
  #[(Entry)entry] 日記
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_link_prev_entry(entry)
    html = "Prev"
    if entry.prev_entry.class.to_s=="Pathname"
      path = entry.prev_entry.relative_path_from(CONFIG::HTML_DIR)
      html = "<a href='#{path.to_s}'>Prev</a>"
    end
    return html
  end

  #=== 概要
  #画像をHTMLに変換する。
  #=== 引数
  #[(Array[pathname])images] HTMLフォルダに保存されたオリジナル画像のパスの配列。
  #=== 戻り値
  #[(Hash[:thumb=>Array[string], :square=>Array[string]])] HTMLデータ。
  def make_link_img(images)
    thumb_arr = Array.new
    square_arr = Array.new
    images.each{|path|
      f = path.basename(".*").to_s.delete(CONFIG::PREFIX_IMG_ORIGINAL) + CONFIG::THUMB_EXTNAME
      d = path.dirname
      original_path = path.relative_path_from(CONFIG::HTML_DIR)
      thumb_path = (d+(CONFIG::PREFIX_IMG_THUMB+f)).relative_path_from(CONFIG::HTML_DIR)
      square_path = (d+(CONFIG::PREFIX_IMG_THUMB_SQUARE+f)).relative_path_from(CONFIG::HTML_DIR)

      thumb = "<a class='thumb' href='#{original_path.to_s}'>"
      thumb << "<img class='thumb' src='#{thumb_path}'>"
      thumb << "</a>"
      thumb_arr << thumb
      square = "<a class='square' href='#{original_path.to_s}'>"
      square << "<img class='square' src='#{square_path}'>"
      square << "</a>"
      square_arr << square
    }
    hash = Hash.new
    hash[:thumb] = thumb_arr
    hash[:square] = square_arr
    return hash
  end

  #=== 概要
  #タグをHTMLに変換する。
  #=== 引数
  #[(string)tags] タグ。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def make_link_tags(tags)
    html = "<a class='tag' href='#{CONFIG::ALL_TAG_LIST_FILE_NAME}'>全てのタグ</a>"
    tags.split.sort.each{|tag|
      html << ", <a class='tag' href='#{tag}.html'>#{tag}</a>"
    }
    return html
  end

  #=== 概要
  #日記本文をHTML文章に変換する。
  #=== 引数
  #[(Arrya[string])text] 日記本文。
  #=== 戻り値
  #[(string)] HTMLデータ。
  def parse_text(text)
    #日記データの構文解析
    html = Array.new
    text << ""
    flag_p = false
    flag_html = false
    flag_pre = false
    text.each{|line|
      line = line.chomp
      #空行時の処理
      #通常モードとHTMLモード(非整形モード)を解除する
      if(line == "")
        if(flag_p)
          html << "</p>"
        elsif(flag_pre)
          html << ERB::Util.h(line)
        end
        flag_p = false
        flag_html = false
      ##空行でないときの処理
      else
        #フラグが立っている場合の処理
        if(flag_html)
          html << line
        elsif(flag_pre)
          #preモードの終わりを示す"?"があれば、モードを終了し</pre>タグを挿入する
          if(line[0,1] == "?")
            flag_pre = false
            html[html.length-1] = html.last + "</pre>"
          else
            html << ERB::Util.h(line)
          end
        #特殊文字"<", "?", "!"の処理
        elsif(line[0,1] == "<" and line[1,1] != "%")
          flag_html = true
          html << line
        elsif(line[0,1] == "?")
          flag_pre = true
          line = line[1,line.length]
	  if(flag_p)
	    html << "</p>"
	    flag_p = false
	  end
          html << "<pre>" + ERB::Util.h(line)
        elsif(line[0,1] == '!')
          if(flag_p)
            html << "</p>"
            flag_p = false
          end
          if(line[1,1] == "!")
            if(line[2,1] == "!")
              if(line[3,1] == "!")
                if(line[4,1] == "!")
                  html << "<h6>" + line[4,line.length] + "</h6>"
                end
              else
                html << "<h5>" + line[3,line.length] + "</h5>"
              end
            else
              html << "<h4>" + line[2,line.length] + "</h4>"
            end
          else
            html << "<h3>" + line[1,line.length] + "</h3>"
          end
        #文頭が特殊文字でない場合の通常処理
        else
          #特殊文字を無効化する際に使う行頭スペースのの処理
          if(line[0] == " ")
            line = line[1,line.length]
          end
          #すでにパラグラフ内にいれば"<br>"を付ける。
          #そうでなければ"<p>"を付けパラグラフ内であるフラグを立てる。
          if(flag_p)
            html << "<br>"
            html << line
          else
            html << "<p>"
            html << line
            flag_p = true
          end
        end
      end
    }
    str = ""
    html.each{|h|
      str << h
      str << $/
    }
    return str
  end
end

#== 概要
#日記の集合
#日記データを読み込み、HTML化したデータに変換する。
class Entries
  #エントリーの数。
  attr_reader :length

  #=== 概要
  #Entriesの初期化を行う。
  def initialize
    @entries = Array.new
    @entries = get_entries
    @length = @entries.length
    @tags = Tags.new
  end

  #=== 概要
  #エントリー配列への参照の定義。
  #=== 引数
  #[(int)index] 配列のインデックス。
  #=== 戻り値
  #[(Entry)] エントリー。
  def [](index)
    return @entries[index]
  end

  #=== 概要
  #各エントリーに対してブロックを評価する。
  def each
    @entries.each{|entry|
      yield(entry)
    }
  end

  private
  #=== 概要
  #全ての日記データファイルを読み込み、Entryオブジェクトとしてパースする。
  #=== 戻り値
  #[(Array[Entry])] エントリーの配列。
  def get_entries
    entries = Array.new
    path = CONFIG::DATA_DIR
    replace = Replace.new(CONFIG::DATA_DIR + CONFIG::REPLACE_STR_FILE_NAME)

    path.entries.sort{|a,b| b.to_s <=> a.to_s}.each{|file|
      full_path = path + file.to_s
      next if !full_path.file? 
      next if full_path.extname!=".txt"

      entry = Entry.new(full_path)
      entry.date = file.to_s[0,8]

      data = full_path.readlines
      text = Array.new
      data.each_with_index{|str,index|
        str = str.to_s.chomp.to_s
        case index
	when 0
	  entry.title = str
	when 1
	  entry.tags = str
	else
	  replace.replace_hash.each{|key, value|
	    str.gsub!(/#{key.to_s}/, value.to_s)
	  }
	  text << str
	end
      }
      entry.text = text

      img_path = CONFIG::HTML_DIR + file.basename(".*").to_s
      if img_path.directory?
        img_path.each_entry{|file|
	  next if file.directory? || !file.to_s.include?(CONFIG::PREFIX_IMG_ORIGINAL)
	  entry.images << img_path + file.to_s
	}
      end
      
      entries << entry
    }

    entries.each_with_index{|entry, index|
      if index+1 != entries.length
        next_entry_path = entries[index+1].path.basename(".*").to_s + ".html"
        entry.next_entry = CONFIG::HTML_DIR + next_entry_path
      end
      if index!=0
        prev_entry_path = entries[index-1].path.basename(".*").to_s + ".html"
        entry.prev_entry = CONFIG::HTML_DIR + prev_entry_path
      end
      permalink = (entry.path.basename(".*").to_s + ".html").to_s
      entry.permalink = CONFIG::HTML_DIR + permalink
    }

    return entries
  end
end

#== 概要
#日記を表現するクラス
class Entry
  #[(pathname)] 日記データのパス。
  attr_accessor :path
  #[(sting)] タイトル
  attr_accessor :title
  #[(sting)] 日付
  attr_accessor :date
  #[(Array[sting])] 本文
  attr_accessor :text
  #[(sting)] タグ一覧
  attr_accessor :tags
  #[(Array[(pathname)]] 画像のパス。
  attr_accessor :images
  #[(pathname)] 次のエントリーのパス。
  attr_accessor :next_entry
  #[(pathname)] 前のエントリーのパス。
  attr_accessor :prev_entry
  #[(pathname)] このエントリーのパス。
  attr_accessor :permalink

  #=== 概要
  #エントリーの初期化。
  #=== 引数
  #[(pathname)path] 日記データのパス。
  def initialize(path)
    @path = path
    @title = ""
    @date = ""
    @tags = ""
    @text = Array.new
    @images = Array.new
    @next_entry = ""
    @prev_entry = ""
    @permalink = ""
  end

  #=== 概要
  #日記の日付とタイトルを結合した文字列を返す。
  #=== 戻り値
  #[(sring)] 日付とタイトルを結合した文字列。
  def to_s
    return "date=" + @date.to_s + " path=" + @path.basename.to_s + " title=" + @title.to_s
  end
end

#== 概要
#タグの集合を表現するクラス。
class Tags
  #=== 概要
  #タグクラスの初期化。
  def initialize
    @tags = Hash.new
  end

  #=== 概要
  #エントリーに設定されたタグをタグリストに追加する。
  #=== 引数
  #[(Entry)entry] エントリー。
  def add(entry)
    tag_arr = entry.tags.split(" ")
    tag_arr.each{|tag|
      if(@tags[tag.intern] == nil)
        @tags[tag.intern] = Tag.new(tag)
      end
      @tags[tag.intern].add_entry(entry)
    }
  end

  #=== 概要
  #各タグに対してブロックを評価する。
  #タグはソートして評価される。
  def each
    @tags.values.sort{|a,b|a.name.to_s<=>b.name.to_s}.each{|tag|
      yield(tag)
    }
  end
end

#== 概要
#タグを表現するクラス。
class Tag
  #[(String)] タグの名前。
  attr_reader :name
  #[Array(Entry)] このタグを含むエントリーの配列。
  attr_reader :entries

  #=== 概要
  #Tagの初期化。
  #=== 引数
  #[(String)name] タグの名前。
  def initialize(name)
    @name = name.to_s
    @entries = Array.new
  end

  #=== 概要
  #このタグを含むエントリーを追加する。
  #=== 引数
  #[(Entry)entry] 追加するエントリー。
  def add_entry(entry)
    @entries << entry
  end
end

#== 概要
#置換文字列を管理するクラス。
class Replace
  #(Hash)検索文字列をkeyとした、置換文字列のハッシュ配列。
  attr_reader :replace_hash

  #=== 概要
  #Replaceの初期化。
  #=== 引数
  #[(pathname)path] 置換文字列を保存するファイル。
  def initialize(path)
    @path = path
    @replace_hash = read_file
  end

  #=== 概要
  #置換文字列を追加する。
  #検索文字列が既に登録されている場合は上書きする。
  #=== 引数
  #[(string)replace_str] 検索する文字列。(置換前文字列)
  #[(string)replace_str] 置換する文字列。(置換後文字列)
  def add_str(search_str, replace_str)
    @replace_hash[search_str.chomp.intern] = replace_str.chomp
    write_file
  end

  #=== 概要
  #置換文字列を削除する。
  #=== 引数
  #[(string)search_str] 削除する検索文字列。
  def del_str(search_str)
    @replace_hash.delete(search_str.chomp.intern)
    write_file
  end

  private
  #=== 概要
  #置換文字列を書き込む。
  def write_file
    File.open(@path.to_s,"w",0770){|file|
      @replace_hash.each{|key, value|
        file.write(key.to_s + "\t" + value.to_s + $/)
      }
    }
  end

  #=== 概要
  #置換文字列を読み込む。
  #=== 戻り値
  #[(Hash)] 検索文字列をkeyとした、置換文字列のハッシュ配列。
  def read_file
    hash_arr = Hash.new
    if @path.exist?
      data = @path.readlines
      data.each{|str|
        arr = str.partition("\t")
	if arr[0]!=""
	  hash_arr[arr[0].intern] = arr[2].chomp
	end
      }
    end
    return hash_arr
  end
end




#=====スクリプト実行開始=====
begin
  myDiary = MyDiary.new
rescue => err
  Debug.print("*****ERRROR*****")
  Debug.print(err.to_s)
  Debug.print("*****Trace******")
  err.backtrace.each{|str|
    Debug.print(str.to_s)
  }
end
#=====スクリプト実行終了=====

template/top.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script type="text/javascript" src="./files/script.js"></script>
<link rel="stylesheet" type="text/css" href="./files/default.css">
<title><%=CONFIG::TITLE %></title>
</head>

<!-- トップページに載せる日記の数。 -->
<% ENTRY_MAX=5 %>
<!-- 日記一覧の数。 -->
<% LIST_MAX=15 %>

<body>
<div id="header">
  <h1><%="<a href='#{CONFIG::TOP_FILE_NAME}'>#{CONFIG::TITLE}</a>" %></h1>
  <p><%=CONFIG::DESCRIPTION %></p>
</div>

<div id="menu">
  <div class="nav">
    <h2>最近のエントリー<a href="./index.rdf"><img src="./files/rss_icon.png"></a></h2>
    <p><%= "<a href='#{CONFIG::ENTRY_LIST_FILE_NAME}'>タイトル一覧</a>" %></p>
    <ul>
      <% LIST_MAX.times{|i| %>
      <li><%= @pages[i].permalink.to_s %></li>
      <% } %>
    </ul>
  </div>

  <!-- 広告 ここから -->
  <div class="nav">
    <h2>欲しい技術書</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=st1&mode=books-jp&search=FreeBSD%20Linux&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <div class="nav">
    <h2>気になるフィギュア</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=st1&mode=toys-jp&search=%E3%83%95%E3%82%A3%E3%82%AE%E3%83%A5%E3%82%A2%20%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%20PVC&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <div class="nav">
    <h2>買いたいカメラ機材</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=bn1&mode=electronics-jp&browse=16462091&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <!-- 広告 ここまで -->

  <div class="nav">
    <h2>カテゴリー</h2>
    <p><%= "<a href='#{CONFIG::ALL_TAG_LIST_FILE_NAME}'>タグ一覧</a>" %></p>
    <%= @tag.tag_list %>
  </div>

  <div class="nav">
    <h2>リンク</h2>
    <ul>
      <li><a href="http://gaso.tumblr.com/">時系列記憶槽 - Tumblr</a></li>
      <li><a href="http://twitter.com/#!/G_A_S_O">G_A_S_O - twitter</a></li>
    </ul>
  </div>
</div>


<div id="section">
  <!-- Topページの記事の繰り返し。 ここから -->
  <% ENTRY_MAX.times{|i| %>
  <div class="article">
    <div class="date"><%= "#{@pages[i].date[0,4]}年#{@pages[i].date[4,2]}月#{@pages[i].date[6,2]}日" %></div>
    <h2><%= @pages[i].title %></h2>
    <%= @pages[i].text %>

    <div class="nav">
      <!-- 正方形サムネイルで全ての画像を表示。 -->
      <% if @pages[i].img[:square].size != 0 %>
        <%= "<div class='info'>" %>
        <%= "<h2>全ての画像</h2>" %>
        <%  @pages[i].img[:square].size.times{|j| %>
        <%= @pages[i].img[:square][j] %>
        <% } %>
        <%= "</div>" %>
      <% end %>

      <!-- パーマリンクとタグ -->
      <div class="info">
        Permalink:<%= @pages[i].permalink.to_s %>
        <br>
        タグ:<%= @pages[i].tags %>
      </div>
    </div>
  </div>
  <% } %>
  <!-- Topページの記事の繰り返し。 ここまで -->
  <div class="nav">
    <p class="center">Prev - <%= @pages[ENTRY_MAX-1].next_entry %></p>
  </div>
</div>


<div id="footer">
  <p>このページ内で掲載している画像、文章等の転載・転用は自由に行ってください。</p>
  <address>
    author : G_A_S_O<br>
    address : gaso@psyche.gaso.jp<br>
    Copyright 2003-<%= Time.now.year.to_s %> G_A_S_O All rights reserved.
  </address>
  <p class="center">
    Generated by <%=SCRIPT_NAME %> version <%=SCRIPT_VERSION %><br>
    Powerd by Ruby version <%=RUBY_VERSION %><br>
    Output Date <%=Time.now.to_s %>
  </p>
</div>

</body>
</html>

template/entry.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script type="text/javascript" src="./files/script.js"></script>
<link rel="stylesheet" type="text/css" href="./files/default.css">
<style type="text/css">
</style>
<title><%=CONFIG::TITLE %></title>
</head>

<body>
<div id="header">
   <h1><%= "<a href='#{CONFIG::TOP_FILE_NAME}'>#{CONFIG::TITLE}</a>" %></h1>
   <p><%=CONFIG::DESCRIPTION %></p>
</div>

<div class="nav">
  <p class="center"><%= @prev_entry %> - <%= @next_entry %></p>
</div>

<div id="menu">
  <!-- 広告 ここから -->
  <div class="nav">
    <h2>欲しい技術書</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=st1&mode=books-jp&search=FreeBSD%20Linux&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <div class="nav">
    <h2>気になるフィギュア</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=st1&mode=toys-jp&search=%E3%83%95%E3%82%A3%E3%82%AE%E3%83%A5%E3%82%A2%20%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%20PVC&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <div class="nav">
    <h2>買いたいカメラ機材</h2>
    <iframe src="http://rcm-jp.amazon.co.jp/e/cm?t=gaso00-22&o=9&p=12&l=bn1&mode=electronics-jp&browse=16462091&fc1=999999&lt1=_blank&lc1=585CA8&bg1=000000&f=ifr" marginwidth="0" marginheight="0" width="300" height="250" border="0" frameborder="0" style="border:none;" scrolling="no"></iframe>
  </div>
  <!-- 広告 ここまで -->
</div>


<div id="section">
  <div class="article">
    <div class="date"><%= "#{@date[0,4]}年#{@date[4,2]}月#{@date[6,2]}日" %></div>
    <h2><%= @title %></h2>
    <%= @text %>

    <div class="nav">
      <!-- 正方形サムネイルで全ての画像を表示。 -->
      <% if @img[:square].size != 0 %>
        <%= "<div class='info'>" %>
        <%= "<h2>全ての画像</h2>" %>
        <%  @img[:square].size.times{|j| %>
          <%= @img[:square][j] %>
        <% } %>
        <%= "</div>" %>
      <% end %>

      <!-- パーマリンクとタグ -->
      <div class="info">
        Permalink:<%= @permalink.to_s %>
        <br>
        タグ:<%= @tags %>
      </div>
    </div>
  </div>
</div>

<div class="nav">
  <p class="center"><%= @prev_entry %> - <%= @next_entry %></p>
</div>

<div id="footer">
  <p>このページ内で掲載している画像、文章等の転載・転用は自由に行ってください。</p>
  <address>
    author : G_A_S_O<br>
    address : gaso@psyche.gaso.jp<br>
    Copyright 2003-<%= Time.now.year.to_s %> G_A_S_O All rights reserved.
  </address>
  <p class="center">
    Generated by <%=SCRIPT_NAME %> version <%=SCRIPT_VERSION %><br>
    Powerd by Ruby version <%=RUBY_VERSION %><br>
    Output Date <%=Time.now.to_s %>
  </p>
</div>

</body>
</html>

template/entry_list.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script type="text/javascript" src="./files/script.js"></script>
<link rel="stylesheet" type="text/css" href="./files/default.css">
<style type="text/css">
div#section{margin: auto;}
</style>
<title><%=CONFIG::TITLE %></title>
</head>

<body>
<div id="header">
   <h1><%= "<a href='#{CONFIG::TOP_FILE_NAME}'>#{CONFIG::TITLE}</a>" %></h1>
   <p><%=CONFIG::DESCRIPTION %></p>
</div>

<div id="section">
  <div class="nav">
    <h2>日記一覧</h2>
    <p>総数:<%= @num %></p>
    <%= @entry_list %>
  </div>
</div>


<div id="footer">
  <p>このページ内で掲載している画像、文章等の転載・転用は自由に行ってください。</p>
  <address>
    author : G_A_S_O<br>
    address : gaso@psyche.gaso.jp<br>
    Copyright 2003-<%= Time.now.year.to_s %> G_A_S_O All rights reserved.
  </address>
  <p class="center">
    Generated by <%=SCRIPT_NAME %> version <%=SCRIPT_VERSION %><br>
    Powerd by Ruby version <%=RUBY_VERSION %><br>
    Output Date <%=Time.now.to_s %>
  </p>
</div>

</body>
</html>

template/tag.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<script type="text/javascript" src="./files/script.js"></script>
<link rel="stylesheet" type="text/css" href="./files/default.css">
<style type="text/css">
div#section{margin: auto;}
</style>
<title><%=CONFIG::TITLE %></title>
</head>

<body>
<div id="header">
   <h1><%= "<a href='#{CONFIG::TOP_FILE_NAME}'>#{CONFIG::TITLE}</a>" %></h1>
   <p><%=CONFIG::DESCRIPTION %></p>
</div>

<div id="section">
  <div class="nav">
    <h2><%= @tag_name %></h2>
    <%= @tag_list %>
  </div>
</div>


<div id="footer">
  <p>このページ内で掲載している画像、文章等の転載・転用は自由に行ってください。</p>
  <address>
    author : G_A_S_O<br>
    address : gaso@psyche.gaso.jp<br>
    Copyright 2003-<%= Time.now.year.to_s %> G_A_S_O All rights reserved.
  </address>
  <p class="center">
    Generated by <%=SCRIPT_NAME %> version <%=SCRIPT_VERSION %><br>
    Powerd by Ruby version <%=RUBY_VERSION %><br>
    Output Date <%=Time.now.to_s %>
  </p>
</div>

</body>
</html>

template/cgi_list.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<style type="text/css">
  input.replace{width: 800px;}
  dt{color: red; text-decoration: underline;}
</style>
<title>日記編集</title>
</head>
<body>
<h2>リンク</h2>
<a href="#1">新規日記作成</a> 
<a href="#2">日記をHTMLに変換</a> 
<a href="#3">日記一覧</a> 
<a href="#4">置換文字列登録</a> 
<a href="#5">置換文字列一覧</a> 
<a href="./doc/">RDoc</a>
<a href="./html/">表示確認</a>
<h2 id="1">新規日記作成</h2>
<%=@create_entry%>
<h2 id="2">日記をHTMLに変換</h2>
<%=@convert_html%>
<h2 id="3">日記一覧</h2>
<%=@entry_list%>
<h2 id="4">置換文字列登録</h2>
<%=@create_replace%>
<h2 id="5">置換文字列一覧</h2>
<%=@replace_list%>
<h2>総日記数</h2>
<%=@num_entries%>
</body>
</html>

template/cgi_edit.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<style type="text/css">
  input.text{width: 800px;}
  textarea{width: 800px; height: 400px;}
</style>
<title>test</title>
</head>
<body>
<h2>日記編集 - <%=@edit_date%></h2>
<%=@edit_form%>
<h2>サムネイル</h2>
<%=@thumb_icon%>
<h2>画像アップロード</h2>
<%=@upload_form%>
<h2>処理日時</h2>
<%=@update_time%>
<br>
<%=@debug%>
</body>
</html>

template/cgi_wait.html


<!DOCTYPE html>
<html lang="ja">
<head>
<meta charset="utf-8">
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.3/jquery.min.js"></script>
<title>test</title>
</head>
<body>
<h2>処理中</h2>
<%=@status_info%>
<%=@reload_script%>
</body>
</html>