wikipage.rb
#!/usr/bin/ruby -Ke
require 'nkf'
require 'cgi'
require '../wiki2xhtml.rb'
class WikiPage
BaseDir='./data/' # クラス変数で保存ディレクトリを設定
@@basedir=BaseDir # クラス変数で保存ディレクトリを設定
@@kcode='-e' # 保存漢字コード
@@curname="現在のページ" # 更新履歴でのカレントwiki名
@@curfname='current.txt' # 現在の最新ページファイル名
@@how2read='how2read.txt' # 読み方ファイル名
@@timefmt='%Y%m%d%H%M%S' # バックアップファイルの時間フォーマット
@@historyfmt="%Y年%m月%d日%H時%M分%S秒" # 表示用の時間フォーマット
@@pfix='.txt' # バックアップファイルの拡張子
def initialize(name="Top") # 特殊ページ名(検索,最近の更新,一覧)の時はpublicメソッドをオーバライドする
@name=name # wiki名
@dir=@@basedir+CGI::escape(NKF.nkf(@@kcode,@name))+'/' #eucの名前をurlエンコードする
end
def exist? # ページの本文が存在するならば真を出力。
test(?e,@dir+@@curfname)
end
def name # ページ名@nameを出力する。
@name
end
def mtime # 最終更新時刻を出力する。Timeオブジェクトを返す。
File.mtime(@dir+@@curfname) if test(?e,@dir+@@curfname)
end
def view # 内容を出力する、もしページが存在しないならばeditメソッドを呼ぶ
fname=@dir+@@curfname
if test(?e,fname)
Wiki2xhtml.new("#{File.open(fname){|f| f.read}}").conv(@name)
else
edit
end
end
def source # 高速化の為にそのまま表示する
fname=@dir+@@curfname
if test(?e,fname)
"#{File.open(fname){|f| f.read}}"
else
""
end
end
def edit # 内容を編集用に出力する(<→&gt;等) 全体を#edit()で囲む
fname=@dir+@@curfname
Wiki2xhtml.new("#{File.open(fname){|f| f.read} if test(?e,fname)}").conv_edit(@name)
end
def history(timestamp="") # timestampである以前のページを出力する,timestampが""の時には履歴を出力する。
fname=@dir+timestamp+@@pfix
if test(?e,fname)
Wiki2xhtml.new("#{File.open(fname){|f| f.read}}").conv(@name)
else # ここはwikiフォーマットが現れるので改善の余地あり
r=[]
Dir.glob(@dir+"[0-9]*"){|fn|
t=File.mtime(fn)
r.push(Wiki2xhtml.history(t.strftime(@@historyfmt),@name,t.strftime(@@timefmt)))
}
r.sort.reverse.join
end
end
def reference # 参照ページを検索しリストを出力する。[[ページ名]]で検索と同じ
%Q(Test reference)
end
def how2read #ページの読み方
File.open(@dir+@@how2read){|f| f.read}
end
def store(content="Damy") #ページ内容を保存する。
fname=@dir+@@curfname
if !test(?e,@dir)
Dir.mkdir(@dir)
File.open(@dir+@@how2read,'w'){|f| f.write(`echo "#{@name}"|kakasi -JH -KH`.upcase.chop)}
end
File.rename(fname,@dir+(File.mtime(fname).strftime(@@timefmt))+@@pfix) if test(?e,fname)
File.open(fname,'w'){|f|f.write(NKF.nkf(@@kcode,content))}
#File.utime(Time.now,Time.now,@dir) # フォルダの更新時刻を最新にする
`touch #{@dir}` # だめだcgiでフォルダのtouchができない
self # とりあえず自身を返しておく
end
def replace(src="Damy src",dist="Damy dist",num=1) # コメント等の為に利用する。n回目マッチ規則が必要
content=''
fname=@dir+@@curfname
File.open(fname){|f|content=f.read}
Dir.mkdir(@dir) unless test(?e,@dir)
File.rename(fname,@dir+(File.mtime(fname).strftime(@@timefmt))+@@pfix) if test(?e,fname)
a=content.split(src) #n回目にマッチした文字を置換する
content=a[0..num-1].join(src)+dist+a[num..(a.size-1)].join(src) # あっているか不明テストを柔軟にかくこと
File.open(fname,'w'){|f|f.write(NKF.nkf(@@kcode,content))}
`touch #{@dir}` # storeと同じにしておく
self
end
def delete # ページを削除する。(管理者モード)
`rm -rf #{@dir}` # ううっ外部コマンドで軟着陸
end
def match(regexp=/./)
fname=@dir+@@curfname
if test(?e,fname) && regexp.match(File.open(fname){|f| f.read})
true
else
false
end
end
def upload(content="Damy Stream data") # 画像用のアップローダ
%Q(Damy Upload Filename)
end
def delcontent(num=1)
%Q(Damy Delete Content Filename)
end
def contents # 画像等のコンテンツのリストを出す コンテンツの削除も必要かもしれない。
%Q(Damy Contents List)
end
end
class WikiPages
@@basedir=WikiPage::BaseDir
include Enumerable
def initialize(nregexp=/./,cregexp=nil)
@nregexp,@cregexp=nregexp,cregexp
end
def each # Enumerable用 実装がWikiPageの構造に依存しまくっていて気持ち悪い。
Dir.glob(@@basedir+"*"){|filename|
page=WikiPage.new(CGI::unescape(File.basename(filename)))
if @nregexp.match(page.name)
if !@cregexp || @cregexp.match(page.source) # 本当はviewがいいんだろうけど…速度の為に
yield page
end
end
}
end
end
wiki2xhtml.rb
#!/usr/bin/ruby
class Wiki2xhtml
NS="http://www.n9d.sytes.net/mxwiki"
def initialize(data="")
@data=data
end
class Line # wikiにおける行を出力するクラス
Multi={' '=>'pre','|'=>'table',','=>'csv','>'=>'indent','='=>'nlist','-'=>'list'}
include Enumerable
def initialize(s="")
@s=s
end
def each # @mを含む行は複数行で返す
s=@s.split("\n")
while a=s.shift
while !s.empty? && Multi[a[0..0]] && Multi[a[0..0]] == Multi[s[0][0..0]]
a+="\n"+s.shift
end
yield a # イテレータ使用
end
end
end
def convline(a="") # リンク及び文字飾りを処理する
a=a.gsub(/(http:\/\/[a-zA-Z0-9\.\?\&=\/%;\-~#_\+:]+)/){%Q(<wiki:url uri="#{$1}" />)}
a=a.gsub(/\[\[(.+?)::(.+?)::(.+?)\]\]/){%Q(<wiki:anchor title="#{$1}" name="#{$2}" timestamp="#{$3}" />)} #パックアップwikiリンク
a=a.gsub(/\[\[(.+?):(<url[^>]+) \/>\]\]/i){%Q(#{$2} title="#{$1}" />)} # URLを含むalias
a=a.gsub(/\[\[(.+?):(.+?):#(.+?)\]\]/){%Q(<wiki:anchor title="#{$1}" name="#{$2} id="#{$3}" />)}#見出しwikiリンク別名
a=a.gsub(/\[\[(.+?):#(.+?)\]\]/){%Q(<wiki:anchor name="#{$1}" id="#{$2} />")} #見出しwikiリンク
a=a.gsub(/\[\[(.+?):(.+?)\]\]/){%Q(<wiki:anchor title="#{$1}" name="$2" />)}#aliasのwikiリンク
a=a.gsub(/\[\[(.+?)\]\]/){%Q(<wiki:anchor name="#{$1}" />)} #通常wikiリンク(ヒット順序=バグの元)
a=a.gsub(/'''(.*?)'''/){"<em>#{$1}</em>"} # イタリック
a=a.gsub(/''(.*?)''/){"<strong>#{$1}</strong>"} # ボールド
a=a.gsub(/__(.*?)__/){%Q(<span style="text-decoration:underline">#{$1}</span>)} # 下線
a=a.gsub(/%%(.*?)%%/){%Q(<span style="text-decoration:line-through">#{$1}</span>)} # 打ち消し線
a=a.gsub(/\(\((.*?)\)\)/){%Q(<wiki:sup content="#{$1}" />)} # 脚注
a
end
def table(str="")
%Q(<table class="normal">\n)+str.split("\n").map{|b|
b.gsub(/^\|/,'<tr><td>').gsub(/\|[^\|]*$/,'</td></tr>').gsub(/\|/,'</td><td>')
}.join("\n")+"\n</table>"
end
def list(str="",mode='-',stab='<ul>',etab='</ul>',snode='<li>',enode='</li>') # リスト
r,level="",0
str.split("\n").each{|ln|
/^(#{mode}+)/.match(ln)
l=$1.size-level
r+=stab*l if l>0
r+=etab*(-l) if l<0
level=$1.size
r+=snode+ln.sub($1,'')+enode+"\n"
}
r+etab*level
end
def conv(name)
Line.new(@data).map{|line|
if line[0..0]==' ' # 整形なし(行頭の' 'は削除
line=line.gsub('&','&').gsub('<','<').gsub('>','>').gsub('"','quot;')
"<pre>\n"+line.split("\n").map{|b|b.gsub(/^ /,'')}.join("\n")+"\n</pre>"
elsif line[0..0]=='>' # >モード未完成(よくわからん)
# line=convline(list(line,'>','<blockquote>','</blockquote>','',''))
line=line.gsub('&','&').gsub('<','<').gsub('>','>').gsub('"','quot;')
else
line=line.gsub('&','&').gsub('<','<').gsub('>','>').gsub('"','quot;')
line.gsub!(/\$([^\$]+)\$/){%Q(<wiki:macro cmd="#{$1}" />)}
case line[0..0]
when '*' # 番号付見出し
line.gsub!(/^(\*+)/,'')
%Q(<wiki:caption level="#{$1.size}" name="#{line}" />)
when '+' # 番号無見出し
line.gsub!(/^(\++)/,'')
%Q(<wiki:heading level="#{$1.size}" name="#{line}" />)
when '-'
convline(list(line))
when '='
convline(list(line,'=','<ol>','</ol>','<li>','</li>'))
when ':' # 説明文
convline("<dl><dt>#{$1}</dt><dd>#{$2}</dd></dl>") if /^:([^:]*):(.+)$/.match(line)
when '|' # 表
convline(table(line))
when '#' # command
%Q(<wiki:cmd cmd="#{$1}" name="#{name}" #{%Q(arg="#{$2}" ) if $2}/>) if /^#([^\)]*)(?:\((.*)\)|$)/.match(line)
else
line=convline(line)
if line==""
"<BR />"
else
%Q(<div class="normal">#{line}</div>)
end
end
end
}.join("\n")
end
def conv_edit(name)
%Q(<wiki:edit name="#{name}" content="#{@data.gsub('&','&').gsub('<','<').gsub('>','>').gsub('"','"')}" />)
end
def self.history(title,name,timestamp)
%Q(<wiki:anchor title="#{title}" name="#{name}" timestamp="#{timestamp}" /><BR />\n)#パックアップwikiリンク
end
end
if __FILE__==$0 # ライブラリテスト用コード
class CGI
CGI_PARAMS={'form'=>['value']}
CGI_COOKIES= nil
end
File.open("helpdata.txt"){|f|
print <<TESTEND
<?xml version="1.0" encoding="EUC-JP"?>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:wiki="http://www.n9d.sytes.net/wiki" xml:lang="ja" lang="ja">
<head><title>test</title></head>