OSC島根2008雑感

スタッフの皆様大変お疲れ様でした。ありがとうございました。私はダラダラ話を聞くだけでお気楽に生きててごめんなさい!そんなわけでOSC島根2008の感想をメモしておきます。

12日

  • 最初の対談は遅刻したから聴いてません!
  • 教育:誰に教えるかで立場も目的もバラバラなので難しそうです。高専とか大学はオープンソースはまぁそりゃいいけど、小中高だと扱い切れない大変さがあるのでしょうか。それならば暇な人が何かを手伝える道筋をどこかに分かり易く示しておけば良いのでしょうかね。あと「オープンソースリテラシー」という言葉が出ていたように記憶しているのですが、それは何なの?とか思いました。また、よしだともこ先生かっこいい!という印象が残りました。女子大で emacs とか一切妥協しないところが素晴しい。
  • 地域コミニティの話:福岡と大分が住みやすくて良いらしいことが分かりました。誰か私を雇って下さい!マジで。すぐに引っ越しますから。
  • まつもとさんに会えた!おお。

13日

  • 午前は行けませんでした!
  • 9arrowsとSKIP:9arrowsは途中から聴いたから全体像が良く分かりませんでした、ごめんなさい。SKIPのキャラクター、かわいいですね!
  • Railsで基幹:COBOLの人をRubyにコンバート、という話がとても興味深く面白いお話でした。COBOL のままで延命とかそういうことは考えないんだ。RailsMVCCOBOL と似てるよ!ということだそうですが、COBOLを知らないから分かりませんが、そうなのですか。それはとっても便利。世界中のCOBOLの人がRailsの人になって万歳!な感じですね。素晴しい。
  • Rubyの課題:おお前田さん、さわやか。Ruby遅いよの話は実際のところほとんどの人は気にしてないんじゃないのかと思いました。そして1.9は速いけど遠いですね。私はどうしても昔ながらの牧歌的Rubyのイメージをひきずっているので、ISO化の話を聞くとまるで別世界かのように感じました。
  • 用事があってライトニングトーク聴けなかった!無念!

まとめ

島根県Rubyでビジネスをしようと本気で考えているのだなぁ、ということが分かりました。本気の本気なんですね、ちょっと驚きました。Rubyで遊びたい人と仕事をしたい人のバランスをとるのはとても難しいことだと思いますが、皆にとって幸せな未来があることを祈っております。

で、改めて Rails ってすごいなぁと思いました。だってここまで来てもなお枯れることなく前進しているわけでしょう。実は人気の秘密は永遠に枯れる気がしないことなんじゃないか?と考え込んでしまいました。

あと、OSCだから当然「オープンソース」という言葉が多かったわけですが、「フリー」という言葉を使っていた人も中には居ましたね。自由のことも時々思い出してあげるとより良い未来があるのではないかなと思いました。

各種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

Rubinius のコミット権をもらっちゃうよ!な話

先日 Rubinius にパッチを送りました。

Rubinius に Module#include のパッチ送ってみました - ¬¬日常日記

パッチは無事に採用されたようです、ありがとうございました。なんか色々と勘違いしているような気がして心配していたのですが、取り込まれて良かった良かった。

それで、Rubinius ではパッチを一つでも送った人にはもれなくコミット権をあげちゃう方式だそうですので、私もコミット権をもらえるそうです(ちなみに Ramaze さんも同様の方針、私はしばらくそれを無視してパッチを送り続けてました)。貧乏人だからもらえるものはもらっておこうというわけで、遠慮なくもらっちゃうよ!

If you do not have commit rights yet, make sure you have a Github user account and contact evan.

とのことですから、もちろんもう GitHub のアカウントは持っているので、あとは evan さんに連絡すればいいだけですね。ドキドキです。

OSC2008島根に行きます!宣言

行きます!というかあるのをすっかり忘れてました!!

オープンソースカンファレンス2008 Shimane - いらっしゃいっ

忘れてたくらいだから何がなんだか良く分かってないけどとりあえず眺めてきます。一番興味があるのはこれです。

オープンソースカンファレンス2008 Shimane - イベント案内 | 2008-09-13 (土): Rubyの課題と取り組み

課題ってなんでしょうかね。そういうことを知るために行ってきます。

あとはなにかなぁ、9Arrows & SKIP の話を聞きに行こうかなぁ。Rails 分からないからそういう方々の空気に触れてくるつもりで。

オープンソースカンファレンス2008 Shimane - イベント案内 | 2008-09-13 (土): Rubyオープンソース9Arrows & SKIPご紹介

そうそうライトニングトークもあるみたいですけれども、まだ申し込めるのでしょうか。空きがあるのなら Ramaze か Selfish か RTask か Wusagi(簡易な分散CMSっぽいヤツ、もちろん Ramaze アプリ!) でやろうかな。と思ったわけですが、土曜日ってもうすぐじゃないですか!今日の夜に申し込んでも間にあうかな?

for in else end 的な話

以下の記事を読みました。

2008-09-09 for in else end

私は Ruby の for 構文は全く使いません。なので for in else end みたいなのが増えてもきっと使わないと思います。だけど記事にあるような場面ってしばしばありますよね。というわけで代替策を考えてみました。

まず高尾さんが挙げた例を引用します。

<ol>
<%- sample_programs = SampleProgram.find(:all, :order => "updated_at") -%>
<%- if sample_programs.length > 0 -%>
  <%- for sp in sample_programs -%>
  <li><%= h(sp.title) %></li>
  <%- end -%>
<%- else -%>
  <li>サンプルプログラムが登録されていません。</li>
<%- end -%>
</ol>

if と for が一緒になってればいい、のかな? では SampleProgram.find は常に配列を返すことを前提として以下のように書いてはどうでしょうか。

require "erb"

sample = []

puts ERB.new(<<__CODE__, nil, "-").result
<ol>
<%- if for sp in sample -%>
  <li><%= sp %></li>
<%- end.empty? then -%>
  <li>サンプルプログラムが登録されていません。</li>
<%- end -%>
</ol>
__CODE__

この結果は次のようになります。

<ol>
  <li>サンプルプログラムが登録されていません。</li>
</ol>

やったね!...と思ってくれる人はひょっとして少ないでしょうか?

しかしですよ、どうせ世の中 rails が流行っているらしいので、猿っぽい汚らわしい拡張を行なってもバチは当たらないのではないかと思うわけです。

require "erb"

sample = []

class Array
  def else(&block)
    block.call if empty?
  end
end

puts ERB.new(<<__CODE__, nil, "-").result
<ol>
<%- for sp in sample -%>
  <li><%= sp %></li>
<%- end.else do -%>
  <li>サンプルプログラムが登録されていません。</li>
<%- end -%>
</ol>
__CODE__

いかがでしょうか。私なら、他人がこんな猿なコード書いているのを見たら、蹴飛ばすと思います。

Rubinius の変なところ:モジュールまわりをいじっていて気付いたところ篇

keita% ./shotgun/rubinius -e "module ::A; end"
An exception has occurred:
    Missing or uninitialized constant: A (NameError)

Backtrace:
    Module(Class)#const_missing at kernel/core/module.rb:713
           Object#__script__ {} at (eval):1
            Kernel(Module)#eval at kernel/core/eval.rb:67
                Compile.execute at kernel/core/compile.rb:74
              Object#__script__ at kernel/loader.rb:277

そこで参照しないで下さいよ!もちろん MatzRuby では次のように大丈夫。

keita% ruby -e "module ::A; end; A" #=> A

このせい(なのかどうか分かりませんが)で他もとっても変。

keita% ./shotgun/rubinius -e "module B; end; p module A; module ::B; self; end; end"
B::B
# MatzRuby では B

うーん、なぜ ::B が B::B になるのか。ひょっとして、"::B"で一度 B を参照して、その中でさらに B を定義しようとしてるのでしょうか。まさに予想外の振舞いです。さらに予想外なのはこれを B をモジュールからクラスに変えると結果が違うこと。

keita% ./shotgun/rubinius -e "class B; end; p module A; class ::B; self; end; end"
A::B
# MatzRuby では B

なぜそこは B ではなく A の下にいれるわけ(これを見るとさっきのモジュールの場合の予測ははずれていそうです)。せめてどちらかだけでも正しく振る舞ってくれると嬉しいのですが、これはやっかいな予感がします。

そしてもう一つ。

keita% ./shotgun/rubinius -e "module A; end; class A; end; p A.class"
An exception has occurred:
    constant is not a class (TypeError)

Backtrace:
    Object#__script__ {} at (eval):1
    Kernel(Module)#eval at kernel/core/eval.rb:67
        Compile.execute at kernel/core/compile.rb:74
      Object#__script__ at kernel/loader.rb:277
keita% ./shotgun/rubinius -e "class A; end; module A; end; p A.class"
Class

というわけで module → class の場合にはちゃんとエラーになるのに、class → module の場合はエラーになりません。あとエラーメッセージの"constant"の部分ってひょっとして"A"を入れようとしてミスしているのではないでしょうか。

あとついでに言うと Module.nesting がちゃんと動きません。これは spec が用意されていますのでそちらで確認してみて下さい。

以上のように、Rubinius はそれっぽく動いているようで、案外こういう基本的な部分がまだまだのようです。直したいところですが、"::B"の解釈が狂ってるの、さすがに直すの大変そうな予感がします。簡単なものはパッチを作って送りたいと思います。

追記

この辺をいじるためには Rubinius の全体像をきちんと把握する必要がありそうです。だというのに Rubinius の VM ってなんか今新しいのを作ってる真っ最中みたいで、とても間が悪い感じ。shotgun 以下のはなんとなく分かったのですが、これは古い方なんですよね。新しい VMC++ で書かれていて、ビルドしてみたら LLVM が云々言ってて、全く手が出せそうにありません。

というか新しいVM、情けないことに動かし方からして全然分かりません。ドキュメントどこ?

そんな感じなので Rubinius はしばらく様子見ということにしておこうかと思いました。なんてこった VMだけじゃなくて kernel 以下のコードもごっそり変わってたりするじゃないのさ!じゃあひょっとして送った Module#include のパッチも意味なかった?

Rubinius に Module#include のパッチ送ってみました

前に Rubinius の Module#inlcude がおかしいから直すって書いたきり、直してないのを思い出しました。

Rubinius で循環継承 - ¬¬日常日記

有言実行ということでとりあえずパッチを作りました(パッチは LightHouse のトラッカーに送ればいいみたいですね)。

これで Module#include が CRuby と同じ振舞いになります。それにしても Rubinius の流儀とかマナーとか良く分かりません。とりあえず送ってみて様子を見ることに。

と、これだけ書いてもつまらないので Rubinius での開発方法をメモしておきます。

  1. git からコードをダウンロード
  2. とりあえず rake build してみる
  3. スペックを書くとかして、とにかくあるべき振舞いを定める
    • 今回は既に spec/ruby/1.8/core/module/include_spec.rb があるのでこれを使いました
  4. コードを書く
    • 今回は kernel/core/module.rb にある Module#include を修正
  5. 再び rake build
  6. テストしてみる
    • ./bin/mspec spec/ruby/1.8/core/module/include_spec.rb みたいな感じ
  7. 修正が終わったら、一応全体のテスト rake spec:full も通してみる

こんな手順で良さそうな気がします。ちなみに以下の文書を参考にしました。

http://rubinius.lighthouseapp.com/projects/5089/howto-develop-with-a-separate-rubyspec-repo

ところで spec/ruby/1.8/core/ 以下は色々とテストが通らないものがある気がするのですが、Rubinius はまだそういう感じなのでしょうか。直した方がいいの?それとも私はなにか勘違いしてるのでしょうか。