ながのRubyの会 #1
2017/12/02
とみたまさひろ
https://docs.ruby-lang.org/en/trunk/NEWS.html
ruby 2.5.0preview1 (2017-10-10 trunk 60153)
class Foo
end
class Bar
end
# Ruby 2.4
Foo::Bar #=> Bar
# Ruby 2.5
Foo::Bar #=> NameError 例外
def foo
begin
...
rescue
...
end
end
これは従来から簡潔に書けた↓
def foo
...
rescue
...
end
array.each do
begin
...
rescue
...
end
end
簡潔に書ける↓
array.each do
...
rescue
...
end
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
Ruby 2.4 は 9.0.0
a = [1, 2, 3]
a.append 4
a #=> [1, 2, 3, 4]
a.prepend 0
a #=> [0, 1, 2, 3, 4]
Dir.entries("/tmp/x") #=> ["..", "abc", "."]
Dir.children("/tmp/x") #=> ["abc"]
Dir.foreach("/tmp/x"){...} # 「.」「..」を含む
Dir.each_child("/tmp/x"){...} # 「.」「..」を含まない
カレントディレクトリの代わりのパスを指定
Dir.glob("/tmp/x/*") #=> ["/tmp/x/abc"]
Dir.glob("*", base: "/tmp/x") #=> ["abc"]
{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 から
seek & read (write) をアトミックに行う
File.open("/tmp/x/abc") do |f|
f.read #=> "abcdefghijklmnopqrstuvwxyz"
f.pread(10, 3) #=> "defghijklm"
end
整数の平方根
Integer.sqrt(9) #=> 3
Integer.sqrt(15) #=> 3
Integer.sqrt(16) #=> 4
# Ruby 2.4
123.round(1) #=> 123.0
123.round(-1) #=> 120
# Ruby 2.5
123.round(1) #=> 123
123.round(-1) #=> 120
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)
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)
# tap は前からある (1.8 ?)
123.tap{|x| x*2} #=> 123
# 2.5 から
123.yield_self{|x| x*2} #=> 246
# 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>
"abcdefg".delete_prefix("abc") #=> "defg"
"abcdefg".delete_suffix("efg") #=> "abcd"
# Ruby 2.4
"hoge".casecmp(123) #=> TypeError
# Ruby 2.5
"hoge".casecmp(123) #=> nil
Unicodeの合成文字単位で処理
gaga = "がが" # 1文字目は「か」と「゙」の合成文字
gaga.chars #=> ["か", "゙", "が"]
gaga.grapheme_clusters #=> ["が", "が"]
スレッド固有パラメータの取り出しをHash風に
Thread.current[:hoge] #=> nil
Thread.current.fetch(:hoge) #=> KeyError "key not found: hoge"
Thread.current.fetch(:hoge, 123) #=> 123
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
Time.at(1511056368, 123456).nsec #=> 123456000
Time.at(1511056368, 123456.789).nsec #=> 123456789
Time.at(1511056368, 123456789, :nsec).nsec #=> 123456789
例外が発生したオブジェクトとキーを返す
begin
hash = {a: 123}
hash.fetch(:b)
rescue KeyError => e
e.receiver #=> {a: 123}
e.key #=> :b
end
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
BSD?
require "erb"
name = "tmtms"
ERB.new("Hello <%=name%>").result #=> "Hello tmtms"
require "erb"
ERB.new("Hello <%=name%>").result_with_hash(name: "tmtms")
# 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"
'102' => Net::HTTPProcessing,
'208' => Net::HTTPAlreadyReported,
'421' => Net::HTTPMisdirectedRequest,
'451' => Net::HTTPUnavailableForLegalReasons,
'506' => Net::HTTPVariantAlsoNegotiates,
'508' => Net::HTTPLoopDetected,
'510' => Net::HTTPNotExtended,
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",
# ...}
7番目の引数
no_proxy = "example.com,example.net:8080"
HTTP.new(address, port, proxy_addr, proxy_port,
proxy_user, proxy_pass, no_proxy)
http://user:password@proxy:port/
Windowsを除く
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,
# ...
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
もうあまり使われてない?
rubygems を -rubygems
コマンドラインオプションで使用できるようにするためのもの。
rubygems は標準で使用されるためもう不要。
標準エラー出力が端末の場合に表示が逆順 (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
標準エラー出力が端末でなければ従来通り
% 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>'
--with-ext
オプションで強制できる% ./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: 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]: ディレクトリ '/misc/tmp/ruby-2.5.0-preview1' から出ます
uncommon.mk:236: ターゲット 'build-ext' のレシピで失敗しました
make: *** [build-ext] エラー 2