Ruby 2.5
ながのRubyの会 #1
2017/12/02
とみたまさひろ
1
自己紹介
とみた まさひろ
長野県北部在住プログラマー
好きなプログラミング言語 Ruby
http://tmtms.hatenablog.com
http://twitter.com/tmtms
2
Rubyは毎年クリスマスにバージョンアップ
3
Ruby 2.5
2017/12/25
4
Ruby 2.5 新機能&変更
ruby 2.5.0preview1 (2017-10-10 trunk 60153)
https://docs.ruby-lang.org/en/trunk/NEWS.html
5
言語仕様
6
トップレベル定数参照
class Foo
end
class Bar
end
# Ruby 2.4
Foo::Bar #=> Bar
# Ruby 2.5
Foo::Bar #=> NameError 例外
7
rescue/else/ensure 節
これは従来から簡潔に書けた↓
def foo
begin
...
rescue
...
end
end
def foo
...
rescue
...
end
8
2.5からはdo〜endブロックでも
簡潔に書ける↓
array.each do
begin
...
rescue
...
end
end
array.each do
...
rescue
...
end
9
文字列内式の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
10
Unicode バージョン 10.0.0
Ruby 2.4 は 9.0.0
11
組み込みライブラリ
12
Array#append, #prepend 追加
a = [1, 2, 3]
a.append 4
a #=> [1, 2, 3, 4]
a.prepend 0
a #=> [0, 1, 2, 3, 4]
13
Dir.children, Dir.each_child 追加
Dir.entries("/tmp/x") #=> ["..", "abc", "."]
Dir.children("/tmp/x") #=> ["abc"]
Dir.foreach("/tmp/x"){...} # 「.」「..」を含む
Dir.each_child("/tmp/x"){...} # 「.」「..」を含まない
14
Dir.glob :base オプション追加
カレントディレクトリの代わりのパスを指定
Dir.glob("/tmp/x/*") #=> ["/tmp/x/abc"]
Dir.glob("*", base: "/tmp/x") #=> ["abc"]
15
Hash#transform_keys,
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 から
16
IO.pread, IO.pwrite 追加
seek & read (write) をアトミックに行う
File.open("/tmp/x/abc") do |f|
f.read #=> "abcdefghijklmnopqrstuvwxyz"
f.pread(10, 3) #=> "defghijklm"
end
17
Integer.sqrt 追加
整数の平方根
Integer.sqrt(9) #=> 3
Integer.sqrt(15) #=> 3
Integer.sqrt(16) #=> 4
18
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
19
Numeric: coerce内の例外
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)
20
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)
21
Object#yield_self 追加
# tap は前からある (1.8 ?)
123.tap{|x| x*2} #=> 123
# 2.5 から
123.yield_self{|x| x*2} #=> 246
22
Process.times の精度向上
# Ruby 2.4
% ruby -e 'p Process.times'
#<struct Process::Tms utime=0.06, stime=0.01, cutime=0.0, cstime
# Ruby 2.5
ruby -e 'p Process.times'
#<struct Process::Tms utime=0.071065, stime=0.015792, cutime=0.0,
23
String#delete_prefix,
delete_suffix, delete_prefix!,
delete_suffix! 追加
"abcdefg".delete_prefix("abc") #=> "defg"
"abcdefg".delete_suffix("efg") #=> "abcd"
24
String#casecmp, casecmp? が例
外を発生しない
# Ruby 2.4
"hoge".casecmp(123) #=> TypeError
# Ruby 2.5
"hoge".casecmp(123) #=> nil
25
String#grapheme_clusters,
each_grapheme_cluster 追加
Unicodeの合成文字単位で処理
gaga = "がが" # 1文字目は「か」と「゙」の合成文字
gaga.chars #=> ["か", "゙", "が"]
gaga.grapheme_clusters #=> ["が", "が"]
26
Thread#fetch 追加
スレッド固有パラメータの取り出しをHash風に
Thread.current[:hoge] #=> nil
Thread.current.fetch(:hoge) #=> KeyError "key not found: hoge"
Thread.current.fetch(:hoge, 123) #=> 123
27
Thread.name=
Ruby 2.3からあった。Windows 10 でもスレッドに名前
をつけられるようになったらしい。
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
28
Time.at で秒以下の単位を指定
Time.at(1511056368, 123456).nsec #=> 123456000
Time.at(1511056368, 123456.789).nsec #=> 123456789
Time.at(1511056368, 123456789, :nsec).nsec #=> 123456789
29
KeyError#receiver, key 追加
例外が発生したオブジェクトとキーを返す
begin
hash = {a: 123}
hash.fetch(:b)
rescue KeyError => e
e.receiver #=> {a: 123}
e.key #=> :b
end
30
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
31
Random.raw_seed が
Random.urandom に名前変更
32
Socket::Ifaddr#vhid 追加
BSD?
33
標準添付ライブラリ
34
Bundler Gem 標準添付
35
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")
36
ERB: trim 指定時 CR LF を trim
# Ruby 2.4
require 'erb'
ERB.new("<%=123%>rn", nil, 1).result #=> "123rn"
# Ruby 2.5
require 'erb'
ERB.new("<%=123%>rn", nil, 1).result #=> "123"
37
Net::HTTP ステータス追加
'102' => Net::HTTPProcessing,
'208' => Net::HTTPAlreadyReported,
'421' => Net::HTTPMisdirectedRequest,
'451' => Net::HTTPUnavailableForLegalReasons,
'506' => Net::HTTPVariantAlsoNegotiates,
'508' => Net::HTTPLoopDetected,
'510' => Net::HTTPNotExtended,
38
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"
# ...}
39
Net::HTTP.new に no_proxy 引数追加
7番目の引数
no_proxy = "example.com,example.net:8080"
HTTP.new(address, port, proxy_addr, proxy_port,
proxy_user, proxy_pass, no_proxy)
40
Net::HTTP: http_proxy環境変数
を使用
41
Net::HTTP: http_proxy環境変数
の認証情報を使用
http://user:password@proxy:port/
Windowsを除く
42
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,
# ...
43
Ripper#state,
Ripper::EXPR_BEG 追加
44
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
45
WEBrick: Serve Name
Indication (SNI) サポート
46
標準ライブラリから mathn 削除
もうあまり使われてない?
47
標準ライブラリから ubygems 削除
rubygems を -rubygems コマンドラインオプションで使
用できるようにするためのもの。
rubygems は標準で使用されるためもう不要。
48
その他
49
バックトレースの順番
標準エラー出力が端末の場合に表示が逆順
(EXPERIMENTAL)
# 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
50
バックトレースの順番
標準エラー出力が端末でなければ従来通り
% 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>'
51
configure で拡張ライブラリを強制
通常は環境に応じて自動判別
--with-ext オプションで強制できる
コンパイルできる環境でない場合は make でエラー
% ./configure --with-ext=openssl,+
% make
...
*** Following extensions are not compiled:
openssl:
Could not be configured. It will not be installed.
/misc/tmp/ruby-2.5.0-preview1/ext/openssl/extconf.rb:94
Check ext/openssl/mkmf.log for more details.
*** Fix the problems, then remove these directories and try again
exts.mk:1853: ターゲット 'note' のレシピで失敗しました
make[1]: *** [note] エラー 1
make[1]: ディレクトリ '/misc/tmp/ruby-2.5.0-preview1' から出ます
uncommon.mk:236: ターゲット 'build-ext' のレシピで失敗しました
make: *** [build-ext] エラー 2
52
以上
53

Ruby 2.5