Ruby 1.9.1がリリースされてから3ヶ月が経ちました。この連載などを参考にしながらRuby 1.9を体験してみた人も多いことと思います。
さて,既に紹介された数多くの新機能や性能向上など,1.9では1.8までのRubyに比べて大幅な改良が行われました。しかしその一方で,1.8での意外な挙動がそのまま残されていたり,1.9で新たに予想外の挙動が追加されていたりもします。
昔の人は言いました。「君子危うきに近寄らず」と。しかし,何が危ないのか分かっていなければ,その危険を避けることもできません。そこで,Windows版のRuby 1.9を題材にしながら,どうやってRubyに埋め込まれた「地雷」を避けていくか,実践的に学習してみることにしましょう。
Windows版Ruby
話を始める前に,今回取り扱うWindows版Rubyについて簡単に説明しておきましょう。実は,Windows上で実行できるRubyには様々な種類が存在します。Rubyインタプリタは自分の実行対象となる環境をRUBY_PLATFORMという定数に格納していますが,各種のWindows版RubyにおけるRUBY_PLATFORMは以下のようになっています。
- mswin32版
- i386-mswin32
- Visual C++ 6.0で32bit版Windows向けにコンパイルされたrubyです。後述のmingw32版とバイナリ互換性があります。
- i386-mswin32_70
- Visual C++ .NETで32bit版Windows向けにコンパイルされたrubyです。
- i386-mswin32_71
- Visual C++ .NET 2003で32bit版Windows向けにコンパイルされたrubyです。
- i386-mswin32_80
- Visual C++ 2005で32bit版Windows向けにコンパイルされたrubyです。
- i386-mswin32_90
- Visual C++ 2008で32bit版Windows向けにコンパイルされたrubyです。
- mswin64版
- x64-mswin64_80
- Visual C++ 2005でx64版Windows向けにコンパイルされたrubyです。
- x64-mswin64_90
- Visual C++ 2008でx64版Windows向けにコンパイルされたrubyです。
- mingw32版
- i386-mingw32
- MinGWで32bit版Windows向けにコンパイルされたrubyです。前述のmswin32版のうちVisual C++ 6.0でコンパイルされたもの(i386-mswin32)とバイナリ互換性があります。
- bccwin32版
- i386-bccwin32
- Borland C++でコンパイルされたrubyです。1.9ではBorland C++向けサポートが打ち切られているため,構築できなくなりました。
- cygwin版
- i386-cygwin
- cygwin向けにコンパイルされたrubyです。
- interix版
- i386-interixN
- SFU(Services for UNIX)向けにコンパイルされたrubyです。Nの部分にはSFUのバージョンに応じた数字が入ります。
特に注記したものを除き,このリストで挙げられたもの同士の間でバイナリ互換性はありません。つまり,例えばi386-mswin32を名乗るruby向けにコンパイルされた拡張ライブラリはi386-mswin32_70を名乗るrubyでは動作しないということです。
このリストを見るだけで頭がクラクラしてきそうですね。ここまで読んだだけで「WindowsでRubyを使うのは危険なんじゃないか」と気づいた人は,既に一定の危機回避能力を身に付けていると言えます。さあ,早く脱出しましょう!
……とはいうものの,ここで脱出してしまうとこの記事はこれで終わってしまうので,とりあえず今回はmswin32版またはmingw32版を対象にすることにしましょう。これらを選んだのは,Windowsがあって,rubyインタプリタが導入できさえすれば,実行には他に特別な環境が必要ではないためです。また,コンパイル環境が存在しない場合にも,mswin32版であればartonさんが提供してくださっているインストールパッケージを利用して簡単に導入することができます(※1)。
- ※1
- Ruby-1.9.1-p0 Microsoft Installter Packageを参照ください。
なお,以下の実行例では実行環境としては日本語版のWindowsを使用します。
分かりやすい地雷――ファイル名
さて,Rubyには以前からディレクトリ(フォルダ)内のファイルの一覧を取得するメソッドとしてDir.entriesが用意されています。改めて説明する必要はないと思いますが,ちょっと動作を確認してみましょう。
問題ないようですね。それでは,今度はファイル名に日本語を混ぜてみましょう。
森鷗外の名前が「?」に化けてしまっています。これは,Rubyが日本語版Windows環境で使用する外部エンコーディングであるWindows-31Jでは「鷗」の字が表現不可能であるのが原因です。WindowsのファイルシステムであるNTFSではUTF-16LE(厳密には多少異なります)でファイル名をつけることができ,またコマンドプロンプトにおいても同様にUTF-16LEでの入出力が可能です。よって,Windowsの内部コマンドを使っていれば何の問題も起きません。ところが,現状のRubyではファイル名のエンコーディングとしてUTF-16LEではなくWindows-31Jを仮定して動作しているため,この「鷗」のような文字をOSから取得しようとすると,ご覧のような文字化けが発生してしまいます。また,ファイル名にこのような文字を使ってしまうと,RubyからOSに正確なファイル名を渡すこともできなくなってしまうため,openなどのメソッドでファイルを扱うこともできなくなってしまいます。
将来のRubyでは,Ruby M17Nの実装がさらに進み,このような問題も例えばUTF-8やUTF-16LEをエンコーディングとして使用することで回避できるようになる見込みです。しかし,現時点では,直接WindowsのAPIを操作するなどの方法を採らない限りはどうしようもありません。よって,Rubyで操作するようなファイルには不用意に日本語のファイル名をつけたりしないのが安全,ということになります。

