Servlet Garden @はてな

2011-04-01 また雪の予報。春はまだかなぁ

JRubyでJavaBeansを簡単に生成する方法 16:24

jruby-users MLでJavaBeansのクラスを簡単に生成する方法はない?という質問が出ていました(http://www.ruby-forum.com/topic/1398824)。Groovyだと、def book = new Book(title: "Foo", author: "Bar") でできるみたいだ。GroovyJavaのためのスクリプティング言語から、このあたりはやはり便利にできていますねぇ。で、JRuby場合。Nick Sieger氏が書いていますが、特にビルトインされているラッパのようなものはありません。ただ、Rubyフレキシブルから、そんな感じでインスタンスを生成できるようにする方法はいろいろとあるはずです。Sieger氏が提案していたのは*new*という名前メソッド定義したモジュールを作って、*extend*でそのモジュール既存クラスに追加する方法でした。さすがです。さっそく試してみました。

まずはこんなディフォルトコンストラクタ(implicit)、setter/getterメソッドだけのJavaBeansを定義して、、、

public class Book {
    private String title;
    private String author;

    public void setTitle(String title) {
        this.title = title;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getTitle() {
        return title;
    }

    public String getAuthor() {
        return author;
    }
}

javacでコンパイルBook.classができました。次に、同じディレクトリにSieger氏がML投稿していたRubyコードコピペして、doが抜けているところを足して、確認用のメソッドを追加したのがこちらです。

require 'java'
java_import 'Book'

module BeanLikeConstructor
  def new(attrs = {})
    super().tap do |obj|
      attrs.each do |k,v|
        obj.send("#{k}=", v) if obj.respond_to?("#{k}=")
      end
    end
  end
end

class Book
  extend BeanLikeConstructor
end

book1 = Book.new(:title => "Foo1", :author => "Bar1"); puts "#{book1.title} by #{book1.author}"
book2 = Book.new(:title => "Foo2", :author => "Bar2"); puts "#{book2.title} by #{book2.author}"

これを実行すると、

Foo1 by Bar1
Foo2 by Bar2

と無事表示されました。上記のコード中obj.send("#{k}=", v)とあるのは、BookクラスJRubyにやってきたときに、setTitle(String title)というメソッドから、title=というメソッドが生成されるようになっているからです。ちなみに、BookクラスJRuby上でどんメソッドを持っているか調べると、

irb(main):004:0> Book.new.methods
=> ["author", "set_author", "set_title", "title=", "setTitle", "author=", "__jcreate!", "getTitle", "get_title", "__jsend!", "title", "setAuthor", "get_author", "getAuthor", "get_class", "notifyAll", "notify", "toString", "notify_all", "clone", "finalize", "to_string", "hash_code", "equals", "getClass", "wait", "hashCode", "equals?", "initialize", "equal?", "java_send", "marshal_dump", "marshal_load", "java_method", "to_s", "java_object=", "synchronized", "java_class", "java_object", "==", "to_java_object", "hash", "inspect", "eql?", "handle_different_imports", "__jtrap", "include_class", "java_kind_of?", "java_signature", "methods", "freeze", "extend", "nil?", "object_id", "method", "tainted?", "is_a?", "instance_variable_get", "instance_variable_defined?", "instance_variable_set", "display", "send", "private_methods", "enum_for", "com", "to_java", "type", "instance_of?", "id", "taint", "class", "java_annotation", "instance_variables", "org", "to_a", "__send__", "=~", "protected_methods", "__id__", "java_implements", "tap", "frozen?", "java", "respond_to?", "instance_eval", "===", "java_package", "untaint", "java_name", "to_enum", "singleton_methods", "instance_exec", "dup", "kind_of?", "java_require", "javax", "public_methods"]

のようになっています。title=とかauthor=とかありますね。getTitle()やgetAuthor()はシンプルにtitle, authorが使えるようになっています


Sieger氏のサンプルコードは使うときにとてもいい感じなのですが、見てすぐに思ったのは"長い"。たかがJavaBeansのインスタンス生成。そこまでしなくてもいいんじゃないか、と思ったのでした。そこで、どうすればもうちょっとシンプルにできるか考えてみました。

require 'java'
java_import 'Book'

book_ = lambda {|data| b = Book.new; data.each do |k,v| b.send("#{k}=", v) end; b}

book1 = book_.call(:title=>"Foo1", :author=>"Bar1"); puts "#{book1.title} by #{book1.author}"
book2 = book_.call(:title=>"Foo2", :author=>"Bar2"); puts "#{book2.title} by #{book2.author}"

不器用な感じのコードですが、ちょこっと書くだけですむ、かも。

るびまゴルフあたりの方々なら、きっともっとかっこいい、短いコードを書いてくれるのでしょうねぇ。



[追記] もう一歩

よりGroovyらしく見えるように callメソッドエイリアス newを定義してみました。

book_ = lambda {|data| b = Book.new; data.each do |k,v| b.send("#{k}=", v) end; b}
class Proc
  alias new call
end

すると、

book3 = book_.new(:title=>"Foo3", :author=>"Bar3"); puts "#{book3.title} by #{book3.author}"

でいける。さらに、1.9モードで使う (jruby --1.9 code.rb ) と、

book4 = book_.new(title: "Foo4", author: "Bar4"); puts "#{book4.title} by #{book4.author}"

でいける。これで、Groovydef book = new Book(title: "Foo", author: "Bar") にさらに近づいたかも。

2011-03-01 もうちょっとで気温が0Cを超える日々がくる

NetBeans 7.0 beta 2 の Rubyサポート 22:18

久々のNetBeansネタです。ご存知の方も多いと思いますが、OracleはついにNetBeansでのRubyサポートを止めちゃいました。開発者たちが次々とOracleを去ってしまい、できる人がいなくなってしまった結果、NetBeansの開発規模を縮小せざるをえなくなった模様です。そこで、これを期に開発はコミュニティが引き取ることになりました。Tom Enebo氏による詳細はこちらに、


ということで、7.0 beta 2のダウロードページにはRuby/Railsの文字はありません。自分インストールしないといけません。

さて、インストール方法ですが、これもTom Enebo氏のブログに書いてあります

難しいところはないので説明する必要は無いと思いますが、8. Reload Catalogをお忘れなく。9. Choose 'Ruby and Rails'の後に Installボタンクリックするステップ以降が書かれていませんが、ま、これがわからない人はいないでしょう。

試しにこのとおり実行してみたら、今まで通り、NetBeansRubyプロジェクトが見えて、Rubyの実行もできました。


以上、これからNetBeansでいこう!

2010-10-07 快晴、気持ちのよい秋の一日。

JRubyConf 2010 二日目

[追加] JRubyConf 2010の写真Engine Yardから公開されました。> http://fb.me/IebGtJxw


さて、と、忘れないうちにJRubyConf 2010二日目のまとめを。


この日は朝10:00スタートゆっくりめの一日です。まずは、Chad Fowler氏とRich Kilmer氏のコンビで"So You Think You Need a Rewrite?"でした。とにかく、おもしろい!の一言です。このお二人、どうしたらこんなに息の合ったすばらしいプレゼンができるのか教えてほしいくらい、すばらしいトークを見せてくれました。知的エンターテイメント、ですね。結論から言うと、"Never Ever Rewrite"なのですが、ここに至るまでの話題はどれもこの業界人間同調しやすいものが選ばれていて、しかも笑えるんです。広大な草原にいる我々プログラマを導いてくれるこの人、といってObject MentorのRobert C. Martin (Uncle Bob)氏が力強い演説をしている最中らしい写真が現れたときには会場から笑いの声が。Fowler氏も名前を出さずに"You should know this person."と。(おぉ、RailsConf行っといてよかった、そうじゃなかったら話題についていけなかったよ、と思った。)また、OMGについては"Oh My God, We set the standard"だそうで。話しとしてはrewriteするとはどういうことかの意義から始まり、次々と新しい言語が登場するわりにはソフトウェアプロジェクトが失敗する割合は変わっていないという事実の紹介、書き換えをするときにはとにかく一度に変更する箇所を小さくというアドバイスなどなど。ただ、大きな書き換えはするものではない、それはあまり報われないということでした。特に、ビジネス系の人たちには嫌われると。Fowler氏の主張は"Code is cheap, knowledge is value."でしたね。


2つ目はRandall Thomas氏による、"Business Ninja 101 - or how tow make money in technology (...without violating geek ethics)"です。こういう視点で話しをしてくれれる人って、あまりいないかも。。。"We get paid to solve problem."ではじまりましたが、職業プログラマの心得えですね。プログラミングお金の話しです。ただ、お金のためにがつがつやるのではなく、アメリカ人はよく言うのですが、"Do the math." つまり、ちゃんと計算しましょうということです。Problem solvingのためにはどんなツールを選ぶのがいいのか、何はまずいのかをよく知っておくべき、と。本当に使うのかどうかわからないような機能まで盛り込んだりしないで、自分お客様無駄金を使わないようにしようではないか、といった話しです。日本とは若干概念が違うので、すんなりうなずけるかどうかはわかりませんが、お金無限に与えられるわけではないので、限られたリソースの中でうまく解決する、ソフトウェアプロジェクトを成功させる心得としていい話しでした。ちなみに、アメリカでもdeath marchって言うんですね。日本語造語かと思っていた。


そして、ここでランチです。二日目はラップ(薄皮でレタスチキン、ハムなどを巻いたもの。二種類あった)とデザートに飲み物。これも、なかなかおいしいものでした。


午後一の話しは Keavy McMinn氏の"Must. Try. Harder." McMinn氏自信がトライアスロンに挑戦した経験を語ってくれたのですが、、、んー、と、彼女英語ジョーク外国人にはとても難しくて、ほとんど理解できず。。。(あーぁ、もっと英語ができればなぁ、、、)。なんで、理解できなかったかというと、テクニカルな話しではないので、スピーカと共通のバックグラウンドを持ち合わせていない、ボキャブラリが違う、と。で、こういうときに人はこう言う(思う)ものだ的なところがまったくわからないので、ジョークも理解できず。。途中で聞くのをあきらめました。はぁ。とてもemotionalな素敵な話しだったらしく、"話してくれてありがとう"な感じのtweetが多数でした。ビデオをご覧になってくださいませ。(^^;


続いて、Joe O'Brien氏。"Your Customers Aren't Stupid and Your Coworkers Are Not Incompetent"というタイトルで、これもemotional系で、スライド無しのプレゼンで、ちょっとつらかった。でも、こっちはプログラミング系なのである程度理解できました。理解できた範囲で。。。。仕事がうまくはかどらなくてストレスを抱えた日々をすごしているとしたら、それはボスお客様がモノを知らなすきるのでもないし、プロジェクトの他の人たちのスキルが無いわけでもなくて、コミュニケーション不足なのだから、もっと話しをしてお互いをわかりあおうじゃないかという内容でした。どうせわからないと最初からあきらめていて、話しをしていないのではないか、とも。ステレオタイプというのも前向きに受け止めていて、人間はみんなステレオタイプなところがあるものだから、コミュニケーションによって克服しようではないかとも言っていました。他に、問題を克服してエキスパートになるためのステップの話し、そして、"Respect other people."とハートウォーミングな話しでした。


二日目のここまでは成功への道、的話しが続いたのですが、ここで、がらりと方向が変わって、実アプリの披露となりました。登場したのは、David Bock氏とArild Shirazi氏のお二人。タイトルは"JRuby - Making the World Safe For Democracy." なんだかスゴいタイトルで、このアプリの元々の(?)プロジェクトは国際的な政治系のところに端を発しているようなのですが、アプリの方は、JRubyを利用した多国語化の実例でした。どうJRubyを利用しているのかというと、、、、国際化関係はJavaの方が完成度が高いとうことで、 JavaのResourceBundleとプロパティ(uuencodeしてあるはず。ん?JRubyはここのあたりにバグがあってUTF-8しか使えなかったような記憶が、、)を利用して、表示を国際化したものでした(昔はよくやったなぁ> ResourceBundle。懐かしい)。ヨーロッパの話しをしていたんですが、なぜか、サンプルは日本語でした。多国語化の他にも、J2EEからRubyに乗り換えて、つまり大幅にrewriteして成功した実例であるということで、Fowler&Kilmer氏の"Never ever rewrite!!"の反例なのでした。


JRubyConf 2010のトリを飾ったのは、Bernerd Schaefer氏の"Bringing Java to the Ruby World."なんだか、半分近くが帰っちゃったんじゃないかと思うくらい、人が減ってしまっていましたよ。お気の毒な感じ。日曜の午後だから仕方がないけれどね。で、この話し、残っていてよかった、と思えるおもしろいものでした。CRubyから(JRubyからではない)Javaを使ってやるぞーのgemなんですよ。私が書いたJRuby embed APIとまったく逆方向の使い方で、なるほどなぁ、と思いました。そのgemは "jruby-jars"というもの(なんか、この名前は聞いたことがある気がする。。。なんだぁ?と思ったまま忘れてしまったような)。ほとんどすべてがCRuby上で動いているもので、"nice startup time"というSchaefer氏のコメントには会場から笑いが。かなり改善されましたが、やっぱりJRubyの起動は遅いですからねぇ。で、いろいろとサンプルを見せてくれました。また、JRuby(Java)はRubyとはまた違う問題を解決してくれるので、rubyistJavaも知っておくべきだ、とのアドバイス。Schaefer氏はJavaはあまり経験がないRubyistだということですが、それでも、JRubyを使う利点に注目しているようで、そのためのツールを披露してくれたのでした。



と、こんな感じのJRubyConf 2010でした。

突然、行くことになったのは hiro asari氏が声をかけてくれて、いろいろ取りはからってくれたからなんです。行けてよかった!hiroさんありがとう。

2010-10-05 紅葉が進みつつある今日この頃

JRubyConf 2010に行ってきました

なぜか突然、JRubyConf 2010に行ってきたので、レポートでも。これは会場で配られていたTシャツコーヒー豆、Ruby Brew。すごく香りのいい豆です。

f:id:yokolet:20101005013748j:image:w240


昨年はサンフランシスコで開催されたJRubyConfですが、今年はオハイオコロンバスというところでした。おそらく日本人には馴染みが無い場所かと(デトロイト近辺の日本人にはお馴染みの場所ではあります。ホンダ工場コロンバス郊外にあるので。自動車業界つながりということで)。カンファレンス会場のQuest Confrence Centerはいかにもアメリカ郊外という雰囲気の場所にあります。(つまり、だだっぴろい感じのところ。いわゆる車が無いとどこにもいけないという典型的アメリカの街)


カンファレンスの会場は一部屋だけ。広さは、たぶんRubyKaigiの小さい方のホールの半分くらい、かな。でも、前の方はほとんど空きがないほど、大勢の人がきています。200人くらい?会場入り口では、フルーツヨーグルトコーヒージュースといった飲み物のサービスがありました。


トップバッターはThomas Enebo氏による”Java in Ruby: Suntory Time”でした。このプレゼンJRubyユーザー必見です。JRubyでコーディグするための、JRubyならではの grammar の話しで、きっと「そこが知りたかったんだ」と思う人は多いのではないでしょうか。たとえば、java_importやjava_send, java_method,java_signatuireなどなど。他にも、JavaメソッドRubyオーバライドする方法やらインタフェースの実装やら。書籍"Using JRuby"(http://pragprog.com/titles/jruby/using-jruby)でもこの辺りの解説がありますが、このプレゼンはそれ以上かも。ビデオが公開されるのかどうかわかりませんが、もし、公開されたらぜひご覧になってください。たとえビデオがないとしても、スライドは公開されるので、それを見るだけでも参考になると思います。他に"Using JRuby"本は参加者限定のディスカウントがあったり。。。


番手はCharles Nutter氏による、Rubotoでした。ご存知、RubyAndroidコードが書けるAPIと実行環境。筑波のJRubyKaigiでデモを見せてくれたので、 参加された方は Rubotoに聞き覚えがあるかも。これからRubotoを使ってみようと思っている人向けの入門編です。とはいっても、単なるgetting startedよりはずっと詳しくて、APIについてもサンプルコードを付けて解説してくれました。もちろん、デモも。開発ツールの使い方や、Android特有の知っておくべきAPIの解説などもあり、これから始める人は特に、知っている人にも便利そうなあたりがあるのではと思います。これも、スライドは公開されるはずです。


三番目はJeremy Hinegardner氏による、”Extending JRuby”でした。このセッション、個人的にはとても興味深いものでした。なんといっても、今私が取り組んでいるpure Java NokogiriはHinegardner氏のいう”Extending JRuby”のひとつ。3つの拡張方法、C extension, Java extension, ffi extensionのうちのJava extensionなんです。Hinegardner氏が作っているという hitimes gemを例に、C extensionの場合はこうして、Java extensionの場合はこうしてという詳しい解説をしてくれました。


そしてここでランチです。サラダパスタチキン、デザートと飲み物でした。豪華ではないけれど、十分だし、おいしい料理でしたよ。参加者は、丸テーブルに適当に座って、話しをしながらの食事です。話題は、RailsConfのとき比べると、もっとディーププログラミング関係が多いかったかな。おそらく、日々、プログラミングな人たちばかりで、businessな人はほとんどいないのでしょう。


午後の最初セッションはGlenn Vanderburg氏による、”Real Software Engineering”でした。アカデミックテーマです。大学情報系の教授が話しそうなSoftware Engineeringとは何かという内容でした。 Software Engineering歴史黎明期から現在に至までの話しにはじまり、Softwareではないreal engineeringとの比較やらでとくとくと解説してくれました。歴史中にはwaterfall開発の話しも。Real engineeringとの比較のところは、実際の建築工事過程とソフトウェア開発をモデリングデザイン工事(コーディング)がそれぞれどのように対応するかを話しつつ、どこで失敗するとどういう結果になるのかをコミカルに説明してくれました。さらに、テスト。Real engineeringの分野の例ではボーイング社が実際に飛行機の翼が折れるまで強風を吹き付ける実験の話しをしながら、Software engineeringの世界テストとの違いに触れていました。

このプレゼンは私には難しい英語で(ハイレベル単語が多々)、なんとか話しを追いかけるのが精一杯でしたが、参加者にはとてもウケていましたね。


続いて、JRubyコミッタのOla Bini氏登場。”The JRuby Testing Story”です。JavaコードRubyテストする話しが中心で、前半は世の中に出回っているテスティングツールについての概要で、後半はBini氏が開発しているJtestR(http://jtestr.codehaus.org/)の話しでした。たぶん、目新しいことは言っていなかったような気がします。世の中にはこんなにたくさんのテスティングツールがあるけれど、JtestRはいくつものツールをサポートしているし、AntMavenからも使えるからJavaな人には便利なツールだという内容。今、JRubyJavaコードテストする目的で使っている人はかなり少ないと思うのですが、これは確かに便利だと思います。テストコードは通常のJavaコードと違って、アーキテクチャとか再利用性とか考えるよりも、さくっと簡単に書けて、短時間でより多くをカバーできるようにしたいもの。こういうところは重厚なJavaよりも、Rubyのほうがいいというのはこの界隈では良く聞く話です。

ところで、今回、初めてBini氏にお会いしたのですが、すごーく背の高い人でした。背の低い私ははるか空を見上げて話しをしているような感じで。。。また、とてもよく話す人だなぁという印象。セッションが終わった後もひとりでしゃべりまくっていましたよ。(あのくらいしゃべれたらいいなぁ、と思いつつぼーっと話しを聞いていた)

Bini氏のセッションが終わったところで、JRubyコミッタ7人並んで記念撮影をしました。そうなんです、現在アクティブに活動しているコミッタほぼ全員(nahiさんがいなかった)が揃ったのでした。


さらにテストの話しが続きます。"Mocks Suck (and what to do about it)"というタイトルでBrian Swan氏が話しをしました。おもしろい話しでした。まずは、Martin Fawler氏がBlikiで語った "Mocks Aren't Stubs"(http://martinfowler.com/articles/mocksArentStubs.html)を引用して、mockとstubの違いにふれ、いかにmockがだめであるかを強調。例えば、可読性が悪くなるし、Railsのようなフレームワークに合わないなど。そこで、mockではなくStubを使いましょうというススメに話しは展開していきました。とにかく、シンプルで可読性のよいstubを使いましょうという結論でした。


そして、もうひとつテストの話し。Jim Weirich氏による"Testing - Why Don't We Do It Like This?"です。スライドはすでにPDFが用意されていて、http://bit.ly/jrc-testingからダウンロードできます。今度は、mockはすばらしいからぜひコレを使って、テストの効率を上げようという話し。ん??Weirich氏の"Thank you, Brian"の始まりは笑えます。Weirich氏はまず、テストは速く終わらないといけないという話しから始めました。どうやら10分というのが目安のようで、これ以上長いと、テストを動かし始めたところでみんな帰っちゃう、テストが失敗したところの修正は翌日になるようです。ところが10分以下だと帰らずに結果を見て、問題があればその日のうちに修正するんだそうで。まぁ、日本では10分以上かかってもじっと待っていてその日のうちに修正しそうでうが、アメリカはそうではないということで。(こういう文化の違いって、ソフトウェア開発スタイルに影響を与えているのかも)Weirich氏によると、mockがいいとはいっても、よいmockを書かないといけないということでした。可読性をよくする必要があるし、普通コードのようにリファクタリングも必要とのこと。テストコードも大切にしないといけないんですね。


この日のセッションはもう一つ。いやぁ、長いです。プレゼンテータが変わるときには十分時間をとってくれていて、トイレにいったり、コーヒーおやつ(用意されている)で休憩したりできるようなスケジュールになっているのはありがたい。


一日目の最後はNick Sieger氏の"Rails3 with A Doulbe-Shot of JRuby"でした。内容は、JRubyとRails3が現在どのような状況かということやら、これから何がリリースされるかなどなど。特にactiverecord-jdbc周りでいろいろ出てきそうでした。筑波のJRubyKaigiのときに、DB2JRuby用アダプタが無いという質問をされていた方がいましたが、出るみたいですよ> DB2アダプタ。

他には、JRubyだんだん速くなってきているとか、あんなgemやこんなgem (Warbler/Trinidadとか neo4+lucuneとか)の話しとか、どちらかというと浅く広く、JRubyはこれからもこんなによくなるし、もっといろいろできるようになるよー、みんなJRubyを使おー、的な話しでした。でも、これは本当で、JRubyそのものばかりではなくて、周り(gemとか)もどんどんよくなってきているなー、という今日このごろです。RubyだけじゃなくてJRubyもお試しください。Javaな人は試しに使ってみて。


夜は、JRubyConfを開催してくれたEdgeCase(http://edgecase.com/)社で、Scotch Whiskyのイベントがありました。asariさんによると、アメリカのstartupはみんなこんなもの、だそうですが、日本会社しかしらない私の目からみると、"なんてすてきな建物!"な会社です。軽井沢とか清里とかにありそうな、すごーく素敵な広ーい別荘って感じ。森の中だったし。ここでいただいた、Ginger Beer、おいしかった!ごちそうさまですー。このイベントは延々、夜中の1時くらいまで続いていました。

とりあえず、ここまで。二日目についてはまた後ほど書こうと思います。

2010-06-20 ミシガンの夏らしいさわやかな暑さ

JRubyいろいろ - BDDなんかやってみちゃうぞぉ

BDD(Behavior Driven Development)、振舞駆動開発、人気ですねぇ。「Ruby逆引きレシピ」では、、、ありました、レシピ181。Rspecを使ったBDD。今や、Ruby世界ではテストっていうとBDDな感じで、rspecとか、そう、あのcucumberが大〜人気。RailsConfですっかりcucumberにかぶれて帰ってきたところなので、今回はcucumberBDDなんかやってみちゃうぞぉ、と。"Make cukes green!"を目指して、きゅうりをかじってみよう!


その1 きゅうり、持ってこい!Cucumberインストール

きゅうりが無いとかじるものもないので、まずは定番のインストールから。Cucumber gemが必要なのは言うまでもないので、気になるのは他に必要なものだよね。。。で、必要なのはrspecだけ。ちまたではよく"cucumberはwebratが必要"みたいなとことが書かれているけれど、、、Railsテストじゃなければ、webratはいらない。まぁ、cucumberはふつーRailsテストに使うから、webratもインストールしておけばいいんですけどね。

で、JRuby場合、「JRubyいろいろ - gem, gem, gem (http://d.hatena.ne.jp/yokolet/20100602#1275509300)」のその1に書いたようにrspec最初から入っているから、cucumberインストールだけでよろしい、と。つまり、きゅうりを持ってくるのに必要なのはコレだけ。

jruby -S gem install cucumber

その2 こんなきゅうり、あります。Cucumberのサンプル

Cucumberインストールしたら、jruby-x.y.x/lib/ruby/gems/1.8/gems/cucumber-0.8.3/examplesを眺めてみる。あるわあるわ、きゅうりがたくさん、、、サンプルがたくさん。このきゅうりただものじゃない。ほんとに。Rubyのためのテスティングフレームワークじゃなくて、Rubyで書いた、汎用(いろいろな言語で使える)テスティングフレームワークな感じです。i18nのサンプルについてはその3で試してみるとして、他は、、、えっと、失敗してしまうものとか、ruby2pythonのように、必要なgemJRuby用にポートされていないとかあるでの、make cukes green!はユーザのために残してあるのかぁ、、、と。(^^;; でも、いろいろあるし、Cucumber Wiki (http://wiki.github.com/aslakhellesoy/cucumber/)にいくと、説明がいろいろあるので、試してみるとおもしろいかも。


その3 きゅうり日本語レシピは?

そして、cucumberと言えば、第22回 Railsアプリの受け入れテストをCucumberで書こう:Ruby Freaks Lounge|gihyo.jp … 技術評論社にちょっとしたサンプルがあるように、自然言語で振舞を記述するワケですが、その自然言語英語だけじゃなくて、44ヶ国語(version 0.8.3)に対応! (jruby -S cucumber --i18n help で表示される) なのでした。Ruby Freaks Loungeのcucumberの回では、misoというgemを使って日本語対応していたけれど、今はもうmisoはいらないみたい。きゅうりにみそ、、、ん、これは、、、もろきゅうだね、しゃれてる、と思ったのですが、ね。今は何も付けずにヘルシーにきゅうりバリバリと食べられるようになっているみたいだ。

ついでに、cucumberキーワードがどんな風に日本語になっているかというと、、、

$ jruby -S cucumber --i18n ja
      | feature          | "フィーチャ", "機能"                                  |
      | background       | "背景"                                           |
      | scenario         | "シナリオ"                                         |
      | scenario_outline | "シナリオアウトライン", "シナリオテンプレート", "テンプレ", "シナリオテンプレ" |
      | examples         | "例", "サンプル"                                    |
      | given            | "* ", "前提"                                     |
      | when             | "* ", "もし"                                     |
      | then             | "* ", "ならば"                                    |
      | and              | "* ", "かつ"                                     |
      | but              | "* ", "しかし", "但し", "ただし"                       |
      | given (code)     | "前提"                                           |
      | when (code)      | "もし"                                           |
      | then (code)      | "ならば"                                          |
      | and (code)       | "かつ"                                           |
      | but (code)       | "しかし", "但し", "ただし"                             |

のようです。

ということで、jruby-x.y.x/lib/ruby/gems/1.8/gems/cucumber-0.8.3/examples/i18n/jaを眺めてみると、、、ありました!こんなfeature

# language: ja
フィーチャ: 加算
  バカな間違いを避けるために
  数学オンチとして
  2つの数の合計を知りたい

  シナリオテンプレート: 2つの数の加算について
    前提 <値1> を入力
    かつ <値2> を入力
    もし <ボタン> を押した
    ならば <結果> を表示

  例:
    | 値1 | 値2 | ボタン | 結果 |
    | 20  | 30  | add    | 50   |
    | 2   | 5   | add    | 7    |
    | 0   | 40  | add    | 40   |

に、こんなsteps

# encoding: UTF-8
Before do
  @calc = Calculator.new
end

After do
end

前提 "$n を入力" do |n|
  @calc.push n.to_i
end

もし /(\w+) を押した/ do |op|
  @result = @calc.send op
end

ならば /(.*) を表示/ do |result|
  @result.should == result.to_f
end

おぉ、これはさっそく試してみよう、、、んー、

$ jruby -S rake cucumber
(in /Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/examples/i18n/ja)
/Users/yoko/Tools/jruby-1.5.1/bin/jruby -I "/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/lib:lib" "/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/cucumber" --format pretty
load error: /Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/examples/i18n/ja/features/step_definitons/calculator_steps -- org.jcodings.exception.EncodingException: invalid code point value (LoadError)
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/rb_support/rb_language.rb:141:in `load_code_file'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/step_mother.rb:84:in `load_code_file'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/step_mother.rb:76:in `load_code_files'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/step_mother.rb:75:in `each'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/step_mother.rb:75:in `load_code_files'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/cli/main.rb:56:in `execute!'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/../lib/cucumber/cli/main.rb:25:in `execute'
/Users/yoko/Tools/jruby-1.5.1/lib/ruby/gems/1.8/gems/cucumber-0.8.3/bin/cucumber:8
rake aborted!
Command failed with status (1): [/Users/yoko/Tools/jruby-1.5.1/bin/jruby -I...]

(See full trace by running task with --trace)

と、例外がでちゃいました。どうやら、ステップ記述日本語があるとJRubyはだめみたいだ。ステップのところだけ英語版に変えると動いたけれど、結果はすべてpendingになってしまう、と。これはcucumberが悪いわけではなく、CRuby ではちゃんと動いて、こんな感じでした。

# language: ja
フィーチャ: 加算
  バカな間違いを避けるために
  数学オンチとして
  2つの数の合計を知りたい

  シナリオテンプレート: 2つの数の加算について # features/addition.feature:7
    前提<値1> を入力            # features/step_definitons/calculator_steps.rb:9
    かつ<値2> を入力            # features/step_definitons/calculator_steps.rb:9
    もし<ボタン> を押した          # features/step_definitons/calculator_steps.rb:13
    ならば<結果> を表示           # features/step_definitons/calculator_steps.rb:17

    例: 
      | 値1 | 値2 | ボタン | 結果 |
      | 20 | 30 | add | 50 |
      | 2  | 5  | add | 7  |
      | 0  | 40 | add | 40 |

# language: ja
フィーチャ: 除算
  バカな間違いを避けるために
  有理数計算できること

  シナリオ: ふつうの数値    # features/division.feature:6
    前提3 を入力       # features/step_definitons/calculator_steps.rb:9
    かつ2 を入力       # features/step_definitons/calculator_steps.rb:9
    もしdivide を押した # features/step_definitons/calculator_steps.rb:13
    ならば1.5 を表示    # features/step_definitons/calculator_steps.rb:17

4 scenarios (4 passed)
16 steps (16 passed)
0m0.014s

JRubyエンコーディング関係はTom Enebo氏などが四苦八苦してなんとかしようと努力中ではありますが、Rubyの1.8と1.9の両方を同時にJavaの上に載せるという複雑さがあって、ところどころでこのような問題が発生しています。Help wanted!


その4 きゅうりレシピ検証

せっかくなので、Make cukes green!の過程をひとつひとつ試してみようじゃぁありませんか。


ところで、Railsとかいろいろなところのテストを見ると、ディレクトリ名がfeaturesとかなんとか決まっているかのような気がするのですが、これは気のせい。Cucumberディレクトリは気にしないみたいなので、ちょびっとのサンプルだから全部ひとつディレクトリの中でやっちゃいましょう。


では、Cucumberサイトhttp://cukes.info/に出ているように、まずはフィーチャーをaddition.featureに記述

Feature: Addition
  In order to avoid silly mistakes
  As a math idiot
  I want to be told the sum of two numbers

  Scenario: Add two numbers
    Given I have entered 50 into the calculator
    And I have entered 70 into the calculator
    When I press add
    Then the result should be 120 on the screen

もうひとつステップも。これは、とりあえず、Givenのステップひとつだけcalculator_steps.rbに書いてみた。

Given /I have entered (.*) into the calculator/ do |n|
  @calculator = Calculator.new
  @calculator.push(n.to_i)
end

で、jruby -S cucumber addition.featureとタイプすると、、、

f:id:yokolet:20100621041801p:image

というように、予想どおりテストが失敗。ということで、Calculatorクラスを書いてみる。Javaで。Javaクラスを、ですよ。だってJRubyなんだから。同じディレクトリにこんなCalculator.javaを書いて、

import java.util.ArrayList;
import java.util.List;

public class Calculator {
  private List<Integer> values = new ArrayList<Integer>();
  private int index = 0;

  public void push(int v) {
    values.add(index++, v);
    if (index > 2) index = 0;
  }
}

javac Calculator.javaで、Calculator.classを作る、と。Javaクラスを使っているのでステップ記述のCalculatorはJava::Calculatorに修正、、、

Given /I have entered (.*) into the calculator/ do |n|
  @calculator = Java::Calculator.new
  @calculator.push(n.to_i)
end

ができたら、再びjruby -S cucumber addition.featureを実行すると、、

f:id:yokolet:20100621043118p:image

おぉ、どうやら、pushはできたらしい。あとはpendingになっているaddとresultをなんとかすればよし。で、こんどのステップはこんな感じに。毎ステップでCalculatorのインスタンスを作っていると、足し算の結果を出せないので、Beforeのところで、インスタンス作成

Before do
  @calculator = Java::Calculator.new
end

Given /I have entered (.*) into the calculator/ do |n|
  @calculator.push(n.to_i)
end

When /I press (\w+)/ do |op|
  @calculator.send op
end

Then /the result should be (.*) on the screen/ do |result|
  result == @calculator.result
end

Javaクラスはこんなふうに修正。

import java.util.ArrayList;
import java.util.List;

public class Calculator {
  private List<Integer> values = new ArrayList<Integer>();
  private int index = 0;

  public void push(int v) {
    values.add(index++, v);
    if (index > 2) index = 0;
  }

  public void add() {
    values.add(2, values.get(0) + values.get(1));
  }

  public int result() {
    return values.get(2);
  }
}

そして、javac Calculator.javaRubyを書き慣れてくると、IDEを使い慣れていると、Javaプログラムををコンパイルするのを忘れるのですよ。修正したのに変わっていないじゃないか!と。Javaコードコンパイルが必要。忘れないようにしよう>自分

そして、またしても jruby -S cucumber addition.featureを実行すると、、、

f:id:yokolet:20100621044249p:image

Yeees! I made cukes green!


その5 もっとJavaきゅうり

ていう感じで、JavaクラスCucumberBDD開発できそう。。。”でもさぁ、JavaだとMavenとか使いたいんだよねぇ”って?あります、そんなJavaきゅうりが。その名もcuke4duke(http://github.com/aslakhellesoy/cuke4duke)。JRubyがあるからこそ、のこのテスティングフレームワーク。cuke4dukeを使うと、ステップ記述Javaコードで書くみたい。たとえば、サンンプルのひとつ、CalledSteps.java

ackage simple;

import cuke4duke.annotation.I18n.EN.Given;
import cuke4duke.annotation.I18n.EN.Then;

import static org.junit.Assert.assertTrue;

public class CalledSteps {
    private boolean magic;

    @Given("^it is (.*)$")
    public void itIs(String what) {
        if (what.equals("magic")) {
            magic = true;
        }
    }

    @Then("^magic should happen$")
    public void magicShouldHappen() {
        assertTrue(magic);
    }
}

アノテーションですね。中ではPicoContainerなんか使っている様子。サンプルの中にはGuiceとか(!)、Scale、Clojureなんかいろいろあって、おもしろそうです。cuke4dukeについてはまた今度の機会に。いろいろ試してみようと思います。


ということで、BDDなんかやってみちゃった、JRubyいろいろでした。


余談ですが、アメリカスーパーでは日本のあのいぼいぼがついているきゅうりは売っていません。日本スーパーに行けばありますが。アメリカもののきゅうりで一番に日本きゅうりに近いのはbaby cucumberと呼ばれているきゅうりで、ピクルスにするきゅうりCucumberっていうきゅうりはどちらかというとズッキーニ系。ちょぉっと”きゅうり”じゃないかなぁ。もっと、ウリな感じ。ズッキーニは輪切りになってサラダロメインレタスの上にのってきたりする。日本レストランだと、ズッキーニ天ぷらになって出てくる。これはけっこういける。意外とおいしいです、ズッキーニ天ぷら