「ヴィンランド・サガ」6巻
…のちのクヌート1世である、って感じの展開。幸村節だねぇ。
日本Ruby会議2008に参加しました
日本最大のRubyイベントである日本Ruby会議2008(RubyKaigi 2008)に参加しました。
とても楽しかったけど、直後から1週間風邪で熱出してダウンしてました。そういえば当日も体調よくなくて、基調講演ほかおいしいセッションを聞き逃してしまいました。
いまさら感はありますが、帰ってブログを書くまでがイベントのことなので、会場でとったメモをこっそり載せます。ざっとしたメモなので、間違いがありましたらご指摘ください。
これを終えたら、ニコ動やほかの方々のレポートを見よう。
全体
正直つくばは遠かったけど、それにみあうだけの立派な会場と仕切り。街もきれいなところだった。ちなみに、会場の隣のショッピングセンターにラーメンの青葉があったのも収穫。
メインホールと多目的ホールに分かれて開催。多目的ホールは展示会場も兼ねていて、企業や団体のほか、ジュンク堂さんの書籍販売もやっていて、各版元(オライリー、技評、翔泳社)の方々が手伝っていた。
1日目
Ruby M17N(成瀬ゆい氏、Martin J. Dürst氏)
Ruby 1.9のM17N(多言語対応)についてのセッション。親子ほど年の離れたコンビがうまくかみあっていたと思う。Dürst氏いわく、「Rubyを使うと若くなる」と。
Ruby 1.9ではM17Nをサポートしている。これは、CSI(Code Set Independent)方式ということで、内部エンコーディングを決め打ちしない方式をとっている。Stringオブジェクト単位でエンコーディング情報を持っている。単なるバイト列であるASCII-8bitというエンコーディングも用意している。あと、ISO-2022-JPのようなステートフルなエンコーディングは、名前だけを知っているDummy Encodingとしている。
で、Character Objectはない(大クラス主義)とか、文字リテラルやString#[]はRuby 1.8では整数だけど1.9ではStringになるとか、同じエンコーディングとだけ比較・結合ができる(ただしASCII文字列とASCIIを含むエンコーディングならいいらしい)とか。あと、$KCODEはobsoleteでMagic commentで指定しようとか、-Kオプションは健在とか、openの引数でencodingを指定とかいう話だった。
Martin Dürst氏は、エンコードを変換するString#encodeライブラリを紹介。ソースファイル名とかはtranscodeとなっているけど、Matz氏の強い要望で「encode」という名前になったとか。
処理としては、UTF-8を変換のハブとして採用。最初は1文字ごとにテーブルを作っていたけど、メモリ効率が悪すぎるので、文字コードから種類を引くテーブル(offsets)と、種類から実際の処理を引くテーブル(infos)の2つにした。オプションは:invalidと:ignoreしかないので増やしたい(ささださんの講演で9月までと期限を切られたのだとか)。
それらを受けて、成瀬氏が、「Encodingを意識しよう」「Encoding独立なコードを書こう」「Magic Commentを書こう」とまとめていた。あと、課題では、Dirなどの対応が議論中だとか。
という本題以上に、Q&Aセッションはコミッターの人たちを交えた激論になっていて面白かった。
- Q: Cygwinは?
- 最近よくなっている
- Q: はまりどころと、具体的な対策は?
- バイト列と文字列を連結するようなコードはエラー
- とりあえず-Kオプションで試して、うまくいったらMagic Commentで
- 例外が起きたら地道につぶす
- Q: Magic CommentがRdocでそのまま出てしまう
- Rdoc直しなはれ(笑)
- Q: \文字コードで書かれた正規表現リテラルのエンコーディングは?
- Script Encoding
- US-ASCIIのアッパーコンパチ
- Q: たとえばUTF-8なスクリプトでEUC-JPテキストを読み込んだときにマッチさせる正規表現は?
- 変換してマッチすることになると思う
- Q: Win32OLEは内部でUnicodeに変換している。今後は自動で変換させないようにするのか、自分でやるのか
- 最近Direntryに関して議論があった
- 自動変換はよくないという方向
- デフォルトをどうするかはまた別
- Q: ライブラリ内で日本語リテラルを書く必要がある場合、どうするのがよいか
- いろいろやりかたがある
- とりあえず変換
- 正規表現
- 受け取ったのと同じエンコーディングで返すのが定石
- 一般的なものは難しい
- オプションで渡す?
- いろいろやりかたがある
- Q:normarize/denormarize(「が」→「か゛」、など)
- やらなくちゃならないとは思っている
- 予定には入っている
- Q: パフォーマンスがよくなさそうだが(table lookupのキャッシュミスなど)、チューニングは?
- 最高速ではないが、まあまあ
- Ruby自体もそんな感じ
- Q: どのぐらい固まったか
- コアはだいたい固まった
- 外縁部はつみのこしが(Dirとか)
- Q: まとまった資料は?
- この発表のスライド
Rubyを教えてるんじゃない、Rubyで教えてるんだってば(増原英彦)
東大の教養学部で、情報科学の概念(計算量や動的計画法など)を教えるのにRubyを使っているという話。
2000年ごろをさかいにComputer Scienceの人気が落ちているというのをグラフで紹介。そうした道には、いままで(日本では)ハッカー系(プログラミング大好きな人)の人が集まっていた。が、それ以外の人を増やす必要がある、ということで、記述が面倒なJavaとかより、Rubyを使っているという話。
で、ソートのサンプル(選択ソートだったかな)を表示。イテレータやメッセージ呼び出しなどのRubyらしい文法は(最初は)使わず、昔でいうPascal的な使い方をしている。
Rubyでよかった点は、多倍長整数がシームレスに使える点や、複数のアルゴリズムを比較するのにベンチマークやグラフ化のライブラリが揃っている点など。あと、悪いアルゴリズムでてきめんに遅くなる(笑)
ほか、学生がハマったところとして、end忘れでエラーが出るんだけど悪い箇所が最初わからない( 学生さんはインデントしてくれない)とか、自作ライブラリが標準ライブラリと同じ名前にしたのでロードされていなかったとか、「"」やインデントが全角空白だったとか、いったエピソードを笑いの中で紹介していた。
成功するRuby教育のプラクティス(吉田裕美)
社内でRuby開発者を増やす方法を紹介。いわく「自分が教えるのがいちばん」。会社や部署の特徴がいかせるし、アフターフォローもできる。社内に勉強する文化が生まれる。実は講師が一番勉強になる。
具体的には、実習をペアプログラミングでやっている。ふつうの実習だと考え込んで止まってしまう人がいるけど、ペアプロなら2人が議論するので、考え込んでいる暇はない。で、スキル差を吸収できるし、実習時間が長くならない。
あと、TDDをうまく利用。テストコードを書くのは難しいので、講師側でテストコードを与えてコードを書かせる。これで達成感(ゲーム感覚)があるし、最後にしっかりくみあわさって動くのが楽しい。
そのほか、ほかの言語の良書をRubyのテキストとして利用してもいいじゃないかという話もあった。
シメは、「教育は場数だ!」ということで。
RSpecによるRailsアプリケーションBDD事例報告(Yugui)
デスマな現場にRspec駆動開発を導入して改善して乗り切った体験談。
状況としては、機能追加、毎日バグが出る、テストされていないコード。初期対応としては、Subversion&Tracの導入(デザイナーさんも)、BuildとDeployの自動化、モジュールごとのさしかえ、Seleniumという策をうったが、それだけは足りずにやめた。具体的には、上からの加速要請や、日々出るバグ、複雑怪奇な依存関係など。
で、Railsでさしかえることにした。で、1か月後のイベントでリリースするのに加え、仕様や構成は試行錯誤となるため、柔軟さが必要。Seesar2も検討したが、中身まで知っているということでRailsを採用した。Seleniumdeで記録した資産を活用し、正常系と異常系のふるまいを規定してRspecによるBDDに落とし込んだ。
フェーズ1は2人。最初はSpecのカバレージ低め。フェーズ2で4人に増えてまわりに浸透、Specのカバレージが増えてSpecがコードの7割になった。ここで1か月。フェーズ3は機能追加やメンテのフェーズで、みんなで取り組んだ(が、会社がなくなった)。
まとめとしては、「ペアプロによる勇気」「動的型のリスクはBDDで排除できる」と。
質疑応答では、「テストを書く暇があったらコードを書け」と上司に言われる場合は? という質問に対し、「わからんやつは黙ってろ」と答えた(会場笑)という名言が生まれた。
Ruby技術者認定試験模擬問題解説
ここで多くの人が多目的ホールへ移動したけど、試験ネタも興味あったのと、体調もいまいちだったので引き続きメインホールで。
問題としては、真になる値はどれ、みたいなRuby独自の挙動を問うものが多いようだ。で、舞台横のIRC画面を見ていると、コミッターの方々が、あーこの仕様残ってたんだ、変えちゃいたい、みたいな話をしていて、よくも悪くも仕様が安定しないなぁ(笑)と思った。
LT:JavaからRubyについて、どうしても言いたいことがある(kuwata)
ここからライトニングトーク。
1人目はTenjinの人らしい。Rubyを教えるのに初級者偏重は大間違いで、Javaは初級者向け、Rubyは上級者向け、上級者に足かせをするな、との話。
LT:dRubyとセキュリティ(西山氏)
drubyを不特定多数に向けて公開するのは危険というのとで、method_missingで充分な例、禁止されているメソッド、$SAFEをあげて制限などの例を上げていた。
RubyとODEでピタゴラ装置(佐々木氏)
3D CGの空間による異色のプレゼン。3D描画ライブラリODE+Ruby Cocoaで、Wiiリモコンを使って操作していた。
スライドがわりの物体の背後で大きなピタゴラ装置が動作していて、後半はそのピタゴラ装置の実演。場内拍手喝采で盛り上がった。
初級者はEnumeratorの夢を見るか?(いまい氏)
Ruby初級者はeachを使いたがるけど、each_sliceとかeach_consも便利だよ、最近はブロックなしのEnumerableなメソッドがEnummeratorオブジェクトを返したりもするよ、という話。
Folk Programming with Ruby(mootoh)
Folk Songみたいな気軽さで、Webアプリ以外で楽しいプログラミングをやろうという話。
具体的にはPlug-in作りで、いちから使うより簡単、使ってもらいやすい=ハードルが低いという。
実例として、Safari+はてブ管理GUIとか、QuickSilver+Twitter、Quartz Composer+Gainer、Vim+Refeを紹介していた。
Ruby.pm(藤氏)
Rubyと同じ処理をPerlの文法の中で扱うPerlモジュールRuby.pmを紹介。RubyのeachをPerlの文法で表現したらこうなるよなぁという記述。Perlの関数をRubyなメソッドから実行したりもできる。
toRubyで見つけたRubyist人生再出発(いけざわ氏)
toRubyはtochigi Rubyの略。おじさんプログラマーがRubyのOOPがわからなくて教えてくれる人がほしいと思ったときに、勉強会開催にこぎつけるまでの熱い体験談。全会場が泣いた!
Ruby 1.9 on Rails 2.1(松田明)
Web+DBシステムは、プログラム中に生SQL→O/Rマッパー→ActiveRecordと進化してきた。でも、「15分で作るブログ」みたいなアプリだったらいいけど、実はDBアクセスはRailsの弱点という話。
で、Rails 2.1からnamed_scopeが導入されて、関係代数(集合演算)を表せるようになったというのを紹介した。
テストベースコードリーディングのすすめ(遠藤氏)
新人Rubyコミッタの人。ソースコードリーディングにはテストを書くのがいいということで、テストが充実していなかったRubyのソースをテストカバレッジ測定ツールにかけ、実行されていない部分をカバーするテストを追加して勉強していたという話。
その結果、ほかのP言語をおさえてテストのカバレッジが85%に上がった。いまも毎晩自動でカバレッジを測定しているのとこと。
A Jail Web Development with Rails 2008 でわっふるわっふる(竹迫氏)
「Ajile」じゃなくて「A Jail」だよ、という話を枕に、YAPC::Asiaで紹介していたmod_waffulを簡単に解説。テスト版は公開中、正式版はパフォーマンスチューニングしてから公開とのことだった。
Industrial-Designed Language: Ruby(斎藤ただし)
パソコンが調子悪いとのことで、スライドなし、しゃべりのみのプレゼン。っていうかもともとスピーチってそういうものだったかも。
Rubyは工業デザインとしてすぐれている、たとえば驚き最小の原則=アフォーダンス、ということを熱く語った。で、最後は、Matzの屍を越えて(え?)よりよい言語を作ろう、というまとめに。
2日目
REST信者から見たRuby on Rails 2.x(山本陽平氏)
RubyのMLでは早くからRESTに注目していて、RubyとRESTはなかよし。また、RailsとRESTはなかよし。
という話をマクラにWebのアーキテクチャスタイルのRESTを解説。
RESTの要件は、全部準拠しなくてはならないものではない、という話が力点が置かれていた。アドレス可能性がいちばん重要で、次に接続性。ステートレス性はあまり重要じゃない、Cookie使わないなんてありえない(山本説)という話だった。
アドレス可能性は、リソースを定義してそれにアドレスを与えること。URIの設計をしてからURIの実装するというURI駆動開発を、Rails、Restlet、Djangoでのそれぞれの例で紹介した。
接続性は、アプリケーション状態エンジンとしてのハイパーメディア。つまり、ページ遷移=状態遷移として設計するという、リンクの設計。Railsでいうと、url_forやlink_toだが、リンクの意味を意識できればもっといい(aのrel属性などの意味づけ)とのことだった。
最後は、実際のところRailsはRESTfulである、初心者がチュートリアルどおり作るとRESTfulになる、という話でまとめてた。
- Q: 考え方を切り替えるコツは?
- A: ぜんぶリソースで考える
- Q: 確認画面はRESTfulでありえるか
- A: それは本当にサーバーサイドでやらなくてはならないのか。クライアントサイドでいいじゃないか。
- Q: ステートレス性とユーザーの認証状態はどう組み合わせるか
- A: ふつうにみなさんがやっているように処理すればいいのでは。ステートレスを考えすぎると処理が重くなるだけ。
Real-World Enterprise Ruby(大場さん、高井さん)
CTCというスーツなSIerでいかにRubyを導入したかという体験談。Ruby案件で売上4.5億とか。
実際にスーツ姿で登壇して、交互にしゃべってボケ・ツッコミっぽい役割分担、ダイナミックな動きなど、スーツというより漫才かも(笑)。
まず、エンタープライズって何? ということで、規模や人数ではない、企業の業務の一部であること、と。
その中にRubyを持ち込んだときには、きちんとRubyを自社内で位置付けて、どうやって会社の利益に貢献するかを会社に説明した。つまり、Rubyをキメると楽しくなる、生産性が高い、というだけでだめだったので、新規顧客・案件の獲得(いままで取りこぼしていた案件をとる)というのを説得材料にした。つまり、JavaからRubyじゃなくて、Javaに加えてRuby、と。
技術部門には、保守・運用フェーズでのサポートを容易。営業部門には、営業向けの提案資料にコピペできる資料を用意。実績面では伊藤忠ウェブテクノロジーラボで武者修行、見積りにはJavaと同じ手法を用意、開発者はCTCテクノロジーでトレーニングや認定試験、技術支援にはコードレビューやトラブルの逐次対応、開発環境にはNetBeans 6推奨、運用環境としてはハードウェアやミドルウェアごとに検証センターで基礎データを収集。
と、必要なものをすべてお膳立てして、想像ではなくデータで回答することが重要だったという話だった。また、松江好きの役員が後押ししてくれたという裏話もあった。
Q&Aでは、営業資料の素を公開できないかという声もあったが、FP値とか入っているので難しいとのことだった。
net-ircというモジュールの実装紹介(cho45)
サブテカのcho45さんのセッション。
irc大好きで、なんでもircに集約している、そこでnet-ircというライブラリを作ったという話。実装はRICEベースなのだけど、RICEはRFC準拠しすぎて使いにくい(UTF-8、nickname長など)、Observerパターンを使っていてオーバーヘッドがある、などから作り直した。
実際に、Net::IRC::Clientを継承して簡単なクライアントを作る例や、Net::IRC::Server::Sessionを継承して簡単なサーバーを作る例を紹介していた。また、作ったアプリケーションとして、ミニブログ-IRCゲートウェイ、Lingr-RCゲートウェイ、mixiに投稿などを紹介した。
で、IRC用botがほかで使えるという長所を語ったあと、Citrus IRC bot frameworkのプラグイン機能の話を経て、後半はDSL論を展開した。
いわく、DSLは濫用しない、と。たとえばscrAPIは引数の意味がわからなくてリファレンスが必要なので悪い例。RakeやRSpecは、ぱっと見でわかり、見よう見真似で使えるからOK。Test::Unitはわからない。ほかにも、DSLはブロックがどこで実行されるのかトレースしづらいうというのも濫用してほしくないところ、と。最後は「高度に発達したDSLは新言語と見分けがつかない」ということばで締めた。
Rubyプログラムの型推論(松本宗太郎)
Rubyプログラムの型推論をするソフトを開発した話。ちょうど公開したところだったとか。
型宣言はなく、ダックタイピングやオープンクラス、動的機能(evalとか__send__とか)、拡張ライブラリを持つというRubyの特徴を生かした。型宣言は追加せず、NoMethodErrorなどのランタイムエラーになるプログラムをrejectする。
実装には、MLの型推論アルゴリズムのunificationや多相レコード型を採用した。この方法のほかには、フロー解析という方法もある(静的アナリシス)。
Reflectionやevalの対応は無理で、しかたなく型注釈を入れることを考えている(これから)。
ほか、Polymorphoic Methodsとか、型の違う要素が並んだ配列のmapとか、ループ中で、Integerを期待する変数に文字列を入れた場合とか、うまくいかないところがあるけど、がんばりすぎず、例外をトラップすればいいと考えている、と。
あと、lambdaにブロックを与えないで呼び出すと外のブロックを引数とするという仕様は頭が痛いのだけど、推奨されていないのでほっとした、という話。
CRubyのGCをどげんかせんといかん(authorNari)
JRuby、Rubinius、CRubyのGC方法を比較して、どげんかせんといかん、という話。
プロセスメモリサイズの肥大化の問題として、ヒープ配列が足りなくなると増設していくけどオブジェクトが残っていると開放できないのでスカスカのヒープ配列が増えていくという問題。これは、配列を小さくするパッチを書いて、1.9-2に採用、と。ただし、Q&Aによると、スループットのパフォーマンスは若干落ちたとのこと。
次に、stop-the-world問題。イタリア人の兄弟が飛び跳ねるゲームを黒塗りで移して、GC中にレスポンスが止まるところを実演。会場にいた小さな子が「○リオだー!」と声を上げていた(笑)。で、markは一度にやるけどsweepは少しずつやるというLazySweepのパッチを書いたけど、まだ取り込まれていないという紹介。
これからやりたいこととしては、BoehmGC採用とか、thread localなフリーリストならキャッシュが効くか、とか、incremental GCもやりたいけどwrite barriorが難しいとかいう話だった。
SVuGy: SVGと遊ぼう (Martin J. Dürst氏)
SVuGyはSVG+Rubyで、SVGを扱うDSL。SveeGeeと発音する。現在0.03で、zipとtar.gzで配布している。ver 0.4も近日公開予定、と。
もともと授業用に図を簡単に作れるようにという実利と、手続き型と宣言型の変換の研究、Rubyの勉強ということから始めた。
単純な記述は「rect 100, 200, 30, 50」みたいに書ける。その他、ブロックでグルーピングとか、スタイルをハッシュ/ブロック/メソッドチェーンの3種類で書けるとか、constant_missingでquoteされていない色属性をつかまえるとか、SVGのidをmethod_missingで処理したりとかの機能を紹介。やりすぎかどうか意見を聞きたいとのことだった。
0.4の新機能としては、SVGをよりサポート、pathなどのオブジェクト、別のオブジェクトに属する点を結ぶ線をきれいに、SVGの読み込み(REXML利用)、いろいろなオブジェクト、レイヤーのサポートとのこと。これはら、レイアウトやAPI、制約、グラフ描画などの高レベルライブラリに取り組みたいとのことだった。
閉会式
元祖高橋メソッド。2009年はYAPCを見習って多言語化(英語とか)を目指したいとのこと。そして、全国各地で地域Ruby会議を開きたい、という話も出た。
RejectKaigi、RejectRejectKaigi
LTであふれたネタ大会RejectKaigiがさらにあふれたので、RejectRejectKaigiも開催。しかも同じ部屋で、ひとつのタイムキーパーで同時進行という無茶さ。さらにステージ横で「Railsレシピブック」のサイン会も開かれ、テラカオス。すごく盛り上がった。
以下、細かいところはわからいけど、メモした範囲で一気に(敬称略)。
- 3の実装の時にアホになるRuby(yoshiori)
- 昨日Rubyはじめました。Rubyも入れました
- 数字をカウントするRubyスクリプトをそのままJRubyで動かしたら日本語になった!
- Rest In Peace 1.8.5(占部)
- 1.8.5はexpired
- patchlevelの推移
- Redmine Ruby 1.9.1(yugui)
- Ruby 1.9開発のプロジェクト管理
- データ移行中
- スタッフ募集中
- 1.9.1は、Sep.25にfix、Dec.25にrelease予定
- 私はDecimalで何をしようとしているか(斎藤ただし)
- あいかわらずパソコンの調子が悪いということで、ノートパソコンの画面を直接会場に見せるプレゼン
- Big Decimalがださすぎるので、Decimalとして再実装した
- Decimalの歌
- ひとばんでつくるRuby + Greaseonkey (さとうたかよし)
- Creamというのを作ったら、アメリカ人に「名前がひどすぎる」と言われてGreaseKitにした
- Objective-Cで書いた。大括弧が多い
- Rubyで書き直したGreaseKit Red
- Remaze(?)
- Communityが強い
- バグは48時間以内に直す
- Award on Rails 2208(?)
- 自分も出ます
- おまけ:ぽろりシミュレータ
- 変なサービスができるまで(星暁雄)
- 梁山泊的なものを追いかける
- コモンズマーカー
- ソーシャルコメント
- アノテーション
- ミニブログ
- 開発者募集中
- Gauche on Rails(yumm3)
- メタプログラミングといえばLisp
- scaffold
- テンプレートにS式
- コントローラで継続
- よいRubyコードをかくにはLispの知識が必要
- Reposh(yhara)
- ハッカーのためのリポジトリシェル
- 怠惰なので実演
- 何度もsvnって
- Hash::mapがあふぉーだんすに優れていない件(ミムラ takkam_m)
- Hash::mapの結果がarrayになる
- mapは写像なはず
- HashからHashを生成するmaph
- String#succ(?)
- matzを266760647回succするとnakada
- 元.succで兄
- 美から鼻
- encoding validation
- 私はいかにしてRubyKaigiを私物化したか(ただ)
- バッグがほしいのでノベルティをトートバッグに
- どこに行っても同じトートバッグを見かけるにはちょっと→スタンプ式
- iDiary.netでニコ動外部プレイヤーを使えるようにした
- 毎日5時に起きてニコ動を見ている
- beeptoys(takkaw)
- ビーブ音源で音楽
- RubyでIdenticon(swdyh)
- AutoPagerizeの人
- IPアドレスからアイコンを生成
- IPアドレス以外に、ドメイン名、ユーザーID、OpenIDのURLなど
- Rubyの実装がなかったので作った「quilt」
- RMagikかGDが必要
- 最新版はgithub
- Illustratorで高橋メソッドプレゼンツール(?)
- Win32OLE
- エフェクト
- 計算もできる
- 写真も置ける
- infix to postfix again(shinh)
- evalで中置き記法を
- method_missingをprintにalias
- _メソッドがmethod_missingになる
- tDiaryとHikiで使うフィルタ(黒田ひらく)
- スパムフィルタ
- 人間が確認
- スパムフィルタ
- Rubyでつくろう二次元プログライング「ず」(naoya_t)
- 有向グラフ
- brainfuckライブラリ(coderepos)
- NDD - Niconico Driven Developlent(井上泰行)
- とにかく作る
- ニコニコにup
- コメントがつく
- やる気になる
- YARVをしのんで(ささださん)
- Nadokaをしのんで
- だれかメンテして
- net-ircよさそうですよね
- Rabbitをインストールできませんでした
- 学生募集中、じゃなくて
- VMで1.9が高速化されました、じゃなくて
- 一部しか入っていない(バグってるから)
- VMの導入はゴールじゃなくてはじまり
- いろいろなことをやるためのプラットフォームとしてのRubyVM
- Nadokaをしのんで
- TechTalk.jp(coji)
- IT勉強会多い
- 動画で
- Rubyバイトコードで遊ぼう(赤井俊平)
- ソースからバイトコードにコンパイル
- VM::InstructionSequence.compile('...')
- rb.comple.to_a:
- メソッド書き換えをやろうとしてloadのバグを発見
- KaigiFreaks(?)
- 動画配信
- 地方RubyKaigiに応募
- 「Ruby札幌が釣れました」
- ?(cho45)
- Rdocのテンプレートを直接作るな
- resh
- require 'future'
- 重い処理を非同期に
- r = f.async.omoi(1);nil
- rを参照したときに待ち
- やる夫で学ぶJRuby最適化(高井)
- いつリリースされるかわからない1.9よりJRubyだお
- サーバVMを使って最適化
- バイトコンパイル
- おそくなってやがる
Regional RubyKaigiのご提案(角谷)
RejectKaigi枠だったけど、単独でメモ。
RubyKaigiのふりかえり。KEEPは、RubyKaigiブランド確立、さまざまな成果物や会合、さまざまなチャレンジ。一方PROBLEMは、規模の拡大、運営負荷の増大、継続可能性。
これからのTRYは、RBAとの密な連携、Ruby Centralとの連携、継続可能な枠組み。
Reject会議大もりあがり、もっとKaigiを、ということで、「我が名はレギオン」「邪神覚醒」というわけで、Regional RubyKaigi。早めに、こまめに。
まずは自分がやってみせたいので、第1回は東京。メンバー募集中。RubyKaigi本編とちがってゆるふわで。待デ続報!
角谷さんのブログを拝見すると、Shibuya.pm Technical Talkみたいなのをイメージしてるみたい。
「初めてのRuby」
日本Ruby会議2008で買い、帰り道で読了。
プログラミング初心者向けではないRuby初心者に向けて、リファレンスでもクックブックでもない形式で、Rubyの特徴的な部分を解説する本。特に、ブロック引数/イテレータや、ダックタイピング、特異メソッド/特異クラス、継承、メタプログラミングあたりに著者が特に注力している感じがして、面白かった。
あと、細かいけど実用的な部分について、Ruby 1.9と1.8の違いを併記していたりするところが、Ruby初学者じゃないけど初級者な自分にとって参考になった。
「喰いしん坊!」19巻
喰いワンGP決勝戦、ついに決着! そして舞台は世界に。
それはさておき、p.92の「未知の外国人」の描写があまりに昔のステロタイプすぎて、吹いた。
Rubyで文字列を桁数で切り詰める
メールや端末へ出力するときに、文字数でもバイト数でもなくて、桁数で文字列を切り詰めることがあります。というか最近ありました。先頭から60桁で切る、とか、固定幅テキストで表を表す、とかいう話です。
「桁数=バイト数」という前提が許されるのは昭和までですが、仲間うちのRuby on Railsアプリで桁数切りをやろうとして悩みました。
もっと簡単な方法がありそうな気がしますが、プログラミング初級者がハマったメモとして残しておきます。簡単な方法があったら教えてえらい人。
以下、Ruby 1.8+UTF-8環境での結果です。
うまくいかない例:正規表現とかprintfとか
正規表現の繰り返し制御は、$KCODEが'NONE'の場合はバイト数で、'u'の場合は文字数でマッチするみたいです。
irb(main):001:0> 'あいうえお'.sub(/^(.{3}).*/, '\1')
=> "\343\201\202"
irb(main):002:0> $KCODE='u'
=> "u"
irb(main):003:0> 'あいうえお'.sub(/^(.{3}).*/, '\1')
=> "あいう"
桁で切るために、一度EUCにして処理し、あとでUTF-8に戻すという方法も考えました。が、これだと、マルチバイト文字の途中に切れ目がある場合、文字の途中で切ってしまっておかしな結果になります。
irb(main):001:0> $KCODE = 'NONE'
=> "NONE"
irb(main):002:0> 'あお'
=> "\343\201\202\343\201\212"
irb(main):003:0> 'あお'.toeuc.sub(/^(.{3}).*/, '\1').toutf8
=> "\352\222\242"
ちなみに、sptintf(printf)や%演算子は、$KCODEにかかわらずバイト数で切るようです。
irb(main):001:0> printf '%.4s', 'あお' あ�=> nil
頭から数えて解決
いい方法が思いつかなかったので、文字列の頭から数を数える単純な方法でメソッドを作ってみました。
class String
def truncate_column(col)
count = 0
ary = []
self.split(//u).each {|c|
count += (c.size == 1 ? 1 : 2)
return ary.join('') if count > col
ary.push(c)
}
self
end
end
「半角カナ入力禁止」が許されるのも昭和までかもしれないので、いわゆる半角カナに対応してみます。
class String
def truncate_column(col)
count = 0
ary = []
self.split(//u).each {|c|
if (c.size == 1) ||
(/[。「」、・ヲァィゥェォャュョッーアイウエオカキクケコサシスセソタチツテトナニヌネノハヒフヘホマミムメモヤユヨラリルレロワン゙゚]/u =~ c)
count += 1
else
count += 2
end
return ary.join('') if count > col
ary.push(c)
}
self
end
end
日本語だけじゃなく
といっても、UTF-8でマルチバイトの文字は、半角カナだけじゃありません。そこで、UAX#11のEast Asian Width属性を参照して全角半角を決めてみます。
…えーと、こんなんなっちゃいました。
class String
RE_UAX11_H = Regexp.new("[#{[8361].pack('U')}
#{[65377].pack('U')}-#{[65500].pack('U')}
#{[65512].pack('U')}-#{[65518].pack('U')}]", Regexp::EXTENDED, 'u')
RE_UAX11_Na = Regexp.new("[#{[162].pack('U')}-#{[163].pack('U')}
#{[165].pack('U')}-#{[166].pack('U')}
#{[172].pack('U')}
#{[175].pack('U')}
#{[10214].pack('U')}-#{[10219].pack('U')}
#{[10629].pack('U')}-#{[10630].pack('U')}]", Regexp::EXTENDED, 'u')
RE_UAX11_N = Regexp.new("[#{[128].pack('U')}-#{[160].pack('U')}
#{[169].pack('U')}
#{[171].pack('U')}
#{[181].pack('U')}
#{[187].pack('U')}
#{[192].pack('U')}-#{[197].pack('U')}
#{[199].pack('U')}-#{[207].pack('U')}
#{[209].pack('U')}-#{[214].pack('U')}
#{[217].pack('U')}-#{[221].pack('U')}
#{[226].pack('U')}-#{[229].pack('U')}
#{[231].pack('U')}
#{[235].pack('U')}
#{[238].pack('U')}-#{[239].pack('U')}
#{[241].pack('U')}
#{[244].pack('U')}-#{[246].pack('U')}
#{[251].pack('U')}
#{[253].pack('U')}
#{[255].pack('U')}-#{[256].pack('U')}
#{[258].pack('U')}-#{[272].pack('U')}
#{[274].pack('U')}
#{[276].pack('U')}-#{[282].pack('U')}
#{[284].pack('U')}-#{[293].pack('U')}
#{[296].pack('U')}-#{[298].pack('U')}
#{[300].pack('U')}-#{[304].pack('U')}
#{[308].pack('U')}-#{[311].pack('U')}
#{[313].pack('U')}-#{[318].pack('U')}
#{[323].pack('U')}
#{[325].pack('U')}-#{[327].pack('U')}
#{[332].pack('U')}
#{[334].pack('U')}-#{[337].pack('U')}
#{[340].pack('U')}-#{[357].pack('U')}
#{[360].pack('U')}-#{[362].pack('U')}
#{[364].pack('U')}-#{[461].pack('U')}
#{[463].pack('U')}
#{[465].pack('U')}
#{[467].pack('U')}
#{[469].pack('U')}
#{[471].pack('U')}
#{[473].pack('U')}
#{[475].pack('U')}
#{[477].pack('U')}-#{[592].pack('U')}
#{[594].pack('U')}-#{[608].pack('U')}
#{[610].pack('U')}-#{[707].pack('U')}
#{[709].pack('U')}-#{[710].pack('U')}
#{[712].pack('U')}
#{[716].pack('U')}
#{[718].pack('U')}-#{[719].pack('U')}
#{[721].pack('U')}-#{[727].pack('U')}
#{[732].pack('U')}
#{[734].pack('U')}
#{[736].pack('U')}-#{[767].pack('U')}
#{[884].pack('U')}-#{[912].pack('U')}
#{[938].pack('U')}-#{[944].pack('U')}
#{[962].pack('U')}
#{[970].pack('U')}-#{[1024].pack('U')}
#{[1026].pack('U')}-#{[1039].pack('U')}
#{[1104].pack('U')}
#{[1106].pack('U')}-#{[4348].pack('U')}
#{[4448].pack('U')}-#{[8207].pack('U')}
#{[8209].pack('U')}-#{[8210].pack('U')}
#{[8215].pack('U')}
#{[8218].pack('U')}-#{[8219].pack('U')}
#{[8222].pack('U')}-#{[8223].pack('U')}
#{[8227].pack('U')}
#{[8232].pack('U')}-#{[8239].pack('U')}
#{[8241].pack('U')}
#{[8244].pack('U')}
#{[8246].pack('U')}-#{[8250].pack('U')}
#{[8252].pack('U')}-#{[8253].pack('U')}
#{[8255].pack('U')}-#{[8305].pack('U')}
#{[8309].pack('U')}-#{[8318].pack('U')}
#{[8320].pack('U')}
#{[8325].pack('U')}-#{[8360].pack('U')}
#{[8362].pack('U')}-#{[8363].pack('U')}
#{[8365].pack('U')}-#{[8450].pack('U')}
#{[8452].pack('U')}
#{[8454].pack('U')}-#{[8456].pack('U')}
#{[8458].pack('U')}-#{[8466].pack('U')}
#{[8468].pack('U')}-#{[8469].pack('U')}
#{[8471].pack('U')}-#{[8480].pack('U')}
#{[8483].pack('U')}-#{[8485].pack('U')}
#{[8487].pack('U')}-#{[8490].pack('U')}
#{[8492].pack('U')}-#{[8526].pack('U')}
#{[8533].pack('U')}-#{[8538].pack('U')}
#{[8543].pack('U')}
#{[8556].pack('U')}-#{[8559].pack('U')}
#{[8570].pack('U')}-#{[8580].pack('U')}
#{[8602].pack('U')}-#{[8631].pack('U')}
#{[8634].pack('U')}-#{[8657].pack('U')}
#{[8659].pack('U')}
#{[8661].pack('U')}-#{[8678].pack('U')}
#{[8680].pack('U')}-#{[8703].pack('U')}
#{[8705].pack('U')}
#{[8708].pack('U')}-#{[8710].pack('U')}
#{[8713].pack('U')}-#{[8714].pack('U')}
#{[8716].pack('U')}-#{[8718].pack('U')}
#{[8720].pack('U')}
#{[8722].pack('U')}-#{[8724].pack('U')}
#{[8726].pack('U')}-#{[8729].pack('U')}
#{[8731].pack('U')}-#{[8732].pack('U')}
#{[8737].pack('U')}-#{[8738].pack('U')}
#{[8740].pack('U')}
#{[8742].pack('U')}
#{[8749].pack('U')}
#{[8751].pack('U')}-#{[8755].pack('U')}
#{[8760].pack('U')}-#{[8763].pack('U')}
#{[8766].pack('U')}-#{[8775].pack('U')}
#{[8777].pack('U')}-#{[8779].pack('U')}
#{[8781].pack('U')}-#{[8785].pack('U')}
#{[8787].pack('U')}-#{[8799].pack('U')}
#{[8802].pack('U')}-#{[8803].pack('U')}
#{[8808].pack('U')}-#{[8809].pack('U')}
#{[8812].pack('U')}-#{[8813].pack('U')}
#{[8816].pack('U')}-#{[8833].pack('U')}
#{[8836].pack('U')}-#{[8837].pack('U')}
#{[8840].pack('U')}-#{[8852].pack('U')}
#{[8854].pack('U')}-#{[8856].pack('U')}
#{[8858].pack('U')}-#{[8868].pack('U')}
#{[8870].pack('U')}-#{[8894].pack('U')}
#{[8896].pack('U')}-#{[8977].pack('U')}
#{[8979].pack('U')}-#{[9000].pack('U')}
#{[9003].pack('U')}-#{[9290].pack('U')}
#{[9450].pack('U')}
#{[9548].pack('U')}-#{[9551].pack('U')}
#{[9588].pack('U')}-#{[9599].pack('U')}
#{[9616].pack('U')}-#{[9617].pack('U')}
#{[9622].pack('U')}-#{[9631].pack('U')}
#{[9634].pack('U')}
#{[9642].pack('U')}-#{[9649].pack('U')}
#{[9652].pack('U')}-#{[9653].pack('U')}
#{[9656].pack('U')}-#{[9659].pack('U')}
#{[9662].pack('U')}-#{[9663].pack('U')}
#{[9666].pack('U')}-#{[9669].pack('U')}
#{[9673].pack('U')}-#{[9674].pack('U')}
#{[9676].pack('U')}-#{[9677].pack('U')}
#{[9682].pack('U')}-#{[9697].pack('U')}
#{[9702].pack('U')}-#{[9710].pack('U')}
#{[9712].pack('U')}-#{[9732].pack('U')}
#{[9735].pack('U')}-#{[9736].pack('U')}
#{[9738].pack('U')}-#{[9741].pack('U')}
#{[9744].pack('U')}-#{[9747].pack('U')}
#{[9750].pack('U')}-#{[9755].pack('U')}
#{[9757].pack('U')}
#{[9759].pack('U')}-#{[9791].pack('U')}
#{[9793].pack('U')}
#{[9795].pack('U')}-#{[9823].pack('U')}
#{[9826].pack('U')}
#{[9830].pack('U')}
#{[9835].pack('U')}
#{[9838].pack('U')}
#{[9840].pack('U')}-#{[10044].pack('U')}
#{[10046].pack('U')}-#{[10101].pack('U')}
#{[10112].pack('U')}-#{[10213].pack('U')}
#{[10224].pack('U')}-#{[10628].pack('U')}
#{[10631].pack('U')}-#{[11805].pack('U')}
#{[12351].pack('U')}
#{[19904].pack('U')}-#{[19967].pack('U')}
#{[42752].pack('U')}-#{[43127].pack('U')}
#{[55296].pack('U')}-#{[56320].pack('U')}
#{[64256].pack('U')}-#{[65021].pack('U')}
#{[65056].pack('U')}-#{[65059].pack('U')}
#{[65136].pack('U')}-#{[65279].pack('U')}
#{[65529].pack('U')}-#{[65532].pack('U')}
#{[65536].pack('U')}-#{[120831].pack('U')}
#{[917505].pack('U')}-#{[917631].pack('U')}]", Regexp::EXTENDED, 'u')
def truncate_column(col)
count = 0
ary = []
self.split(//u).each {|c|
if (c.size == 1) ||
(RE_UAX11_H =~ c) || (RE_UAX11_Na =~ c) || (RE_UAX11_N =~ c)
count += 1
else
count += 2
end
return ary.join('') if count > col
ary.push(c)
}
self
end
end
ちなみに定数部分は、こんなやっつけRubyスクリプトで生成しました。
#!/usr/bin/ruby -Ku
PROTOTYPES = %w{ A F H N Na W }
HALF_PROTOTYPES = %w{ H Na N }
h = {}
PROTOTYPES.each {|e| h[e] = [] }
current = nil
start_n = end_n = nil
open('EastAsianWidth.txt') {|f|
f.each {|line|
next if /^#/ =~ line || /^$/ =~ line
code, prop = line.chomp.sub(/ .*/, '').split(/;/)
code.gsub!(/[\dA-F]+\.\.(\dA-F)/, '\1')
code_n = code.hex
next if code_n < 0x80
if (current == prop)
end_n = code_n
else
if current
h[current].push(
if start_n == end_n
"\#{[#{start_n}].pack('U')}"
else
"\#{[#{start_n}].pack('U')}-\#{[#{end_n}].pack('U')}"
end
)
end
start_n = end_n = code_n
current = prop
end
}
}
HALF_PROTOTYPES.each {|e| puts " RE_UAX11_#{e} = Regexp.new(\"[#{h[e].join("\n ")}]\", Regexp::EXTENDED, 'u')" }
別解
nkfを使う方法も考えたんですが、半角カナが2桁になっちゃうんですよね。
#!/usr/bin/ruby -Ku
require 'nkf'
class String
def truncate_column(col)
NKF.nkf("-F#{col} -Ww -x", self).sub(/\n.*/m, '')
end
end
puts 'あアaあ'.truncate_column(4)
修正2008-06-19: 誤ってEast Asian Width属性のA・H・Naを半角扱いするコードになっていたので、H・Na・Nに修正。
「Q.E.D.」30巻
初期のころから「殺人事件に限らない本格ミステリマンガ」という評判があったけど、今回は帯に「今度の事件は殺人ではない、殺人!?」と。まぁ、殺人もあるけど。
「人形殺人」は、人形が刺されていた事件に始まる連続事件。印象によるミスリーディングにやられた。
「犬の茶碗」は、詐欺師を騙し返そうというコンゲームもの。というネタは最近いろいろあるけど、さすがミステリマンガの第一人者、かけひきがみごとに決まった。伏線もはまってる。



