Ruby 2.7.0-preview1 での変更内容を試す

 今年のクリスマスにリリースされる予定の Ruby 2.7 の preview1 が 5/30 にリリースされました。

www.ruby-lang.org

プレビュー版は、年末の正式リリースに向け、新たな機能を試し、フィードバックを集めるために提供されています。

ということで、正式リリースまでに仕様が変更になる可能性もありますが、現状の変更内容で試せるものをざっと試してみました。

Pattern Matching

 今回の主要な変更点であるパターンマッチについては以前書いたものがありますので、そちらを参照いただければと思います。

blog.akanumahiroaki.com

REPL improvement

 Ruby の REPL である irb が大幅に進化しています。入力内容に応じてインクリメンタルにシンタックスハイライトが行われたり、複数行編集がサポートされ、かなり使いやすくなっています。

f:id:akanuma-hiroaki:20190609164650g:plain

メソッド参照演算子

 メソッドオブジェクトの参照演算子として新たに .: が追加されました。今までも method というメソッドがありましたが、それと同じように使える演算子になります。例えば下記のようなクラスがあるとします。

class Sample
  def initialize(name)
    @name = name
  end

  def name(name)
    @name = name
  end

  def self.class_method(value)
    puts "Class method called with value '#{value}'."
  end

  def instance_method(value)
    puts "Instance method in sample '#{@name}' called with value '#{value}'."
  end
end

 今までの method メソッドを使ってメソッドオブジェクトを取り出すには下記のように書きます。

s = Sample.new('test')
cm = Sample.method(:class_method)
im = s.method(:instance_method)

cm.call('hoge')
# => Class method called with value 'hoge'.

im.call('fuga')
# => Instance method in sample 'test' called with value 'fuga'.

s.name('sam')
im.call('fuga')
# => Instance method in sample 'sample' called with value 'fuga'.

 2行目、3行目を .: を使って書き直すと下記のような形になります。

cm = Sample.:class_method
im = s.:instance_method

 メソッド参照演算子については下記サイトで詳しく解説されていましたので参考にさせていただきました。

qiita.com

デフォルトのブロックの仮引数

 これまではブロックに渡される値にアクセスするための仮引数を定義する必要がありましたが、デフォルトで @1 という指定でアクセスすることができるようになります(Numbered parameters)。下記の例では array という配列の要素についてこれまでのやり方で仮引数 v を定義してアクセスするパターン(3行目)と、デフォルトの仮引数を使用するパターン(5行目)を示しています。

array = %w(a b c d e)
p array
array.each {|v| puts v }
puts '---'
array.each { puts @1 }

 実行してみると Numberd parameters を使った書き方でもこれまでと同様の出力が得られていることが確認できます。

["a", "b", "c", "d", "e"]
a
b
c
d
e
---
a
b
c
d
e

 Numbered parameters については下記サイトでも詳しく解説されていました。

tech.smarthr.jp

開始値省略範囲式

 配列等で取り出す範囲を指定する場合、終了値を省略して最後まで全てとすることはできましたが、開始値を省略して最初の値からとすることはできませんでした。2.7では開始値も省略することができるようになります。

array = %w(a b c d e)

p array[0..2]
# => ["a", "b", "c"]

p array[..2]
# => ["a", "b", "c"]

各要素の出現回数のカウント

 新たに Enumerable#tally というメソッドが追加され、配列等に含まれている各要素の数をカウントすることができるようになります。

array = %w(apple banana apple chocolate apple banana)
p array.tally
# => {"apple"=>3, "banana"=>2, "chocolate"=>1}

ブロックを伴わない Proc.new と proc が deprecated

 これまではブロックを渡すメソッドの中での下記4つの書き方は同じ挙動でしたが、ブロックを伴わない Proc.newproc が deprecated となり、 warning が出るようになっています。代わりにブロック変数 &block を使いましょう、という内容です。

def block_method(&block)
  Proc.new.call
  # => warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
  # => A block is given to the method.

  proc.call
  # => warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
  # => A block is given to the method.

  block.call
  # => A block is given to the method.

  yield
  # => A block is given to the method.
end

block_method { puts 'A block is given to the method.' }

ブロックを伴わない lambda はエラー

 ブロックを渡すメソッドの中でブロックを伴わない lambda の利用はエラーになるようになりました。例えば下記のようなコードを書いてみます。

def block_method(&block)
  lambda
  yield
end

block_method { puts 'A block is given to the method.' }

 2.6.3 では warning は出るものの実行されていました。

lambda_sample.rb:2: warning: tried to create Proc object without a block
A block is given to the method.

 2.7 では下記のようにエラーになるようになっています。

Traceback (most recent call last):
        2: from lambda_sample.rb:6:in `<main>'
        1: from lambda_sample.rb:2:in `block_method'
lambda_sample.rb:2:in `lambda': tried to create Proc object without a block (ArgumentError)

新元号「令和」を表す合字 U+32FF サポート

 Unicode のバージョンが 12.1.0 になり、令和を表す合字が追加になっています。

irb(main):001:0> RUBY_VERSION
=> "2.7.0"
irb(main):002:0> "\u32FF"
=> ""

 この変更は 2.6 にもバックポートされているようで、 2.6.3 でも同じように使用できました。

bugs.ruby-lang.org

irb(main):001:0> RUBY_VERSION
=> "2.6.3"
irb(main):002:0> "\u32FF"
=> ""

 2.5.5 では下記のように使用できません。

irb(main):001:0> RUBY_VERSION
=> "2.5.5"
irb(main):002:0> "\u32FF"
=> "\u32FF"

Date.jisx0301, Date#jisx0301, および Date.parse で非公式に新元号に仮対応

  JIS X 0301 の新しい版で正式な仕様が決定されるまでの暫定的なものとのことですが、 Date.jisx0301, Date#jisx0301, および Date.parse で非公式に新元号に仮対応されました。下記のように 2019年5月1日は令和 R として表示されます。

irb(main):001:0> RUBY_VERSION
=> "2.7.0"
irb(main):002:0> Date.new(2019, 5, 1).jisx0301
=> "R01.05.01"
irb(main):003:0> Date.parse('2019-05-01').jisx0301
=> "R01.05.01"

 この変更も 2.6 にバックポートされているようで、同様に使用することができます。

irb(main):001:0> RUBY_VERSION
=> "2.6.3"
irb(main):002:0> require 'date'
=> true
irb(main):003:0> Date.new(2019, 5, 1).jisx0301
=> "R01.05.01"

 2.5.5 では対応されておらず、平成 H と表示されます。

irb(main):001:0> RUBY_VERSION
=> "2.5.5"
irb(main):002:0> require 'date'
=> true
irb(main):003:0> Date.new(2019, 5, 1).jisx0301
=> "H31.05.01"

そのほかの変更点

 今回は実際には確認しませんでしたが、他にも下記のような点が変更になっているということです。JIT については Rails との組み合わせだと逆に遅くなるということもあるようですが、今後のそれぞれの動きにも注目したいです。

  • 断片化したメモリをデフラグするCompaction GCが導入されました。

  • パフォーマンスの改善: JIT

  • Unicode および Emoji のバージョンが 11.0.0 から 12.0.0 になりました。

  • Ruby のビルドに C99 に対応したコンパイラが必要になりました。

まとめ

 2.7.0 の preview1 ということで、今後 preview2、 preview3、 Release Candidate を経て年末にリリースされることになります。今回は本当に簡単に試した程度で、今のところは 2.6 からバージョンアップするとしても大きな変更は必要なさそうに思っていますが、リリースまでの変更内容をキャッチアップして出来るだけスムーズに既存の環境をバージョンアップできるようにして、新たに導入された便利な機能は早く使っていけるようにしたいと思います。