Ruby2.3.0 の新機能

Ruby 2.3.0 リリース

まずはInstall

$ brew update
$ brew upgrade ruby-build

$ RUBY_CONFIGURE_OPTS="--enable-shared                                                                                                                                         
--with-readline-dir=`brew --prefix readline`
--with-openssl-dir=`brew --prefix openssl`
--with-libyaml-dir=`brew --prefix libyaml`" \
rbenv install 2.3.0

$ rbenv global 2.3.0

$ ruby --version
ruby 2.3.0p0 (2015-12-25 revision 53290) [x86_64-darwin15]

追加機能

Frozen String Literal プラグマ

公式ブログにはmagic commentの内容が記載されていないので補足。

# frozen_string_literal: true

のような magic comment および --enable-frozen-string-literal という引数を使用することで、デフォルトString リテラルを freeze してくれる。
 
irbでやるとこんな感じ。

str = 'abcde'
str.gsub!('a', 'x')
=> "xbcde"

# frozen_string_literal: true
str = 'abcde'
str.gsub!('a', 'x')
RuntimeError: can't modify frozen String
  from (irb):5:in `gsub!'
    from (irb):5
    from /Users/rochefort/.rbenv/versions/2.3.0/bin/irb:11:in `<main>'

 
エラー時は、"can't modify frozen String" で特定できて分かりやすいです。

$ cat -n replace.rb
     1 # frozen_string_literal: true
     2 def replace(str)
     3   str.gsub!('a', 'x')
     4 end
     5 str = 'abcde'
     6 replace(str)
     7

$ ruby replace.rb
replace.rb:3:in `gsub!': can't modify frozen String (RuntimeError)
  from replace.rb:3:in `replace'
  from replace.rb:6:in `<main>'

所感

私自身文字列リテラルにミュータブルを期待した使い方を時々します。
gsub!, tr! も使いますし、objectの生成が抑えれるのでloopの中で << を使ったりします。
どう対応するかというと、dup 使ってミュータブルにしたり、magic commentでfalseにするという対応が必要とのこと。
まぁ、頻度でいうと、ミュータブルを期待していることの方が少ないとは思いますが、
この対応を入れるのは気乗りしません。
 
背景としては、Ruby2.2以前では文字列リテラルを使う時に、毎回オブジェクトを生成していて
GCの対象となりパフォーマンスに影響があったようです。
また、Ruby2.1以降、String#freeze を使用すると、同一オブジェクトを使用するような最適化が入るようになりました。
freeze入れると早くなるようになったため、Rails界隈でそういったPRが沢山出てきたそうです。
確かにこれはuglyなので、今回のmagic commentの対応というのは、頷けます。
しかし、Ruby3.0では、文字列リテラルはデフォルトfrozenになるそうで(正式にどうなるかは分かりませんが)、
そうなると正直そこまで困らないにしても、ミュータルブルを期待するケースでは嬉しくないなぁとうのが実感です。
他にも、String#new 時はミュータブルにする案なども検討されているようです。
ちょっと前のRebuildでこの辺りについてお話しされていました。
詳しくは、Rebuild: 118: The Lonely Operator (Matz, a_matsuda) 00:34:08 ぐらいから。

safe navigation operator

通称lonely operator(ボッチoperator)。
active supportの try! と同じ機能。
今後は、基本ボッチを使えばok。

obj = nil
obj&.foo
=> nil

obj = false
obj&.foo
NoMethodError: undefined method `foo' for false:FalseClass

ちなみにactive_supportは以下。

require 'active_support'
require 'active_support/core_ext'
# try
obj = nil
obj.try(:foo)
=> nil

obj = false
obj.try(:foo)

# try!
obj = nil
obj.try!(:foo)

obj = false
obj.try!(:foo)

所感

これは良いですね。
try と try! の違いは、reciverがnil以外の時に nilを返すか、NoMethodError を返すかです。
try は問題点があり、単なるmethod typo時に気づかないケースがありました。そのため、try! が推奨されていたようです。(知らんかった)
詳しくは、Rebuild: 118: The Lonely Operator (Matz, a_matsuda) 00:26:44 ぐらいから。

did_you_mean

yuki24/did_you_mean がバンドルされました。

>> mthosd
NameError: undefined local variable or method `mthosd' for main:Object
Did you mean?  methods
               method

これは、便利。どう実装されているのか気になります。

その他、細かいところでいろいろ入っているようです。
ruby/NEWS at v2_3_0 · ruby/ruby

ご参考

サンプルコードでわかる!Ruby 2.3の主な新機能 - Qiita
細かいところまで、実コードで解説されてます。 Hash#dig, Array#dig, Enumerable#grep_v 良さそう。