|
このドキュメントは、いくつかのサンプルを示してamritaをCGIで使う方法を説明します。 サンプルとしてブックマークのシステムを使います。
このサンプルは下記のURLでデモしています。
最初にモデルクラスを作成します。
!/usr/bin/ruby require 'amrita/template'
class Item include Amrita::ExpandByMember attr_reader :group, :name, :url def initialize(group, name, url) @group, @name, @url = group, name, url end
def to_s %Q[#{@group}|#{@name}|#{@url}] end def link e(:a, :href=>@url) { @url } end end
class BookmarkList attr_reader :groups def initialize @groups = {} end
def load_from_file(path) File::open(path) do |f| f.each do |line| begin add_new_item(*line.chomp.split('|')) rescue end end end end def save_to_file(path) File::open(path, "w") do |f| @groups.each do |k, v| v.each do |data| f.puts data.to_s end end end end
def add_new_item(group="", name="", url="", *x) item = Item.new(group, name, url) @groups[group] ||= [] @groups[group] << item end end if __FILE__ == $0 require 'runit/testcase' require 'runit/cui/testrunner'
class TestBMModel < RUNIT::TestCase def test_item item = Item.new("aa", "bb", "http://www.xxx.com/") assert_equal("aa", item.group) assert_equal("bb", item.name) assert_equal("http://www.xxx.com/", item.url) end def test_bookmarkmodel bm = BookmarkList.new assert_equal(0, bm.groups.size()) assert_equal({}, bm.groups)
bm.add_new_item("g", "nm", "http://www.xxx.com/") assert_equal(1, bm.groups.size()) assert_equal(1, bm.groups["g"].size()) assert_equal("nm", bm.groups["g"][0].name) assert_equal("http://www.xxx.com/", bm.groups["g"][0].url) end def test_load bm = BookmarkList.new bm.load_from_file("bookmark.dat.sample") assert_equal(3, bm.groups.size())
assert_equal(3, bm.groups["BBS"].size()) assert_equal("2ch", bm.groups["BBS"][0].name) assert_equal("http://www.ruby-lang.org/", bm.groups["Script Languages"][0].url) end def test_save tmp = "/tmp/bmtest#{$$}" bm = BookmarkList.new bm.load_from_file("bookmark.dat.sample") bm.add_new_item("html", "amrita", "http://kari.to/amrita/") assert_equal(4, bm.groups.size())
assert_equal(3, bm.groups["BBS"].size()) assert_equal("2ch", bm.groups["BBS"][0].name) assert_equal("http://www.ruby-lang.org/", bm.groups["Script Languages"][0].url) assert_equal(1, bm.groups["html"].size()) assert_equal("amrita", bm.groups["html"][0].name) bm.save_to_file(tmp)
bm = BookmarkList.new bm.load_from_file(tmp) assert_equal(4, bm.groups.size()) assert_equal(3, bm.groups["BBS"].size()) assert_equal("2ch", bm.groups["BBS"][0].name) assert_equal("http://www.ruby-lang.org/", bm.groups["Script Languages"][0].url) assert_equal(1, bm.groups["html"].size()) assert_equal("amrita", bm.groups["html"][0].name) ensure File::unlink tmp end end if ARGV.size == 0 RUNIT::CUI::TestRunner.run(TestBMModel.suite) else ARGV.each do |method| RUNIT::CUI::TestRunner.run(TestBMModel.new(method)) end end end
Item というクラスはブックマークの項目に対応します。 このクラスには、group, name, url. という3つのアトリビュートが存在します。
BookmarkList は Item の集まりです。 グループごとにいくつかの Item を保持していて、 ファイルに保存したりロードしたりできます。
このモデルクラスはHTMLに関する処理を含んでいません。 そのため、添付のテストスクリプトのように簡単にユニットテストをすることができます。
bookmark.cgi はブックマークを表示して、新しいエントリーの入力を受けつけます。
bookmark.cgi はこのテンプレートを使用します。
<html> <body> <h1>amrita bookmark sample</h1> <div id="groups"> <h1 id="group_name"></h1> <table border="1"> <tr><th>name</th><th>url</th></tr> <tr id=items> <td id="name"></td> <td id="link"></td> </tr> </table> </div>
<hr> <form id="form" method="post"> <table> <tr> <th>group:</th> <td id=group_sel></td> </tr> <tr> <th>new_group:</th> <td><input name="group" type="text"> </td> </tr> <tr> <th>title:</th> <td><input name="title" type="text"> </td> </tr> <tr> <th>url:</th> <td><input name="url" type="text"> </td> </tr> <tr><th> <td><input value="newitem" type="submit"> </td> </tr> </table> </form> </body> </html>
これが bookmark.cgi のコードです。
!/usr/bin/ruby require 'cgi' require 'amrita/template' require 'bmmodel' include Amrita
DATAFILE_PATH="bookmark.dat" TEMPLATE_PATH="bookmark.html" CACHE_PATH="/tmp/bookmark" def make_model_data(bm, selected_group) groups = bm.groups.keys.sort
data = { :groups => groups.collect do |k| { :group_name=>k, :items=>bm.groups[k] } end , :form => { :group_sel=>e(:select, :name=>"group_sel") { groups.collect do |g| if g == selected_group e(:option, :value=>g, :selected=>"selected") { g } else e(:option, :value=>g) { g } end end }, } } data end
def generate_output(bm, group) Amrita::TemplateFileWithCache::set_cache_dir(CACHE_PATH) tmpl = Amrita::TemplateFileWithCache[TEMPLATE_PATH] tmpl.use_compiler = true tmpl.expand($stdout, make_model_data(bm,group)) end def main bm = BookmarkList.new bm.load_from_file(DATAFILE_PATH) cgi = CGI.new url = cgi['url'][0] group = "" if url group = (cgi['group'][0]).to_s group = (cgi['group_sel'][0]).to_s if group == "" name = (cgi['title'][0]).to_s name = url if name == "" bm.add_new_item(group, name, url) bm.save_to_file(DATAFILE_PATH) end puts cgi.header generate_output(bm, group) end
main
新しい項目を入力した後のグループの選択肢は、 最後に入力したグループ名がデフォルトに設定されています。 その処理を行なっているのはここです。
:form => { :group_sel=>e(:select, :name=>"group_sel") { groups.collect do |g| if g == selected_group e(:option, :value=>g, :selected=>"selected") { g } else e(:option, :value=>g) { g } end end }, }
このコードが以下のHTMLを生成します。
<td> <select name="group_sel"> <option value="BBS">BBS</option> <option value="Script Languages" selected="selected">Script Languages</option> <option value="TestXSS">TestXSS</option> </select> </td>
このHTMLがテンプレート内の group_sel に対応する所に挿入されます。
Amrita::TemplateFileWithCache::set_cache_dir(CACHE_PATH) tmpl = Amrita::TemplateFileWithCache[TEMPLATE_PATH] tmpl.use_compiler = true tmpl.expand($stdout, make_model_data(bm,group))
Amrita::TemplateFileWithCache は Amrita::TemplateFile に コンパイルされたコードをキャッシュして再利用する機能を追加したものです。
CACHE_PATH の中にTEMPLATE_PATH に対応するキャッシュデータが存在し、 テンプレートより新しければ、そのコンパイルされたコードを自動的に再利用します。
注意: このディレクトリは他のユーザが修正できないように確実に設定してください。
現状のバージョンでは、amritaはキャッシュの内容をチェックしません。 もし、ここを修正されるとamritaに任意のコードを実行させることが可能になって非常に危険です。
ここの記述が理解できない場合は、TemplateFileWithCache::set_cache_dirは使用しないでください。
これはAmritaScriptで書かれたブックマークの表示プログラムです。
<html> <body> <amritascript> <!-- require "bmmodel" include Amrita
bm = BookmarkList.new bm.load_from_file("bookmark.dat") groups = bm.groups.keys.sort data = { :groups => groups.collect do |k| { :group_name=>k, :items=>bm.groups[k].collect do |item| { :name=>item.name, :link=>a(:href=>item.url) { item.url } } end } end } //--></amritascript>
<div id="groups"> <h1 id="group_name"></h1> <table border="1"> <tr><th>name</th><th>url</th></tr> <tr id="items"> <td id="name">name</td> <td><a id="link">url with link</a></td> </tr> </table> </div> </body> </html>
apache配下で実行するには
* httpd.confを修正して<tt>AllowOverride FileInfo</tt> と <tt>Options ExecCGI</tt> を+cgi-bin+ ディレクトリに設定してください * bin/amshandlerをそのディレクトリにコピーしてください
* .htaccess に以下の記述を追加します。 AddHandler amrita-script ams Action amrita-script /amrita/cgi-bin/amshandler
bookmark.cgi は mod_ruby配下で実行することもできます。 httpd.confに下記の指定を行なってください。
LoadModule ruby_module /usr/lib/apache/mod_ruby.so RubyRequire apache/ruby-run Alias /amrita/cgi-bin/ /home/tnaka/cvswork/amrita/sample/cgi/
<Location /amrita/cgi-bin> Options ExecCGI SetHandler ruby-object RubyHandler Apache::RubyRun.instance SetEnv AmritaCacheDir /tmp/bookmark # be careful </Location>