君の瞳はまるでルビー - Ruby 関連まとめサイト

Ruby 1.8/1.9/2.0 系の違い

最終更新: 2015-03-31 (火) 21:53:21 (814d)

僕がつまずいた Ruby 1.8/1.9/2.0 系の環境の差異をまとめていきます。

概要

具体的な内容に言及する前に体感(≒経験則)をまずざっと書きます。

  • Ruby 1.8 と 1.9 の差異
    • 最も大きいのは「多言語化(M17N)対応」の有無である。
      • マルチバイト文字列の扱いに互換性がない。
      • そのため対応を考慮せず書いたプログラムは、片方のバージョンでしか動かない。
      • Ruby 1.8 から 1.9 への移行、その逆、もしくは両バージョンのサポートをするには対応がほぼ必須*1といえる。
  • Ruby 1.9 と 2.0 の差異
    • 1.9 から 2.0 への移行は簡単である。
    • 2.0 は 1.9 との互換性を強く意識しており、基盤の改良*2と機能追加が中心であるという認識である。
    • 自分が開発しているプログラムに関して言うと 1.9 から 2.0 への移行に際して書き換えは一切不要であった。
    • 一部、Ruby 1.8 と 1.9 の互換性を維持するためのに残してきた機能の削除があり、2.0 への移行時の発生した問題の多くは、本来 1.9 移行時に必要だった対応を先延ばししてきた結果と考えた方が妥当であり、Ruby 2.0 自体が原因ではないと考える。
    • 2.0 で追加された新機能を使うのであれば 2.0 以降が必須になるためその旨をはっきりと名言する必要がある。
    • そのため 1.9 を視野にいれるならば、2.0 で追加された新機能の利用はオプションとするか避けるべきと考える。
    • ただし、それ以上過敏になる必要はなさそう。

Ruby 1.8 の寿命について

既に以下のようなアナウンスが出ており、今後、1.8 系の利用は推奨されないという前提を踏まえた上で必要があればという意味合いで情報をまとめています。

ライブラリ/ツールの開発者は、どこまで 1.8 系をサポートするべきか選択が迫られている時期に来ていることを自覚する必要があります。

必要に応じて差異を埋める方法を検討していますが、いずれの差異に関しても Ruby 1.8 系をサポート対象から除外するという選択肢があります。

<<目次>>

検証環境

OSWindows 7(64bit)
RubyMRI(RubyInstaller for Windows)

構文

メソッド呼び出し前の改行

Ruby 1.8 系では以下が構文エラーになる。

object
  .method()

Ruby 1.9/2.0 系では動作する。

オプションパラメータのハッシュ指定

Ruby 1.8 系では以下が構文エラーになる。

def function1(*args)
  p args
end

function1(
  :value1 => 1,
  :value1 => 2,
  :value1 => 3,  # 最後のカンマが構文エラー
)

Ruby 1.9/2.0 系では動作する。

組み込みライブラリ

Kernel

require メソッド

  • 標準の検索パスに違いがある。
  • 複数回ロードの判定に違いが存在する。
    • Ruby 1.8 系では同一のファイルであっても、パスの文字列が異なれば別ファイルとみなしてロードする。
    • 例えば絶対パス指定と検索パスからの相対パス指定の両方を行った場合、異なるものと見なされ、それぞれごとにロードされる。
    • 具体的な弊害事例
      • 定数を定義している場合に重複定義の警告が出る。
      • クラス変数などの操作に関して、定義読み込み時に1度しか行わないと想定した処理に不具合が生じる。
    • Ruby 1.8/1.9/2.0 ともに同じように動かすには?
      • 絶対パス指定と相対パス指定(異なる起点からの相対パスも含む)を混在しないこと。

標準出力/標準エラー出力

コンソールへの文字列出力のエンコードの動きに違いがあります。

  • Ruby 1.8 系
    • Shift_JIS で出力しないと Windows のコマンドラインで文字化けが発生する。
  • Ruby 1.9 系(1.9.3 の中のどこかのバージョンで変わったという記憶がある)
    • 出力時に自動でコンソール用の文字コード(Shift_JIS)に変換して出力してくれる。
  • Ruby 2.0 系
    • 1.9 系同様、文字コードを認識し、変換して出力してくれる。

String

多言語化(M17N)対応

主観ですが、これが Ruby 1.8 と Ruby 1.9 の一番の大きな違いであり、一番大きな壁だと思います。

  • Ruby 1.8 は多言語化(M17N)に対応していない。
  • Ruby 1.9 は多言語化(M17N)に対応している。

多言語化対応の違いによって以下のような違いがあります。

  • Ruby 1.8 系
    • 文字コードはグローバルな変数($KCODE)によって制御される。
      • 従って、ある瞬間、システム内で利用される文字コードは単一のものに限られる。
    • 文字コードの変換を行うには外部のライブラリを使う必要がある。
      • 標準添付ライブラリに「文字コード」用のライブラリがいくつかあるので、通常はそれらを使うことになる。
    • 文字コードとして正しくないバイト列でも許容される
    • String#[] や String#[]= はバイト単位の処理である。
  • Ruby 1.9 系
    • 文字コードはインスタンス毎に識別される。
      • encoding メソッドでインスタンス毎の文字コードがわかる。
    • 標準で文字コードの変換を行う encode メソッドが存在する。
    • 文字コードとして正しくないバイト列は許容されず、うまく対処しないと例外が発生する
    • String#[] や String#[]= は文字単位の処理である。

以下、主観的なバージョン毎に感じる長所と短所です。

  • Ruby 1.8 系
    • 長所
      • 文字コードの扱いが緩く、例外が発生しにくく、とりあえず動く。
    • 短所
      • 文字コードの変換が面倒である。
  • Ruby 1.9 系
    • 長所
      • 文字コードの変換が簡単で、細かい扱いができる。
    • 短所
      • うまく処理しないと、文字コード関連の例外のオンパレードに悩まされる。

一度 Ruby 1.9 の便利さになれてしまうと Ruby 1.8 には戻れないと思います。ただし、それは新規の話であり、既存のシステムの移行やライブラリのサポートは大変でしょう。

Hash

each 系メソッド

  • Ruby 1.9 系の each は設定順にキー/値を取り出すが、Ruby 1.8 系の each は設定順とは全く異なる。Ruby 1.8 系の Hash のドキュメントに「列挙する順序は不定です。」とハッキリ書いてあります。
  • 1.8/1.9 ともに同じように動かすには?
    • keys.sort を利用して順序の保証を自分で行う。
    • Hash ではなく Array を使う。
    • そもそも順序に依存する処理は書かない。
    • などなど。

to_s メソッド

  • Ruby 1.8 と 1.9 では読みやすさが異なる。

以下事例です。

puts {"key1" => "value1", "key2" => "value2", "key3" => "value3"}

# ruby 1.8 系の場合の出力結果
key3value3key2value2key1value1

# ruby 1.9 系の場合の出力結果
{"key1"=>"value1", "key2"=>"value2", "key3"=>"value3"}
  • Ruby 1.8 の出力フォーマットにはキー/値の全てに区切りが無い。
  • each 系メソッドで触れている通り、出力順序も設定順とは異なる。

assoc/rassoc メソッド

  • Ruby 1.8 には存在しない。

Dir

exist? メソッド

  • Ruby 1.8 には存在しない。
  • 1.8/1.9 ともに同じように動かすには?
    • 代替として File.directory? を使う。

Mutex

  • 1.8 系では組み込みライブラリに Mutex クラスは存在せず、標準添付ライブラリの thread に存在する。
  • 1.8/1.9 ともに同じように動かすには?
    • require 'thread' を必ず行う。

標準添付ライブラリ

csv

  • インターフェイスに互換性がない。

Time

parse メソッド

  • 解析対象が日時を示していなかった場合の動作が違う。
    • Ruby 1.8 系
      • Time.now が返ってくる。
    • Ruby 1.9 系
      • ArgumentError が発生する。

例えば以下のような事例を実行した場合です。

require 'time'

puts Time.parse("abcdef")
  • Ruby 1.8/1.9 ともに同じように動かすには?
    • 未検討。

コメント

本ページの内容に関して何かコメントがある方は、以下に記入してください。

最新の10件を表示しています。 コメントページを参照

  • 2.0の情報も期待します。Matzも1.9はいずれサポートしないというスピーチをしていたので。 -- 初心者 2013-03-14 (木) 14:56:33
  • 2.0 ももうそろそろ使いはじめるので、もちろんそこで発見した差異についても順次追記していこうと思っています。 -- トゥイー 2013-03-14 (木) 20:03:47
  • assoc/rassoc メソッドのリンクが to_s になってます。訂正願います。 -- riocampos 2013-07-02 (火) 01:36:56
  • 指摘ありがとうございます。気付けてよかったです。修正しました。 -- トゥイー 2013-07-03 (水) 08:06:18
お名前: