gem update と rubygems-update (1.3.3)

Windows での「gem update」の際、sqlite3-ruby など、ネイティヴ拡張が必要なのに Windowsなのでコンパイルできなくてアップデートに失敗する者があると、そこでアップデート作業が終わってしまい(恐らくアルファベット順で)その順番以降の gem のアップデートが行われなかった。
仕方ないので「gem list」からジェム名称を拾って個別に「gem update <ジェム名称>」してたものだ。
ジェムのアップデートに伴ない、1.3.3 からはそんなことしなくても良くなった。一つのジェムがアップデートに失敗しても、ジェムのアップデート作業はずっと続いて最後まで実行してくれる。まあ、失敗した者は入らない(アップデートされない)けど。
ちょっと便利になったかな、と言うか少し不便が無くなったのか。

>gem --version
1.3.3

Racc のインストール (/1.9.1)

WindowsXP(Sp3)にて、Ruby は artionさんの 1.9.1 (ActiveScriptRuby and Other packagesより Ruby-1.9.1-p0)、gem を 1.3.2 にアップデートしたら racc のインストールがうまくいかなくなった。というか、それ以前からインストールは途中で失敗する感じなんだけど、raccコマンド自体は動作するので問題にしていなかった。それが、gem のバージョンチェックが厳しくなったのか、動かなくなった。「:in `bin_path': can't find gem racc ([">= 0"])」
「gem install racc」のエラーはこんな感じ

Building native extensions.  This could take a while...
ERROR:  Error installing racc:
        ERROR: Failed to build gem native extension.

C:/PROGRA~1/RUBY-1~1.1/bin/ruby.exe extconf.rb
extconf.rb:3:in ``': No such file or directory - uname -p (Errno::ENOENT)
        from extconf.rb:3:in `
'

ちなみに

<云々>>gem --version
1.3.2

C:\Program Files\Ruby-1.9.1\lib\ruby\gems\1.9.1\gems\racc-1.4.6 とかにいって「ruby setup.rb」しても同じ所でエラーになる(エラーメッセージはもう少し詳しい)。「ruby setup.rb config」でも同じエラー。
ということで、同所 README.ja.rdoc の示唆に従い、「--without-ext」してみる。

<云々>1.9.1\lib\ruby\gems\1.9.1\gems\racc-1.4.6>ruby setup.rb config --without-ext
      • > bin
<--- bin
      • > lib
      • > lib/racc
<--- lib/racc <--- lib skipping ext/* by user option

こんどはエラーない、つづけて「setup」「install」、いちいち「skipping ext/* by user option」といわれるがインストール成功。

<云々>>racc --version
racc version 1.4.6

できた。しかし、gem list には載ってこない。gemコマンド方面でもこんな感じにインストールオプション渡してインストール出来るのかな?

あと、extなしというのは、racc の解析機 parse に、C版が使えず、ピュアRuby版を使う事になるのでちょっと遅くなるかもです。切り替えは自動なのであんまり意識する事はないかもしれない。

全角マイナスの問題

あんまりカテゴリが多いのも頭悪そうなんだが、実際頭の悪い問題なので。あと、全角と言う表現も頭悪いし。

現象

  1. いまどきの Linux で全角マイナス記号「−」を使う
    • いまどきだし UTF-8
    • 入力は隣の Windows機の PuTTY端末から、WindowsIME で漢字(全角)変換して入力
    • PuTTY端末上で普通に全角っぽい表示
  2. 出力は Shift_JIS にして欲しいと言うことなので NKF で変換、或いは 1.8系RubyNKFライブラリで変換
  3. チェックの為に逆変換する、違う字になってる。
    • UTF-8 としては正規の全角マイナスになってる。
    • 隣の Windows機の PuTTY端末では半角幅で表示される。
      • それを Windows機のデスクトップでエディタとかにコピペすると半角マイナスになってる
  4. もう一度 Shift_JIS にしてまた UTF-8 にしてとかは戻る、もう安定的。

詳細

Linux(UTF-8環境)の 1.8系Rubyirb で確かめてみる

  1. LinuxWindows機の PuTTY端末から、全角マイナスを入力
    • 1.8系Ruby的には "\357\274\215"
  2. それを NKF.nkf '-W -s', で変換する、シフトJISの全角マイナス
    • 1.8系Ruby的には "\201|"
      • この縦棒はなんだよ、\174 です
  3. それを NKF.nkf '-S -w', で変換する、UTF-8
    • 1.8系Ruby的には "\342\210\222"
    • それは 1.9Ruby的な "\u2212" と同じ
  4. それを NKF.nkf '-W -s', で変換する、1.8系Ruby的には "\201|"
  5. それを NKF.nkf '-S -w', で変換する、1.8系Ruby的には "\342\210\222"
    • 安定的になった

Windows環境の方には 1.9コンソールを入れてるのでそのirbでちょっと
"\u2212" は所要のものだ

irb(main):039:0> "\u2212".force_encoding('UTF-8').each_byte{|b| puts '%o'%b }
342
210
222
=> "竏・

"\357\274\215"だって間違ってるわけじゃない

irb(main):040:0> "\357\274\215".force_encoding('UTF-8').valid_encoding?
=> true

変換は出来ないけど

irb(main):041:0> "\357\274\215".force_encoding('UTF-8').encode('Shift_JIS')
Encoding::UndefinedConversionError: "\xEF\xBC\x8D" from UTF-8 to Shift_JIS
        from (irb):41:in `encode'
        from (irb):41
        from C:/Program Files/Ruby-1.9.1/bin/irb.bat:20:in `<main>'

NKFなら変換できる

irb(main):044:0> NKF.nkf('-W -s', "\357\274\215".force_encoding('UTF-8')).each_byte{|b| puts '%o'%b }
201
174
=> ""

事情

普通に Debian GNU/Linux 上で Railsアプリケーションを作っていた。一部出力として Shift_JIS が欲しい(何かの結果のテキストのファイルダウンロードサービス)ということだったので、NKF で変換して出すようにした。
スペック(rspec-raile)を取ろうとした、まあ住所っぽいもので全角文字使用(半角文字は使わない)なので番地の区切りに全角マイナスを使ってみた。(実際そういう入力がある)
スペック自体は Linux上で実行するので、比較する文字列なんかは UTF-8 でスペックファイルに書いてある方が見易い。だから全部 UTF-8 に再変換してからマッチャ呼ぶことにした。
すると合わない、マッチャが通らない。どうしよう。
と言う事で調べた。

対策

多分ちゃんとした対策はない。Windowの sshクライアントでの全幅半幅表示という完全に表示だけの問題とも絡んでるのですっきりした解決はないだろうと思う。
所要のスペックファイルでの比較を Shift_JIS側で行う感じかな。1.8系Ruby では文字列はバイト列なので単純な比較(や、含む含まれる)なら可能だろうし。正規表現マッチは無理っぽいかな。
1.9になれば正規表現も使えるようになるだろうけど、問題自体は回らないでしょう。
ただまあスペックだけに頼らずどこかで Shift_JISの全角マイナスを目視で確かめるような手順にした方が良いでしょう。

@ruby.exe -Ku racc <文法ファイル名>

Windows での、Racc文法ファイルの文字コードの扱いについて、前の項(Windowsで 1.9.1 と Racc とスクリプトエンコーディング - Rubyとか Illustratorとか SFとか折紙とか)の機序もう少し詳しく見てみる、「るびま」を参考に。

文法ファイルには UTF-8文字が混じっているという状況

まず、「-Ku」の無い場合

  1. racc <文法ファイル名>
  2. Windowsが racc.bat を探し当ててそれを実行
  3. ruby.exe racc <文法ファイル名> を実行
    1. racc は拡張子無しの Rubyスクリプト (専ら raccライブラリ本体を load する)
    2. magic comment なし、コマンドラインオプションも、環境変数 RUBYOPTも、shebang の -K もないので、script encoding は US-ASCII
    3. それはそれとして default_external もオプション等での明示的な指定が無い、すると locale
      1. それは Windows-31J(Encoding::Windows_31J)
    4. 一方 default_internal は nil
  4. <文法ファイル名>ファイルを読む、default_external = Windows-31J と想定
    1. UTF-8文字列が出てきたら、想定が違うとエラー

「-Ku」付きの場合

  1. racc -Ku <文法ファイル名>
  2. Windowsが racc.bat を探し当ててそれを実行
  3. ruby.exe -Ku racc <文法ファイル名> を実行
    1. racc は拡張子無しの Rubyスクリプト (専ら raccライブラリ本体を load する)
    2. magic comment なしなので、コマンドラインオプションの -Ku をみて sctipt encoding は UTF-8
    3. それはそれとして default_external も、オプションの -Ku をみて UTF-8
    4. 一方 default_internal は nil。こっちは -Kオプションを見ない
  4. <文法ファイル名>ファイルを読む、default_external = UTF-8 と想定
    1. UTF-8文字列が出てきても大丈夫
  5. default_internal が nil なので、文法ファイル文字列は内部的にも UTF-8 (externalと同じ)

こんな感じかな、間違ってないよね。
前項では、スクリプトエンコーディングという言葉を出したけど、微妙に適切ではなかったかも。

Windowsで 1.9.1 と Racc とスクリプトエンコーディング

そういうわけで Windows(XP SP3)で Ruby-1.9.1 で Racc(1.4.6)、文法ファイルの日本語エンコーディングどうしよう。なんというか、SVNキーワード $Date$ の曜日だけなんだけどね、UTF-8N。
と、エラー。

<どこか>\esoteric>racc Hhyy.y
C:/PROGRA~1/RUBY-1~1.1/lib/ruby/gems/1.9.1/gems/racc-1.4.6/bin/racc:143:in `read
': "\x9F" followed by "," on Windows-31J (Encoding::InvalidByteSequenceError)
        from C:/PROGRA~1/RUBY-1~1.1/lib/ruby/gems/1.9.1/gems/racc-1.4.6/bin/racc
:143:in `block in main'
        from C:/PROGRA~1/RUBY-1~1.1/lib/ruby/gems/1.9.1/gems/racc-1.4.6/bin/racc
:277:in `section'
        from C:/PROGRA~1/RUBY-1~1.1/lib/ruby/gems/1.9.1/gems/racc-1.4.6/bin/racc
:141:in `main'
        from C:/PROGRA~1/RUBY-1~1.1/lib/ruby/gems/1.9.1/gems/racc-1.4.6/bin/racc
:308:in `<top (required)>'
        from C:/Program Files/Ruby-1.9.1/bin/racc:19:in `load'
        from C:/Program Files/Ruby-1.9.1/bin/racc:19:in `<main>'

rubyコマンドラインオプション「-Ku」付ければ何とかなるんだけど

<どこか>\esoteric>ruby -Ku "C:\Program Files\Ruby-1.9.1\bin\racc" Hhyy.y

<どこか>\esoteric>

というわけで、1.9.1\bin の racc.bat をちょっと調整。コマンドライン第一引数に -K オプションを設定できるようにした、第一オプション限定。

@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"ruby.exe"" "C:/Program Files/Ruby-1.9.1/bin/racc" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF
:WinNT
if "%1" GEQ "-K" (
  @"ruby.exe" %1 "%~dpn0" %2 %3 %4 %5 %6 %7 %8 %9
) else (
  @"ruby.exe" "%~dpn0" %*
)

WinNT側のみ。SHIFT がバッチパラメータ「%*」に影響しないのでちょっと無様。

<どこか>\esoteric>racc -Ku Hhyy.y

<どこか>\esoteric>

Windowsの 1.9.1 で gem で racc

というわけで、Windows (XP SP3) で Ruby-1.9.1 で gem から Racc をインストールする。

C:\Program Files\Ruby-1.9.1\bin>gem update --system
Updating RubyGems
Nothing to update
C:\Program Files\Ruby-1.9.1\bin>gem install racc
Building native extensions.  This could take a while...
ERROR:  Error installing racc:
        ERROR: Failed to build gem native extension.

"C:/Program Files/Ruby-1.9.1/bin/ruby.exe" extconf.rb install racc
extconf.rb:3:in ``': No such file or directory - uname -p (Errno::ENOENT)
        from extconf.rb:3:in `<main>'


Gem files will remain installed in C:/Program Files/Ruby-1.9.1/lib/ruby/gems/1.9
.1/gems/racc-1.4.6 for inspection.
Results logged to C:/Program Files/Ruby-1.9.1/lib/ruby/gems/1.9.1/gems/racc-1.4.
6/ext/racc/cparse/gem_make.out
Updating class cache with 1261 classes...
C:\Program Files\Ruby-1.9.1\bin>gem list -l

*** LOCAL GEMS ***


C:\Program Files\Ruby-1.9.1\bin>

エラーになる。なんだかなあ。

raccコマンドファイル

しかし、この時点で Racc自体は gemディレクトリに入っている(Gem files will remain)、それに Ruby-1.9.1\bin にはバッチファイルや raccコマンドファイルも入っている。
だから動かそうとすれば動く。ただ、gem からは見えないのでアンインストールは出来ないかも、アップデートも不安か。

C:\Program Files\Ruby-1.9.1\bin>ruby racc
no input

C:\Program Files\Ruby-1.9.1\bin>ruby racc --version
racc version 1.4.6

C:\Program Files\Ruby-1.9.1\bin>ruby racc --runtime-version
racc runtime version 1.4.6 (rev. $Id$); c core version 1.4.5 (rev. 1.8)

runtime のバージョンがずれてるのはちょっと気に掛かるかな。runtime 自体は ruby同梱でしたっけ。

racc.bat ファイル

しかし、そのバッチファイルが動かない。

C:\Program Files\Ruby-1.9.1\bin>racc
ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。

C:\Program Files\Ruby-1.9.1\bin>racc.bat
ファイル名、ディレクトリ名、またはボリューム ラベルの構文が間違っています。

なんでだ

@ECHO OFF
IF NOT "%~f0" == "~f0" GOTO :WinNT
@"ruby.exe"" "C:/Program Files/Ruby-1.9.1/bin/racc" %1 %2 %3 %4 %5 %6 %7 %8 %9
GOTO :EOF
:WinNT
@"ruby.exe"" "%~dpn0" %*

行頭「@」がコマンドのエコーを抑制するし、ちょっと悩んでしまったけど、単純な事だった。そういえば前もそうだったよね。
最後の行、「"」が重複してる。これを一文字削除すればOK

@"ruby.exe" "%~dpn0" %*

これで racc 動く様になった。

C:\Program Files\Ruby-1.9.1\bin>racc
no input

C:\Program Files\Ruby-1.9.1\bin>racc.bat --runtime-version
racc runtime version 1.4.6 (rev. $Id$); c core version 1.4.5 (rev. 1.8)

一応前掲の Helloworld言語とか、HQ9+言語とかのジェネレートは(それなりの 1.9対応の上で)成功した。

1.9.1(artonさん)と環境変数

取り敢えず Windows (XP SP3) では、artonさんのパッケージ(ActiveScriptRuby and Other packagesより)で Ruby 1.9.1 を試している。1.8系も共存させてる。それで、1.9.1パッケージをインストールすると、「Ruby-1.9 console」が入る、パスとか調整してあって、1.9.1の ruby系コマンドが使える。
さて、artonさんがちゃんとしてくれてるので(L'eclat des jours(2009-02-19)) 1.8系コンソールとの使い分けも十全な筈だ、本当は。しかし、僕は自分で環境変数いじってて、1.8系bin へのパスも Path に付け加えている。その辺で普通に起動したコマンドプロンプトでも ruby が使えるようにと、1.8系スタートメニューから起動したコンソールだけからじゃなく。
というわけで、「Ruby-1.9 console」の Path、先頭に 1.9系のパスがあるのだけど、後ろの方に 1.8系のパスも書いてある。ちょっとやばい、混乱しそうだ、1.9ではまだいれてない ruby系コマンドを 1.8系から呼んでしまいそうだ。何とかしないと。

set Path=%Path:1.8=%

取り敢えず開いた「Ruby-1.9 console」で「set Path=%Path:1.8=%」とかする。Path環境変数のなかの「1.8」がなくなるのでもう 1.8系へのパスは通っていない、大丈夫だ。
setコマンドの拡張環境変数置換は「set /?」参照

環境変数の置換は、次のように拡張されます:

   %PATH:文字列1=文字列2%

は、PATH 環境変数を展開し、その結果に含まれるすべての "文字列1""文字列2" に置き換えます。"文字列2" に空の文字列を指定すると、展開
された出力からすべての "文字列1" を削除することができます。"文字列1"
をアスタリスクで始め、展開された出力の先頭から、文字列1 の残りの部分
が最初に現れるまでのすべてを一致させることもできます。

しかし、毎回こんなコマンドを実行するのは大変だ、絶対忘れる。

setenv19.bat

Ruby-1.9 console」の作動機序はちゃんと調べられないでいるのだけど、取り敢えず C:\Program Files\Ruby-1.9.1\bin\setenv19.bat に手を入れたらなんとかなった。

@echo off
@if not "%~d0" == "~d0" goto WinNT
C:\PROGRA~1\RUBY-1~1.1\bin\ruby -x "C:/PROGRA~1/RUBY-1~1.1//bin/setenv19.bat" %1 %2 %3 %4 %5 %6 %7 %8 %9
@goto endofruby
:WinNT
"%~dp0ruby" -x "%~f0" %*
@goto endofruby
#!C:/PROGRA~1/RUBY-1~1.1//bin/ruby
require 'winpath'
path = Pathname.new(File.dirname($0)).shortname.gsub(File::SEPARATOR, File::ALT_SEPARATOR)
ENV['PATH'] = "#{path};#{ENV['PATH']}"
if ARGV.size > 0
  cmd = 'start ruby -Ks "' + ARGV[0] + '"'
else
  if ENV['OS'] == 'Windows_NT'
    cmd = "start cmd"
  else
    cmd = "start command"
  end
end
system(cmd)
__END__
:endofruby

Rubyスクリプト部分で実際に ENV['PATH'] を触っているところ

ENV['PATH'] = "#{path};#{ENV['PATH'].gsub '1.8', ''}"

これでなんとかなった。文字列'1.8' を消しただけでは変な無効なパス文字列が残るんだけど、まあ許してもらおう。
「"%~dp0ruby" -x "%~f0" %*」この辺の説明は「バッチパラメータ」とか Rubyコマンドラインオプションとか