この記事は Ruby 2.5.0 preview1 時点のものです。Ruby 2.5 リリース版については http://tmtms.hatenablog.com/entry/2017/12/30/ruby25 を見てください。
Rubyは毎年クリスマスにバージョンアップされます。
今年も問題なければ12/25にRuby 2.5が出ると思います。
https://docs.ruby-lang.org/en/trunk/NEWS.html を元に変更内容を調べてみました。
- 言語仕様
- 組み込みライブラリ
- Array#append, #prepend 追加
- Dir.children, Dir.each_child 追加
- Dir.glob :base オプション追加
- Hash#transform_keys, transform_keys! 追加
- IO.pread, IO.pwrite 追加
- Integer.sqrt 追加
- Integer#round, floor, ceil, truncate が整数を返す
- Numeric: coerce内の例外
- Range: <=>内の例外
- Object#yield_self 追加
- Process.times の精度向上
- String#delete_prefix, delete_suffix, delete_prefix!, delete_suffix! 追加
- String#casecmp, casecmp? が例外を発生しない
- String#grapheme_clusters, each_grapheme_cluster 追加
- Thread.name=
- Thread#fetch 追加
- KeyError#receiver, key 追加
- Time.at で秒以下の単位を指定
- Random.raw_seed が Random.urandom に名前変更
- 標準添付ライブラリ
- Bundler Gem 標準添付
- ERB#result_with_hash 追加
- ERB: trim 指定時 CR LF を trim
- Net::HTTP ステータス追加
- Net::HTTP::STATUS_CODES 追加
- Net::HTTP.new に no_proxy 引数追加
- Net::HTTP: http_proxy環境変数を使用
- Net::HTTP: http_proxy環境変数の認証情報を使用
- RbConfig::SIZE_OF, RbConfig::LIMITS 追加
- Ripper#state, Ripper::EXPR_BEG 追加
- Set#to_s, #=== 追加
- BasicSocket#read_nonblock, #write_nonblock が O_NONBLOCK をセットしない
- Socket::Ifaddr#vhid 追加
- WEBrick: Server Name Indication (SNI) サポート
- 標準ライブラリから mathn 削除
- 標準ライブラリから ubygems 削除
- その他
言語仕様
トップレベル定数参照
class Foo end class Bar end # Ruby 2.4 Foo::Bar #=> Bar # Ruby 2.5 Foo::Bar #=> NameError 例外
2.5 の方が自然ですね。
rescue/else/ensure 節
def foo begin ... rescue ... end end
これは従来から次のように begin を省略できましたが、
def foo ... rescue ... end
2.5からはdo〜endブロックでも省略できます。
array.each do begin ... rescue ... end end
↓
array.each do ... rescue ... end
簡潔に書けて良いです。
文字列内式のRefinement
class A def to_s "a" end end module B refine A do def to_s "b" end end end class C using B def x A.new.to_s #=> "b" "#{A.new}" #=> "b" 2.4 では "a" end end
Unicode バージョン 10.0.0
Ruby 2.4 は 9.0.0
Unicode 9.0.0 と 10.0.0 の違いはわかってませんが…。
組み込みライブラリ
Array#append, #prepend 追加
append, prepend は push, unshift と同じなんですが、同じことをするにも複数の名前があるってのがRubyっぽいですね。
a = [1, 2, 3] a.append 4 a #=> [1, 2, 3, 4] a.prepend 0 a #=> [0, 1, 2, 3, 4]
Dir.children, Dir.each_child 追加
ディレクトリ内のエントリを .
, ..
を除いて返すメソッドが追加されました。
Dir.entries("/tmp/x") #=> ["..", "abc", "."] Dir.children("/tmp/x") #=> ["abc"]
Dir.foreach("/tmp/x"){...} # 「.」「..」を含む Dir.each_child("/tmp/x"){...} # 「.」「..」を含まない
Dir.glob :base オプション追加
Dir.glob にカレントディレクトリの代わりのパスを指定できるオプションが追加されました。
Dir.glob("/tmp/x/*") #=> ["/tmp/x/abc"] Dir.glob("*", base: "/tmp/x") #=> ["abc"]
Hash#transform_keys, transform_keys! 追加
ハッシュ中の値を変換する transform_values メソッドは 2.4 からありましたが、キーを変更する transform_keys メソッドが追加されました。
{a: 1, b: 2, c: 3}.transform_keys(&:upcase) #=> {A: 1, B: 2, C: 3} {a: 1, b: 2, c: 3}.transform_values{|v| v*2} #=> {a: 2, b: 4, c: 6} ←これは 2.4 から
IO.pread, IO.pwrite 追加
ファイルの特定の位置から read, write するメソッド追加。POSIXの同名システムコールと同じ。 ファイルポインタは変更されません。
File.open("/tmp/x/abc") do |f| f.read(5) #=> "abcde" f.pread(10, 3) #=> "defghijklm" f.read(5) #=> "fghij" end
Integer.sqrt 追加
平方根を整数で返す。
Integer.sqrt(9) #=> 3 Integer.sqrt(15) #=> 3 Integer.sqrt(16) #=> 4
Integer#round, floor, ceil, truncate が整数を返す
# Ruby 2.4 123.round(1) #=> 123.0 123.round(-1) #=> 120 # Ruby 2.5 123.round(1) #=> 123 123.round(-1) #=> 120
Numeric: coerce内の例外
数値とオブジェクトを比較した時に、coerce メソッドが呼ばれてるんですが、その際に発生した例外が ArgumentError となって隠蔽されてしまっていたのですが、そのまま例外が上がるようになりました。
class A def coerce(other) raise 'hoge' end end # Ruby 2.4 1 < A.new #=> in `<': comparison of Integer with A failed (ArgumentError) # Ruby 2.5 1 < A.new #=> in `coerce': hoge (RuntimeError)
Range: <=>内の例外
これも同上です。
class A def <=>(x) raise 'hoge' end end # Ruby 2.4 Range.new(A.new, A.new) #=> in `initialize': bad value for range (ArgumentError) # Ruby 2.5 Range.new(A.new, A.new) #=> in `<=>': hoge (RuntimeError)
Object#yield_self 追加
# tap は前からある (1.8 ?) 123.tap{|x| x*2} #=> 123 # 2.5 から 123.yield_self{|x| x*2} #=> 246
Process.times の精度向上
# Ruby 2.4 % ruby -e 'p Process.times' #<struct Process::Tms utime=0.06, stime=0.01, cutime=0.0, cstime=0.0> # Ruby 2.5 ruby -e 'p Process.times' #<struct Process::Tms utime=0.071065, stime=0.015792, cutime=0.0, cstime=0.0>
String#delete_prefix, delete_suffix, delete_prefix!, delete_suffix! 追加
"abcdefg".delete_prefix("abc") #=> "defg" "abcdefg".delete_suffix("efg") #=> "abcd"
String#casecmp, casecmp? が例外を発生しない
# Ruby 2.4 "hoge".casecmp(123) #=> TypeError # Ruby 2.5 "hoge".casecmp(123) #=> nil
String#grapheme_clusters, each_grapheme_cluster 追加
Unicodeの合成文字単位で処理
gaga = "がが" # 1文字目は「か」と「゙」の合成文字 gaga.chars #=> ["か", "゙", "が"] gaga.grapheme_clusters #=> ["が", "が"]
Thread.name=
スレッドに名前をつけることができる機能が Ruby 2.3からあったんですが、Windows 10 でも有効になったらしいです。Windows 使ってないので未確認です。
Thread.new do Thread.current.name = "hogehoge" end
% ps -L -o pid,lwp,comm -p 14655 PID LWP COMMAND 14655 14655 ruby 14655 14656 ruby-timer-thr 14655 14657 hogehoge
Thread#fetch 追加
key が無い場合に Hash#[key]
は nil を返して、Hash#fetch(key)
は例外を発生させるんですが、それと同じような振る舞いをする Thread#fetch
が追加されました。
Thread.current[:hoge] #=> nil Thread.current.fetch(:hoge) #=> KeyError "key not found: hoge" Thread.current.fetch(:hoge, 123) #=> 123
KeyError#receiver, key 追加
例外が発生したオブジェクトとキーが例外に保持されるようになりました。
begin hash = {a: 123} hash.fetch(:b) rescue KeyError => e e.receiver #=> {a: 123} e.key #=> :b end
Time.at で秒以下の単位を指定
Time.at(1511056368, 123456).nsec #=> 123456000 Time.at(1511056368, 123456.789).nsec #=> 123456789 Time.at(1511056368, 123456789, :nsec).nsec #=> 123456789
Random.raw_seed が Random.urandom に名前変更
標準添付ライブラリ
Bundler Gem 標準添付
ERB#result_with_hash 追加
コンテキストの変数じゃなくて、ハッシュで値を渡すこともできるようになりました。
require "erb" name = "tmtms" ERB.new("Hello <%=name%>").result #=> "Hello tmtms"
require "erb" ERB.new("Hello <%=name%>").result_with_hash(name: "tmtms")
ERB: trim 指定時 CR LF を trim
LF単独だと削除されましたが、CR LFは削除されなかったのが削除されるようになりました。
# Ruby 2.4 require 'erb' ERB.new("<%=123%>\r\n", nil, 1).result #=> "123\r\n" # Ruby 2.5 require 'erb' ERB.new("<%=123%>\r\n", nil, 1).result #=> "123"
Net::HTTP ステータス追加
'102' => Net::HTTPProcessing, '208' => Net::HTTPAlreadyReported, '421' => Net::HTTPMisdirectedRequest, '451' => Net::HTTPUnavailableForLegalReasons, '506' => Net::HTTPVariantAlsoNegotiates, '508' => Net::HTTPLoopDetected, '510' => Net::HTTPNotExtended,
Net::HTTP::STATUS_CODES 追加
require 'net/http/status' Net::HTTP::STATUS_CODES #=> {100=>"Continue", 101=>"Switching Protocols", # 102=>"Processing", 200=>"OK", 201=>"Created", # 202=>"Accepted", 203=>"Non-Authoritative Information", # 204=>"No Content", 205=>"Reset Content", 206=>"Partial Content", # ...}
Net::HTTP.new に no_proxy 引数追加
no_proxy = "example.com,example.net:8080" HTTP.new(address, port, proxy_addr, proxy_port, proxy_user, proxy_pass, no_proxy)
Net::HTTP: http_proxy環境変数を使用
HTTPプロキシ情報としてhttp_proxy環境変数が使われるようになりました。
Net::HTTP: http_proxy環境変数の認証情報を使用
http://user:password@proxy:port/
ただしWindowsでは使われないようです。環境変数がプロセスごとに独立してないから?
ただし Linux, FreeBSD, Darwin に限られます。
ps コマンド等で、他のユーザーに環境変数の値が参照される可能性があるためのようです。
RbConfig::SIZE_OF, RbConfig::LIMITS 追加
require "rbconfig/sizeof" RbConfig::SIZEOF #=> {"int"=>4, "short"=>2, "long"=>8, "long long"=>8, # "__int128"=>16, "off_t"=>8, "void*"=>8, "float"=>4, # "double"=>8, "time_t"=>8, "clock_t"=>8, "size_t"=>8, # ... RbConfig::LIMITS #=> {"FIXNUM_MAX"=>4611686018427387903, # "FIXNUM_MIN"=>-4611686018427387904, "CHAR_MAX"=>127, # "CHAR_MIN"=>-128, "SCHAR_MAX"=>127, "SCHAR_MIN"=>-128, # "UCHAR_MAX"=>255, "WCHAR_MAX"=>2147483647, # ...
Ripper#state, Ripper::EXPR_BEG 追加
Set#to_s, #=== 追加
s = Set.new([1, 2, 3]) # Ruby 2.4 s.to_s #=> "#<Set:0x00560b825243b8>" s === 2 #=> false s === s #=> true # Ruby 2.5 s.to_s #=> "#<Set: {1, 2, 3}>" s === 2 #=> true Set#include? と同じ s === s #=> false
to_s
はいいけど、===
は互換的な問題おきるかもしれないですね。
BasicSocket#read_nonblock, #write_nonblock が O_NONBLOCK をセットしない
require 'io/nonblock' s = TCPSocket.new("127.0.0.1", 80) s.nonblock? #=> false s.read_nonblock(10) # Ruby 2.4 s.nonblock? #=> true # Ruby 2.5 s.nonblock? #=> false
Socket::Ifaddr#vhid 追加
vhid が何なのかわからなかったです。BSDで使われてる何か?
WEBrick: Server Name Indication (SNI) サポート
SSL/TLSの何からしいです。よくわかってません。
標準ライブラリから mathn 削除
もうあまり使われてないから?
標準ライブラリから ubygems 削除
ruby はコマンドラインオプション -r
でライブラリを読み込めるんですが、r で始まる名前のライブラリの場合は先頭の r を省いた名前のライブラリを用意することで、オプションの -r
と合わせて自然に読めるようになります。
ubygems は rubygems の別名で、-rubygems
コマンドラインオプションで使用できるようにするためのものですが、rubygems は require しなくても標準で使用されるためもう不要なのでした。
その他
バックトレースの順番
標準エラー出力が端末の場合に表示が逆順になります。
# Ruby 2.4 % ruby /tmp/a.rb /tmp/a.rb:8:in `c': unhandled exception from /tmp/a.rb:5:in `b' from /tmp/a.rb:2:in `a' from /tmp/a.rb:10:in `<main>'
# Ruby 2.5 % ruby /tmp/a.rb Traceback (most recent call last): 3: from /tmp/a.rb:10:in `<main>' 2: from /tmp/a.rb:2:in `a' 1: from /tmp/a.rb:5:in `b' /tmp/a.rb:8:in `c': unhandled exception
標準エラー出力が端末でなければ従来通り。
% ruby /tmp/a.rb 2>&1 | cat /tmp/a.rb:8:in `c': unhandled exception from /tmp/a.rb:5:in `b' from /tmp/a.rb:2:in `a' from /tmp/a.rb:10:in `<main>'
configure で拡張ライブラリを強制
通常は configure 時の環境に応じて使えるライブラリが自動判別されますが、--with-ext
オプションで強制することができます。コンパイルできる環境でない場合は make でエラーになります。
% ./configure --with-ext=openssl,+ % make ... *** Following extensions are not compiled: openssl: Could not be configured. It will not be installed. /tmp/ruby-2.5.0-preview1/ext/openssl/extconf.rb:94: OpenSSL library could not be found. You might want to use --with-openssl-dir=<dir> option to specify the prefix where OpenSSL is installed. Check ext/openssl/mkmf.log for more details. *** Fix the problems, then remove these directories and try again if you want. exts.mk:1853: ターゲット 'note' のレシピで失敗しました make[1]: *** [note] エラー 1 make[1]: ディレクトリ '/tmp/ruby-2.5.0-preview1' から出ます uncommon.mk:236: ターゲット 'build-ext' のレシピで失敗しました make: *** [build-ext] エラー 2
結構非互換が多いような気はしますが、いろいろ便利になってますね。期待!