Ruby 2.7 新機能

とみたまさひろ

2020-02-15

Nagano.rb #5
#naganorb

自己紹介

Rubyとの関わり

  • 1997〜 当時は 1.1

  • 〜2018/9 長野 Ruby で開発

  • 2018/10〜 東京 not Ruby

  • 最近ちょっとだけ Ruby

    • 某P言語で書かれたプログラムを RSpec でテスト

Rubyは毎年12/25にリリース

アドベントカレンダー

https://ja.wikipedia.org/wiki/アドベントカレンダー

アドベントカレンダー (Advent calendar) は、クリスマスまでの期間に日数を数えるために使用されるカレンダーである。待降節の期間(イエス・キリストの降誕を待ち望む期間)に窓を毎日ひとつずつ開けていくカレンダーである。すべての窓を開け終わるとクリスマスを迎えたことになる。

インターネット上などで、12月の1日から25日までに、特定のテーマに沿って毎日ブログなどに記事を投稿していくという企画がある。元々のアドベントカレンダーになぞらえて、この企画もアドベントカレンダーと呼ばれている。特にプログラミングに関連するアドベントカレンダーの企画が多数行われている。

Ruby 2.7 アドベントカレンダー

https://qiita.com/advent-calendar/2019/ruby27

Ruby 2.7 新機能など

irb

対話型Ruby

Ruby 2.7 で大幅に機能向上

リアルタイムのコードハイライト

複数行編集

メソッド補完

マニュアル表示

履歴保存

しかし遅い

入力1文字毎に処理してるため

きっとそのうち改善される

Numbered parameter

ブロック引数には名前をつける必要があった

[5, 2, 4, 1, 3].sort { |a, b| a <=> b }  #=> [1, 2, 3, 4, 5]

いちいち名前を考えなくてもいい場合
_+数字(1〜9) を使えるようになった

[5, 2, 4, 1, 3].sort { _1 <=> _2 }  #=> [1, 2, 3, 4, 5]

_1, _2, … は今までローカル変数だったので
混在させると warning

_2 = 99
[5, 2, 4, 1, 3].sort { _1 <=> _2 }  #=> [5, 2, 4, 1, 3]
# warning: `_2' is reserved for numbered parameter;
# consider another name

パターンマッチング

他の言語にはあるらしい(しらない)

ArrayやHashなどのオブジェクトの構造をマッチング

(experimental)

Array

obj = [0, [1, 2, 3]]

case obj
in [a, [b, *c]]
  p a #=> 0
  p b #=> 1
  p c #=> [2, 3]
end

Hash

obj = {a: 0, b: 1, c: 2}

case obj
in {a: 0, x: 1}
  # ここは通らない
in {a: 0, b: var}
  p var #=> 1
end

適合するパターンが無ければエラー

obj = [1, "hoge"]

case obj
in {a: var}
  # 適合しない
in [a, b, c]
  # 適合しない
end
#=> [1, "hoge"] (NoMatchingPatternError)

elseも書ける

obj = [1, "hoge"]

case obj
in {a: var}
  # 適合しない
in [a, b, c]
  # 適合しない
else
  "no match"
end
#=> "no match"

ifで条件指定も

def hoge(obj)
  case obj
  in [a, b] if a == b.to_i
    true
  else
    false
  end
end

hoge [123, "123"]  #=> true
hoge [123, "456"]  #=> false
hoge "xxxx"        #=> false

型(クラス)指定

def hoge(obj)
  case obj
  in [String => s, Integer => n]
    s * n
  in [a, b]
    a + b
  end
end

hoge ["abc", 2]  #=> "abcabc"
hoge [3, 4]      #=> 7

組み込みクラスだけじゃなくて
自分でもパターン定義可能らしい

詳しくは RubyKaigi 2019 の発表を

Pattern matching - New feature in Ruby 2.7
https://rubykaigi.org/2019/presentations/k_tsj.html

キーワード引数まわりのwarning

Rubyのキーワード引数はHashの表記を使用

Hash

{:hoge => 123, :fuga => 456}

キーがシンボルの場合 (Ruby 1.9〜)

{hoge: 123, fuga: 456}

引数

def foo(a, b, opts)
  a    #=> 1
  b    #=> 2
  opts #=> {hoge: 123, fuga: 456}
end
foo(1, 2, {hoge: 123, fuga: 456})

引数末尾のHashは { } を省略可

def foo(a, b, opts)
  a    #=> 1
  b    #=> 2
  opts #=> {hoge: 123, fuga: 456}
end
foo(1, 2, hoge: 123, fuga: 456)

キーワード引数っぽい

キーワード引数

Ruby 2.0〜

def foo(a, b, hoge: nil, fuga: nil)
  a    #=> 1
  b    #=> 2
  hoge #=> 123
  fuga #=> 456
end
foo(1, 2, hoge: 123, fuga: 456)

その結果

def foo(hash={}, key: nil)
end

foo({a: 123})
# `foo': unknown keyword: :a (ArgumentError)

カオス

def foo(hash={}, key: nil)
  hash  #=> {"a"=>123}
  key   #=> 456
end

h = {"a" => 123, :key => 456}
foo(h)

Ruby 3 では Hash とキーワード引数を分離する予定

そのために 2.7 で warning

def foo(hash={}, key: nil)
end
h = {:key => 456}
foo(h)
# warning: Using the last argument as keyword parameters is
# deprecated; maybe ** should be added to the call
def foo(hash={}, key: nil)
end
h = {"a" => 123, :key => 456}
foo(h)
# warning: Splitting the last argument into positional
# and keyword parameters is deprecated

始端省略Rangeリテラル

範囲オブジェクトのリテラル表記

r = (3..9)

2.6 から終端省略可能

r = (3..)
r.each { |i| p i } # 無限ループ

2.7 から始端省略可能

r = (..9)

# イテレータとしては使えない
r.each { |i| p i } # can't iterate from NilClass

# 両端省略は不可
r = (..)  # syntax error, unexpected ')'

DSL的な使用

require 'sequel'

db = Sequel::Database.new

db[:table].where(col: 3..9).sql
#=> SELECT * FROM table WHERE ((col >= 3) AND (col <= 9))
db[:table].where(col: 3..).sql
#=> SELECT * FROM table WHERE (col >= 3)
db[:table].where(col: ..9).sql
#=> SELECT * FROM table WHERE (col <= 9)

コメント行を挟んだ

メソッド呼び出し

メソッド呼び出しは . の前後で改行可能

"hoge".upcase
"hoge".
  upcase
"hoge"
  .upcase

. 終わりの行の後にコメント行を挟む

"hoge".
  # コメント
  upcase

2.7からはこっちも可能

"hoge"
  # コメント
  .upcase

GC.compact

フラグメント化したメモリを再配置

「GC」?

長時間動き続けるプロセスで
肥大化したプロセスメモリを小さくできるかも

Date.jisx0301 の令和対応

require 'date'

Date.today.jisx0301  #=> "R02.02.15"

以上

「プロと読み解くRuby 2.7 NEWS」
https://techlife.cookpad.com/entry/2019/12/25/121834

次の Ruby は 2020/12/25 予定

2.8 じゃなくて 3 かも?