Ruby 2.3 プレビュー(組み込み・標準ライブラリ編)

Misoca開発チームのeitoballです。RubyKaigi2015 が、もうすぐ開催ですね。ワクワクしています。

今日は、前回 に引き続き、Ruby 2.3 の新しく追加される予定の機能を試していきたいと思います。今回は、組み込みライブラリの非互換な変更と標準ライブラリの変更を見ていきます。


組み込みライブラリの互換性のない変更

Array

Array#select! Array#keep_if Array#reject! Array#delete_if

ブロックを呼び出す毎に呼び出し元の Array オブジェクトを変更しないようになります。[Feature #10714]

配列の長さに応じて指数関数的非線形にこれらのメソッドの処理時間が長くなってしまうのを防ぐためにこの変更が適用されたようです。

以下のようなコードで試してみました。2.3 と 2.2 の実行結果を比べてみると 2.2 では、途中で配列の長さが変わっています。2.3 でも、配列の内容は途中で変わっていますが、このようなメソッドを使うときは、配列の別の部分を参照する必要がないはずなので、問題ないと思います。

a  = [1, 2, 3, 4, 5, 6]
a.reject! do |e|
  p a
  e % 2 == 1
end
p a
ruby 2.3.0preview1 (2015-11-11 trunk 52539) [x86_64-darwin14]
[1, 2, 3, 4, 5, 6]
[1, 2, 3, 4, 5, 6]
[2, 2, 3, 4, 5, 6]
[2, 2, 3, 4, 5, 6]
[2, 4, 3, 4, 5, 6]
[2, 4, 3, 4, 5, 6]
[2, 4, 6]
ruby 2.2.3p173 (2015-08-18 revision 51636) [x86_64-darwin14]
[1, 2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[2, 3, 4, 5, 6]
[2, 4, 5, 6]
[2, 4, 5, 6]
[2, 4, 6]
[2, 4, 6]

Array#pack

使用できるテンプレート文字に jJ が追加されます。それぞれプラットフォーム上のポインタと同じサイズの整数と符号付き整数です。 [Feature #11215]

Enumerable

Enumerable#chunkEnumerable#slice_before

引数として、initial_state を受け取らないようになります。状態を管理するには、ローカル変数を使用して下さい。 [Feature #10958]

2.2 で、すでに警告が出ていますので、順当な廃止だと思います。

$ ruby -ve '[3, 2, 4, 5].chunk("state") { |elt, state| elt % 2 == 0 }'
ruby 2.2.3p173 (2015-08-18 revision 51636) [...]
-e:1: warning: initial_state given for chunk.  (Use local variables.)

File::Stat

File#Stat#ino

Windows プラットフォーム上では、常に 0 を返していましたが、Windows API での BY_HANDLE_FILE_INFORMATION 構造体の nFileSizeHighnFileSizeLow を合わせたもの(nFileSizeHigh << 32 | nFileSizeLow)を返します。

IO

IO#close

IO オブジェクトが既にクローズしている IO オブジェクトに対して、 #close を読んでも、 IOError は、発生しなくなります。 [Feature #10718]

IO#each_codepoint

入力の終端(EOF)に達する前に変換できないキャラクタに遭遇すると例外(ArgumentError)が発生するようになります。 [Bug #11444]

Module

Module#define_method

メソッド定義、Proc、もしくは、Methodインスタンス、ブロックが必要になります。ブロックがない場合は、ArgumentError が発生するようになります。 [Bug #11283]

class Foo
  define_method(:with_body) { p self } # => ok
  define_method(:with_proc, Proc.new { p self }) # => ok
  define_method(:with_method, self.new.method(:to_s)) # => ok
  class << self
    def define_method_with_block(&block)
      define_method(:with_block, &block)
    end
  end
 define_method_with_block { p self } # => ok
 define_method(:no_body) # => ArgumentError: `define_method': tried to create Proc object without a block

Object

Object.define_singleton_method

Module#define_method と同様です。

String

String#unpack

Array#pack と同様です。

標準ライブラリの変更(主なもののみ)

Net::FTP

Net::FTP#mlstNet::FTP#mlsd の追加

RFC 3659 で定義されている MLST と MLSD コマンドを発行するメソッドが追加されます。

ObjectSpace (objspace

ObjectSpace.count_symbols の追加

シンボルを種類ごとにカウントした結果を Hash として返すメソッドが追加されます。ソースコードext/objspace/objspace.c)には、"This method is only for MRI developers interested in performance and memory usage of Ruby programs." とコメントがあり、CRuby 開発者向けのようです。

irb> require 'objspace'
irb> ObjectSpace.count_symbols
=> {:mortal_dynamic_symbol=>0, :immortal_dynamic_symbol=>1, :immortal_static_symbol=>3587, :immortal_symbol=>3588}
  • mortal_dynamic_symbol: ガーベジコレクタ(GC)により回収される予定の(動的に作成された)シンボルの数
  • immortal_dynamic_symbol: GC で回収されないようにマークされた動的に作成されたシンボルの数
  • immortal_static_symbol: GC で回収されない(静的に作成された)シンボルの数
  • immortal_symbol: GC で回収されない全ての種類のシンボルの数(immortal_dynamic_symbolimmortal_static_symbol の合計)

ObjectSpace.count_imemo_objects の追加

(これはよくわかりません。)ruby内部(VM)で使用される特別なオブジェクトを種類ごとにカウントした結果を Hash として返すメソッドが追加されます。このメソッドにも ObjectSpace#count_symbols と同じコメントがあり、CRuby 開発者向けのようです。

irb> require 'objspace'
irb> ObjectSpace.count_imemo_objects
=> {:imemo_iseq=>1162, :imemo_ment=>3604, :imemo_cref=>279, :imemo_svar=>103, :imemo_throw_data=>2, :imemo_ifunc=>6, :imemo_memo=>6}

ObjectSpace.internal_class_of の追加

オブジェクトの ruby 内部でのクラスを返すメソッドが追加されます。ソースコードext/objspace/objspace.c)には、"Note that you should not use this method in your application." とコメントされています。

irb> require 'objspace'
irb> s1, s2 = '', ''
irb> [s1, s2].map { |s| ObjectSpace.internal_class_of(s) }
[String, String]
irb> s1.singleton_class # => 特異クラスを作成
#<Class:#<String:0x007fe123836268>>
irb> [s1, s2].map { |s| ObjectSpace.internal_class_of(s) }
=> [#<Class:#<String:0x007fe123836268>>, String]

ObjectSpace.internal_super_of の追加

クラス、もしくは、モジュールの ruby 内部での親クラスを返すメソッドが追加されます。ソースコードext/objspace/objspace.c)には、"Note that you should not use this method in your application." とコメントされています。

irb> require 'objspace'
irb> String.ancestors
=> [String, Comparable, Object, Kernel, BasicObject]
irb> s1 = ObjectSpace.internal_super_of(String)
=> #<InternalObject:0x007f8b8c8d4108 T_ICLASS> # Comparable のための内部クラス
irb> s2 = ObjectSpace.internal_super_of(s1)
=> Object
irb> s3 = ObjectSpace.internal_super_of(s2)
=> #<InternalObject:0x007f8b8c8dd618 T_ICLASS> # Kernel のための内部クラス
irb> s4 = ObjectSpace.internal_super_of(s3)
=> BasicObject
irb> s5 = ObjectSpace.internal_super_of(s4)
=> nil

OpenSSL

OpenSSL::SSL::SSLSocket#accept_nonblockOpenSSL::SSL::SSLSocket#connect_nonblock での、exception: false のサポート

ARGF.read_nonblock のように exception: false を指定すると OpenSSL::SSL::SSLSocket#accept_nonblock を呼び出した際、IO::WaitReadableIO::WaitWritable が発生する代わりに :wait_readable:wait_writable が返されるようになります。

Pathname

Pathname#descendPathname#ascend での、ブロックなしでの呼び出しのサポート

Pathname#descendPathname#ascend で、ブロックなしで呼び出すと Enumerator オブジェクトが返すようになります。 [Feature #11052]

e = Pathname.new('/path/to/some/file.rb').descend
e.each do |v|
 p v
end

Socket

Socket#connect_nonblockSocket#accept_nonblock、他5メソッド

ARGF.read_nonblock のように exception: false を指定すると これらのメソッドを呼び出した際、IO::WaitReadableIO::WaitWritable が発生する代わりに :wait_readable:wait_writable が返されるようになります。

適用されるメソッドは以下になります。

  • Socket#connect_nonblock
  • Socket#accept_nonblock
  • TCPServer#accept_nonblock
  • UNIXServer#accept_nonblock
  • BasicSocket#recv_nonblock
  • BasicSocket#recvmsg_nonblock
  • BasicSocket#sendmsg_nonblock

BasicSocket#recvBasicSocket#recv_nonblock で、入力を格納するための String オブジェクトの受け入れのサポート

IO#readIO#read_nonblock のように入力を受け入れるための String オブジェクトを受け付けるようになります。「to reduce GC overhead」との事です。

require 'socket'
buf = ''
UNIXSocket.pair do |s1, s2|
  s1.puts "Hello World"
  s2.recv(4, nil, buf)
}
p buf #=> "Hell"

IOio/wait

IO#wait_readable の変更

IO#wait_readable は、読む込むことができるバイトがあるかどうかチェックしないようになります。

Objecttimeout

Object#timeout

このメソッドが呼ばれるとこのメソッドは将来廃止され、 Timeout.timeout を使うように警告を発するようになります。


修正履歴

  • [2015-12-11 07:20] "Array#select! Array#keep_if ..." で、「配列の長さに応じて指数関数的に」を「配列の長さに応じて指数関数的非線形に」に修正しました。(コメント#1)