2010年12月24日金曜日

C-u M-x shell とその省力化

Emacs の中で shell というコマンドをよく利用する。仕事で使うOSはWindowsだけど、安易にマウスに手を伸ばさないで、目を閉じて、GNUのコマンド群やPerlのワンライナーを頭の中で組み合わせて、打鍵して、実行する。

その shellを使うにあたり、ただ単にM-x shellと実行すると、*shell*バッファが1個だけしか使えないのだが、並行作業が多いので複数のバッファを使いたくなる(顧客ごと、プロジェクトごとのバッファ)。

複数の *shell* を開くには、いわゆる「前置引数(prefix argument)」を使って shellコマンドを実行する。具体的には次のようにキーを打つ。

C-u M-x shell[Enter][Enter]

この結果、*shell*, *shell*<2>, *shell*<3>,...という具合に番号付きのバッファが順次生成されてゆく。

仕事上の要求はこれで満足されるが、それにしてもC-u M-x shell[Enter][Enter]と毎回打っていると面倒になってくる。なので、この操作をもっと省略するにはどうすればいいかを考える。

最初、 (shell) をラップする関数を定義して、それにキーを割り当てるという方法を思い付いたが、どうも前置引数関連の関数/変数の仕様がよく理解できず挫折( (universal-argument), current-prefix-arg など )。

仕方が無いので、以下のようにキーボードマクロで実現することにした。

1. C-u M-x shellをマクロとして記録

次のようにキーを打つ。

C-x ( C-u M-x shell[Enter][Enter] C-x )
2. キーボーマクロに名前を付ける

名前はとりあえずたった一文字の「s」にすることにして、次の式を評価。

(name-last-kbd-macro 's)

この時点で、M-x s[Enter] を実行するとシェルが複数起動するようになるはず。

3. キーボードマクロの永続化
(insert-kbd-macro 's)

*scratch*バッファで上の式を評価すると、下のような出力が得られるはず。

(fset 's
   [?\C-u ?\M-x ?s ?h ?e ?l ?l return return])

これがキーボードマクロの定義。今後も使用するため、 .emacs, init.el 等に貼り付けておく。

2010年12月16日木曜日

IE5.5 で MochiKit のセレクタ(MochiKit.Selector)を使うときに

ほとんどの仕事でIE6以上がサポート対象となるのだが、まれにIE5.5もサポートしなければならないこともある。

IE5.5で何が困るかと言うと、JavaScriptライブラリである。普段はもっぱら jQuery を使ってJavaScriptを書くのだが、残念ながらIE5.5ではエラーが発生してしまう。

ちょっとしたスクリプトなら組み込みのJavaScript関数だけで対応するが、それが効率的でない場合は jQueryに代わるライブラリを導入する。JavaScriptのいわゆる「軽量ライブラリ」はたくさんあるのだが、一体何を使うか? 自分の場合は MochiKit を使う(IE5.5でエラーが発生しないのと、むかし使ったゆえの惰性もある)。

そのような状況で、つまり MochiKit と IE5.5 の組み合わせで頻繁に犯してしまうミスがあるので備忘のため書いておく。

Classセレクタ(Class Selector)は要素もセットで記述するべし

たとえばHTMLドキュメントに foo というclassをもつ div 要素があったとして、

NG
  MochiKit.DOM.addLoadEvent(function(){
    alert($$('.foo').length);
  });

このコードでは結果が 0 になってしまう。なぜか .fooだけでは目的の要素が取得できないのだな。

OK
  MochiKit.DOM.addLoadEvent(function(){
    alert($$('div.foo').length);
  });

セレクタに、要素 div も指定すると期待通りに 1 が得られる。

2010年12月15日水曜日

Redirectディレクティブのパラメータの形式

ある日サーバーの乗り換えを実施したところ、一部のURLで404エラーが発生するようになってしまった。

原因は、乗り換え前のサーバーとApacheのバージョンが変わってしまってリダイレクトが効かなくなったため。根本的には、 .htaccess 内のRedirectディレクティブで形式エラーが発生したためであった。

エラーのログ(apache の error_log)

[Fri Dec 10 20:18:06 2010] [alert] [client xxx.xxx.xxx.xxx] /foo/bar/baz/.htaccess: Redirect to non-URL, referer: http://example.com/index.html

.htaccess で Redirect to non-URL ですよ、と。

.htacces の修正

修正前
Redirect permanent /foo.html /foo/index.html

最後のパラメータ(リダイレクト先)がURLの形式になっていなかった。乗り換え前のサーバーではこれで問題なかったのだが…

修正後
Redirect permanent /foo.html http://example.com/foo/index.html

httpスキームとホスト名を追加してURLの形式にしたらOK。ホスト名を指定してしまうとWebサイトのテスト工程などで不便になるのだが、やむをえず。

Redirectディレクティブの仕様を調べてみる

ApacheのドキュメントからRedirectのSyntaxを引用:

Redirect [status] URL-path URL

リダイレクト元を表すURL-pathとリダイレクト先を表すURLの形式については、バージョン1.3, 2.0, 2.2 ごとに仕様記述が変化している(mod_alias は比較的素朴で安定したモジュールだと思われるが、それでも変化している)。仕様を読む限り、バージョン2.2からリダイレクト先の記述でスキームやホスト名を省略できることになったようだ。

Apache 1.3 の場合
パラメータ URL-path, URL の形式については特に記述が無い。
Apache 2.0 の場合
URL について、「スキームとホスト名で始まる完全なURLであるべし」と記述されている。
The new URL should be an absolute URL beginning with a scheme and hostname
この文で、"an absolute URL" という英語に「絶対URL」という用語をあてる人もいるが、混乱を招くようだ。"absolute"は"complete"でもあるから「完全なURL」としておいたほうが適切と思われる。
Apache 2.2 の場合
URL について、さらに「しかし、スラッシュで始まるURL-pathも使用できる。その場合は現在のサーバーのスキームとホスト名が付加される」と追記されている。
, but a URL-path beginning with a slash may also be used, in which case the scheme and hostname of the current server will be added.

この文で"URL-path"の書体はイタリックではない。よって一般的な用語としての"URL-path"であり、SyntaxにおけるURL-pathではないと思われる。

2010年12月12日日曜日

Windows7 に C/Migemo & migemo.el を導入

Emacsで、いわゆる日本語インクリメンタルサーチを実現する。

日本語インクリメンタルサーチつまり Migemo の辞書検索モジュールには Ruby/Migemo と C/Migemo の二つの実装がある。ここでは高速かつRuby不要という点から後者を利用する。

前提としている環境

  • Windows 7 Home Premium 64bit
  • Cygwin 1.7.7
  • GNU Emacs 23.1.1 (i386-mingw-nt6.1.7600)

※Cygwinのバージョンは uname -a コマンドを打つと確認できる。

導入作業

辞書ファイルをインストール

KaoriYa.net より「バイナリ(DLL) 1.3 64bit版 for Windows (約3.46MB)」をダウンロード。

解凍すると、/dict/utf-8 に辞書ファイルが計5個生成される。これ(UTF-8の辞書)を emacs向けのフォルダに置く。ここでは、 ~/.emacs.d/site-lisp/migemo/ に置くこととする。

$ cd ~/download  #ダウンロードしたファイルがある場所へ移動
$ unzip -q cmigemo-1.3-w64dll.zip
$ ls cmigemo-1.3-w64dll/dict/utf-8/
han2zen.dat
hira2kata.dat
migemo-dict
roma2hira.dat
zen2han.dat
$ mv cmigemo-1.3-w64dll/dict/utf-8 ~/.emacs.d/site-lisp/migemo/
C/Migemo の dllファイル および exeファイル を作る

さらに「ソースコード 1.3(予定) 開発版」をダウンロード。

Cygwinを起動して、以下のようにコンパイル&設置を行う。

$ cd ~/download  #ダウンロードしたファイルがある場所へ移動
$ tar xvjf cmigemo-1.3c.tar.bz2  #解凍
$ cd cmigemo-1.3
$ make cyg  #コンパイル
$ cp build/{cygmigemo1.dll,cmigemo.exe} "C:\cygwin\bin"  #dll と exe を cygwin/bin に設置
migemo.el のインストール

C/Migemo を emacs から実行するための elisp が "migemo.el".

オリジナルのソースコードは積極的にメンテナンスされていないようなので、どなたか分からないが個人的にElispを公開しているかたのものを使うことにする。

sakito / dot.emacs.d / source – Bitbucket よりダウンロードして、load-pathに置く(~/.emacs.d/site-lisp/など)。

emacs の*scratch*バッファを使うなどして下記elispコードを評価。

;; migemoの設定
(setq migemo-command "cmigemo")
(setq migemo-options '("-q" "--emacs" "-i" "\a"))
(setq migemo-dictionary (expand-file-name "~/.emacs.d/site-lisp/migemo/utf-8/migemo-dict"))
(setq migemo-user-dictionary nil)
(setq migemo-regex-dictionary nil)
(setq migemo-use-pattern-alist t)
(setq migemo-use-frequent-pattern-alist t)
(setq migemo-pattern-alist-length 1000)
(setq migemo-coding-system 'utf-8-unix)
(load-library "migemo")
(migemo-init)

動作のテスト&設定の永続化
"C-s"で日本語インクリメンタル検索が動作するか試す。問題がなければ上のelispコードを .emacs や init.el に保存しておく。

2010年12月10日金曜日

お客様のIPアドレスを教えてください、というときに

毎日仕事をしていると、顧客が利用しているPCあるいはそのネットワークのIPアドレスを調べなければならない時がある。たとえば、顧客自身によるサイトアクセスをGoogle Analytics で計上しないよう設定する仕事。この場合、顧客のIPアドレスを教えてもらって、GAの管理画面で設定を行う。

「IPアドレスを教えてください」の一言で済めばよいのだが、顧客によってはIPアドレスなんてまったく知らない。ネットワークについていろいろ説明するのが面倒だし、社内SEの人に聞いてもらうのも何だから、とりあえずアクセスしてもらってApacheのアクセスログから調べようか、なんて泥臭い方法も思い浮かぶのだが、やっぱり顧客自身に調べてもらいたい。

そこで、シンプルな無料サービスを使って調べてもらう。

顧客向けメールのテンプレ

次の内容をメールで送信して、調べてもらう。

IPアドレスを調べる手順です

1. http://www.iphiroba.jp/index.php を開いてください

2. [環境変数チェック] をクリックしてください

3. [簡易版] をクリックしてください

4. [リモートアドレス(IP) REMOTE_ADDR] の欄にある数字が「IPアドレス」になります。
   例:192.168.0.1

5. これをコピー&ペーストし、メールでご返信ください

2010年12月2日木曜日

SWFのメタデータ(幅や高さ等)を調べるPerlモジュール

以前書いた Technical Memorandum: FLVのメタデータ(動画の幅や高さ等)を調べるPerlモジュール と同じような内容…

SWFの場合は、CPANにある「SWF::Header」を使う。

プログラム例

#!/usr/bin/perl
# swfinfo.pl
# 引数で指定されたSWFファイルのメタデータを出力する
# 前提:SWF::Headerがインストールしてあること(CPANにある)
use SWF::Header;
use Data::Dumper;
my $h = SWF::Header->read_file($ARGV[0]);
print Dumper($h);

実行例

$ perl ./swfinfo.pl ./foo.swf
$VAR1 = {
          'width' => 940,
          'count' => 50,
          'version' => 9,
          'background' => '#000000',
          'duration' => '4.16666666666667',
          'height' => 200,
          'xmin' => 0,
          'rate' => 12,
          'ymax' => 4000,
          'signature' => 'CWS',
          'filelen' => 124058,
          'ymin' => 0,
          'xmax' => 18800
        };