本稿では Ruby 2.0.0 の注意点や、他の特筆するべき機能追加についてまとめています。
なお、公式には NEWS ファイルに変更点がまとまっていることになっています。
書いた人:naruse
Magic Comment を書いていないファイルの文字列リテラルのエンコーディング (default script encoding) が UTF-8 に変更されました。[#6679]
Ruby 1.9 においては、default script encoding は US-ASCII でした。しかし、以下のようなメリット・デメリットを考えた結果、上記の通り UTF-8 へと変更することになりました。
典型的には、Magic Comment を書いていないコードでバイナリをエスケープを使いながらソースコードに埋め込んでいる場合にはこの変更によって問題が発生する可能性があります。この場合、Magic Comment を明示的に書くようにするか、[#6767] で追加された String#b を用いて、ASCII-8BIT へと明示的に変更してください。
拡張ライブラリ iconv が削除されました。[#6322]
今後は String#encode や Encoding::Converter、あるいはどうしても iconv が必要な場合は iconv.gem を用いてください。
1.8 時代にはお世話になったオプション、-K を指定した場合、-w をつけているときには警告を表示するようになりました。
書いた人:yhara
String クラスには、文字列に対して列挙を行う each_line、each_char、each_byte、each_codepoint というメソッドがあり、それらと同じ動作をする lines、chars、bytes、codepoints メソッドがありました。
Ruby 2.0.0 ではこれらのうち、lines、chars、bytes、codepoints の方が Enumerator ではなく配列を返すようになりました。このため、1.9 で
のように書いていたプログラムが、2.0 では
のように to_a なしで書けるようになりました。
一方、この影響で、
のようなプログラムがエラーになるようになりました。配列には with_index メソッドがないからですね。この場合は、以下のように each_char の方を使用してください。
なお IO、StringIO、ARGF にも同名のメソッドがありますが、2.0.0 では IO#bytes 等は deprecated になり、使うと warning が表示されるようになりました。 IO#bytes の返り値の型が String#bytes と異なるのは気持ち悪いけど、かといってファイル全体を配列化したいケースはあまりなさそうなので 1、IO の方は deprecated にしようという判断がされました。2 3
この場合も bytes ではなく each_byte の方を使うことが推奨されています。
関連チケット:http://bugs.ruby-lang.org/issues/6670
書いた人:ささだ
inspect を定義していないクラスでは、to_s が使われていましたが、2.0.0 か ら Object#inspect が使われることになりました。
従来のように inspect を使いたければ、明示的に inspect が to_s を使うよう に定義するようにしましょう。
書いた人: ささだ
Integer (Fixnum, Bignum) と Float オブジェクトが必ず freeze されるようになりました。多分、無いと思いますが、これらの数値オブジェクトにインスタンス変数や特異メソッドなどを追加するプログラムは動かなくなりました。そのようなプログラムは窓から外に放り出しましょう。
関連チケット:http://bugs.ruby-lang.org/issues/3222, http://bugs.ruby-lang.org/issues/6936
書いた人:ささだ
シンボルの配列 [:a, :b, :c] を、%i(a b c) のように省略して書けるようになりました。
%w (文字列展開しない) 、%W (文字列展開する) に対応して、%i (文字列展開しない) 、%I (文字列展開する) があります。
書いた人:ささだ
Module#include に似た、Module#prepend という機能が追加されました。Module#include と異なり、prepend するクラス (モジュール) よりもメソッド探索順序を前にもってくる仕組みになります。
詳しくは、下記に記事をまとめてみたのでご覧下さい。
書いた人:yhara
Enumerable に size というメソッドが追加されました。Enumerable なオブジェクトの要素の個数を返すメソッドには count がありますが、count は個数だけ知りたいときでも要素をすべて列挙してしまうという欠点がありました。
size は Enumerable を include している各クラスで適切にオーバーライドされていて、要素をすべて列挙することなしに個数を教えてくれます。例えば、Ruby 2.0 では「1000 個の中から 3 個を選ぶ組み合わせの数」の計算を
のように書けるようになりました (count を使うと長さ 166167000 の配列をメモリ上に確保しようとするため、とても長い時間がかかってしまいます) 。
なお、個数が事前に分からないようなケースでは、size は nil を返します。たとえば「ファイルの中の行の数」はファイルを全部読むまで分からないため、
は nil を表示します。
関連チケット:https://bugs.ruby-lang.org/issues/6636
書いた人:yhara
Ruby には to_a や to_s という、オブジェクトを配列や文字列に変換する一連のメソッドがあります。Ruby 2.0 ではこれに to_h という、オブジェクトをハッシュに変換するメソッドが加わりました。
具体的には、Struct、OpenStruct、ENV を to_h でハッシュに変換できるようになっています。またコーナーケースとして、Hash は to_h で self をそのまま返します。nil は to_h で空のハッシュ ({}) を返します。4
これから書くプログラムでは、オブジェクトのハッシュとしての表現を返すようなメソッドは to_h という名前をつけると良いでしょう。
書いた人:ささだ
File.dirname(FILE) と同じようなことができる Kernel#dir メソッドが追加されました。dir だけでそのファイルのディレクトリ名が取得できます。
書いた人: nari
Array#bsearch というメソッドが追加されました5。このメソッドでは、ソートされた配列6について、指定した条件の要素をバイナリサーチを利用して見つけます。プログラミングコンテストなどの機会に自前で bsearch を実装しなくて済むので、個人的にはかなり嬉しい機能です。
まず、例を示します。下記の例はすべて Ruby 本体の RDoc から引用しています。
bsearch はブロックの引数に配列内の任意の要素が渡され、ブロックは true/false のいずれかを返す必要があります。そして、それぞれ以下のような振る舞いをします。
例もあわせて説明を読むと、なんとなく理解できそうですね。
さて、実は bsearch は二つのモードがあり、ここまでは find-minimum というモードについてのみ説明してきました。 ここからは二つ目のモードである find-any モードについても説明していきます。
それぞれのモードはブロックの返り値の種類のよって切り替わります。 ブロックで true/false を返す場合は find-minimum モードで動き、数値を返す場合は二つ目の find-any モードで動きます。
find-any モードは、条件に合致する範囲(i…j)にある、任意の要素を見つける機能です。ブロックが返す数値によって以下のような振る舞いになります。
例もあわせて読むとなんとなくわかりそうな感じですね! ちなみに find-any モードは libc の bsearch(3) を参考にしているそうです。
書いた人:ささだ
Thread#[] によって、スレッドローカル変数(スレッド間で共有する変数)を扱うことができましたが、Fiber を切り替えると無効になってしまうと言う問題がありました (これらの値を Fiber ローカル変数と言うことにします)。
そこで新しく、Fiber を切り替えても共通で使えるスレッドローカル変数を扱うための API が次のように用意されました。
殆どのケースでは、Thread#[] によって操作する、Fiber 間で独立した Fiber ローカル変数を利用すると良いと思いますが、時々この新しい API が必要になるかもしれません。注意して使って下さい。
書いた人:ささだ
スレッドおよびファイバが利用する VM およびマシンスタックのサイズが環境変数でそれぞれ指定できるようになりました。
デフォルトのスタックサイズも大きくなっています。普通に使う分にはあまり気にしなくても良いと思います。
この記事も参考にして下さい:Ruby VM アドベントカレンダー #21 VM のスタックサイズチューニング
書いた人:ささだ
Ruby 2.0.0 から、いくつかのデバッグ機能が追加されました。
などなどです。詳しくは今号の YARV Maniacs 【第 11 回】 最近の YARV の事情 (から参照されている Ruby VM アドベントカレンダー)をご参照下さい。
いちばんありそうなのは行の列にする場合ですが、この用途には IO#readlines という昔からあるメソッドが存在します。 ↩
knu さんは、将来 Enumerable とインデックスアクセスの機能を併せ持つ LazyArray のようなクラスを返り値にすることを考えているようです。 ↩
評判がすごく悪ければ、2.0.1 で元に戻ることはあるかも知れません :-p ↩
これによって、opts[:foo] が nil かどうかを気にせずに hash = opts[:foo].to_h のように書けるわけですね。 ↩
ちなみに Range#bsearch もあってそっちも似たような感じ。 ↩
バイナリサーチ (二分探索) は配列がソートされていることを前提に行う探索アルゴリズムなので、配列がソートされていない場合の動作は未定義です。 ↩