Ruby 2.5 の変更内容 その3 - 標準添付ライブラリ

https://docs.ruby-lang.org/en/trunk/NEWS.html を元に Ruby 2.5 の変更内容を調べてみました。

長くなったので3つにわけてます。


個人的には coverage の分岐カバレッジ取得に SimpleCov とかが対応してくれるのを期待してます。



bigdecimal

BigDecimal::VERSION 追加

BigDecimal.new, .ver が deprecated

% ruby -w -rbigdecimal -e BigDecimal.ver
-e:1: warning: BigDecimal.ver is deprecated; use BigDecimal::VERSION instead.

BigDecimal#clone, #dup が同じオブジェクトを返す

数値オブジェクトだから Integer 等と同じく Immutable ってことだと思います。

require 'bigdecimal'

# Ruby 2.4
b = BigDecimal(1)
b.object_id == b.dup.object_id #=> false

# Ruby 2.5
b = BigDecimal(1)
b.object_id == b.dup.object_id #=> true

coverage

Coverage が分岐カバレッジ、メソッドカバレッジをサポート

低レベルAPIなのでアプリ等が対応するのを待ちたいところ。

drb

DRb の ACL::ACLEntry.new が IPAddr::InvalidPrefixError を無視しない

2.4 ではエラーになりませんでした。

require 'drb/acl'

ACL::ACLEntry.new("192.168.0.0/255.255.0.1") #=> invalid mask 255.255.0.1 (IPAddr::InvalidPrefixError)

erb

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"

bin/erb: デフォルトのエンコーディングが ASCII-8BIT から UTF-8 になった

# Ruby 2.4
% erb <(echo '<%="a".encoding%>')
ASCII-8BIT

# Ruby 2.5
% erb <(echo '<%="a".encoding%>')
UTF-8

ipaddr

require 'ipaddr'

IPAddr.new("192.168.1.2/255.255.0.0").prefix #=> 16
IPAddr.new("127.0.0.1").loopback?            #=> true
IPAddr.new("10.1.2.3").private?              #=> true
IPAddr.new("169.254.0.0/16").link_local?     #=> true

IPAddr.new が不正なアドレスマスクで例外を発生

Ruby 2.4 ではエラーになりませんでした。

require 'ipaddr'

IPAddr.new("192.168.0.0/255.255.0.1") #=> invalid mask 255.255.0.1 (IPAddr::InvalidPrefixError)

IPAddr#ipv4_compat, ipv4_compat? が deprecated

RFC4291 で IPv4-Compatible IPv6 address が deprecated になったためのようです。

% ruby -w -ripaddr -e 'p IPAddr.new("::127.0.0.1").ipv4_compat?'
-e:1: warning: IPAddr#ipv4_compat? is obsolete
true

irb

irb コマンドでなくても binding.irb が有効

a = 123
binding.irb
b = 456

みたいなスクリプトを書いて irb コマンドで実行すると binding.irb の行で止まって対話的に調査できました。

% irb hoge.rb
hoge.rb(main):001:0> a = 123
=> 123
hoge.rb(main):002:0> binding.irb
irb(main):001:0> 

ruby で実行した場合はエラーになってました。

% ruby hoge.rb
hoge.rb:2:in `<main>': undefined method `irb' for #<Binding:0x005626a1596280> (NoMethodError)

これがエラーにならずに irb で止まるようになりました。

% ruby hoge.rb

From: hoge.rb @ line 2 :

    1: a = 123
 => 2: binding.irb
    3: b = 456

irb(main):001:0> 

logger

Logger.new の引数に String を渡した場合はファイル名としてだけ扱う

Logger.new("| command") とした場合に command が実行されていましたが、文字列は単なるファイル名として扱うようになりました。

mathn

mathn 削除

もうあまり使われてないからのようです。RubyGems にはあるので使いたい場合は gem install すれば使うことができます。

matrix

Matrix.combine, Matrix#combine 追加

複数の Matrix オブジェクトの演算をブロックを用いて行えます。

require 'matrix'

a = Matrix[ [1, 2], [3, 4] ]
b = Matrix[ [5, 6], [7, 8] ]
a + b                                #=> Matrix[[1, 2], [3, 4]]
a.combine(b){|x, y| x + y }          #=> Matrix[[1, 2], [3, 4]]
Matrix.combine(a, b){|x, y| x + y }  #=> Matrix[[1, 2], [3, 4]]

Matrix#hadamard_product, #entrywise_product 追加

行列演算には詳しくないのでわかりません。

net/http

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.new の第3引数に明示的に nil を指定する必要があります。

Net::HTTP: http_proxy環境変数の認証情報を使用

http://user:password@proxy:port/

ただし Linux, FreeBSD, Darwin に限られます。 他のOSでは、ps コマンド等で他のユーザーに環境変数の値が参照される可能性があるためのようです。

openssl

OpenSSL ライブラリのバージョンが 2.0 から 2.1 に

詳しくは https://github.com/ruby/ruby/blob/v2_5_0/ext/openssl/History.md

pathname

Pathname#glob 追加

require 'pathname'

Pathname.new("/etc").glob("p*d")
#=> [#<Pathname:/etc/pam.d>, #<Pathname:/etc/passwd>, #<Pathname:/etc/profile.d>]

psych

Psych.load_documents, detect_implicit, add_ruby_type, add_private_type, read_type_class, object_maker, tagurize, to_yaml_propaties, psych_yaml_as, yaml_initialize, yaml_as 廃止

Ruby 2.4 で既に deprecated だったメソッドが削除されました。

Psych.load, Psych.load_file, Psych.parse の fallback 引数が :fallback キーワード引数に変更

もともと非公開引数だったようなので既存コードに対する影響はないと思います。

Psych.load, Psych.safe_load に :symbolize_names キーワード引数追加

true を指定すると返されるHashのキーがシンボルになります。

require 'psych'

Psych.load("abc: 123")                         #=> {"abc"=>123}
Psych.load("abc: 123", symbolize_names: true)' #=> {:abc=>123}

Psych::Handler#event_location 追加

rbconfig

RbConfig::SIZEOF, 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

Ripper#state, Ripper::EXPR_BEG 追加

Ripperは詳しくないのでわかりません。

rubygems

バージョン 2.7.3

Ruby 2.4.0 では Rubygems 2.6.8, Ruby 2.4.1 では Rubygems 2.6.11, Ruby 2.4.2 では Rubygems 2.6.13 でした。 各バージョンの変更内容は http://blog.rubygems.org/

ubygems 削除

ruby はコマンドラインオプション -r でライブラリを読み込めるんですが、r で始まる名前のライブラリの場合は先頭の r を省いた名前のライブラリを用意することで、オプションの -r と合わせて自然に読めるようになります。

ubygems は rubygems の別名で、-rubygems コマンドラインオプションで使用できるようにするためのものですが、rubygems は require しなくても標準で使用されるためもう不要なのでした。

securerandom

SecureRandom.alphanumeric 追加

ランダムな英数字文字列を生成します。

require 'securerandom'

SecureRandom.alphanumeric     #=> "9S64YBvQnqOyauQV"
SecureRandom.alphanumeric(5)' #=> "K0J8N"

set

Set#to_s 追加

require 'set'

s = Set.new([1, 2, 3])

# Ruby 2.4
s.to_s   #=> "#<Set:0x00560b825243b8>"

# Ruby 2.5
s.to_s   #=> "#<Set: {1, 2, 3}>"

Set#=== 追加

今までは未定義だったので Object#=== が動いていたのですが、Set#include? と同じ動きになりました。

require 'set'

s = Set.new([1, 2, 3])

# Ruby 2.4
s === 2  #=> false
s === s  #=> true

# Ruby 2.5
s === 2  #=> true
s === s  #=> false

もしかしたら互換的な問題おきるかもしれないですね。

stringio

StringIO#write が複数文字列を受けつける

API としては IO#write の変更と同じです。

strscan

StringScanner#size, #captures, #values_at 追加

最後に適合したサブグループに関するメソッド

require 'strscan'

ss = StringScanner.new(Time.now.to_s)
ss.scan(/(?<date>\d+-\d+-\d+) (?<time>\d+:\d+:\d+)/)
ss.size                    #=> 3  サブグループだけでなく適合した部分全体も含む
ss.captures                #=> ["2017-12-29", "20:47:03"]
ss.values_at(1, 2)         #=> ["2017-12-29", "20:47:03"]
ss.values_at(:date, :time) #=> ["2017-12-29", "20:47:03"]

socket

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で使われてる何か?

uri

URI.open 追加

Kernel.open のエイリアスとして追加されました。Kerlen.open は将来廃止される予定のようです。

URI中の連続した「/」の扱い

pathの連続した「/」は今まではひとつになっていましたが連続したまま残るようになりました。

https://url.spec.whatwg.org/ では、pathは0文字要素も含むことができるとなっているためのようです。

# Ruby 2.4
URI.parse("http://example.com/hoge//fuga/")+"x"
#=> #<URI::HTTP http://example.com/hoge/fuga/x>

# Ruby 2.5
URI.parse("http://example.com/hoge//fuga/")+"x"
#=> #<URI::HTTP http://example.com/hoge//fuga/x>

webrick

WEBrick: Server Name Indication (SNI) サポート

名前ベースのバーチャルホストでHTTPS対応できる仕組みのようです。詳しくないのでよくわかってません。

WEBrick::HTTPResponse#body= に Proc を指定可

require 'webrick'

server = WEBrick::HTTPServer.new Port: 8080
server.mount_proc '/' do |req, res|
  res.content_length = 8
  res.body = proc{ |socket| socket.write "hogehoge" }
end
server.start

Proc に限らず call メソッドを持っているオブジェクトなら何でも指定できそうな感じです。

zlib

Zlib::GzipWriter#write が複数文字列を受けつける

API としては IO#write の変更と同じです。