Ruby言語やLinuxのネタが多いです。
January 02, 2006 [おもひで]
module A
module_function
FOO = "foo"
def foo; p FOO; end
module B
extend A #(1)
module_function
def bar
foo #(2)
p FOO #(3)
end
end
end
A::B.bar
上記(1)でA::BはAをextendしないと(2)でエラーになるけど、(3)は使える。なんとなく、メソッド呼び出しもできちゃって良いような気がする、というかいつもそれで間違える。あ、でも、@@foo, @foo等の変数たちもextendしないとダメなのね。定数だけ例外、なのか・・・。
January 05, 2006 [おもひで]
■ [Ruby-GNOME2] udbm-gtk
UDBM(UPPAAL DBM Library)の、グラフィカルビューアとしてRuby/GTK2を使って頂いています。irbから操作しているみたいなので、実際はウィジェットライブラリみたいな感じなのかな。きれいなグラフが書けるみたいです。
January 06, 2006 [おもひで]
■ [Ruby-GNOME2] 困った質問
例えば、Widgetの使い方の質問があったとき、「なんでそうなってるの?」という質問をされると非常に答えに窮する。
なぜならば、オレはWidgetに対しRubyからアクセスする部分(つまりWrapper)については実装しているけど、Widgetそのものを実装したわけではないため、そのWidgetがどうしてそのようなAPI/実装になっているかなんて背景までは知らないからだ。
結果、答えとしては「オリジナルのWidget作者に聞いてみてくれ。」ということになるのだが、オリジナルのWidget作者に質問するためにはRubyのコードではなく、Cのコードで書き直して例示しないと作者の人は困ってしまうだろう(その人もRuby-GNOME2を使ってくれているのなら話は別だけど...)。
■ これって、Ruby-GNOME2のように、オリジナルのもののバインディング、というもののウィークポイントだよね。質問者もフラストレーションが溜まるだろうと言うことは容易に想像できる。
それに対し、ではどうすれば解決できるかというと、オリジナルのライブラリとRuby-GNOME2の両方に精通した人が現れる、ということだ。
え?オレ?ムリムリ、だって量多すぎるんだもん。
オレができるのはせいぜいC版とRuby版の両方を作り比べてみて、その両者の動きが違うようであればRuby側のバグとして改修して、それ以外の時は「GTK+でも同じだねー」という確認を取るところまでだね。
■ [Misc] ケースバイケース
上記の話の流れで、「ウインドウサイズを(デフォルト状態から)変更できなくするのはUIデザインとしてどうよ?」という質問があったので「ケースバイケースじゃないかと思うんだけど・・・。どうして?」と返したところ「画面が小さい場合に問題になるんじゃない。」という返事が。
でもさぁ、それこそケースバイケースなんだと思うんだけどなぁ。
例えば、PDAや携帯なんかをターゲットにするのか、PCをターゲットにするのか、PCにしたって、640x400の画面サイズからサポートするのか1024x768からをターゲットにするのか、それによって全然状況が違ってくるよね。
第一、小さい画面をサポートするのであれば、ウインドウサイズが変更できるかどうか、ということよりも別のこと(ボタンの配置自体の見直しなど)を考える必要があるはず。PCと携帯で同じボタンの配置が使えるわけないしね。
■ ちょっと話は変わっちゃうかもしれないんだけど...。
最近までWWWアプリを作る場合、JavaScriptを使うのはいろいろなWWWブラウザのことを考えるとよろしくない、というような風潮があったような気がしたけど、Ajaxが出てきたらそんなこと言う人いなくなっちゃったね。
もちろん、機が熟したってこともあるんだろうけど、「せめてw3mでは使えるようにしとこーよー」とか言う人はだいぶ減ってしまったような気がする。
いや、別にそれが悪いこととは思って無くてむしろ肯定派なんだよね。
つまり、結局はそのアプリの作り手が、そのアプリがどういったユーザを対象にするのか適切に考えているかってことが大切なんだよね。w3mもターゲットにするんであればそのように作れば良いんだし、極端な話、IE特化でも良いわけだし。
■ ・・・ってか、case by caseって英語の使い方、間違ってるような気がしてきた。It depends.とかって言った方が良かったのかな・・・ダメだこりゃorz。
January 07, 2006 [おもひで]
■ [Ruby] Ruby-GetText-Packageサンプルブログ特集(笑)
Ruby-GetText-Packageのギリシャ語翻訳がようやく届いた。これで、10言語(一部12言語)をサポートできたことになる。
そこで記念にRuby-GetText-Packageに含まれるRuby on Railsを使ったサンプルブログアプリケーションの画像イメージを取ってみた。全部同じエラー画面ね。ちょっと大きいけどご容赦を。
■ まずはen(英語)。まぁ、見慣れてるって言えば見慣れてるかな。

■ 次はja(日本語)。わかりやすい。(当たり前か)。

■ 次からはロケールのアルファベット順、ということでまずはcs(Czech:チェコ語)。

■ de(ドイツ語)。昔、ちょっと習った記憶がないこともないが、ほぼ読めず。

■ el(ギリシャ語)。ギリシャ語の字っておもしろい形をしてるね。

■ es(スペイン語)。他に比べると英語に近いかなぁ。

■ fr(フランス語)。これも読めんなー。

■ ko(韓国語)。ハングル自体は最近なじみが出てきたけど、やっぱり全く読めないや。

■ nl(オランダ語)。これも多少英語に近いか・・・。

■ pt_BR(ポルトガル語(ブラジル))。これもなんとなく読める文字が多い気がする。< ホントか?

January 10, 2006 [おもひで]
■ ようやく私が持っている個人的なコンテンツはyotabanana.comに集約できました。
実は去年中にはやっておこうと思っていたのですが、なんと一年かかってしまいました。ってか一年って早いですねー。
■ 新しいコンテンツともどもよろしくお願いします。
January 14, 2006 [おもひで]
■ [Ruby] Ruby-GetText-Package-1.1.1
リリースしました。バグフィクスとギリシャ語の追加です。
特にRuby on Rails周りの不具合を改修してますので、そちらでご利用の方はアップデートしてくださるようお願いします。
January 15, 2006 [おもひで]
■ [Ruby] Ruby on RailsでRuby-GetText-Packageを使う
ようやく日本語版チュートリアルをアップデートしました。Ruby on RailsでL10n化を考えている方はぜひご一読ください。
■ しっかし、英語と日本語の両方をメンテナンスするのはとてもつらいなー。むー。
■ [Hiki] オプションプラグイン-1.1
Hiki-0.8.5で動作するように改修しました。
January 16, 2006 [おもひで]
■ ここでは簡単なライブラリ"FooClient"というのを想定する。
このクラスは設計の良し悪しは別として(^^;)、requireした瞬間にFooサーバーに接続し、Rubyプログラムが終了するタイミングで接続を解除する仕様とする。
# fooclient.rb
module FooClient
#require時にServerに接続してしまう
@connected = true
at_exit {
p "at_exit"
#at_exit時に接続を解除
@connected = false
}
module_function
def connected?; @connected; end
end
if $0 == __FILE__
p FooClient.connected?
end
んで、テスト
# test.rb
require 'test/unit'
require 'fooclient'
class FooClientTest < Test::Unit::TestCase
def test_connected
assert_equal true, FooClient.connected?
end
end
んでもって、テストを実行してみると、テストが失敗してしまう(FooClient.connected?がfalseを返す)。FooClientでは確かにat_exitを使ってるのが気持ち悪いことは気持ち悪いけど、でも、テストプログラムのassert_equalの部分はまだat_exitを呼び出す前のような感じがするし・・・。
と、小一時間くらいは悩んでしまったわけだが、理由は簡単で、test/unit.rbが内部で以下のようなコードを持っているのが原因だ。
at_exit do
unless $! || Test::Unit.run?
exit Test::Unit::AutoRunner.run
end
end
これは、test.rbにテストを実行するようなコードを一切書く必要が無いような配慮だ。プログラム終了をトリガーにしてTest::Unit::AutoRunner.runを実行する。
ちなみに、at_exitは以下のようなサンプルを実行するとその動きがわかると思う。
% cat at.rb
at_exit { p 1 }
at_exit { p 2 }
p 3
% ruby at.rb
3
2
1
つまり、at_exitに最後に登録したものから呼ばれることになる(2→1)。
■ さて、上の例の回避策をどうすれば良いかというと、上記のat_exitの順序を意識しつつ、requireの呼び出しをすればよい。おそらくほとんどの場合、require 'test/unit'を最後に呼び出すことになるだろう(つまり、他のライブラリのat_exitを呼び出す*前に*テストを実行する)。
test.rb require 'fooclient' require 'test/unit' : :
■ でもなぁ。requireの順番を気にするなんていう回避策はいただけないよなぁ、と言う場合のもう一つの回避策としては、Test::Unit::AutoRunner.runをtest.rb内で呼び出すという手がある。そうすれば、test/unit.rbのat_exitは関係なくなるからね。
test.rb
require 'test/unit'
require 'fooclient'
class FooClientTest < Test::Unit::TestCase
def test_connected
assert_equal true, FooClient.connected?
end
end
exit Test::Unit::AutoRunner.run
■ まぁ、どっちもどっちか。でも、オレはこっちの方が好きかな。やっぱり、Rubyインタプリタが終了することをトリガーにメインのプログラム(テスト)を実行するってのはちょっとトリッキーすぎな気がする。
■ ともかく、自分が開発していないライブラリを混ぜてテストするときはここであげた点を意識しておいた方がいいだろうね。
at_exitに優先度つけれたら良いのかもしれないけど...。
January 20, 2006 [おもひで]
■ [Ruby] 保存しておいた文字列を高速に検索する
同じHTTPリファラから10回以上のアクセスがあった場合、それ以上(11回目から)のアクセスができないようにするためにはどのような実装が良いのかな。
■ まずは、リファラのURLをHashのキーとして持つことを考えてみた。
@deny_urls = Hash.new
def allow?(referer)
ret = true
if @deny_urls[referer]
if @deny_urls[referer] >= 10
ret = false
else
@deny_urls[referer] += 1
end
else
@deny_urls[referer] = 1
end
ret
end
s = Time.now
(0...10000).each do |i|
(0...15).each do
allow?("http://www.yotabanana.com/#{i}")
allow?("http://www.yahoo.com/#{i}")
allow?("http://www.google.com/#{i}")
end
end
p Time.now - s
なんだか、if文だらけになっちゃったし、使用例の部分もいまいちだけど、まぁいっか。
■ まぁ、ともかく、次に、keyに文字列のhashを使ってみる(ってかRubyのHashってこういう使い方しても大丈夫なんだっけ?(^^;))。
def allow?(referer)
ret = true
hash = referer.hash #(1)
if @deny_urls[hash]
if @deny_urls[hash] >= 10
ret = false
else
@deny_urls[hash] += 1
end
else
@deny_urls[hash] = 1
end
ret
end
allow?メソッドのとこだけ書き換え。他は同じね。
■ で、両者の性能を測ると
% ruby test.rb 4.146538 % ruby test2.rb 3.488657
うーん、もうちょっと高速化したいなぁ。他に高速化する方法ってある?
ポイントとしては、以下の感じ。Rubyクイズスタート!応募はツッコミ欄で!!ちなみに応募しても何も出ません(ってオイ(^^;))
- (1)のような数値化はallow?メソッドの中で実行する必要がある。(ループの外には出せない)
- 別にデータ構造自体Hashでなくてもいい。
- だいたい(90%以上で良いかな)うまくいけばOK。
- データは不可逆でOK。
January 28, 2006 [おもひで]
■ [tDiary] アクセスカウンタ表示プラグイン-2.0
久しぶりに全面見直しをかけました。まともにいじるのは2002/10以来なので2年以上経ってしまいました(苦笑)。
■ 変更点ですが、内部的な安定性の向上、設定画面の追加、kiribanプラグインの追加です。
設定画面からは全ての項目の設定ができるようになりました。キリ番をちょこちょこ指定したい人は格段に使いやすくなったと思います。
#英語版を使う場合はen/counter.rbを一緒に入れてください。
■ また、kiribanプラグインですが、これは、設定画面で「全て」「今日」「それ以外」のメッセージを記述をしておくと、<%= kiriban %>と書いたところに適切に展開してくれるものです。メッセージを変更したい場合も、設定画面からすぐにできますので、ぜひ使ってみてください。うまく使えばきっと楽しいキリ番ライフになるんじゃないかと思います(?)。
■ あ、そうそう、デフォルトでかなりの種類のロボット系ユーザエージェントからのアクセスをカウントしないようにしました。導入後、急にアクセス数が減る感じがしてちょっとがっかりするかもしれません(私のところでも1/5程度に...orz)。
■ あとは内部的な話ですが、今回データをカウンタデータとアクセス元データの2つに分け、極力カウンタデータが壊れないようにしました。アクセス元データのサイズも以前に比べてかなり抑えることができたので全般的に負荷が軽くなったのではないかと思います。
■ [tDiary] リファラエディタプラグイン-1.2.2
設定画面でのカテゴリ表示を「リンク元」のところで表示するようにしました。
ちょっとした修正で現状不満のない方はアップデートする必要はありません。
■ [Hiki] ヘッダタイトル変更プラグイン
0.8.5で動作するように記述内容を変更しました。
January 31, 2006 [おもひで]
■ [Rails] パッチ2題
1つめは、ActiveRecordのvalidates_length_ofが日本語だとうまくいかない件。うまくいかないっていうか、結局バイト数になっちゃってるからそこを文字数でカウントしてあげるようにすれば良いだけなんだけどね。
(activate-x.x.x/lib/activerecord/validations.rbへのパッチね)
--- validations.rb.old 2006-01-31 02:22:42.000000000 +0900
+++ validations.rb 2006-01-31 02:41:03.000000000 +0900
@@ -459,7 +459,7 @@
message = (options[:message] || options[message_options[option]]) % option_value
validates_each(attrs, options) do |record, attr, value|
- record.errors.add(attr, message) unless !value.nil? and value.size.method(validity_checks[option])[option_value]
+ record.errors.add(attr, message) unless !value.nil? and value.split(//).size.method(validity_checks[option])[option_value]
end
end
end
あ、そうそう、どこかで$KCODEを指定しとかないとsplit(//)がうまく動作しないので念のため。
■ もう一つは、Content-Typeをアプリ側で指定してしまうとRJSが動作しなくなる件。例えば以下のような例。
class ApplicationController < ActionController::Base
before_filter :set_charset
def set_charset
@headers["Content-Type"] = "text/html; charset=utf-8"
end
end
■ これって、.rjsなファイルだったら強制的にContent-Typeをtext/javascriptにしちゃえばいいと思うんだけど、それをせずにすでに指定された上記の"text/html; charset=utf-8"を使うのが問題だと思う。
なので、このパッチは.rjs/.rxmlの時は強制的にContent-Typeを書き換えるようにする。
以下は、SVN版のactionpack/lib/action_view/base.rbへのパッチ
--- base.rb.old 2006-01-31 02:05:28.000000000 +0900
+++ base.rb 2006-01-31 02:05:38.000000000 +0900
@@ -394,10 +394,10 @@
body = case extension.to_sym
when :rxml
"xml = Builder::XmlMarkup.new(:indent => 2)\n" +
- "@controller.headers['Content-Type'] ||= 'text/xml'\n" +
+ "@controller.headers['Content-Type'] = 'text/xml'\n" +
template
when :rjs
- "@controller.headers['Content-Type'] ||= 'text/javascript'\n" +
+ "@controller.headers['Content-Type'] = 'text/javascript'\n" +
"update_page do |page|\n#{template}\nend"
end
else
■ で、これ、RailsのMLに投げたら、Trac使え、と言われたので言われたとおりにhttp://dev.rubyonrails.org/を見てみたところ、テストケース書け!って書いてある。ってか、正直書き方わかりません....ということで放置の方向で。あ、いや、誰かテスト書いて〜。

Before...
▲ むとう [すみません、もう少し詳しくお願いしますm(__)m。]
▲ なかだ [testrbというのは、まさにそのTest::Unit::AutoRunner.runを実行するためのスクリプトです..]
▲ むとう [なるほど。そういうコマンドがあるんですね。 お恥ずかしながら知りませんでした。 ありがとうございます。]