はじめに
Rubyは毎年12月25日にアップデートされます。
Ruby 2.7については2019年12月21日にrc2がリリースされました。
この記事ではRuby 2.7で導入される変更点や新機能について、サンプルコード付きでできるだけわかりやすく紹介していきます。
ただし、Ruby 2.7は多くの新機能や変更点があり、1つの記事に収まらないのでいくつかの記事に分けて書いていきます。
番号指定パラメータ、パターンマッチ構文、キーワード引数に関する仕様変更についてはすでに他の記事で説明したので、本記事ではそれ以外の変更点を説明しています。
すでに説明したRuby 2.7の新機能や変更点はこちら
Ruby 2.7の新機能や変更点は非常に多いので、いくつかの記事に分けて説明しています。
以下の記事はすでに公開済みです。
- サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 1 - 番号指定パラメータ(numbered parameter) - Qiita
- サンプルコードでわかる!Ruby 2.7の新機能・パターンマッチ(前編) - Qiita
- サンプルコードでわかる!Ruby 2.7の新機能・パターンマッチ(後編) - Qiita
- サンプルコードでわかる!Ruby 2.7の主な新機能と変更点 Part 2 - キーワード引数に関する仕様変更 - Qiita
本記事の情報源
本記事は以下のような情報源をベースにして、記事を執筆しています。
- Ruby 2.7.0-rc2 リリース
- rc2のNEWSページ
- プロと読み解くRuby 2.7 NEWS - クックパッド開発者ブログ
- リリースノートやNEWSに記載されている各種issue
また、issueを追いかけてもピンと来なかった内容については、ブログ「ruby trunk changes」のコミット解説を参考にさせてもらいました(nagachikaさん、どうもありがとうございます!)。
動作確認したRubyのバージョン
本記事は以下の環境で実行した結果を記載しています。
$ ruby -v
ruby 2.7.0rc2 (2019-12-22 master 75acbd5f00) [x86_64-darwin19]
(2019.12.26追記)正式リリースされたRuby 2.7.0でも動作確認済みです。
$ ruby -v
ruby 2.7.0p0 (2019-12-25 revision 647ee6f091) [x86_64-darwin19]
フィードバックお待ちしています
本文の説明内容に間違いや不十分な点があった場合は、コメント欄や編集リクエスト等で指摘 or 修正をお願いします🙏
それでは以下が本編です!
構文や言語機能上の変更点
パターンマッチ構文が試験的に導入された(別記事にて説明済み)
Ruby 2.7ではパターンマッチ(またはパターンマッチング)構文が試験的に導入されました。
関数型言語で広く使われているパターンマッチという機能が実験的に導入されました。 渡されたオブジェクトの構造がパターンと一致するかどうかを調べ、一致した場合にその値を変数に代入するといったことができるようになります。
以下はパターンマッチ構文の使用例です。
case {status: :error, message: 'User not found.'}
in {status: :success}
puts "Success!"
in {status: :error, message: message}
puts "Error: #{message}"
end
#=> Error: User not found.
パターンマッチについては以下の記事で詳しく説明しています。
キーワード引数と普通の引数の自動変換が非推奨になった(別記事にて説明済み)
Ruby 2.7ではキーワード引数と普通の引数の自動変換が非推奨になり、警告が発生します。
以下は警告が発生するようになったコードの例です。
def foo(key: 0)
p key
end
foo({key: 42})
#=> The last argument is used as the keyword parameter
#=> 42
警告が発生するコードはRuby 3で動かなくなります。
詳しい内容はこちらの記事をご覧ください。
ブロックの仮引数として番号指定パラメータが導入された(別記事にて説明済み)
Ruby 2.7ではブロックの仮引数として番号指定パラメータ(numbered parameter)が試験的に導入されました。
(2019.12.27追記)
試験的な導入ではなく、Ruby 2.7.0で正式に導入されたようです。(参考)
これにより、|s|
のように明示的に引数名を指定する代わりに、_1
のような連番でブロックの仮引数を受け取ることができます。
# 番号指定パラメータを使わない場合
%w(1 20 300).map { |s| s.rjust(3, '0') }
#=> ["001", "020", "300"]
# 番号指定パラメータを使う場合
%w(1 20 300).map { _1.rjust(3, '0') }
#=> ["001", "020", "300"]
# 番号指定パラメータを使わない場合
[1, 2, 3, 4].inject(0) { |memo, n| memo + n }
#=> 10
# 番号指定パラメータを使う場合
[1, 2, 3, 4].inject(0) { _1 + _2 }
#=> 10
詳しい内容はこちらの記事をご覧ください。
メソッドの内のブロックを伴わないProc.new/procとlambdaが警告またはエラー扱いとなった
Ruby 2.6まではメソッド内でブロックなしのProc.new/procやlambdaを呼ぶと、暗黙的にメソッド呼び出し時に引き渡したブロックが割り当てられていました。
def proc_without_block
# このprocにはこのメソッドを呼びだしたときに
# 引き渡したブロックが暗黙的に割り当てられる
proc.call * 100
# Proc.newを使った場合も同様
# Proc.new.call * 100
end
proc_without_block { 123 }
#=> 12300
def lambda_without_block
# lambdaの場合も同様
lambda.call * 100
end
lambda_without_block { 123 }
#=> 12300
Ruby 2.7ではProc.new/procのときに警告が、lambdaのときは例外が発生するようになりました。
def proc_without_block
proc.call * 100
end
# Ruby 2.7では警告が出る
proc_without_block { 123 }
#=> warning: Capturing the given block using Kernel#proc is deprecated; use `&block` instead
def lambda_without_block
lambda.call * 100
end
# Ruby 2.7では例外が発生する
lambda_without_block { 123 }
#=> ArgumentError (tried to create Proc object without a block)
開始値省略範囲式(beginless range)が試験的に導入された
Ruby 2.7では開始値省略範囲式(beginless range)が試験的に導入されました。
numbers = [10, 20, 30, 40, 50]
# beginless rangeを使って配列の最初の3要素を取得する
numbers[..2]
#=> [10, 20, 30]
# 従来通り次のように書いても同じ
numbers[0..2]
#=> [10, 20, 30]
Ruby 2.6で導入されたendless rangeと組み合わせると次のようなコードも書けます。
n = -5
ret =
case n
when ..-1
'minus'
when 1..
'plus'
else
'zero'
end
ret
#=> minus
特殊変数の$;
と$,
に非nil値を設定すると警告が出るようになった
Ruby 2.7ではsplitメソッドのデフォルトの区切り文字を表す特殊変数$;
と、デフォルトの出力フィールド区切り文字列(joinメソッドなどで使われる)を表す$,
で、nil以外の値を設定すると警告が出るようになりました。
また、その状態でsplitメソッドやjoinメソッドを呼び出した際も警告が出ます。
# デフォルト値はnil
$; #=> nil
# 引数なしでsplitメソッドを呼ぶと空白文字で分割される
'ab,c d'.split #=> ["ab,c", "d"]
# 非nil値を設定すると警告が出る
$; = ','
#=> warning: non-nil $; will be deprecated
# splitメソッドを呼んだときも警告が出る
'ab,c d'.split #=> ["ab", "cd"]
#=> warning: $; is set to non-nil value
# デフォルト値はnil
$, #=> nil
# 引数なしでjoinメソッドを呼ぶと空文字で連結される
%w(a b c).join #=> "abc"
# 非nil値を設定すると警告が出る
$, = '-'
#=> warning: non-nil $, will be deprecated
# joinメソッドを呼んだときも警告が出る
%w(a b c).join #=> "a-b-c"
#=> warning: $, is set to non-nil value
ヒアドキュメント識別子に付ける'
や"
が同じ行にないと構文エラーが出るようになった
下のコードのようにヒアドキュメントの識別子に付ける'
や"
が同じ行にない場合、Ruby 2.6までは警告が出ていましたが、Ruby 2.7からはsyntax errorが発生するようになりました。
s = <<~"TEXT
"
Hello!
TEXT
#=> Ruby 2.6では以下の警告が発生する
# warning: here document identifier ends with a newline
#=> Ruby 2.7ではsyntax errorが発生する
# unterminated here document identifier
# s = <<~"TEXT
# syntax error, unexpected end-of-input
# s = <<~"TEXT
フリップフロップ構文の警告が撤回された
Ruby 2.6からフリップフロップ構文を使うと警告が発生するようになっていましたが、Ruby 2.7では(正確にはRuby 2.6.4以降では)この変更が撤回され、警告が出なくなりました。
numbers = 1..10
ret =
numbers.map do |n|
# この下の行がフリップフロップ構文
if (n % 3 == 0)..(n % 2 == 0)
n * 10
end
end
#=> Ruby 2.6.0〜2.6.3では以下の警告が発生していたが、
# Ruby 2.6.4以降とRuby 2.7では発生しなくなった
# warning: flip-flop is deprecated
ret.compact
#=> [30, 40, 60, 90, 100]
フリップフロップ構文って何?という方は以下の記事をご覧ください。
改行を伴うメソッドチェーンにコメント行を挟み込めるようになった
Ruby 2.7では、以下のように改行を伴うメソッドチェーンにコメント行を挟み込めるようになりました。
200
# 次の値(つまり201)を得る
.then(&:succ)
# 文字列に変換する
.then(&:to_s)
# 逆順にする
.then(&:reverse)
#=> "102"
ドットが後に来るパターンでも大丈夫です。
200.
# 次の値(つまり201)を得る
then(&:succ).
# 文字列に変換する
then(&:to_s).
# 逆順にする
then(&:reverse)
ちなみに、Ruby 2.6では以下のように構文エラーが発生していました。
syntax error, unexpected '.', expecting end-of-input
.then(&:succ)
privateメソッドをself付きで呼び出せるようになった
これまでRubyのprivateメソッドは「レシーバを指定して呼び出すことができないメソッド」とされてきました。
そのためクラス内でもself
付きでprivateメソッドを呼び出すと例外が発生していました。
class Foo
def hello
# nameはprivateメソッドなのでself付きで呼び出すことはできない
"I am #{self.name}"
end
private
def name
'Alice'
end
end
foo = Foo.new
# self.nameと書いていたので、例外が発生する
foo.hello
#=> `hello': private method `name' called for #<Foo:0x00007fb0488b24c8> (NoMethodError)
Ruby 2.7ではself付きでprivateメソッドを呼び出せるようになりました。
class Foo
def hello
# Ruby 2.7ではself付きでprivateメソッドを呼び出せる
"I am #{self.name}"
end
private
def name
'Alice'
end
end
foo = Foo.new
foo.hello
#=> "I am Alice"
# もちろん、クラスの外からはレシーバ付きでprivateメソッドを呼び出すことはできない
foo.name
#=> private method `name' called for #<Foo:0x00007f91049094e8> (NoMethodError)
ちなみに、これまでのRubyでもセッターメソッドだけはprivateでも例外的にself付きで呼び出すことができていました。(こちらの記事も参考)
class Foo
def initialize
@name = 'Alice'
end
def hello
"I am #{self.name}"
end
def change_name
# Ruby 2.6以前でも、セッターメソッドだけはprivateでもself付きで呼び出せた
self.name = 'Bob'
end
private
def name=(value)
@name = value
end
def name
@name
end
end
foo = Foo.new
foo.hello
#=> I am Alice
foo.change_name
foo.hello
#=> I am Bob
今回のRuby 2.7の変更により、セッターメソッドか、そうでないかに関わらず、一貫してprivateメソッドをself付きで呼び出せるようになります。
rescue修飾子を伴う多重代入の挙動が変わった
Ruby 2.6では以下のようにrescue修飾子と多重代入を行うと次のような結果になっていました。
# ZeroDivisionErrorが発生するが、rescueする
a, b = [1/0, 2/0] rescue [10, 20]
a #=> nil
b #=> nil
これは次のようにパースされていたためです。
(a, b = [1/0, 2/0]) rescue [10, 20]
Ruby 2.7ではパースのされ方が以下のように変更されました。
a, b = ([1/0, 2/0] rescue [10, 20])
これにより、rescue修飾子から返される配列を多重代入できるようになりました。
a, b = [1/0, 2/0] rescue [10, 20]
a #=> 10
b #=> 20
特異クラス構文内でyieldを使うと警告が出るようになった
Ruby 2.7では、以下のように特異クラス構文内でyieldを呼び出すと警告が出るようになりました。(こんなコードを書くことは、まれだと思いますが・・・)
def yield_in_class_syntax
class << Object.new
yield
end
end
yield_in_class_syntax { puts 'nihao!' }
#=> warning: `yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575]
# nihao!
全引数を別のメソッドに引き渡す...
引数が導入された
Ruby 2.7ではあらゆる引数を受け取って、別のメソッドに引き渡す...
引数が導入されました。
def add(a, b)
a + b
end
def add_with_description(...)
# 受け取った引数をすべてそのままaddメソッドに引き渡す
answer = add(...)
"answer is #{answer}"
end
add_with_description(2, 3)
#=> answer is 5
別のメソッドを呼び出すときは丸かっこ(()
)が必須です。丸かっこがないと開始と終了のない範囲オブジェクト(nil...nil
)と見なされます。
# (...)と書かなかった場合は、nil...nilをaddメソッドを渡したことになる(警告も出る)
answer = add ...
#=> warning: ... at EOL, should be parenthesized?
メソッドの仮引数も別メソッドに渡す引数も、いずれも...
になっている必要があります。
片方だけが通常の引数だったり、引数の一部だけが...
になっていたりすると、構文エラーになります。
def add_with_description(a, b)
# 仮引数は通常の引数で、別メソッドの呼び出しが...になっていると構文エラー
answer = add(...)
"answer is #{answer}"
end
# 引数の一部が通常の引数で、残りが...になっていると構文エラー
def add_with_description(a, ...)
answer = add(a, ...)
"answer is #{answer}"
end
セキュリティモデル関連の特殊変数やメソッドのサポートが縮小された
RubyにはCGIプログラミングをサポートするためのセキュリティ機能(セキュリティモデル)が用意されています。(参考)
しかし、近年のエコモデルではこの仕組みはあまり役に立たないため、サポートが縮小されつつあります。
特殊変数の$SAFE
はRubyの「セーフレベル」を設定するために使われていましたが、Ruby 2.7ではこの変数を変更したり、参照したりすると警告が表示されます。
# 参照すると警告が出る
$SAFE
#=> warning: $SAFE will become a normal global variable in Ruby 3.0
# 0
# 変更しても警告が出る
$SAFE = 1
#=> warning: $SAFE will become a normal global variable in Ruby 3.0
また、taint, untaint, trust, untrust といった、セキュリティモデルに関連するメソッドも無効化されています。(オブジェクトは汚染状態にはならない)
some = "puts '@&%&(#!'"
some.tainted?
#=> false
# Ruby 2.7では呼びだしても何も変化がない
some.taint
some.tainted?
#=> falseのままになる(Ruby 2.6ではtrueになる)
シンタックスハイライトや自動インデントなど、irbが大きく進化した
Ruby 2.7ではirbが大きく進化しました。
2019.12.26追記:正式リリースされた2.7.0では警告は表示されません(ここから↓)
それに関連して、irbを起動すると、以下のようなメッセージが表示されます。
$ irb
This version of IRB is drastically different from the previous version.
If you hit any issues, you can use "irb --legacy" to run the old version.
If you want to just erase this message, please use "irb --multiline" or
add `IRB.conf[:USE_MULTILINE] = true` to your ~/.irbrc file.
irb(main):001:0>
メッセージを翻訳すると次のようになります。
本バージョンのIRBは以前のバージョンから大幅に変わっています。
もし何か問題があれば、"irb --legacy"というコマンドで以前のバージョンに戻すことができます。
このメッセージを消したい場合は、"irb --multiline"というコマンドを使うか、~/.irbrcファイルにIRB.conf[:USE_MULTILINE] = true
を追加してください。
2019.12.26追記:正式リリースされた2.7.0では警告は表示されません(ここまで↑)
従来のirbに戻したり、新しいirbのままメッセージの表示をなくしたいときは、上のメッセージにあるとおり、irb --legacy
やirb --multiline
といったコマンドで起動します。
続いて、新しいirbの変更点を以下で紹介します。
進化その1) シンタックスハイライトされる
irb内に打ち込んだコードが自動的にシンタックスハイライトされます。
進化その2) 自動的にインデントしてくれる
進化その3) 上下キーで複数行の入力履歴をまとめて行き来できる
ただし、長いメソッドやif文を入力したあとだと、履歴をさかのぼるのがちょっと大変かもしれません。
進化その4) TABキーを押すと入力候補を表示してくれる
メソッドを途中まで入力してTABキーを押すとクラス名やメソッド名、変数名などの入力候補を表示してくれます。
進化その5) TABキーを2回押すとクラスやメソッドのドキュメントを表示してくれる
メソッド名を入力してTABキーを2回押すとクラスやメソッドのドキュメントを表示してくれます。
表示を戻すときはq
を押します。
~/.irbrcを編集してirbの設定を変更する
冒頭のメッセージにもあったように、~/.irbrc
に以下の設定を追加するとデフォルトの起動モードを変えられます。
# trueなら新しいバージョン、falseなら以前のバージョンで起動
IRB.conf[:USE_MULTILINE] = true
自動インデントを無効化する場合は、以下の設定を追加します。
IRB.conf[:AUTO_INDENT] = false
入力履歴はデフォルトで1000件保存されます。(~/.irb_history
という履歴ファイルが作成されます)
履歴をもっと増やしたい、または減らしたい、という場合は~/.irbrc
で好みの件数を設定できます。(nilを設定すると入力履歴が無効化されます)
IRB.conf[:SAVE_HISTORY] = 2000
参考: What's new in Interactive Ruby Shell (IRB) with Ruby 2.7 – Saeloun Blog
2020.5.8追記:Ruby 2.7のirbがペーストすると遅すぎる問題について
すごく便利になったRuby 2.7のirbですが、その副作用として(?)長い複数行テキストをペーストしたときにめちゃくちゃ遅くなる(最悪ハングする)という問題があります(Ruby 2.7.1で確認)。
pasting in multiline irb is slow · Issue #43 · ruby/irb
これはrails console
を経由した場合も同じです。
この問題を回避するためには、--legacy
や--nomultiline
のオプションを付けて、以前のバージョンで起動する必要があります。
$ irb --legacy
ただし、rails console
ではこの方法が使えないため、上で紹介したように~/.irbrc
に以下の設定を入れてください。
IRB.conf[:USE_MULTILINE] = true
Object#method
とModule#instance_method
がRefinementsを考慮するようになった
Ruby 2.6ではRefinementsによって定義されたメソッドを、method
メソッドやinstance_method
メソッドを使って取り出すことができませんでした。(オーバーライドされていた場合は、オーバーライド前のメソッド定義を取り出していました)
# Ruby 2.6の場合
# Refinementsを使ってStringクラスにshuffleメソッドを追加する
module StringShuffle
refine String do
def shuffle
chars.shuffle.join
end
end
end
using StringShuffle
# Ruby 2.6ではメソッドオブジェクトとしてshuffleメソッドを取り出せない
m = 'abcdef'.method(:shuffle)
#=> NameError: undefined method `shuffle' for class `String'
# instance_methodを使った場合も同様
m = String.instance_method(:shuffle)
#=> NameError: undefined method `shuffle' for class `String'
Ruby 2.7ではmethod
メソッドやinstance_method
メソッドを使った場合でも、Refinementsによる拡張が考慮されるようになりました。
# Ruby 2.7ではshuffleメソッドが取り出せる
m = 'abcdef'.method(:shuffle)
m.call
#=> 'dabefc'
# instance_methodを使った場合も同様
m = String.instance_method(:shuffle)
m.arity
#=> 0
カテゴリ別に警告の表示・非表示を制御できるコマンドラインオプションが追加された
Ruby 2.7では -W
オプションが拡張され、カテゴリ別に警告の表示・非表示が制御できるようになりました。
非推奨(deprecation)警告を非表示にする
ruby -W:no-deprecated your_code.rb
試験的機能(experimental feature)警告を非表示にする
ruby -W:no-experimental your_code.rb
RUBYOPT環境変数を使って制御する
RUBYOPT環境変数を使って制御することもできます。
RUBYOPT=-W:no-deprecated bundle exec rspec
複数のオプションを指定したい場合は次のようにスペースで区切ります。
RUBYOPT='-W:no-deprecated -W:no-experimental' bundle exec rspec
Warning[(カテゴリ)]を使ってカテゴリ別に警告の表示・非表示を制御できるようになった
これは「構文や言語機能上の変更点」ではないのですが、上で説明した-W
オプションと内容が近いので、このタイミングで一緒に説明しておきます。
Ruby 2.7では以下のようにWarning[カテゴリ]を使ってRubyのコード内で警告の表示・非表示を制御することも出来ます。
# 非推奨警告を非表示にする
Warning[:deprecated] = false
def buy_burger(menu, drink: true, potato: true)
end
params = { drink: true, potato: false }
# 以下のコードは非推奨警告の対象になるが、Warning[:deprecated]にfalseをセットしたので警告が表示されない
buy_burger('fish', params)
コマンドラインやRUBYOPT
環境変数で-W:no-deprecated
のようなオプションを設定している場合は最初からfalseになっています。
# -W:no-deprecatedオプションを付けて起動した場合は最初からfalse
Warning[:deprecated]
#=> false
指定可能なカテゴリは:deprecated
と:experimental
の2つだけです。
それ以外のカテゴリを指定すると例外が発生します。
# 無効なカテゴリを指定すると例外が発生する
Warning[:hoge] = false
#=> ArgumentError: unknown category: hoge
警告によってはコード実行時ではなく、コードを読み込んだタイミングで警告が発生するものがあります。(パターンマッチ構文など)
その場合はWarning[(カテゴリ)]を使っても警告を非表示にはできません。(コマンドラインオプションやRUBYOPT
環境変数を使って制御してください)
# 試験的機能の警告を非表示にする
Warning[:experimental] = false
# しかし、パターンマッチ構文の警告は実行時ではなく、コードを読み込んだタイミングで警告が表示される
case 0
in n
# ...
end
#=> warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!
続いて、クラス単位でRuby 2.7の新機能や変更点を紹介していきます。
Array
&
と同じ振る舞いをするintersectionメソッドが追加された
Ruby 2.7では両方の配列に含まれる要素を重複なく返すintersection
メソッドが追加されました。
これは従来の&
演算子と同じ挙動になります。
a = [1, 1, 3, 5]
b = [3, 2, 1]
# 2つの配列に共通して含まれる要素は1と3(重複なしで返す)
a.intersection(b)
#=> [1, 3]
# Ruby 2.6以前では&演算子を使う方法しかなかった
a & b
#=> [1, 3]
ちなみにRuby 2.6では|
演算子と同じunion
メソッドと、-
演算子と同じdifference
メソッドが追加されました。
a = [1, 2, 3]
b = [3, 4, 5]
# a | bと同じ
a.union(b)
#=> [1, 2, 3, 4, 5]
a = [1, 2, 3, 4, 5]
b = [0, 1, 2]
# a - bと同じ
a.difference(b)
#=> [3, 4, 5]
|
と-
に名前付きのメソッドが追加されたのであれば、&
にもあった方がいいのでは?ということでintersection
メソッドが追加されたみたいです。
Feature #16155: Add an Array#intersection method - Ruby master - Ruby Issue Tracking System
Array / Range
minmaxメソッドが高速化した
これまでArrayクラスのminmax
メソッドはEnumerableモジュールによって提供されていましたが、Ruby 2.7では高速化のためArrayクラス自身に実装されました。
# Ruby 2.6
[].method(:minmax)
#=> #<Method: Array(Enumerable)#minmax>
# Ruby 2.7
[].method(:minmax)
#=> #<Method: Array#minmax()>
Rangeクラスについても同様にminmax
メソッドがRangeクラス自身に実装されました。
# Ruby 2.6
(1..3).method(:minmax)
#=> #<Method: Range(Enumerable)#minmax>
# Ruby 2.7
(1..3).method(:minmax)
#=> #<Method: Range#minmax()>
Range#minmaxがRange#maxの値を最大値として返すようになった
後方互換性のない変更点です。
上で説明したように、Ruby 2.7ではRange#minmax
はEnumerableモジュールからRangeクラス自身に実装されました。
この関係でRange#minmax
が返す最大値はRange#max
に対応する値になります。
以下はRuby 2.6でRuby 2.7で実行結果が異なるコード例です。
('a'..'aa').max
#=> "aa"
# Ruby 2.6ではminmaxの最大値として"z"が返る
('a'..'aa').minmax
#=> ["a", "z"]
# Ruby 2.7では"aa"が返る(Range#maxの値と一致する)
('a'..'aa').minmax
#=> ["a", "aa"]
(1..(5.5)).max
#=> 5.5
# Ruby 2.6ではminmaxの最大値として5が返る
(1..(5.5)).minmax
#=> [1, 5]
# Ruby 2.7では5.5が返る(Range#maxの値と一致する)
(1..(5.5)).minmax
#=> [1, 5.5]
Comparable
clampメソッドに範囲オブジェクトを渡せるようになった
Ruby 2.7ではclampメソッドに範囲オブジェクトが渡せるようになりました。
# Ruby 2.6以前
-1.clamp(0, 2) #=> 0
1.clamp(0, 2) #=> 1
3.clamp(0, 2) #=> 2
# Ruby 2.7からは範囲オブジェクトも渡せる
-1.clamp(0..2) #=> 0
1.clamp(0..2) #=> 1
3.clamp(0..2) #=> 2
ちなみに、clampメソッドはRuby 2.4で追加された比較的新しいメソッドです。
参考 指定された範囲内の値を返すようにするComparable#clamp
Complex(複素数オブジェクト)
<=>
メソッドが追加され、条件付きで大小比較ができるようになった
Ruby 2.7では複素数オブジェクトに<=>
メソッドが追加され、以下のような比較をしても例外が発生しなくなりました。
# Ruby 2.6
0 <=> 0i
#=> NoMethodError (undefined method `<=>' for (0+0i):Complex)
# Ruby 2.7
0 <=> 0i
#=> 0
ただし、以下の条件を満たさない場合はnilが返ります。
- 複素数オブジェクトの虚部がゼロである
- 比較対象のオブジェクトが実数、または虚部がゼロの複素数オブジェクトである
# 虚部がゼロでなければnil
Complex(2, 3) <=> Complex(2, 3) #=> nil
Complex(2, 3) <=> 1 #=> nil
# 比較対象のオブジェクトが実数でないのでnil
Complex(2) <=> :a #=> nil
# 虚部がゼロ、かつ比較対象のオブジェクトが実数なので比較可能
Complex(5) <=> 2 #=> 1
# 虚部がゼロ、かつ比較対象のオブジェクトが虚部ゼロの複素数なので比較可能
Complex(5) <=> Complex(2) #=> 1
Dir
globと[]
にヌル文字で区切るパターンを渡すと例外が発生するようになった
Ruby 2.7ではDir.glob
とDir.[]
にヌル文字で区切るパターンを渡すと例外が発生するようになりました。
Dir.glob("foo\0bar")
#=> ArgumentError (nul-separated glob pattern is deprecated)
Dir["foo\0bar"]
#=> ArgumentError (nul-separated glob pattern is deprecated)
ちなみにRuby 2.6がリリースされたときには警告が出るようになっていて、段階的にこの機能が削除されたことになります。
# Ruby 2.6
Dir.glob("foo\0bar")
#=> warning: use glob patterns list instead of nul-separated patterns
Encoding
CESU-8エンコーディングが追加された
Ruby 2.7ではCESU-8エンコーディング(Wikipedia)が使えるようになりました。
s = "いろは"
encoded = s.encode("CESU-8")
encoded.encoding == Encoding::CESU_8
#=> true
Enumerable
select(filter)とmapを同時に行うfilter_mapメソッドが追加された
Ruby 2.7ではselect(filter)とmapを同時に行うfilter_mapメソッドが追加されました。
このメソッドを使うとブロックの戻り値が真であるものだけがmapの結果として返されます。
numbers = [1, 2, 3, 4, 5]
# filter_mapを利用して偶数の要素だけ値を10倍する(奇数は要素から除外)
numbers.filter_map { |n| n * 10 if n.even? }
#=> [20, 40]
# Ruby 2.6以前だと下のどちらかの書き方になる
numbers.select(&:even?).map { |n| n * 10 }
numbers.map { |n| n * 10 if n.even? }.compact
ちなみに、filter_map
では偽の要素(nil
またはfalse
)が除外されますが、compact
はnil
の要素だけが除外されるところが違うので少し注意が必要です。
[1, nil, false].filter_map(&:itself)
#=> [1]
[1, nil, false].compact
#=> [1, false]
破壊的なfilter_map!
メソッドは用意されていないようです。
numbers.filter_map! { |n| n * 10 if n.even? }
#=> NoMethodError (undefined method `filter_map!' for [1, 2, 3, 4, 5]:Array)
要素ごとの個数をカウントするtallyメソッドが追加された
Ruby 2.7では要素ごとの個数をカウントするtallyメソッドが追加されました。
order = ['ピザ', 'パスタ', 'ピザ', 'ドリア', 'ドリア']
order.tally
#=> {'ピザ' => 2, 'パスタ' => 1, 'ドリア' => 2}
# Ruby 2.6以前で同等のことを実現するコード例
order.each_with_object(Hash.new(0)) { |o, h| h[o] += 1 }
#=> {'ピザ' => 2, 'パスタ' => 1, 'ドリア' => 2}
ちなみに、tallyという名前は線の本数で数を表現する、tally marks(画線法)に由来するそうで
Enumerator
自由なデータ変更を伴いつつ、無限のシーケンスを生成できるproduceメソッドが追加された
Ruby 2.7では自由なデータ変更を伴いつつ無限のシーケンスを生成できるproduceメソッドが追加されました。
# 1を順番にインクリメントさせるシーケンスから最初の5つを取り出す
# (第1引数の1はシーケンスの初期値)
Enumerator.produce(1, &:succ).take(5)
#=> [1, 2, 3, 4, 5]
# 0から999までのランダムな数字を5つ作成する(初期値を与えないパターン)
Enumerator.produce { rand(1000) }.take(5)
#=> [110, 725, 554, 755, 861]
こちらの記事にはproduceメソッドを使ってフィボナッチ数列を作成するコード例が載っていました。
# https://blog.saeloun.com/2019/11/27/ruby-2-7-enumerator-produce
Enumerator.produce([0, 1]) { |base_1, base_2|
[base_2, base_1 + base_2]
}.take(10).map(&:first)
#=> [0, 1, 1, 2, 3, 5, 8, 13, 21, 34]
lazyなenumeratorを非lazyなenumeratorに変換するeagerメソッドが追加された
Ruby 2.7ではlazyなenumeratorを非lazyなenumeratorに変換するeagerメソッドが追加されました。
# lazyなenumeratorを作成する
lazy = [1, 2, 3].lazy.map { |x| x * 2 }
# 非lazyなenumeratorに変換する
enum = lazy.eager
# Enumeratorのインスタンスになっている
# (eagerを呼ばなければEnumerator::Lazyのインスタンス)
enum.class #=> Enumerator
# 非lazyなので普通に配列で返ってくる
# (lazyのままだと、またEnumerator::Lazyが返るので、to_aする必要がある)
enum.map { |x| x / 2 }
#=> [1, 2, 3]
Feature #15901: Enumerator::Lazy#eager - Ruby master - Ruby Issue Tracking System
Enumerator::Yielderオブジェクトにto_procメソッドが実装された
Enumerator::Yielderオブジェクトがto_proc
メソッドを実装したため、<<
や.yield
を使わなくても(&y)
のような記法で済むようになりました。
# Ruby 2.6以前
# (ブロック引数のyがEnumerator::Yielderオブジェクト)
enum = Enumerator.new { |y|
# y << i の代わりに y.yield i と書いても良い
(1..3).each { |i| y << i }
}
enum.map { |i| i * 10 }
#=> [10, 20, 30]
# Ruby 2.7
enum = Enumerator.new { |y|
# (&y)でOK
(1..3).each(&y)
}
enum.map { |i| i * 10 }
#=> [10, 20, 30]
Feature #15618: Implement Enumerator::Yielder#to_proc - Ruby master - Ruby Issue Tracking System
Fiber
resumeすると同時にresumeされたfiber内で例外を発生させるraiseメソッドが追加された
Ruby 2.7はresumeすると同時にresumeされたfiber内で例外を発生させるraiseメソッドが追加されました。
fib = Fiber.new do
counter = 0
loop { counter += Fiber.yield }
counter
end
fib.resume
fib.resume(10)
fib.resume(100)
# raiseメソッドを使ってfiber内でStopIteration例外を発生させ、ループを終了させる
# ループが終了するとcounterの値が返ってくる
fib.raise(StopIteration)
#=> 110
Feature #10344: [PATCH] Implement Fiber#raise - Ruby master - Ruby Issue Tracking System
File
ドットで終わる文字列をextnameメソッドに渡すとドットを返すようになった
Ruby 2.7ではドットで終わる文字列をextnameメソッドに渡すとドットを返すようになりました。
# Ruby 2.6
File.extname('foo.')
#=> ""
# Ruby 2.7
File.extname('foo.')
#=> "."
FrozenError
例外の発生原因となった凍結されたオブジェクトをreceiverメソッドで受け取れるようになった
Ruby 2.7では例外の発生原因となった凍結されたオブジェクトをreceiverメソッドで受け取れるようになりました。
frozen_str = 'abc'.freeze
begin
frozen_str.upcase!
rescue FrozenError => err
# receiverメソッドで、例外の発生原因となったオブジェクトを取得できる
err.receiver
#=> "abc"
# 元のオブジェクトと同一のオブジェクトが返るので、equal?で比較するとtrueが返る
err.receiver.equal?(frozen_str)
#=> true
end
FrozenErrorオブジェクトをnewする際は、receiver:
オプションでreceiver
メソッドが返すオブジェクトを指定できます。
frozen_str = 'abc'.freeze
e = FrozenError.new('test', receiver: frozen_str)
e.receiver.equal?(frozen_str)
#=> true
GC
断片化したメモリをデフラグするGC.compactメソッドが導入された
Ruby 2.7では断片化したメモリをデフラグするGC.compactメソッドが導入されました。
# 断片化したメモリをデフラグする
GC.compact
技術的な解説はRuby 2.7.0.preview3のリリースノートより引用します。
一部のマルチスレッドなRubyプログラムを長期間動かし、マーク&スイープ型GCを何度も実行していると、メモリが断片化してメモリ使用量の増大や性能の劣化を招くことが知られています。
Ruby 2.7ではGC.compact というメソッドを導入し、ヒープをコンパクションすることが出来るようになります。ヒープ内の生存しているオブジェクトを他のページに移動し、不要なページを解放できるようになるとともに、ヒープをCoW (Copy on Write) フレンドリーにすることが出来ます。 [Feature #15626]
IO
BOMを見て外部エンコーディングを判別できるset_encoding_by_bomメソッドが導入された
Ruby 2.7ではBOMを見て外部エンコーディングを判別できるset_encoding_by_bomメソッドが導入されました。
ただし、ファイルをバイナリモードで開いていなかったり、すでに外部エンコーディングが設定されていたりした場合はArgumentErrorが発生します。
# BOMが付いているファイルをバイナリモード("rb"の"b")で開く
io = File.open("test/fixtures/bom.txt", "rb")
# デフォルトの外部エンコーディングはASCII_8BIT
io.external_encoding
#=> Encoding::ASCII_8BIT
# encodingを判別する
io.set_encoding_by_bom
#=> Encoding::UTF_8
# 外部エンコーディングがUTF-8に変わる
io.external_encoding
#=> Encoding::UTF_8
以下はBOMが付いていないUTF-8のテキストファイルを開いた場合の挙動です。
# BOMが付いていないファイルをバイナリモードで開く
io = File.open("test/fixtures/no_bom.txt", "rb")
# デフォルトの外部エンコーディングはASCII_8BIT
io.external_encoding
#=> Encoding::ASCII_8BIT
# encodingを判別する(BOMがないのでnilが返る)
io.set_encoding_by_bom
#=> nil
# 外部エンコーディングはASCII_8BITのまま
io.external_encoding
#=> Encoding::ASCII_8BIT
Integer
[]
メソッドがビットの範囲を指定できるようになった
Ruby 2.7では[]
メソッドを使って指定した範囲のビットの値を取り出せるようになりました。
# 0番目のビットから4桁ぶん取得する
0b01001101[0, 4]
#=> 0b1101 (10進数では13)
# 0番目から3番目までのビットを取得する([0, 4]と同じ)
0b01001101[0..3]
#=> 0b1101
# 整数値を指定すると、その位置のビットの値を返す(Ruby 2.6以前からの仕様)
0b01001101[0] #=> 1
0b01001101[1] #=> 0
0b01001101[2] #=> 1
0b01001101[3] #=> 1
Kernel
PathnameメソッドにPathnameオブジェクトを引数として渡すと引数そのものを返すようになった
Ruby 2.7ではKernel#Pathname
メソッドにPathnameオブジェクトを引数として渡すと引数そのものを返すようになりました。
pathname = Pathname.new('/tmp')
# Kernel#PathnameにPathnameオブジェクトを渡すと引数自身が返る
Pathname(pathname).equal?(pathname)
#=> true
なお、上のコードでは大文字で始まるPathname
が2回出てきますが、前者がクラス名(定数)で、後者はメソッドである点に注意してください。
# Pathnameはクラス名(定数)
Pathname.new('/tmp')
# Pathnameは(大文字で始まっているが)メソッド
Pathname(pathname)
Method
inspectメソッドがメソッドの引数や定義場所の情報も返すようになった
Ruby 2.7ではMethod#inspect
メソッドが、メソッドの引数や定義場所の情報も返すようになりました。
class SampleClass
def example_for_inspect(a, b=nil, *c, d:, e: nil, **rest, &block)
end
end
# Ruby 2.6
SampleClass.new.method(:example_for_inspect).inspect
#=> "#<Method: SampleClass#example_for_inspect>"
# Ruby 2.7
SampleClass.new.method(:example_for_inspect).inspect
#=> "#<Method: SampleClass#example_for_inspect(a, b=..., *c, d:, e: ..., **rest, &block) (your path)/sample_class.rb:2>"
Module
定数の定義場所を返すconst_source_locationメソッドが追加された
Ruby 2.7ではModule#const_source_location
メソッドを使って、定数の定義場所を確認できるようになりました。
module ConstantExample
FOO = 123
end
# const_source_locationメソッドを呼ぶと、定義場所のパスと行番号が返る
ConstantExample.const_source_location(:FOO)
#=> ["(your path)/const_example.rb", 2]
autoload?メソッドがinheritフラグを受け取れるようになった(未執筆)
(僕は使い方がいまいちよくわからなかったので、@tmtmsさんの以下のブログ記事を参照してください🙏)
nameメソッドが常に凍結された文字列を返すようになった(試験的な変更)
Ruby 2.7ではModule#name
メソッドが常に凍結された文字列を返すようになりました。
ただし、これは試験的な変更です。
name = Time.name
p name #=> "Time"
# Ruby 2.6
name.frozen? #=> false
# Ruby 2.7
name.frozen? #=> true
Module / Proc
ruby2_keywordsメソッドが追加された(未執筆)
(僕は使い方がいまいちよくわからなかったので、@tmtmsさんの以下のブログ記事を参照してください🙏)
NilClass / TrueClass / FalseClass
to_sメソッドを呼ぶと凍結された文字列を返すようになった(試験的な変更)
Ruby 2.7ではnil
/true
/false
に対してto_s
メソッドを呼ぶと、凍結された文字列を返すようになりました。
ただし、これは試験的な変更です。
s = nil.to_s
p s #=> ""
# Ruby 2.7(Ruby 2.6ではfalse。以下同様)
s.frozen? #=> true
s = true.to_s
p s #=> "true"
s.frozen? #=> true
s = false.to_s
p s #=> "false"
s.frozen? #=> true
ObjectSpace::WeakMap
true/falseやシンボルなど、特別なオブジェクトをキーや値に指定できるようになった
Ruby 2.7ではtrue/falseやシンボルなど、特別なオブジェクトをWeakMapのキーや値に指定できるようになりました。
wm = ObjectSpace::WeakMap.new
x = 'Hello'
wm[true] = x
wm[true] #=> Hello
wm[nil] = x
wm[nil] #=> Hello
wm[1] = x
wm[1] #=> Hello
wm[:foo] = x
wm[:foo] #=> Hello
# Ruby 2.6ではエラーになる
wm[true] = x
#=> ArgumentError (cannot define finalizer for TrueClass)
Proc
to_sメソッドの戻り値に@
が含まれなくなった
後方互換性のない変更点です。
Ruby 2.7ではProc#to_s
の戻り値に@
の文字が含まれなくなりました。
# Ruby 2.6
->{}.to_s
#=> "#<Proc:0x00007fba7c952db8@(irb):36 (lambda)>"
# Ruby 2.7
->{}.to_s
#=> "#<Proc:0x00007fda4c934c38 (irb):41 (lambda)>"
なお、この変更は@
ではなくスペースで区切られていれば、ターミナルでobject_idをダブルクリックしたときにobject_idだけをきれいに選択できるから、という理由で導入されたようです。
Range
Range#===
メソッドが文字列に対してもRange#cover?
を使うようになった
後方互換性のない変更点です。
Ruby 2.6(2.7ではなく、2.6です)では===
を呼びだしたとき、Range#include?
メソッドで判定不能だった場合はRange#cover?
メソッドで範囲内かどうかをチェックするように変更されました。
参考:サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita
しかし、文字列に対して===
を呼びだしたときはRange#include?
が使われていました。
Ruby 2.7では文字列の場合でもRange#cover?
が使われるようになります。
('A'..'Z').cover? 'ANA'
#=> true
('A'..'Z').include? 'ANA'
#=> false
# Ruby 2.6ではinclude?が使われるのでfalse
('A'..'Z') === 'ANA'
#=> false
# Ruby 2.7ではcover?が使われるのでtrue
('A'..'Z') === 'ANA'
#=> true
参考:Bug #15449: Range#=== is not using cover in Ruby 2.6 - Ruby master - Ruby Issue Tracking System
RubyVM
RubyVM.resolve_feature_path
が$LOAD_PATH.resolve_feature_path
に移動した(未執筆)
(僕は詳しい内容がよくわからなかったので、@tmtmsさんの以下のブログ記事を参照してください🙏)
String
Unicodeバージョンが12.1.0に、Unicide Emojiバージョンが12.1になった
Ruby 2.7ではUnicodeバージョンが12.1.0に、Unicide Emojiバージョンが12.1になりました。
RbConfig::CONFIG['UNICODE_VERSION'] #=> 12.1.0
RbConfig::CONFIG['UNICODE_EMOJI_VERSION'] #=> 12.1
ちなみにUnicode 12.1では「令和」の合字が追加されています。
12.1 では日本の新年号「令和」の合字一文字のみを加えており、総文字数は 137,929 となりました。
The Unicode Blog: Unicode コンソーシアムは「令和」をサポートする Unicode 12.1 を正式リリースしました
Symbol
start_with?メソッドとend_with?メソッドが追加された
Ruby 2.7ではSymbolクラスにstart_with?
メソッドとend_with?
メソッドが追加されました。
文字通りレシーバであるシンボルが指定された文字列で始まっていれば(または終わっていれば)trueを、そうでなければfalseを返します。
:foo_bar.start_with?('foo') #=> true
:foo_bar.start_with?('oo') #=> false
:foo_bar.end_with?('bar') #=> true
:foo_bar.end_with?('ba') #=> false
ちなみに引数は文字列で指定します。シンボルで指定すると例外が発生します。
:foo_bar.start_with?(:foo)
#=> TypeError (no implicit conversion of Symbol into String)
Time
ミリ秒以下を切り上げ/切り下げできるceil/floorメソッドが追加された
Ruby 2.7ではTimeクラスにミリ秒以下を切り上げ/切り下げできるceil/floorメソッドが追加されました。
# ミリ秒以下に10桁の値を持つTimeオブジェクトを作成する
t = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r)
t.iso8601(10)
#=> 2010-03-30T05:43:25.0123456789Z
# ミリ秒以下を切り上げる
t.ceil(0).iso8601(10)
#=> 2010-03-30T05:43:26.0000000000Z
t.ceil(5).iso8601(10)
#=> 2010-03-30T05:43:25.0123500000Z
# ミリ秒以下を切り下げる
t.floor(0).iso8601(10)
#=> 2010-03-30T05:43:25.0000000000Z
t.floor(5).iso8601(10)
#=> 2010-03-30T05:43:25.0123400000Z
inspectメソッドがミリ秒の情報も返すようになった
Ruby 2.7ではTime#inspect
メソッドがミリ秒の情報も返すようになりました。
t = Time.new(2010, 3, 30, 5, 43, "25.0123456789".to_r, '+09:00')
# Ruby 2.6ではinspectもto_sも返ってくる文字列は同じ
t.to_s
#=> 2010-03-30 05:43:25 +0900
t.inspect
#=> 2010-03-30 05:43:25 +0900
# Ruby 2.7ではinspectメソッドがミリ秒以下の情報も返す
t.inspect
#=> 2010-03-30 05:43:25 123456789/10000000000 +0900
UnboundMethod
bindとcallを同時に行うbind_callメソッドが追加された
Ruby 2.7ではbindとcallを同時に行うUnboundMethod#bind_call
メソッドが導入されました。
# https://github.com/ruby/ruby/blob/v2_7_0_rc2/NEWS から引用
class Foo
def add_1(x)
x + 1
end
end
class Bar < Foo
def add_1(x) # override
x + 2
end
end
obj = Bar.new
p obj.add_1(1) #=> 3
p Foo.instance_method(:add_1).bind(obj).call(1) #=> 2
p Foo.instance_method(:add_1).bind_call(obj, 1) #=> 2
標準ライブラリ関連のアップデート
Date
令和の和暦を"R01"のように表示したりパースしたりできるようになった
Ruby 2.7では令和の和暦を"R01"のように表示したりパースしたりできるようになりました。
require 'date'
reiwa_date = Date.new(2019, 5, 1)
reiwa_date.jisx0301
#=> R01.05.01
Date.parse("R01.05.01")
#=> #<Date: 2019-05-01 ((2458605j,0s,0n),+0s,2299161j)>
ERB
ERBインスタンスをマーシャリングしようとすると例外が発生するようになった
Ruby 2.7ではERBインスタンスをマーシャリングしようとすると例外が発生するようになりました。
require 'erb'
str = "hoge"
erb = ERB.new("value = <%= str %>")
# ERBインスタンスをマーシャリングすると例外が発生する
Marshal.dump(erb)
#=> TypeError (singleton class can't be dumped)
open-uri
Kernelのopenメソッドを使うと警告が出るようになった
Ruby 2.7ではopen-uri
ライブラリが提供しているopen
メソッドを使うと警告が出るようになります。
require 'open-uri'
# open-uriが提供しているopenメソッドを使うと警告が出る
open("http://www.ruby-lang.org/")
#=> warning: calling URI.open via Kernel#open is deprecated, call URI.open directly
# 代わりにURI.openメソッドを使う
# (この場合も事前に'open-uri'ライブラリをrequireしておく)
URI.open("http://www.ruby-lang.org/")
なお、この変更はRuby 2.5のリリース時に予告されていました。
URI.open method defined as an alias to open-uri's Kernel.open. open-uri's Kernel.open will be deprecated in future.
Webページを開いた際のデフォルトの文字コードがUTF-8になった
Ruby 2.7ではWebページを開いた際のデフォルトの文字コードがUTF-8になりました。
require 'open-uri'
URI.open("http://www.ruby-lang.org/") do |f|
puts f.charset #=> utf-8
end
OptionParser
不明なオプションが渡されると"Did you mean?"が表示されるようになった
Ruby 2.7のOptionParserでは不明なオプションが渡されると"Did you mean?"が表示されるようになりました。
require 'optparse'
OptionParser.new do |opts|
opts.on("-f", "--foo", "foo") {|v| }
opts.on("-b", "--bar", "bar") {|v| }
opts.on("-c", "--baz", "baz") {|v| }
end.parse!
$ option_parser_sample.rb --fooo
Traceback (most recent call last):
option_parser_sample.rb:7:in `<main>': invalid option: --fooo (OptionParser::InvalidOption)
Did you mean? foo
Pathname
globメソッドにオプション引数としてbaseが渡せるようになった
Ruby 2.7ではPathname.glob
メソッドのオプション引数としてbase:
が渡せるようになりました。
この引数はDir.glob
メソッド(Dir.[]
メソッド)のbase:
オプションに委譲されます。
[PARAM] base:
カレントディレクトリの代わりに相対パスの基準にするベースディレクトリを指定します。指定した場合、結果の頭にはベースディレクトリはつかないので、絶対パスが必要な場合はベースディレクトリを追加する必要があるでしょう。
require 'pathname'
path = '/tmp'
# /tmpディレクトリ以下のパスを表すPathnameオブジェクトの配列が返る
Pathname.glob("*", File::FNM_DOTMATCH, base: path)
#=> [#<Pathname:.>, #<Pathname:..>, ...]
その他
Ruby 2.7ではこれ以外にもさまざまな変更点がありますが、全部は説明しきれないのでNEWSのページに載っていた内容で、ここまでに説明していない情報を箇条書きにしておきます。
- RubyGemsのバージョンが3.1.2になった(参考)
- Bundlerのバージョンが2.1.2になった(参考)
- エスケープ文字が含まれる場合のCGI.escapeHTMLメソッドの呼び出しが2倍から5倍速くなった(参考)
- CSVのバージョンが3.1.2になった(参考)
- Object#DelegateClass accepts a block and module_evals it in the context of the returned class, similar to Class.new and Struct.new.
- JSONのバージョンが2.3.0になった
- Add Net::FTP#features to check available features, and Net::FTP#option to enable/disable each of them. [Feature #15964]
- Add ipaddr optional parameter to Net::HTTP#start to replace the address for TCP/IP connection [Feature #5180]
- Net::IMAP / Add Server Name Indication (SNI) support. [Feature #15594]
- Racc / Merge 1.4.15 from upstream repository and added cli of racc.
- Reline / New stdlib that is compatible with readline stdlib by pure Ruby and also has a multiline mode.
- REXMLのバージョンが3.2.3になった(参考)
- RSSのバージョンが0.2.8になった(参考)
- StringScannerのバージョンが1.0.3になった(参考)
- 以下のライブラリがbundled gemでなくなり、明示的なgemのインストールが必要になった
- CMath (cmath gem)
- Scanf (scanf gem)
- Shell (shell gem)
- Synchronizer (sync gem)
- ThreadsWait (thwait gem)
- E2MM (e2mmap gem)
- 以下のライブラリがdefault gemとしてrubygems.orgに公開された
- benchmark
- cgi
- delegate
- getoptlong
- net-pop
- net-smtp
- open3
- pstore
- readline
- readline-ext
- singleton
- 以下のライブラリもdefault gemになった。ただし、rubygems.orgにはまだ公開されていない
- monitor
- observer
- timeout
- tracer
- uri
- yaml
-
did_you_mean
gemがbundled gemからdefault gemに昇格した -
Profiler__
モジュールとprofile.rbが標準ライブラリから削除された(Ruby 2.0から誰もメンテナンスしていないため) - パフォーマンス、もしくは実装上の改善
- Fiber
- File.realpath
- Hash
- MonitorとMonitorMixinのパフォーマンスが改善された
- Thread
- JIT
- その他の変更
- RubyのビルドにC99に対応したコンパイラが必要になった
- IA64アーキテクチャのサポートが削除された
- 開発リポジトリがSubversionからGitに変更された(ただし、GitHubではなく https://git.ruby-lang.org/ruby.git でホストされている)
- RUBY_REVISIONが数値ではなく文字列になった(リポジトリがSubversionからGitに変わった影響)
- RUBY_DESCRIPTIONにSubversionのrevisionではなく、Gitのrevisionが含まれるようになった
- Support built-in methods in Ruby with
_builtin
syntax.
まとめ
というわけで、この記事ではRuby 2.7で導入されたさまざまな新機能や変更点を説明しました。
いやあ、今年は例年以上に変更点が多いですね!!
「Rubyは死んだ」とか言ってるのはいったい誰なんでしょうか?
個人的にはEnumerable#tally
やEnumerable#filter_map
の使用頻度が高くなりそうな予感がします。
Rubyって配列やハッシュ周りのメソッドがめちゃくちゃ豊富なのが好きです、僕は。
irbの進化もすさまじくて、簡単な動作確認がすこぶる効率アップしそうですね。
そして、今年も楽しいクリスマスプレゼントを届けてくれたMatzさんやコミッタのみなさんに感謝したいと思います。どうもありがとうございました!
みなさんもぜひRuby 2.7の新機能を試してみてください😉
あわせて読みたい
本記事の中でもいくつか紹介しましたが、@tmtmsさんも毎年アドベントカレンダーでRubyの新機能を解説されています。
僕が説明を端折った機能も丁寧に解説されているので、こちらも一緒にチェックすることをお勧めします。
Ruby 2.7 Advent Calendar 2019 - Qiita
こちらの記事では、Rubyコミッタの笹田さんと遠藤さんが「Ruby 2.7でなぜそのような変更が行われたのか」という背景を解説されています。こちらもあわせて読むと、Ruby 2.7の新機能をより深く理解できるはずです。
プロと読み解くRuby 2.7 NEWS - クックパッド開発者ブログ
Ruby 2.3〜2.6の新機能は以下の記事にまとめてあります。
こちらもあわせてどうぞ。
- サンプルコードでわかる!Ruby 2.3の主な新機能 - Qiita
- サンプルコードでわかる!Ruby 2.4の新機能と変更点 - Qiita
- サンプルコードでわかる!Ruby 2.5の主な新機能と変更点 Part 1 - Qiita
- サンプルコードでわかる!Ruby 2.5の主な新機能と変更点 Part 2 - Qiita
- サンプルコードでわかる!Ruby 2.6の主な新機能と変更点 - Qiita
PR: 本記事を読んでもよくわからなかったRuby初心者の方へ
「本文に一通り目を通してみたけど、なんかよくわからない用語がたくさん出てきて、イマイチちゃんと理解できなかった😣」というRuby初心者の方は、拙著「プロを目指す人のためのRuby入門」(通称チェリー本)を読んでみてください。
本書の内容を一通り理解すれば、この記事の内容も問題なく読みこなせるはずです!
ちなみに本書の対象バージョンはRuby 2.4.1ですが、Ruby 2.5以降で発生する記述内容との差異は、それぞれ以下の記事にまとめてあります。なので、多少バージョンが古くても安心して読んでいただけます😊