|
|||||||
このドキュメントは、いくつかのサンプルを示して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>