よたらぼ
自分の興味の赴くままにIT技術系のネタを取りとめもなくメモっています。
Ruby言語やLinuxのネタが多いです。

May 01, 2002

[Misc] XREA + tDiary + Namazu, yasqueeze.rb

最新のyasqueeze.rbに合わせてドキュメントを見なおした。

[tDiary] アンカー自動生成プラグイン-1.1.0リリース

自分が作ったプラグインの中(といってもまだ6つくらいしかないけど)でも1,2を争うほど使い勝手も実用度も高いと(勝手に)思っている....割には全く人気のないアンカー自動生成プラグインだが、めげずにバージョンアップしてみた。

辞書ファイルをWWWブラウザから登録できるようになったのでさらに使いやすくなったはず。

というわけでダレか使ってみてくれ〜。 ホント使いやすいんだってばさ〜。

[tDiary] プラグインを書くときのTips

tDiaryでプラグインを書くときに気になったことをいくつかまとめてみた。

[tDiary] (1) @で始まる変数(インスタンス変数)を使うときは要注意

プラグインは他のプラグインも含めて1つのクラス(とインスタンス)を形成する。したがって、@で始まるインスタンス変数は他のプラグインからもアクセスできてしまう。

例えば、以下の例で、hoge1からの結果を1と期待していると(プラグインはアルファベット順に読み込まれる)実際は2が返されてしまう。

このように、プラグインではいつどのようなものが後から追加されるか分からないのでインスタンス変数にはなるべく重複しないような名前を選ぶ必要がある。

そこで例えば、@付きの変数についてはファイル名をプレフィクスにつける等にするとかなりの確率で問題を回避できる。上の例で言えば、 @hoge1_hoge, @hoge2_hogeだ。

あるいは、Moduleを使う方法もある。これはもうちょっと後ろで触れることにする。

hoge1.rb
  -------------
  @hoge = 1
  def hoge1
    @hoge
  end
  -------------
 
  hoge2.rb
  -------------
  @hoge = 2
  -------------

もちろん、なるべくインスタンス変数を使わずにメソッドローカルな変数を(@なし)を使うように心がけるというのは言うまでもない。

[tDiary] (2)そのプラグイン限定のプライベートなメソッドを定義したい

実はtDiaryのプラグインではいわゆるプライベートな宣言は意味をなさない。なぜなら、全てのプラグインで1つのクラスを形成していて、1つのクラスの内部ではプライベートだろうがパブリックだろうがお構いなしにアクセスできるからだ。

また、ユーザからは使用させないがプログラミング上の効率から定義するメソッドというのもあるが、そのようなメソッドは先のインスタンス変数と同様に特に名前問題に注意する必要がある。

例えば、以下の例のように日記の本文中にと書くプラグインを作ったとする。formatメソッドはhoge1.rbの中でしか使わない*つもり*のものだ。しかしながら、実はhoge2.rbでも同じ宣言がされているため、上書きされてしまい(プラグインはアルファベット順に読み込まれる)結果が予期しないものとなってしまう。

hoge1.rb
  -------------
  def format(v)
    "[" + v + "]"
  end
  def hoge1(str)
    format(str)
  end
  -------------
 
  hoge2.rb
  -------------
  def format(v)
    "---" + v + "---"
  end
  -------------

結局のところ、そのプラグインのみで使うことができる、そのファイルローカルなメソッドを作ることはできない。

そこで、@付きの変数(インスタンス変数)と同様に、ファイル名をプレフィクスにつける等にするとかなりの確率で問題を回避できる。

その他に、Moduleを定義する方法もある。そこで、次にModuleを使った方法を紹介する。

もちろん、名前の問題はユーザが直接扱うメソッドについても同様のことが言えてしまう。まぁ、でも、これはすでに存在するプラグインを調べて、重複しない名前を付ける努力をするしかないかな。

[tDiary] (3) Moduleを使う

RubyのModuleは機能をひとまとめにしておき、いろいろなクラスから呼び出すためのものだが、単純に名前空間を分けるために使うこともできる。先ほどの2つの例を合わせたようなコード例を書いてみる。

hoge1.rb
  -------------
  module Hoge1
    @hoge = 1
    def format(v)
      "[" + @hoge.to_s + ":" + v + "]"
    end
    module_function :format
  end
 
  def hoge1(str)
    Hoge1.format(str)
  end
  -------------
 
  hoge2.rb
  -------------
  @hoge = 2        #これなら影響受けない。
  -------------

もちろん、この例でもhoge2.rbでmodule Hoge1を上書きすることはできるが、なるべくファイル名と同じModuleを使うようにすれば、かなりの確率で問題を回避できるし、Module内部では自由に変数名・メソッド名をつけられるのでコード的にもすっきりする。

[tDiary] (4) requireについて

プラグインは、実際はtdiary.rbの内部に取り込まれる形になるので、tdiary.rb自体がrequireしているライブラリについては、改めてrequireする必要はない。例えば、1.4.1では、cgi, nkf, pstore等。

[tDiary] (5) デバッグモード

CVS版では新たにデバッグモードが追加された。プラグインファイルの先頭の方に@debug = true と書く。

こうすることで、特に呼び出したメソッドの名称が間違えていた場合などにエラーが発生するようになるため、若干デバッグがしやすくなる。

それから、$DEBUG = trueを追加すると、さらにいろいろとメッセージが出るようになるのだが、Warningレベル(例えば例外が出たときにはrescueしていてもメッセージが出てしまう)でもメッセージが出るため、全てのWarningを消す必要はないはず。

ただ、注意しなければいけないのが、@debugは他のプラグインでも有効になってしまうこと。自分以外のプラグインのバグも見つけてしまうかも。まぁ、その時はそのプラグイン作者に報告してあげると良いだろう。

[tDiary] (6) メソッド名のつけ方

ちょっと話は変わってメソッド名のつけ方。

メソッド名は基本的に小文字で始めれば良いのだが、単語の区切り方は2通りある。1つは'_'でつなぐ方法ともう一つは単語の区切りを大文字にする方法(Camel Case)だ。

def hoge_fuga
end
 
def hogeFuga
end

これについては人によって好き嫌いが発生し、JavaなどでもCamel Caseが使われていることから過去にも何度か論争の種になっているのだが、実は、Ruby的には前者が好まれる。実際のところtDiary本体でもそのようになっている。

この辺のRuby的なコーディング手法の指針が欲しい人は、高橋征義さんによるRuby Coding Conventionが参考になると思う。

ちなみに、Javaでいうところのgetter/setterもあまり好まれない。

def get_hoge
  @hoge
end

例えば、上記の場合は

def hoge
  @hoge
end

あるいは attr_reader :hoge というようにアクセッサを使う...でも、これはプラグインの場合はあまり使わないかな。

[tDiary] (7) ファイル名のつけ方

ファイル名はなるべくメソッド名と同じにするのが好ましいが、複数のメソッドがある場合は、なるべくメソッド名から外れない程度で象徴的な名前にする。

[tDiary] (8) CSS

通常、プラグインは何らかのHTMLを返すと思うが、その際にCSSについても配慮が必要。なるべく、テーマから変更しやすいようにclass/idづけした方が良い。なお、CSSのclass/id名には'_'を使えないので注意。

つづく.... かも。

本日のツッコミ(全1件) [ツッコミを入れる]

ただただし [FAQに入れちゃった:-)]


May 01, 2003

[Hiki][tDiary]プラグインに埋め込まれた表示文字列の言語を選択可能に

昨日の話をちょっと考えてみたのだが、以下のような案はどうだろう。

実は、この考え方自体はtDiary本体が採用しているので新しくはないのだが、プラグインには使われていないので、これを機会にtDiaryプラグインでもこのルールが適用されれば良いなとはちょっと思う...が自分で作ったプラグインを適用させるのはちょっとめんどくさいか(^^;)。

すでに切り出されているプラグインがあるとのこと。知らんかった<アホ

試しに、Hiki-0.5系添付のreferer.rbのshow_refererというメソッドを例に考えてみる。

def show_referer(db)
  s = '<div class="referer">このページへのリンク元<ul>'
 
  referers(db).each do |ref|
    disp = replace_url(ref[0].unescape).escapeHTML
     s << %!<li>#{ref[1]} <a href="#{ref[0]}">#{disp}</a>!
  end
 
  s << '</ul></div>'
end

で、これだと思いっきり日本語が埋め込まれてしまっているので英語サイトでは使えない。

そこで、表示文字列のみを別メソッドに括りだすというプラグインコーディング上のルールを作る。

def show_referer_label
  'このページへのリンク元'
end
 
def show_referer(db)
  s = '<div class="referer">#{show_referer_label}<ul>'
 
  referers(db).each do |ref|
    disp = replace_url(ref[0].unescape).escapeHTML
     s << %!<li>#{ref[1]} <a href="#{ref[0]}">#{disp}</a>!
  end
 
  s << '</ul></div>'
end

英語で使いたい人は、以下のようなプラグインを別途用意する。例えば、referer_en.rbとでもしてpluginディレクトリに置けば、表示時にはこちらが使われることになる。

def show_referer_label
  'Referrer'
end

このreferer_en.rbをプラグイン提供者が用意するのがベストだが、少なくともこの仕組みに準じるように作っておけば、ユーザ自身が作ることもできなくはない。 きたさんの指摘のような場合は仕掛けだけ仕込んで、あとはユーザに任せてしまえば良い...とすればプラグイン作者も少しは気が楽になる...かな。

幸い、このような文字列は1つのプラグインにそれほど数があるモノでもないので対応するのはそれほど大変ではないだろう。

それに、バージョンアップの度にプラグイン自体を書き換えたりする必要がないのは非常に助かる。もちろん、バージョンアップの際に元になる文字列の意味が変更されたり、表示項目が増えたりしたら対応しないといけないけど、それはまぁしょうがないと。

ただ、この案で難しいのがRuby-GNOME2のように、1つのHikiで英語・日本語のサイトを運用している場合だ。

そのような場合、上記の仕組みだけだと全部英語(あるいは日本語)になってしまう。

そこで、Hikiを拡張して、plugin/*.rbを読み込む直後に、plugin/#{$lang}/*.rbも一緒に読み込むようにする。$langのディレクトリが存在しない場合は読み込まない。

こうしておけば、上記例のreferer_en.rbは、plugin/en/referer.rbとでもしておけば良い。

まとめると、

  1. Hiki本体としては、plugin/*.rbを読み込んだ直後にplugin/#{$lang}/*.rbを読み込むような仕掛けを用意する。
  2. 各プラグインは、日本語文字列を別メソッド化しておく
  3. 標準添付のモノに関しては、misc/plugin/en/ディレクトリを作ってそこに上記に対応した英語のリソースを追加してもらえるとよりベター

#きたさんのツッコミの後にこの文章自体を見直して一部書き直してます。

本日のツッコミ(全8件) [ツッコミを入れる]

Before...

たけうち [yoshimiさんの案はプラグイン単体で解決するところが良いですね。ただ、日本語しか考慮していないプラグインを作者以..]

むとぽん [ふと思ったのですが、plugin/#{$lang}/referer.rbはplugin/#{$lang}/refer..]

shiro [WiLiKi本体ではGNUのgettextに似たしくみを使っています. 万能ではないですが、基本となるメッセージ文字..]


May 01, 2005

[Ruby] (続) WEBrick on Win32

WEBrick::HTTPServer.newでCGIInterpreterを渡せば良いのか。そーかそーか。

srv = WEBrick::HTTPServer.new({:BindAddress => '127.0.0.1',
                               :Logger => WEBrick::Log::new($stderr, WEBrick::Log::DEBUG),
                               :CGIInterpreter => 'c:\ruby\bin\ruby.exe',
                               :Port => 10080})

でも、これだと外部の拡張ライブラリ(Ruby/GLibね)を使おうとするとDLLが無いって言われるんだよなー。どうもPATH(環境変数)がうまく読み込めないっぽい。これもCreateProcess()の制限なのかなー。うーむ。

これも

[Ruby] Ruby-GetText-Package-0.9.0

リリースしました。今回のウリはCGIとERBのサポートです。簡単ですがチュートリアルっぽいものも用意したので興味のある方はどうぞ。

本日のツッコミ(全2件) [ツッコミを入れる]

たむら [:CGIPathEnv つうのがあります。 http://www.ruby-lang.org/ja/man/?cmd..]

むとう [なるほど。それを使うんですね。 うーん、先にリリースしちゃいましたー。Ruby-GetText-Package。残念..]


更新 設定