明けましておめでとうございました。本年もよろしくお願いいたします。
また悪い癖が始まったと言われつつ、新しいパソコンが欲しくなってきました。しかも、またもやノート型。はたして僕は何台ノート型パソコンを持てば気がすむのでしょうか。でも、ちょっとだけ言い訳すると、以前メインで使っていたLet'sNoteは知っている人に譲りました。
ともあれ、とりあえず自分の希望を整理すると、こんな感じです。
以上の条件を満たすパソコンをこれから探してきます。お金のことは見つかってから考えよう(そんなんで、いいのか)。
それはそうと、Rubyの実験を始める。まずは手始めに、『Rubyを256倍使うための本 網道編』を教科書にする。
最初のものは、こんな感じ。どうも、Xreaでは、.rb ではうまく動いてくれない。.cgiにすると、問題なく動くのだけど……。設定が悪いのだろうか? .htaccess の設定はこんな感じ
AddType cgi-script .rb AddType application/x-httpd-eruby .rhtml Action application/x-httpd-eruby /usr/local/bin/eruby
引き続き、RubyをCGIとして使う勉強を。
まずは自分の環境を知るために、こんなのを試してみる。とりあえず、僕のローカル環境ではうまく動作した。サーバー上ではどうだろう(注1)。
ちなみにこのテストは、環境を知る目的+XreaでeRubyが動くかも確かめています。
昨日、Xreaの環境を調べるために、eRuby を使った実験をしたのだけど、案の定、うまく動いてくれなかった。ローカル環境ではうまく動いたので、サーバー上での設定が悪いのだろう。
というわけで、eRuby については、Xreaのサポートにたずねるとして、とりあえず普通に Ruby で書くことにする。
ちなみに、eRuby バージョンはこんな感じ。
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> <HTML> <HEAD> <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=ISO-2022-JP"> <TITLE lang="ja">environment variables</TITLE> </HEAD> <BODY> <H1>環境変数を表示</H1> <DL> <% ENV.each do | name, value | %> <DT><%= name %></DT> <DD><%= value %></DD> <% end %> </DL> </BODY> </HTML>
いろいろと調べた結果、どうやら Xreaには eruby がインストールされていないのじゃないかという結論になった(でも、まだ確信はないのだけど)。
うーん、どうしよう。eruby を僕のディレクトリにインストールするなんて技術はないし……。かと言って、eRuby を諦めるのもちょっと……。
おかげさまで、「あれどこ」をVectorで公開してから、500人の方にダウンロードしてもらいました。と言っても、僕のサイトからダウンロードしていただいた方は、カウントしていないので、それも含めると、もうちょっといくのかもしれません。いずれにせよ、本当にありがとうございます。
Xreaの不具合で、掲示板の書き込みが消えてしまいました。結構、ショック大きいです。
と言うのも、他のコンテンツは、(ある意味当然ながら)自分のPC上にデータがあるので、復旧はそれほど難しくないのですけれど、掲示板のデータは、サーバー上にしかないわけです。はっきり言って、お手上げ。今回のような事故はそれほど頻繁に起こらないと考えたいのですが、掲示板の書き込みをバックアップする方法も検討しておいた方がいいかも。他の人はどうしているんだろう。
そうそう、InterWomanの2月の特集で、僕のサイトを取り上げていただきました。今月は、月末発売の『J-skyしようよ』でも紹介してもらう予定になっています。ありがたいこってす。
先週から今週にかけて、なぜかバタバタしています。なぜバタバタしているのか、自分でも理由が分かりません。気が付いたら今日は金曜日かという日々だったりします。30歳、もうちょっと落ち着いて生活しようと思います。
それはともかくとして、掲示板のデータが消えた問題、なんとか解決しました。データをバックアップしてくれていたXreaに感謝。ただ、僕の掲示板はたま〜に書き込みがある程度なので、これでよかったけれど、活発な掲示板だとこうはいかなかったのでしょうね。
ともあれ、このサーバーの環境を調べる実験、以前見事に失敗していましたが、再度チャレンジ。Rubyのライブラリを調べていたら、CGIライブラリの中にちゃんとサンプルが書いてありました。今度はそれを使って試してみます。
と言うわけで、予告通り、Xreaの環境を調べる実験をしました。使ったCGIは下記の通りです。
#! /usr/local/bin/ruby # サーバーの環境を取得する require "cgi" cgi = CGI.new("html4") # add HTML generation methods cgi.out() do cgi.html() do cgi.head{ cgi.title{"TITLE"} } + cgi.body() do cgi.pre() do CGI::escapeHTML( ENV.collect() do |key, value| key + " --> " + value + "¥n" end.join("") ) end end end end
その結果は、下記の通り。
PATH --> /usr/local/bin:/usr/bin:/bin DOCUMENT_ROOT --> /virtual/tomikura/public_html HTTP_ACCEPT --> */* HTTP_ACCEPT_ENCODING --> gzip, deflate HTTP_ACCEPT_LANGUAGE --> ja HTTP_CONNECTION --> Keep-Alive HTTP_HOST --> tomikura.s2.xrea.com HTTP_REFERER --> http://tomikura.s2.xrea.com/mkweb/index.html SCRIPT_FILENAME --> /virtual/tomikura/public_html/cgi-bin/env.cgi SERVER_ADDR --> 61.206.38.202 SERVER_ADMIN --> admin@s2.xrea.com SERVER_NAME --> tomikura.s2.xrea.com SERVER_PORT --> 80 SERVER_SOFTWARE --> Apache/1.3.22 (Unix) mod_layout/3.0.3 mod_gzip/1.3.19.1a GATEWAY_INTERFACE --> CGI/1.1 SERVER_PROTOCOL --> INCLUDED QUERY_STRING --> REQUEST_URI --> /cgi-bin/env.cgi SCRIPT_NAME --> /cgi-bin/env.cgi
落語の検索システムと言えば、落語検索エンジン「ご隠居」が有名です。実際非常に便利で、僕も時々利用させてもらっているのですが、僕のサイトのお題も200題を超えた頃から、検索できた方が便利という声をいくつかもらうようになりました。XreaではCGIが使えるので、現在、検索用のCGIを作っています。
先週末、ローカルでのテストも無事終わり、いよいよサーバーで公開しようと思ったのですが、どういうわけか上手く動いてくれません。うーん、どうしてだろう。特に変わったことしているわけではないのだけど……。eRubyを使っているのが悪いのかなぁ。
ちょっとeRuby(正確には、erblライブラリ)を使った実験をしてみたところ、どうも問題は検索用のCGI側ではなく、erblのrequireの仕方に問題がありそう。気になる部分を直して、サーバーで実験してみよう。
などと呑気なことを考えていたら、掲示板そのものも同じ症状になっていることが発覚。うわー、なぜだ! 3月14日までは正常に動いていたので、多分、今回ごちょごちょやっていたときに、.htaccess の設定か、パーミッションの設定を間違えるような操作をしてしまったのだろう。困った。
取り急ぎ、.htaccess の設定を下記の通り記述する。
Addtype cgi-script .cgi
先日の問題、何とか解決。不具合の原因は、すべて eRuby で出力しようとしていたこと。最初のおまじないについては、大人しく print で出すことにすると、うまく動いた。
と言うわけで、後はコツコツとデータの入力。
反面教師になるかもしれないので、先日作った落語検索CGIのソースコードを掲載しておこう。正直恥ずかしいけれど、今の僕はこのレベルということで。
#! /usr/local/bin/ruby # 落語検索(SearchRakugo) # FileName: rakugosearch.cgi # Author: Masaya Tomikura (vzx01036@nifty.ne.jp) =begin =機能 フォームから取得した検索語とデータファイルを比較し、マッチした行の「お題」と「URL」を取得する。 結果は、eRuby で整形して出力する。 =データファイルの書式 お題(title):URL(url):登場人物(person):落ち(punch_line):キーワード(keyword) =検索対象 お題、登場人物、落ち、キーワード =【履歴】 2002.03.10 : Ver.1.00 2002.03.28 : Ver.1.10 正規化表現をまとめる。 文字コードをEUCにセットする。 =end require 'cgi' require 'erbl.rb' require 'kconv' class SearchRakugo ### 初期化 ### def initialize cgi = CGI.new('html4') @result = [] @title = setCode(cgi['title'][0]) @person = setCode(cgi['person'][0]) @punch_line = setCode(cgi['punch_line'][0]) @keyword = setCode(cgi['keyword'][0]) end ### 文字コードをEUCに変換 ### def setCode(word) if word == '' then word = '' else word = Kconv.toeuc(word) end end ### 検索ルーチン ### def search db_name = "rakugo.dat" # データファイルの指定 i = 0 # 検索語を正規表現に変換 stitle = setReg(@title) sperson = setReg(@person) spunch = setReg(@punch_line) skey = setReg(@keyword) # 検索語にマッチする行からお題とURLを取得 File.foreach(db_name) do |line| title, url, person, punch_line, keyword = line.split(/:/) if (stitle =‾ title && sperson =‾ person && spunch =‾ punch_line && skey =‾ keyword) @result[i] = line @result[i] = [] @result[i] = url, title i = i + 1 end end end ### 検索結果の表示 ### def show result_file = File::readlines("result.rhtml").join print "Content-Type: text/html; charset=EUC-JP¥n¥n" print ERbLight::new(result_file).result(binding) end ### 検索語の正規表現化 ### def setReg(word) if word == nil then word = // else word = Regexp.new(word) end end end ##### ここからがメイン ##### rakugo = SearchRakugo.new rakugo.search rakugo.show
備忘録のページに検索機能を付けようか? さすがに200超えると、テキストだけとはいえ表示までに時間がかかるし……。
欲しい機能としては、分野毎に表示する機能と、キーワード検索ができれば充分なので、なんとかなるかも。
備忘録のページに検索機能を付ける計画、とりあえずインタフェースとアプリケーション部分のプロトタイプができあがる。後はデータの変換。こちらはコツコツするしかないか。
5月6日に思い立った備忘録に検索機能を付ける件、サーバー上でのテストに成功する。今回作ったスクリプトはこんな感じです。
#! /usr/local/bin/ruby =begin 備忘録検索システム Author : Masaya Tomikura (vzx01036@nifty.ne.jp) ver.1.00 : 2002.06.17 =機能 フォームから取得した検索語とデータファイルを比較し、マッチした項目を表示する。 また、フォームからではなく、リンクからも指定できる。(現状、未実装) =データ形式 No◆カテゴリー◆本文◆発言者◆出典◆日付 =end require 'cgi' require 'kconv' require 'erbl' ##### 検索語クラス ##### =begin このクラスでは、下記のことを行う。 *文字コードをEUCに変換する なお、注意点として、引数はハッシュを前提とする。具体的には、cgi.paramsから取得する =end class Word attr_reader :form def initialize(hash) @form = hash set_euc() end private ### EUCに設定 ### def set_euc @form.each_key {|key| # cgiのフォームに入力がない場合は「""」に設定する @form[key] = "" if @form[key].first == nil @form[key] = Kconv::toeuc(@form[key].first) } end end ##### 検索クラス ##### =begin このクラスでは、下記のことを行う。 *ファイルからデータを取得する。 *引数として与えられたキーワードを正規化した上で検索する。 *結果は、eEubyを使って出力する。 =end class Search def initialize(word) @target = word @result = [] search() show() end private ### 検索 ### def search db_name ="oneline.dat" search_word = {} i = 0 # キーワードを正規化する @target.each_key {|key| # @target そのものではなく、正規化したキーワードは search_word[] とする search_word[key] = Regexp.new(@target[key]) } # 実際に検索する File.foreach(db_name) do |line| line.chop! no, category, oneline, person, source, date = line.split("◆") if ( search_word['categoly'] =‾ category && search_word["word"] =‾ oneline && (search_word['person'] =‾ person || search_word['person'] =‾ source)) @result[i] = line @result[i] = [] @result[i] = no, oneline, person, source, date i = i + 1 end end end # 結果を出力する def show result_file = File::readlines("result.rhtml").join print "Content-Type: text/html; charset=EUC-JP¥n¥n" print ERbLight::new(result_file).result(binding) end end ##### ここからがメイン処理 ##### cgi = CGI.new('html4.0') word = Word.new(cgi.params) Search.new(word.form)
本当は、データの区切りを「◆」なんて特殊な文字を使わずに、「,」の方がいいのだろうけれど、ちょっと面倒くさいことになりそうなので、手抜きしています。
出力するための rhtmlファイルは、こんな感じです(こちらは必要な部分だけ)。
<!-- ユーザの指定した語句を表示 --> <% if @target['categoly'] == "" then @target['categoly'] = "なし" end if @target['word'] == "" then @target['word'] = "なし" end if @target['person'] == "" then @target['person'] = "なし" end hit = @result.size %> <P class="result">カテゴリー<STRONG>「<%= @target["categoly"] %>」</STRONG>、 キーワード<STRONG>「<%= @target['word'] %>」</STRONG>、 人物<STRONG>「<%= @target["person"] %>」</STRONG> で検索した結果、<STRONG><%= hit %>件</STRONG>見つかりました。</P> <HR> <!-- 検索結果を表示 --> <% if @result.empty? then %> <P> お探しのものは見つかりませんでした……。</P> <% else %> <% @result.each do |result| %> <P><STRONG>#<%= result[0] %></STRONG> <%= result[1] %><BR> <SMALL>【<%= result[2] %>】 (<%= result[3] %>) (<%= result[4] %>)</SMALL></P> <% end %> <% end %>
しばらく前から、なぜか韓国からのダイレクトメールが届くようになりました。最近では毎日10通くらいのペースで届いています。多分ダイレクトメールだと思うのですが、僕の環境ではそもそもハングル文字を表示できないので、何が書いてあるのかさっぱり分かりません。
AirHでつなぎ放題環境なので、特に神経質になっているわけではないのですが、でもそろそろ煩わしくなっているのも確かです。せめて英語で送ってくれれば……。
今、僕のサイトで使っている「浜ちゃんの浜ちゃん的心」の掲示板スクリプト、使いやすいのだけど、微妙な点で違和感があります。これ、どうにかならないかなぁと最近感じています。
具体的には、こんなところがちょっと……な点です。
細かな点では、投稿者の IPアドレスを書きだしているとか、「さん」を自動的につけてしまうという問題もあります。
僕が Perl を自由に読み書きできれば、簡単に直せる範囲なのかもしれないのですが、残念ながら、Perl はよく分かりません。勉強もかねて、Ruby で自作してみようか。
と言うわけで、引き続き掲示板について。
僕が必要だと思う機能は、こんな感じです。
まずはこういうことができそうな既存の掲示板CGIを探してみよう。
引き続き、Rubyで書かれた掲示板を探しつつ、勉強もかねて自分で掲示板が作れないか考えています。
とりあえず、非常におおざっぱなユースケースを書いてみよう。
クラス候補になりそうなのは、「掲示板」と「投稿記事」くらいなのかなぁ。とりあえず、掲示板のクラスについて考えてみよう。
# 掲示板クラス require 'erb/erbl' class Board def initialize( board_url ) @board_url = board_url # 書出し先の位置を把握 end def post( reply_no = "" ) # 投稿画面を出力する # 出力には ERuby を使用 end def write( article = "" ) # 投稿された記事を HTML に書き出す # 出力には ERuby を使用 end def make_log # 一定数の書き込みがあった場合、過去ログを作成する end end
HTMLファイルを作成するときには、ファイルのロック機能が必要になる。あと、過去ログの作成はプライベートメソッドにした方がよさそう。
とりあえず、RubyUnitを使って、掲示板クラスのテストスクリプトを作り始める。初期化部分のテストスクリプトは、こんな感じ。
require 'runit/testcase' require 'runit/cui/testrunner' require 'board' class TestBoard < RUNIT::TestCase ### 初期化のテスト ### def test_initialize board = Board.new("test_bbs") assert_instance_of(Board, board) end end if $0 == __FILE__ if ARGV.size == 0 suite = TestBoard.suite else suite = RUNIT::TestSuite.new ARGV.each do |testmethod| suite.add_test(TestBoard.new(testmethod)) end end RUNIT::CUI::TestRunner.run(suite) end
「がらくた箱」で公開していた「じゃんけんするJavaScript」に不具合。クリアボタンを押しても、表示上は「0勝0敗0分」になっているにもかかわらず、内部的にはクリアになっていなかった。
これ、すごく単純なミスで、クリアボタンに対応する関数内で、
function cls() { var win = 0; var lose = 0; var even = 0; }
と再び変数宣言をしていたというポカミス。恥ずかし〜! しかも、1年間も気付かずに放置されっぱなし。うひゃ〜。指摘してくださったオオカミさんに、感謝、感謝!
ともあれ、もう一つの課題、Mozilla1.0 及び Wazilla1.0で、フォーム内に情報を表示することについても対応したいのだけど、メインで使っている Libretto には IE 以外のブラウザを入れていないので、検証に時間がかかりそう。Linux 上で作業した方がいいかも。
再び掲示板について。
僕が Libretto ff という小さなディスプレイで作業をしているからなのでしょうけれど、書き込み画面は別ウィンドウで立ち上がってくれた方が、何かと好都合です。あと、返信の場合は、自動的に元記事にリンクを張ってくれればいいなと思います(今の「浜ちゃんの浜ちゃん的心」の掲示板スクリプトでは、投稿者が元記事の番号を入力する仕組みになっています)。
入力画面そのものは、eRuby を使うことにして、とりあえず 掲示板クラスの役割としては、
こんなところ。返信の場合であれば元記事の番号を受け取って、出力画面を作成すればいいか。新規投稿の場合は、元記事の設定なしで出力画面を返すというのが post メソッドの働きにする。
と言うわけで、投稿画面を出すメソッドのテストスクリプトはこんな感じに。
##### post メソッドのテスト ##### def test_post reply1 = "1" reply_nil = nil post_html = File::readlines("test_bbs/post.html").join board = Board.new("test_bbs") # reply があった場合 reply_num = "1" post_interface = ERbLight::new(post_html).result(binding) assert_equal(post_interface, board.post(reply1)) # 新規投稿の場合 reply_num = "" post_interface = ERbLight::new(post_html).result(binding) assert_equal(post_interface, board.post(reply_nil)) end
実際のスクリプトは、こんな感じ。
##### 投稿画面の提供 ##### def post( reply_num ) reply_num = "" if reply_num == nil post_html = File::readlines(File::join(@board_url, "post.html")).join return ERbLight::new(post_html).result(binding) end
ここしばらく放置プレイ状態だった掲示板について、この週末はちょっと時間をとれそうなので続きをば。
Board クラスとしては、投稿フォームからの入力内容を元に新しく index ファイルを再構築する実装が必要になるのだろうけれど、Board クラスを呼び出す側にしてみたら、どんな風に書き込まれたかなんてことは、知ったこっちゃないわけで、とにかく書き込み後の index ファイルを表示できればいいわけなんだろうから、具体的には書き込み後の掲示板の URI を取得できればいいのではないかと思う。
と言うわけで、Board クラスの write メソッドの骨格はこんな感じになるのかなぁ。
##### 記事の書き込み ##### def write ( article ) # 何らかの方法で index ファイルを作成 return File::join( @board_url, "index.html" ) end
でも、テストとしては、正常に(というか意図通りに)書き込まれたかを確かめたいわけなので、そのためのテストコードはどう書けばいいのだろう?
掲示板の書き込み部分について、引き続き。
最終的には、書き込み後の index ファイルの URI を返すとしても、index.html への書き込みそのものは掲示板クラスのお仕事。単純に考えれば、index.html 内に特定の目印を付与しておいて、その目印を見付けたら、そこに新しい書き込み部分を書きだして新しく index.html を生成する方法にするのが楽そう。
テストコードは、すごくずぼらな気がするけれど、こんな感じにしてみる。
##### 記事書き込みの確認 ##### def test_write article = {"title" => "test title", "name" => "hogehoge", "body" => "これは書き込みのテストです"} File::copy("test_bbs/base_index.html", "test_bbs/index.html") board = Board.new("test_bbs") board.write(article) test_new_index = File::readlines("test_bbs/test_new_index.html").join new_index = File::readlines("test_bbs/index.html").join assert_equal(test_new_index, new_index) end
実際のコードはこんな感じ。
def write( article = "" ) num = File::readlines(File::join(@board_url, "id")).join.to_i + 1 template_file = File::readlines(File::join(@board_url, "template.rhtml")).join new_article = ERbLight::new(template_file).result(binding) index_file = File::join(@board_url, "index.html") if num % @max_num == 1 && num != 1 # backup ファイルの作成処理 else backup_file = File::join(@board_url, "index.bak") File::rename(index_file, backup_file) p_write(new_article, backup_file) end return index_file end ## 最終的には private メソッド化する def p_write( new_article, base_file ) File::open(File::join(@board_url, "index.html"), "w"){|index_file| File::open(base_file, "r"){|file| while line = file.gets if line =‾ // index_file.write(new_article) else index_file.write(line) end end } } end
とりあえずこれでテストが通ったので、次はバックアップファイルの作成処理に取りかかろう。
例外処理は一切なしの状態ですけど、とりあえず Boardクラスの基本的な機能は完成。スナップショットは、こんな感じです。
#! /usr/local/bin/ruby require 'erb/erbl' class Board def initialize( board_url ) base_url = "./" @board_url = base_url + board_url # 指定されたディレクトリが存在しない場合の処理 # ここから先は最終的に設定ファイルに移行 @max_num = 20 @board_file = "index.html" end ##### 投稿画面の提供 ##### def post( reply_num ) reply_num = "" if reply_num == nil post_html = File::readlines(File::join(@board_url, "post.html")).join return ERbLight::new(post_html).result(binding) end ##### 書き込み ##### def write( article = "" ) num = p_number() template_file = File::readlines(File::join(@board_url, "template.rhtml")).join new_article = ERbLight::new(template_file).result(binding) index_file = File::join(@board_url, @board_file) ### 過去ログの作成判断 ### if num % @max_num == 1 && num != 1 backup_file = p_make_log(num) else backup_file = File::join(@board_url, "index.bak") File::rename(index_file, backup_file) end p_write(new_article, backup_file) return index_file end ##### 実際の書き込み ##### def p_write( new_article, base_file ) File::open(File::join(@board_url, @board_file), "w"){|index_file| File::open(base_file, "r"){|file| while line = file.gets if line =‾ // index_file.write(new_article) else index_file.write(line) end end } } end ##### ログの作成 ##### def p_make_log( num ) file_num = (num / @max_num).truncate log_file = file_num.to_s + ".html" index_file = File::join(@board_url, @board_file) File::rename(index_file, File::join(@board_url, log_file)) body_template = File::readlines(File::join(@board_url, "body_template.rhtml")).join backup_file = File::join(@board_url, "index.bak") File::open(backup_file, "w"){|file| file.write(body_template) } return backup_file end ##### 記事 id の管理 ##### def p_number # idファイルが存在しない場合の処理 id_file = File::join(@board_url, "id") num = File::readlines(id_file).join.to_i + 1 File::open(id_file, "w"){|file| file.write(num) } return num end end
まだまだ、怪しげな部分はたくさんあるし(危険な香もするし)、それ以前に、ファイルロックに関する処理と、各種の例外処理をくわえていかなければいけないのだろうけれど、とりあえずプロトタイプは出来たと自分を納得させ、これからしばらくは入力されたフォームデータに対する処理について考えていこう。
とりあえず、Boardクラスの作業はこれくらいにして、フォームの内容を取得して、それに対する処理を行うクラスについて考えていこう。
繰り返しになるけれど、やりたいことはこんなこと。
こんなところかなぁ。
CGI クラスで取得したフォームからの入力項目は、{'key' => ['value1', 'value2'...]}みたいな感じで格納されるので、value の最初の値だけを取り出すことにして、こんな感じになるのかなぁ、
class Article def initialize( cgi_params ) @params = {} @params.default = "" @params = cgi_params.first end end
テストスクリプトはこんな感じ。
class TestArticle < RUNIT::TestCase def test_initialize cgi_params = { "test1" => ["test_1", "test_2"], "test2" => ["test_2"], "test3" => [nil] } article = Article.new(cgi_params) assert_instance_of(Article, article) assert_equal("test_1", article.params["test1"]) assert_equal("test_2", article.params["test2"]) assert_equal("", article.params["test3"]) end end
昨日思いついた記述だと、テストを通ってくれない。と言うわけで手直し。
class Article attr_reader :params def initialize( cgi_params ) @params = Hash.new() @params.default = "" cgi_params.each_key{|key| if cgi_params[key].first == nil @params[key] = "" else @params[key] = cgi_params[key].first end } end end
ついでに、[] で params の値を取り出せるようにする。
def []( *args ) @params[*args] end
これにあわせてテストスクリプト部分も書き直す。
def test_initialize (省略) assert_equal("test_1", article["test1"]) assert_equal("test_2", article["test2"]) assert_equal("", article["test3"]) assert_equal("", article["none_key"]) end
これが通ったので、機能部分について。
文字コードの変換で用意しておきたいのは、EUC と JIS なので、それを実装しよう。Kconv 使うのが楽かも。例によって、何も考えずに書いたスクリプトは、こんな感じ。
def toeuc @params.each_key{|key| @params[key].toeuc } end def tojis @params.each_key{|key| @params[key].tojis } end def toeuc! @params.each_key{|key| @params[key] = @params[key].toeuc } end def tojis! @params.each_key{|key| @params[key] = @params[key].tojis } end
今日は時間があるので、Articleのメソッドを書いていこう。
HTMLタグを外すメソッドと、リンクを設定するメソッドを書く。ソースコードをここに記載しておこうと思ったのだけど、HTMLの要素をうまく表示することが出来なかったので、とりあえず、スナップショットを別ファイルでおいておきます。
改行コードを見付けたら、<BR> を付加するメソッドを書こうと思ったのだけど、ちょっと詰まる。
def set_br self.gsub(/¥n/, "<BR>¥n;") end
こんな感じで記述できそうなのだけど……、これを、article["test1"].set_br みたいな使い方をしたいけど、これ、Article クラスのメソッドにしてしまうと、あまり面白くないかも。String クラスを拡張した方がいいのかなぁ。
とりあえず、Article クラス側でやりたいことはできあがったような気がしてきたので、再びBoardクラスに手を入れる。
残る作業としては、
こんなところかなぁ。
元記事へのリンクについては、正直 Board クラスの役割にすべきかどうか迷っているのだけど(と言うか、eRuby 側で処理した方がいいような)、とりあえずは Board クラスのメソッドにしておく。
def reply( re_num, str ) if re_num == "" link_article = "" else id_file = File::join(@board_url, "id") num = File::readlines(id_file).join.to_i file_num = (re_num.to_i / @max_num).truncate + 1 if file_num == (num / @max_num).truncate + 1 link_article = '<A href="#' + re_num.to_s + '">' + str + '</A>' else link_article = '<A href="' + file_num.to_s + '.html#' + re_num.to_s + '">' + str + '</A>' end end return link_article end
自分で書いていて、あまりスマートじゃないような気がしてきたけど……。
テストコードはこんな感じ。
def test_reply article = {"test1" => "10"} File::copy("test_bbs/base_index.html", "test_bbs/index.html") make_id_file("25") board = Board.new("./test_bbs") board.write(article) assert_equal('', board.reply("", "元記事")) assert_equal('<A href="1.html#10">元記事</A>', board.reply("10", "元記事")) assert_equal('<A href="#21">元記事</A>', board.reply("21", "元記事")) end
たとえ1週間に2、3個の書き込みしかないとしても、その2、3個が一度に集中するということは充分考えられるので、ファイルのロック機能は必須です。というわけで、掲示板に実装しなければいけないのですけれど、手抜きして本体のモジュールは、256倍に掲載されているものをそのまま使うことにする。楽だ〜。
暇を見つけて、こそこそと作ってきた掲示板スクリプトですが、とりあえずローカルでの稼働試験に成功。と言うわけで、この週末に時間を作れれば、Xreaでの試験運用を始めてみようと思う。
がらくた箱で公開するかどうかは、まだちょっと微妙。ドキュメントを作成しなければいけないのは勿論だけど、管理ツールとか、テンプレートの例をいくつか作れてからにしようかなぁ。とは言いつつ、バザール方式に乗っ取って、できたらとりあえず公開してしまうというのもありだと思うけれど。
ともあれ、掲示板を作ろうかなと思い立ってから、ここまでこぎ着けるのに、なんだかんだ言いながら4ヶ月経っているわけで、やっぱプログラムを本職にしなくてよかったと思う今日この頃。