2011-04-01 また雪の予報。春はまだかなぁ
■ JRubyでJavaBeansを簡単に生成する方法
jruby-users MLでJavaBeansのクラスを簡単に生成する方法はない?という質問が出ていました(http://www.ruby-forum.com/topic/1398824)。Groovyだと、def book = new Book(title: "Foo", author: "Bar") でできるみたいだ。GroovyはJavaのためのスクリプティング言語だから、このあたりはやはり便利にできていますねぇ。で、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}"
でいける。これで、Groovy の def book = new Book(title: "Foo", author: "Bar") にさらに近づいたかも。
2011-03-01 もうちょっとで気温が0Cを超える日々がくる
■ NetBeans 7.0 beta 2 の Rubyサポート
久々の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ボタンをクリックするステップ以降が書かれていませんが、ま、これがわからない人はいないでしょう。
試しにこのとおり実行してみたら、今まで通り、NetBeansのRubyプロジェクトが見えて、Rubyの実行もできました。
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とはまた違う問題を解決してくれるので、rubyistはJavaも知っておくべきだ、とのアドバイス。Schaefer氏はJavaはあまり経験がないRubyistだということですが、それでも、JRubyを使う利点に注目しているようで、そのためのツールを披露してくれたのでした。
と、こんな感じのJRubyConf 2010でした。
突然、行くことになったのは hiro asari氏が声をかけてくれて、いろいろ取りはからってくれたからなんです。行けてよかった!hiroさんありがとう。
2010-10-05 紅葉が進みつつある今日この頃
■JRubyConf 2010に行ってきました
なぜか突然、JRubyConf 2010に行ってきたので、レポートでも。これは会場で配られていたTシャツとコーヒー豆、Ruby Brew。すごく香りのいい豆です。
昨年はサンフランシスコで開催された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でした。ご存知、RubyでAndroidのコードが書ける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はいくつものツールをサポートしているし、AntやMavenからも使えるからJavaな人には便利なツールだという内容。今、JRubyをJavaコードをテストする目的で使っている人はかなり少ないと思うのですが、これは確かに便利だと思います。テストコードは通常の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のときに、DB2のJRuby用アダプタが無いという質問をされていた方がいましたが、出るみたいですよ> 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にかぶれて帰ってきたところなので、今回はcucumberでBDDなんかやってみちゃうぞぉ、と。"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のように、必要なgemがJRuby用にポートされていないとかあるでの、make cukes green!はユーザのために残してあるのかぁ、、、と。(^^;; でも、いろいろあるし、Cucumber Wiki (http://wiki.github.com/aslakhellesoy/cucumber/)にいくと、説明がいろいろあるので、試してみるとおもしろいかも。
そして、cucumberと言えば、Ruby Freaks Lounge:第22回 Railsアプリの受け入れテストをCucumberで書こう|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!
せっかくなので、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とタイプすると、、、
というように、予想どおりテストが失敗。ということで、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を実行すると、、
おぉ、どうやら、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
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.java。Rubyを書き慣れてくると、IDEを使い慣れていると、Javaのプログラムををコンパイルするのを忘れるのですよ。修正したのに変わっていないじゃないか!と。Javaのコードはコンパイルが必要。忘れないようにしよう>自分。
そして、またしても jruby -S cucumber addition.featureを実行すると、、、
Yeees! I made cukes green!
ていう感じで、JavaのクラスをCucumberでBDD開発できそう。。。”でもさぁ、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っていうきゅうりはどちらかというとズッキーニ系。ちょぉっと”きゅうり”じゃないかなぁ。もっと、ウリな感じ。ズッキーニは輪切りになってサラダのロメインレタスの上にのってきたりする。日本食レストランだと、ズッキーニは天ぷらになって出てくる。これはけっこういける。意外とおいしいです、ズッキーニ天ぷら。




