テンプレートエンジンの仕様
まだ変わるかもしれませんが、今のところこんな仕様です。
- テンプレートは基本的にただのHTMLファイル
- {HOGE}のような{}で囲まれた独自タグを使用する。これはレンダリング時に別の文字列に置換される。
のような最後に_のついた独自タグを使用する。これはレンダリング時にイテレータとして機能し、複数回ループされレンダリングされる。 の中の置換タグは{HOGE}を使用するが、 外のタグとの混同を防ぐために{HOGE_}という記述方法を推奨する。 - 今のところ条件分岐の記述はできない。条件分岐はPHP上で行なう。
- 今のところテンプレート内にPHPは記述できない(HTMLとして解釈される?未検証)。
このテンプレートエンジンの実装はPHPで数十行なんですが、汎用的に使うには条件分岐がないのがネックになるかもしれません。現在ブログエンジンを作っている限りでは今のところ支障はないようです。
ブログエンジン作ってます
アウトラインプロセッサ「AOISO」は、この半年ぜんぜん進んでいません。
何も書かないのもあれなので、ちょっと話題がそれますが、仕事で作っているブログエンジンのことでも書きます。
ブログエンジンはもういくらでもありますね。MTとWPだけでもお腹いっぱいだし。しかし自分で作る意義というのもあるのです。きっと。
僕が作ってるブログエンジンはこんな感じです。
- SQLiteで動く(将来的にはMySQL対応したい)。
- 複数ブログ対応。
- 複数管理ユーザ対応。
- 複数カテゴリ対応。
- 校正プロセスがある。
- トラックバック機能はない。
- テンプレートがhtml。
- 静的HTMLでなく動的に逐次レンダリングする(将来的には静的HTMLも出力させたい)。
想定しているのはブログというよりは、HTMLで書かれたサイトにフォームから更新できるような仕組みを埋め込むためのCMSのサブセットのようなものです。企業サイトなんかではよくMTで組まれていますがあれをMTなしで実現するためのものです。
MTを使ってもいいんですが、あれはライセンスの問題がある(OSS版は中途半端)だし、小規模サイトにはちょっと大袈裟すぎます。WPは複数ブログに対応していないので1サイトに複数インストールしないといけなくて不便です。そういうわけで軽量でシンプルなブログエンジンを自作することにしたのです。
言語はPython・・・にしたいところなんですが、日本のレンタルサーバの実情を考えてPHPにしました。ぶっちゃけPHPはよく知らないので試行錯誤しながらやっています。「軽量」というコンセプトなのでPearなどの外部ライブラリは使用しない方針です。PDOすら使っていません(これはMySQL対応の時には使うことになるかもしれません)。テンプレートエンジンも自作しています。
完成したら会社のサイトでオープンソースで公開しようかなと思っています。
Qtがすごいことに
で、ちょっと話がずれますが、最近Qtのことを完全無視していたので久し振りにチェックしてみたら、Qt Creatorというのが現れてすごいことになってますね。C++限定ですがRADと言ってもいいくらいのGUIビルダー連動のIDEです。Qtそのものも3までしか知らないのでその進化っぷりにも驚きました。Webkit対応とか。まああれは元々KDE由来なんで逆輸入みたいなもんですが。
そういうわけでQtもやってみたくなりました。とは言え、AOISOに関してはGTKからwxに変えた経緯もあるしそれでまたまたQtに変えてたらいつまでたっても完成しないのでwxのままいきますが。
Qt Creator、Pythonサポートしないかなぁ。
今日もDDLを
テーブル構造をちょっと弄って、サンプルのINSERT文も更新(rev.54)。行数としては数行だけど、頭の中の整理ができてきたので気持的にはだいぶ進みました。
以前からアウトラインプロセッサにありがちな「ノード=タイトル+本文」という構造はおかしいのではないかと思っていたのですが、じゃあ具体的にどうするのかというあたりのアイデアが漠然としていました。この辺にちょこっと書いてますが、ノードよりも小さい単位が必要じゃないかということで内部的にチップと呼んでる最小単位があって、それをグループ化したものがノード、という感じを目指してます。DDLはそれで進めているんですが、クラスは「ノード=タイトル+本文」のままなのでこれからここを変えていくことになるでしょう。
空のDBかどうかの判定
久しぶりに更新。
pysqliteで動的にDBを作成したりする場合、新規につくられたものか既存のものかをどうやって判定しようかと考えて、以前は以下のコードにしていました。
self.con = sqlite.connect(path) cur = self.con.cursor() cur.execute("SELECT count(*) FROM SQLITE_MASTER") cnt = cur.fetchone()[0] if cnt==0: self.__initTables()
以前はこれで通ってたと思うのですが、今日やってみたらセグメンテーション違反で落ちる。pythonの問題ではなく、sqliteコマンドでやっても同様に落ちる。何も落ちなくてもとは思うが、DDLが全く定義されていないDBで"SELECT count(*) FROM SQLITE_MASTER"は(仕様かバクかはともかく)NGということなのだろう。しかし"SELECT * FROM SQLITE_MASTER"なら通るので以下のようにしてみました。
self.con = sqlite.connect(path) cur = self.con.cursor() cur.execute("SELECT * FROM SQLITE_MASTER") try: cnt = cur.fetchone()[0] except: self.__initTables()
これでうまくいきました。こういうのってほんとは定石があるのかな?
ほか、ちょこちょこと弄ってコミット(rev.52、53)。
wxPythonとXRCとAUIの関係
ドッカブルウインドウってwxでできるんだろうか? と調べていて、wxAUIほにゃららというやつを使えばできることを知りました。早速wxPythonでやってみる。
test1.py
#!/usr/bin/python # -*- coding: UTF-8 -*- import wx import wx.aui class MyFrame(wx.Frame): def __init__(self, title, pos, size): wx.Frame.__init__(self, None, -1, title, pos, size) self.auimgr = wx.aui.AuiManager(self) txtctrl1 = wx.TextCtrl(self, -1, "Hello",wx.DefaultPosition, wx.Size(200,200),wx.TE_MULTILINE) txtctrl2 = wx.TextCtrl(self, -1, "World",wx.DefaultPosition, wx.Size(200,200),wx.TE_MULTILINE) self.auimgr.AddPane(txtctrl1,wx.LEFT, "hello") self.auimgr.AddPane(txtctrl2,wx.BOTTOM, "world") self.auimgr.Update() def OnQuit(self, event): self.Cose() if __name__ == '__main__': app = wx.App() frame = MyFrame("test",wx.DefaultPosition,wx.Size(300,300)) frame.Show() app.MainLoop()
案外簡単。
ところが、aoisoではGUI編集をXRCedでやってますので、上記のようなGUI直書きではありません。調べてみるとXRCedにはAUI関係のコントロールは用意されていない様子。ということはカスタムウィジェットのようにunknownを使ってやるのか・・・と思いきや、unknownはコンテナには使えないらしい。じゃぁどうするんだ、ということでいろいろ試してみたら何のことはない。以下のようにできました。
test2.py
#!/usr/bin/python # -*- coding: UTF-8 -*- import wx import wx.xrc as xrc import wx.aui class MyApp(wx.App): def OnInit(self): self.res = xrc.XmlResource("test2.xrc") self.frame = MyFrame(self) self.frame.Show() return True class MyFrame(wx.Frame): def __init__(self, app): pre = wx.PreFrame() app.res.LoadOnFrame(pre, None, "ID_FRAME_1") self.PostCreate(pre) self.auimgr = wx.aui.AuiManager(self) self.text1 = xrc.XRCCTRL(self,"ID_TEXT_1") self.text2 = xrc.XRCCTRL(self,"ID_TEXT_2") self.auimgr.AddPane(self.text1,wx.LEFT,"hello") self.auimgr.AddPane(self.text2,wx.BOTTOM,"world") self.auimgr.Update() if __name__ == "__main__": app = MyApp(False) app.MainLoop()
test2.xrc
<?xml version="1.0" ?> <resource> <object class="wxFrame" name="ID_FRAME_1"> <object class="wxTextCtrl" name="ID_TEXT_1"> <style>wxTE_MULTILINE</style> </object> <object class="wxTextCtrl" name="ID_TEXT_2"> <style>wxTE_MULTILINE</style> </object> </object> </resource>
要するに、XRC上はFrameに直置きして、実行時にaddPaneすれば良い、と。