Ruby
プロを目指す人のためのRuby入門

Ruby 2.6で発生する「プロを目指す人のためのRuby入門」との差異について

はじめに

2018年12月25日に、Rubyの新しいバージョンであるRuby 2.6がリリースされました。
一方、昨年の11月に出版した書籍「プロを目指す人のためのRuby入門」(通称・チェリー本。以下、本書)は執筆当時最新だったRuby 2.4.1を対象にしています。

本書は紙の本であるため、簡単に内容をアップデートすることができません。しかし、何もしないとどんどん内容が古くなってしまい、「本の通りやってみたけど、今使っているRubyとなんか動きが違う」ということになってしまいます。

そこで新しいRubyのバージョンがリリースされて、本書の説明と異なる部分が出てきたときは、毎回ネット上でその差異を説明するようにしています。その説明を読めば、動きが違う部分があってもきっと落ち着いて対処できるはず、という算段です。

というわけで、この記事ではRuby 2.6で発生する「プロを目指す人のためのRuby入門」との差異(以下の4点)について説明します。

  • 範囲(Range)リテラルで終端の値を省略できるようになった(4.5)
  • rescue節のないelse節を書くと構文エラーになる(9.6.3)
  • 二重に例外が発生した場合に、元の例外(cause)も詳細に出力される(第9章のコラム)
  • Bundlerが標準ライブラリに取り込まれた(12.8.2)

なお、上記のリストや本文に出てくる章番号や項番号は、書籍の中で使われている番号です。

参考: もう読みましたか?Ruby 2.5の差異はこちら

一つ前のバージョンであるRuby 2.5で発生する差異については以下の記事にまとめてあります。

Ruby 2.5で発生する「プロを目指す人のためのRuby入門」との差異について - Qiita

上記の記事と重複する内容はこの記事では説明しません。
ですので、まだ読まれていない方は先に上の記事を読んでから、この記事に戻ってくることをお勧めします。

それでは以下が本編です。

範囲(Range)リテラルで終端の値を省略できるようになった(4.5)

Ruby 2.6では範囲(Range)リテラルで終端の値を省略できるようになりました。

# Ruby 2.6では以下のように、終端を省略することが可能
r1 = (1..)  #=> 1..
r2 = (2...) #=> 2...

たとえば次のように書くと、文字列の3文字目から最後までを抜き出すことができます。

"abcde"[2..] #=> "cde"

また、これは参考情報ですが、Ruby 2.5以前では終端に-1を指定することで上のコードと同じことが実現できます(この内容は本書未掲載)。

# Ruby 2.5以前の書き方
"abcde"[2..-1] #=> "cde"

rescue節のないelse節を書くと構文エラーになる(9.6.3)

Ruby 2.6では次のように、例外処理としてrescue節のないelse節を書くと構文エラーになります。

# Ruby 2.6では構文エラー
begin
  1 / 0
else
  # do something
end
#=> SyntaxError (else without rescue is useless)

とはいえ、このような例外処理は意味がない(エラーメッセージにもあるとおりuseless)ですし、例外処理のelse節自体が滅多に使われない機能であるため、この変更点についてはちょっと頭の片隅に置いておくだけで十分だと思います。
(本書でも上のようなコード例は登場していません。)

二重に例外が発生した場合に、元の例外(cause)も詳細に出力される(第9章のコラム)

本書359ページに掲載した「二重に例外を発生させないようにしよう」というコラムの中で、以下のようなサンプルコードを使って二重に例外が発生した場合の挙動について説明しました。

def some_method
  1 / 0
rescue => e
  # messageと書くつもりがmesageと書いてしまった
  puts "エラーが発生しました: #{e.mesage}"
  puts e.backtrace
end

some_method

上記のコードをファイルに保存して実行すると、Ruby 2.5では以下のようにe.mesageのタイプミス(NoMethodError)だけが詳しく出力されていました。

$ ruby sample.rb
Traceback (most recent call last):
    2: from sample.rb:9:in `<main>'
    1: from sample.rb:1:in `some_method'
sample.rb:5:in `rescue in some_method': undefined method `mesage' for #<ZeroDivisionError: divided by 0> (NoMethodError)
Did you mean?  message

しかし、Ruby 2.6ではタイプミスの部分だけでなく、元の例外(ここではZeroDivisionError)に関する詳細情報も一緒に出力されます。

$ ruby sample.rb       
Traceback (most recent call last):
    2: from sample.rb:9:in `<main>'
    1: from sample.rb:2:in `some_method'
sample.rb:2:in `/': divided by 0 (ZeroDivisionError)
    2: from sample.rb:9:in `<main>'
    1: from sample.rb:1:in `some_method'
sample.rb:5:in `rescue in some_method': undefined method `mesage' for #<ZeroDivisionError: divided by 0> (NoMethodError)
Did you mean?  message

これはコラムの後半で説明した、causeメソッドを使った元の例外情報出力と、やっている内容はほぼ同じです。
(つまり、自分でわざわざコードを書かなくてもRubyが同じことをやってくれるようになりました!)

ただし、この詳細情報を自動的に得るためには「一番外側の例外がまったくrescueされないこと」という条件があります。
irbでは発生した例外が内部的にrescueされているためなのか、Ruby 2.5と同じような出力結果になります。

参考までに、先ほどのサンプルコードをRuby 2.6のirbで実行した場合の実行結果を載せておきます。

> def some_method
>   1 / 0
> rescue => e
>   puts "エラーが発生しました: #{e.mesage}"
>   puts e.backtrace
> end
> 
> some_method

Traceback (most recent call last):
        6: from /Users/jnito/.rbenv/versions/2.6.0-rc1/bin/irb:23:in `<main>'
        5: from /Users/jnito/.rbenv/versions/2.6.0-rc1/bin/irb:23:in `load'
        4: from /Users/jnito/.rbenv/versions/2.6.0-rc1/lib/ruby/gems/2.6.0/gems/irb-0.9.6/exe/irb:11:in `<top (required)>'
        3: from (irb):8
        2: from (irb):1:in `some_method'
        1: from (irb):4:in `rescue in some_method'
NoMethodError (undefined method `mesage' for #<ZeroDivisionError: divided by 0>)
Did you mean?  message

Bundlerが標準ライブラリに取り込まれた(12.8.2)

12.8.2項ではBundlerを使うために、gem install bundler のようなコマンドでBundlerをインストールする必要があると書きました。ですが、Ruby 2.6ではBundlerが標準ライブラリとして取り込まれているため、別途インストールする必要がありません。

# Ruby 2.6ではBundlerがインストール済み
$ bundle --version
Bundler version 1.17.2

なお、本書ではBundler 1.15.1を対象にしていましたが、Ruby 2.6では1.17.2がインストールされます。Bundlerのバージョンが異なるため、bundle init後に作成されるGemfileの内容が若干異なります。
ですが、Gemfileの編集方法やbundler関連の実行コマンド等はとくに変わらないため、そのまま本書の内容を読み進めてもらって大丈夫です。

その他、注目の新機能など

特筆すべき差異は上記の4点ですが、その他にもRuby 2.6では数多くの新機能や変更点が導入されています。
その中から「プロを目指す人のためのRuby入門」と関連が深そうなポイントを以下にピックアップしておきます。

  • [配列] select/select!のエイリアスメソッドとしてfilter/filter!が追加された(4.4.2に関連)
  • [配列] 和集合と差集合を返すunion/differenceメソッド(4.7.4に関連)
  • [配列や範囲] 繰り返し可能なオブジェクトを連鎖できるEnumerable#chain、Enumerator#+(4.7.8に関連)
  • [文字列] splitメソッドがブロックを受け取れるようになった(4.7.11に関連)
  • [ハッシュ] merge/merge!/updateメソッドに複数のハッシュを渡せるようになった(5.6.2に関連)
  • [配列やハッシュ] to_hメソッドでブロックを受け取れるようになった(5.6.7に関連)

それぞれの詳細については(そしてそれ以外の新機能や変更点についても!)、下記の記事で詳しく説明しているのでこちらをご覧ください。

サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita

まとめ:Ruby 2.6の時代でもチェリー本はまだまだ現役!(当社調べ)

というわけで、この記事ではRuby 2.6で発生する「プロを目指す人のためのRuby入門」との差異をまとめました。

著者である僕自身が言うのも変かもしれませんが、Ruby 2.6の時代になっても「プロを目指す人のためのRuby入門」の内容はまだまだ現役だと確信しました!

この記事と、去年執筆した「Ruby 2.5との差異」の記事に目を通せば、それだけでお手持ちのチェリー本を「Ruby 2.6対応版」にアップデートすることが可能です💪(注:みなさんの脳内で)

Rubyは毎年12月25日にアップデートされるので、年が経つごとに本書の対象バージョンである2.4.1との「数字上の差」は開いていってしまいますが、本書で説明した大部分の内容はRuby 2.6でも有効です。ですので、読者のみなさんはどうぞご安心ください。

そして、まだ「プロを目指す人のためのRuby入門」を読まれていない方は、お近くの書店やAmazonで一度手に取っていただけると幸いです。
みなさん、どうぞよろしくお願いします😄

プロを目指す人のためのRuby入門|技術評論社
9784774193977.jpg