各種1.9対応パッチ投げますよ!

ruby1.9 に対応してる gem は少な過ぎると思うわけです。いや、だって trust/untrust 使いたいんだから(せっかく作ってもらったのに使わなかったらもったいない!)、1.9 じゃなきゃダメなの。そういうわけだからあちこちパッチ投げますよ!

Ramaze さん

Ramazeさんは 1.9 対応してるハズなのに!なんてこった動かないよ!あわてて直しておきます(持ってて良かったコミット権(追記:実はこれは trunk のバグじゃないかという噂で私の早とちり、持っててごめんなさいコミット権))。

http://github.com/manveru/ramaze/commit/85724c13ab64b5dbb63793b85f571f3c75a85da6

配列の最後に "," を付けるのはヤメましょう。

と思ったらこれって 1.9 trunk のバグだ(と思います、きっと)。やっちまったよ!ごめんなさいと上のコミットにコメントしておきました。

いやだって 1.9 はきれいな ruby だから配列の "," を認めないに違いないと思ったのですよ。本気で。でも実際は次のように 1.9 trunk は通常は配列末の "," を認めるので単なるバグでしょう。(追記:この書き方自体が大嘘だ!と気付きました、ごめんなさい)

keita% ruby1.9 -e "p [1,2,3,4,5,]"
[1, 2, 3, 4, 5]

ていうか ruby-core にこれを問題提起したのは Ramaze 作者の manveru さんで、時間的に考えて、ほぼ間違いなく私のコミットが疑問の発端ですよね。お手間をとらせてしまって本当にごめんなさい。

追記:この問題が本当はどういうものなのかについて次にまとめました。興味のある方は是非ご覧下さい。

1.9 trunk の proc{}[1,] 問題 - ¬¬日常日記

ruby-git

case 文の時にコロン使うのはやめましょう。

          case type
          when /blob/:   Blob
          when /commit/: Commit
          when /tree/:   Tree
          end

というわけで ":" を ";" に修正。その上で rake test してみると...。

keita% ruby1.9 -S rake test                 [/home/keita/Repos/GitHub/ruby-git]
(in /home/keita/Repos/GitHub/ruby-git)
Loaded suite /usr/bin/rake
Started
EEEEEEEE..E........E.EEEE.EEEE...E....E....E.......EEEE..F.E.EEE.EEEEEE
Finished in 7.035092285 seconds.

# 以下エラーの山

なんてこった、絶望的だ!

ruby-git は全体としてコードが汚ないので色々直したくなる心をぐっと抑えつつ、最小限のパッチを作っていきます。エラーは以下の二種類の繰り返しみたいなもの。

  • TypeError: cannot assign nil; use Hash#delete instead
  • NoMethodError: undefined method `to_a' for "-a":String

前者のは ENV['A'] = @var みたいな形になっているらしくって、@var がたまたま nil だからエラーになっているみたいです。え、ENVに nil 入れちゃダメなの?これは知りませんでした。直し方はメッセージの通り Hash#delete を使うだけで大丈夫です(このためにちょっと記述が煩雑になるのですが、どうしてこういう風に変更になったんでしょうかね? 追記:答えは [ruby-list:40865] Re: Ruby without false or nil にありました)。後者のは、確か String#to_a って 1.9 ではなくなるんでしたよね。配列に変換したいなら Kernel#Array を使いましょう。

そんなわけでこの二点を直しました。そしたら次のような新たなエラーが。

  • NoMethodError: undefined method `each' for "HEAD":String

おお、String#each も 1.9 にはないのでしたね。それはいいんだけど、これは別に1.9対応云々がどうじゃなくって、単純なユニットテストの記述ミスですよ(tests/units/test_tree_ops.rb:83)。

        c = g.commit_tree(tr, :parents => 'HEAD')

これは parents と複数形になっていて、こっちを使う時には配列で渡すべきことを期待してるはず(String#each がなくなってこういうバグが発見しやすくなりましたね、素晴しいと思います)。でも実際こうしてミスしてるんだから、配列じゃなくても良いように勝手に修正しておくことにしましょう。

以上の修正を加えて再度テストを実行します。

keita% ruby1.9 -S rake test                 [/home/keita/Repos/GitHub/ruby-git]
(in /home/keita/Repos/GitHub/ruby-git)
Loaded suite /usr/bin/rake
Started
fatal: Not a valid object name
.F........F..............................................F.............
Finished in 19.287180246 seconds.

まだ失敗してるじゃないの!と思うかも知れませんが、これは元々失敗する項目どもですので気にしないことにします。思うにこれらはただのテストの記述ミスか、もしくは作者さんの環境において限定的に成功するという禍々しいテスト項目なのです。

では以上の成果をプルしてもらえるようにリクエストしておきます。GitHub が出来てから本当にパッチが送り易くなりました!GitHub さんとってもとってもありがとう!!

Commits · keita/ruby-git · GitHub

ついでにプチ情報ですが、ruby-git は rubyforge の gem を更新する気がないような気がします。README では以下のように GitHub から直接ダウンロードすることを推奨しています。

sudo gem install schacon-git --source=http://gems.github.com

だから古い gem を入れて苦しまないようにご注意あれ。

RedCloth

1.9 trunk では gem からインストールしようとしても次のように make できません(RedCloth 4.0.3)。

keita% gem1.9 install RedCloth
Building native extensions.  This could take a while...
ERROR:  Error installing RedCloth:
	ERROR: Failed to build gem native extension.

/usr/local/bin/ruby1.9 extconf.rb install RedCloth
creating Makefile

make
gcc -I. -I/usr/local/include/ruby-1.9.0/i686-linux -I/usr/local/include/ruby-1.9.0 -I. -D_FILE_OFFSET_BITS=64  -fPIC  -O2 -g -Wall -Wno-parentheses -O2   -o redcloth_attributes.o -c redcloth_attributes.c
ext/redcloth_scan/redcloth_attributes.rl: In function ‘redcloth_attributes’:
ext/redcloth_scan/redcloth_attributes.rl:68: error: ‘struct RString’ has no member named ‘ptr’
ext/redcloth_scan/redcloth_attributes.rl:68: error: ‘struct RString’ has no member named ‘ptr’
ext/redcloth_scan/redcloth_attributes.rl:68: error: ‘struct RString’ has no member named ‘len’
ext/redcloth_scan/redcloth_attributes.rl: In function ‘redcloth_link_attributes’:
ext/redcloth_scan/redcloth_attributes.rl:77: error: ‘struct RString’ has no member named ‘ptr’
ext/redcloth_scan/redcloth_attributes.rl:77: error: ‘struct RString’ has no member named ‘ptr’
ext/redcloth_scan/redcloth_attributes.rl:77: error: ‘struct RString’ has no member named ‘len’
ext/redcloth_scan/redcloth_attributes.rl:78:2: 警告: ファイル末尾に改行がありません
make: *** [redcloth_attributes.o] エラー 1

まずはレポジトリを clone してきます。

http://github.com/jgarber/redcloth/tree/master

それで rake compile すると Ragel 6.2 以上が必要ですよと言われたので Ragel をアップデートします(私の環境には6.0が入っていました)。

Ragel State Machine Compiler

最新版 6.3 をインストールしてから rake compile に再挑戦します。そうしたら今度は

keita% ruby1.9 -S rake compile
rake aborted!
uninitialized constant PLATFORM

だそうです。こいつはあまりに obsolete だぜ!早速"RUBY_PLATFORM"に修正します。

#52 [PATCH] RUBY_PLATFORM instead of PLATFORM - RedCloth - jgarber

でも、これを直したところでやはり rake compile に失敗するのは変わりがありません。gem をインストールしようとした時と同じエラーが表示されます。ragel をアップデートしたら勝手に直るのかな、と甘い期待を抱いていたのですが、そういうものでもないようです。

しかしエラーを見る限りでは修正は難しくないものと思います。というのも "error: ‘struct RString’ has no member named ‘ptr’" って良く見ますからね。RSTRING(str)->ptr はダメですよ!README.EXT.ja には次のようにあります。

構造体からデータを取り出すマクロが提供されています.文字列
strの長さを得るためには「RSTRING_LEN(str)」とし,文字列strを
char*として得るためには「RSTRING_PTR(str)」とします.配列の
場合には,それぞれ「RARRAY_LEN(ary)」,「RARRAY_PTR(ary)」と
なります.

だからこっちを使いましょう。ext/redcloth_scan/redcloth_attributes.rl だけでなく他にもいっぱい RSTRING(str)->ptr しちゃってるところがありますので、こういうのをあらかた直してしまいます。この修正後、きちんとコンパイルできました。rake gem して gem 作成に成功!

#53 [PATCH] RSTRING_PTR and RSTRING_LEN - RedCloth - jgarber

でも rake test してみるとテストに失敗してしまいます。

  1) Failure:
test_smiley(TestExtensions) [/home/keita/Repos/GitHub/redcloth/test/test_extensions.rb:29]:
<"<p>You&#8217;re so silly! <img src='/images/emoticons/58_80.png' title=':P' class='smiley' /></p>"> expected but was
<"<p>You&#8217;re so silly! <img src='/images/emoticons/:_P.png' title=':P' class='smiley' /></p>">.

  2) Failure:
test_html_threshold_lang_attribute(TestFormatters) [/home/keita/Repos/GitHub/redcloth/test/helper.rb:17]:
<"<p lang=\"fr-fr\">En français.</p>"> expected but was
<"<p lang=\"fr-fr\">En fran\xC3\xA7ais.</p>">.

4926 tests, 4928 assertions, 2 failures, 0 errors

まず 1) についてですがこれはテスト(test/test_extensions.rb)自体に問題があります。

    def refs_smiley(text)
      text.gsub!(/(\s)~(:P|:D|:O|:o|:S|:\||;\)|:'\(|:\)|:\()/) do |m|
        bef,ma = $~[1..2]
        filename = "/images/emoticons/"+(ma.split(//).collect{|l| l[0] }.join('_'))+".png"
        "#{bef}<img src='#{filename}' title='#{ma}' class='smiley' />"
      end
    end

これはありがちな非互換性問題ですね。filename のところ collect の "l[0]" がマズい。1.8 なら指標位置の文字に対応する数値を返していたわけですが、1.9 では文字を返すんですよね。こう時には String#unpack で堪え忍びます。

#54 [PATCH] Fixed test/test_extensions.rb for ruby1.9 - RedCloth - jgarber

次に 2) ですが、これは単純に ruby1.9 -EUTF-8 とかすると解決するのかな、と思ったら違って困った!眠くなってきたから原因がよく分からないので誰か直して下さい!

ひょっとして 1.9 trunk をコンパイルし直したらこれ解決するのかも、と期待してやってみたら、もっとエラー増えた!もう知らん、寝る!!(追記:結局この増えた分のエラーというのは、単純に RedCloth を再コンパイルしたら直りました)

まとめ

今回は Ramaze, ruby-git, RedCloth の Ruby1.9 対応を試みました(残念ながら Ramaze については足を引っ張っただけになっちゃいましたが)。何が問題で、どうやって直したのかを、割と詳しく書いてみたつもりです。理由は、他の方がライブラリを 1.9 対応しようと思った時に少しでも役に立てばいいなと思ったからです。

正直なところ、直さなきゃならないライブラリとその修正箇所は山ほどあるのだと思います。でもみんなで直せば怖くないよ!皆さんも一緒に 1.9 対応パッチを各所に投げまくりましょう!!

追記

RedCloth にパッチが取り込まれました。4.0.4 がリリースされればこれで大体のところ 1.9 でも動くようになるかと思われます。しかし結局まだテストが一つ失敗したままなので、誰か直して!

Fixed compatibility issues with Ruby 1.9. [Keita Yamaguchi] · jgarber/redcloth@3ca59c9 · GitHub