13F

備忘録

Struts 2をいじり中

2007-12-13 01:11:03 | Java
Struts 2 は Struts 1.xよりだいぶ楽になっているんだけど、リンク作るのに2つのタグと一時変数みたいのまで必要なのはなんとも。
<s:url action="blog" method="show" var="url">
  <s:param name="id">1</s:param>
</s:url>
<s:a href="%{url}">BlogAction#showへのリンク</s:a>

試してないけど、伝家の宝刀 jsp:attribute を使えば、形だけは1つにまとめて一時変数的なものも消せるのだろうか……。
<s:a>
  <jsp:attribute name="href"><s:url action="blog" method="show">
    <s:param name="id">1</s:param>
  </s:url></jsp:attribute>
  <jsp:body>BlogAction#showへのリンク</jsp:body>
</s:a>

逆に長くなってしまった。結局、最初の方法しかないのか。

アクセス解析ツール&サービス

2007-12-10 20:58:27 | Weblog
アクセス解析ツール&サービス13種類徹底比較! 史上最強の機能比較表

これを参考にしてAdBlockを設定すれば「主要な」トラッキングを弾くことができそうだ的な意味で有用なまとめ。
(shinobi.jp とか良く見かけるんだけど、主要なサービスじゃないのかな。)

データをhiddenで受け渡す(自分用まとめ)

2007-12-10 02:05:05 | Weblog
HiddenとWebアプリケーション
Hiddenを使う必要のあるアプリケーション

いくらでも穴がありそうで怖いが、一応個人的な考え。

何個でもブラウザウインドウを開いて同時に処理することを許す(たとえば、入力⇒確認⇒完了がウインドウごとに並行して行えるような)場合、hiddenは有用だと思うし、場合によってはいまでも採用することもあるんじゃないかなぁ、と。(上のサイトが引用しているサイトの例に出てるのは注文の場面なので、複数ウインドウで同時にやるってことはあんまりないってことは置いといて)

そういう場合は各々のウインドウが個別に状態を持つ必要があるので、クライアントのウインドウごとに処理中の状態を保持させる(つまり、hiddenで持ちまわす)のが一番自然な実装に思える。セッションを使っても同じようなことはできるけど、hiddenではクライアントに持たせていた処理中情報をサーバ内に持たなければならず、サーバリソースに制限ができてしまうし、管理も面倒くさい。

hidden方式とセッション方式の違いは、クライアントからの入力が毎回行われる(最初は手動で、あとは自動で)か、最初だけかという点だけで、送られてくるデータの検証を必要なタイミングで行わないと死亡というのは同じであり、それを行っていれば安全性に根本的な違いはないんじゃないだろうか。(ただし、見せたくない内部コードのようなものをミスでhiddenに出してしまう、とかはあるかも)

hiddenの利点は、ステートレスであるためクライアントがウインドウをいくら開いても何の問題もないこと。欠点は、アプリケーションを作るときに処理中データをhiddenに吐き出したりその値が返ってきたとき再度検証したりするのが面倒くさいということと、ユーザ入力から別のデータを作成するような場合に、実装によっては毎回作り直す必要があり処理時間を食うかもしれないということか?

セッションに入れてしまう方法の利点と欠点は全く逆で、アプリケーションは物凄く簡単に作れるけども、状態をサーバ側に保持しなければならないために、同時に処理できる数に一応制限があることだ。簡単というのも何も考えなければの話で、どんどん浪費される「ウインドウごとの処理状態」に使うリソースが無視できないレベルになってくるとちょっと面倒そうだ。

Ruby on Rails 2.0では、セッションデータはデフォルトでCookieに保存するようになったそうだ。ちょっと違う話ではあるけど、これも、出来ればステートレスにしたい、サーバリソースは使いたくないというhidden的な考えに似たものを感じなくもない。

SJISファイルシステムでMercurial

2007-12-05 22:00:55 | Weblog
対応する気は無いらしい。
http://selenic.com/pipermail/mercurial-devel/2007-October/003174.html

「ファイル名はファイル内のデータと同じで、(Unicodeに変換することも含む)いかなる変更も加えるべきではない」という原則を、SJISみたいな雲古な文字コードのために崩すつもりは無いって感じみたい。まあ、残念ですが御尤もです。よく見ると「伝説のエロ仙人」とかいう名前の人がさりげなく真面目な投稿をしていたりするのが救いだ。

日本語ファイル名なんて使うのはせいぜいドキュメント類くらいだから、メリットがあればソースコードはMercurial、ドキュメント類はSubversion、というのもあり、かなぁ……。

このへん、Javaでは最初から国際化のことが考られているので(Unicodeマッピングの問題はあったけど……)、シングルバイト圏の人が何も考えずに作ったようなプログラムであっても、文字コードの問題が起こることはほとんどない。
new File("表ソ十.txt").exists()
みたいなプログラムも、その環境のファイルシステムでそういう名前のファイルが存在すればきちんと扱うことができる。

ひょんなところで、改めてJavaの有難味を感じてみたりして。

WindowsでRedmine+Mercurial を試していろいろ敗退

2007-12-05 00:29:25 | Weblog
Redmine でも Mercurial をリポジトリとして使うことが可能らしいと知ったので同時に試してみた。

Redmine のインストールは、SVNでtrunkを引っ張ってきてdoc/INSTALL の通りにやるだけだからまあ簡単。最初、
C:\usr\redmine\trunk> rake db:migrate RAILS_ENV="production"
(in C:/usr/redmine/trunk)
rake aborted!
no such file to load -- initializer
C:/usr/redmine/trunk/rakefile:4
とか謎のエラーが出て困ったものの、よく見たら肝心の rails のインストールがまだだった(SVN版だと vender/rails に無い)。gem install rails --include-dependencies して解決。

Mercurial のインストールも Binary Packages からダウンロードしたインストーラ一発で非常に簡単。とりあえず設定はあとにして
C:\repos> hg init sample
ローカルリポジトリ作成。ここまでは順調。まずはシングルバイト発祥ソフトの泣き所から試してみる。
C:\repos\sample> echo foo > ソ十表.txt
C:\repos\sample> hg add ソ十表.txt
ソ十表.txt: No such file or directory
やっぱりか……。
ソース版をインストールすれば こちら の対応でなんとかなるそうだけどソース版のインストールにはCコンパイラが必要らしい。Cygwinですか。

とりあえずこの問題は無視して、「テスト.txt」というファイルを登録し Redmine で化けずに見られるかどうか試してみた。こっちもダメ。Redmine の /lib/redmine/scm/adapters/abstract_adapter.rb とか mercurial_adapter.rb あたりでSJIS⇒UTF-8変換をかけると表示だけはうまくいくようになるけど、パラメータのエンコーディングの問題かなにかで日本語ファイル名からのリンクはだめ。

とりあえず眠いのであきらめる。Windowsの道は険しい……。


分散型SCM

2007-12-04 00:23:00 | Weblog
リーナス・トーバルズ「Subversion ほど無意味なプロジェクトはない」

から改めて分散型SCMというものを見直す。CVSからSubversionに移行しようとしていた時期に、分散型というものもあってArchとかあるよとは聞いたけど、難しそうだと食わず嫌いしてしまった覚えがある。ちょっと見た限りでは複数拠点開発とかマージトラブルなどのSubversionで面倒くさいところがうまくできている感じ。↓の辺りを見るとMercurialが良さそうなのでMercurial使ってみようかな。
Pythonで分散バージョン管理
Mercurial と Trac のメモ

個人的にはMercurial自体がPythonで出来ていて、Tracプラグインも作られていることがいちばんの決め手だ。

Ruby認定試験受けてきた

2007-12-01 20:24:28 | Ruby
東京会場で受けてきた。

解答欄がひとつずつずれていたとかいうことでもなければ合格はできたと思うけど、この程度で Certified Ruby Programmer と呼べるのかどうか……以下感想。
  • 普段使いもしないコマンドラインオプションとか環境変数とかirbコマンドを必死こいて覚えていったら全く出題されず。覚えてもしょうがないから問題無しでいいやという判断自体は正しいと思うけど、それなら出題範囲から外せばいいのに……。
  • 言語自体の仕様よりも、組み込みクラス(特にArray,Hash,String。あとDir,File,Range,Timeあたりが少し)のメソッドクイズのほうに重点が置かれていた。
  • わかりづらい言葉遣いは勘弁してほしい。たとえば、
    いくつかの代入文とか
    
    if true
      puts 何か
    elsif ~
      puts 他の何か
    end
    みたいなプログラムの「結果がどうなるか」とか。「結果」が「最後に返される値」のことなら nil だろうが、「出力」のことなら「何か」になるとか、そういうの。しかも「nil」も「何か」も選択肢に存在するという……。


Rubyの制御構造

2007-11-26 21:11:27 | Ruby
Rubyは色々な状況でいろんな文を書くことができるので、リファレンスに載ってないような場合にどうなるのかよくわからないことがある…。たとえば制御構造。
def m1
  yield
end

def m2(&block)
  block.call
end

def m3(proc)
  proc.call
end

m1 { return :block }             # LocalJumpError: unexpected return
m1(&(Proc.new { return :proc })) # LocalJumpError: unexpected return
m1(&(lambda { return :lambda })) # LocalJumpError: unexpected return *1
m2 { return :block }             # LocalJumpError: unexpected return
m2(&(Proc.new { return :proc })) # LocalJumpError: unexpected return
m2(&(lambda { return :lambda })) # => :lambda *2
m3(Proc.new { return :proc })    # LocalJumpError: unexpected return
m3(lambda { return :lambda })    # => :lambda

m1 { break :block }              # => :block
m1(&(Proc.new { break :proc }))  # LocalJumpError: break from proc-closure *3
m1(&(lambda { break :lambda }))  # LocalJumpError: break from proc-closure
m2 { break :block }              # => :block
m2(&(Proc.new { break :proc }))  # LocalJumpError: break from proc-closure
m2(&(lambda { break :lambda }))  # => :lambda *4
m3(Proc.new { break :proc })     # LocalJumpError: break from proc-closure
m3(lambda { break :lambda })     # => :lambda

  • *1 がダメで *2 がOKなのがよくわからない……
  • *3 とか *4 は、Rubyリファレンスマニュアルの2007/10/14更新版 ではOKとされているっぽいけど、実際はダメみたい。
  • next はどのパターンでもOKみたいなので、next使うのがいいのかな?

Ruby: joinと無限ネスト配列のつづき

2007-11-17 00:01:14 | Weblog
ブロックつき join を試していて問題になった配列の無限ネスト関係だけど、元の join からして何となく良くわからない。
a = [1,2,3]; a.push a
a.inspect
=> [1, 2, 3, [...]]
b = [1,2,3]; c = [4,5,6]; b.push c; c.push b
b.inspect
=> [1, 2, 3, [4, 5, 6, [...]]]

これはわかりやすい(自分自身が再度出てきたら '[...]' になる)。ところが join だと、
a.join
=> "123123[...]"
b.join
=> "123456[...]"

なんで前者は "123[...]" じゃないのだろうか? 連結のアルゴリズムが前回自分で実装したようなものだから、という理由かもしれないけど、他人に説明しようとしたときどう言えばいいのか難しい。

というか、そもそも '[...]' が出てくるなんて機能には誰も期待していないということなのかも……。

Rubyでブロックつきjoinのつづき

2007-11-16 23:47:12 | Weblog
前にやってみたブロックをサポートする join だが、「事前にmapで変換すればいいだけじゃね?」という心の声が聞こえたのでやってみた。
[1,2,3].map {|x| x+1}.join('--')
=> "2--3--4"

なーんだ、再定義なんて悪辣なことしなくてもこれで済むんじゃん?と思ったがまだ早い。join の仕様としては「要素がまた配列であれば再帰的に (同じ sep を利用して) join した文字列を連結します。」(リファレンスマニュアルより)とのことなので、配列を含む配列も連結できなければ。
[1,2,3,[4,5,6]].map {|x| x+1}.join('--')
=> TypeError: can't convert Fixnum into Array

ですよねー。

これではもとの仕様を満たせない。map のブロックの中で Array かどうか判定するなんてことをはじめると本末転倒だけどどうしよう? ああ、でも都合よく多次元配列を一次元に直してくれる flatten なんてのがあるじゃないか。
[1,2,3,[4,5,6]].flatten.map {|x| x+1}.join('--')
=> "2--3--4--5--6--7"

できた!

……と思うのはまだ早い。リファレンスマニュアルには、さらにこんなことが書いてある。「配列要素が自身を含むような無限にネストした配列に対しては、以下のような結果になります。」
ary = [1,2,3]; ary.push ary
p ary.join      # => "123123[...]"

無限ネストの場合、途中で '[...]' なんていう良くわからない固定値が出力されなければならないのだ。flatten はこんなことをしてくれるだろうか?
a = [1,2,3]; a.push a
a.flatten.map {|x| x+1}.join('--')
=> ArgumentError: tried to flatten re

ああー、やっぱり無限ネストは想定の範囲外のようで。

結局、あんまりいい方法はなさそうだ。無駄な時間を過ごしてしまった。