Posted by naruse on 6 Dec 2022
Ruby 3.2.0 Release Candidate 1 が公開されました。Ruby 3.2では多くの機能を追加しています。
WASIベースのWebAssemblyサポート
WASIベースのWebAssemblyへのコンパイルがサポートされました。これにより、ブラウザやサーバーレスエッジ環境、その他のWebAssembly/WASI環境でCRubyのバイナリが利用できるようになります。現在この移植版はThread API以外のbasic testとbootstrap testをパスしています。
Background
もともとWebAssembly (Wasm)が導入されたのは、プログラムをブラウザの上で安全かつ高速に実行するためでした。しかし、様々な環境で安全かつ効率的にプログラムを実行するという目的は、Webだけでなく一般的なアプリケーションで長らく求められていたものです
WASI (The WebAssembly System Interface)はそのようなユースケースのために設計されました。そのようなアプリケーションはOSと通信する必要がありますが、WebAssembly自体はシステムインターフェイスを持たないVMの上で実行されます。WASIはこのシステムインターフェイスを規格化します。
RubyのWebAssembly/WASIサポートは、このようなプロジェクトを活用することを狙っています。これにより、Ruby開発者がそのような有望なプラットフォームで動くアプリケーションを書けるようになります。
ユースケース
このサポートは、開発者がCRubyをWebAssembly環境で利用することを促進します。たとえば、TryRuby playgroundのCRubyサポートです。CRubyをウェブブラウザの上で試すことができるようになりました。
技術的な話
現時点のWASIとWebAssemblyには、Fiberや例外やGCを実装するための機能に一部足りないものがあります。CRubyではこのギャップを埋めるために、ユーザランドで実行を制御できるAsyncifyというバイナリ変換技術を使っています。
さらに、WASIの上にVFSを実装しました。これにより、Rubyアプリを単一の.wasmファイルに容易にパッケージ化できます。Rubyアプリの配布が少しかんたんになります。
参考文献
ReDoSに対するRegexpの改善
正規表現マッチングは予想外に時間がかかることがあることが知られています。もし信頼できない入力に対して非効率な可能性のある正規表現をマッチしていると、Denial of Service攻撃を効率的にできてしまう可能性があります(正規表現DoS、ReDoSなどと言われます)。
Ruby 3.2では、ReDoSを大幅に軽減する2つの改善を導入しました。
Regexpのマッチングアルゴリズムの改善
Ruby 3.2から、Regexpのマッチングアルゴリズム自体がメモ化の最適化によって大幅に改善されました。
# 次のマッチングはRuby 3.1では10秒かかりますが、Ruby 3.2では0.003秒で終わります
/^a*b?a*$/ =~ "a" * 50000 + "x"
このアルゴリズムの改善で、ほとんどの(我々の実験では90%程度の)正規表現が線形時間でマッチ判定できるようになります。
(プレビューリリースのユーザへ:この最適化は、マッチングのたびに入力長に比例したメモリを消費することがあります。このメモリ確保は通常遅延され、また、通常の正規表現であれば入力長のたかだか10倍程度のメモリを消費するだけなので、実用上の問題は発生しないと考えています。もし実アプリの正規表現マッチングでメモリ不足に陥った場合は報告してください)
提案チケットは https://bugs.ruby-lang.org/issues/19104 です。
Regexpのタイムアウトの導入
上記の最適化は、ある種の正規表現には適用できません。たとえば、後方参照や先読み・後読みのような発展的機能や、非常に大きい固定回数繰り返しを使っている場合には適用されません。この場合の対策として、正規表現マッチングのタイムアウト機能が導入されました。
Regexp.timeout = 1.0
/^a*b?a*()\1$/ =~ "a" * 50000 + "x"
#=> 1秒後にRegexp::TimeoutError
なお、Regexp.timeoutはグローバルな設定です。もし一部の特別な正規表現にだけ異なるタイムアウトを設定したい場合は、Regexp.new
のtimeout
キーワードを指定してください。
Regexp.timeout = 1.0
# This regexp has no timeout
long_time_re = Regexp.new('^a*b?a*()\1$', timeout: Float::INFINITY)
long_time_re =~ "a" * 50000 + "x" # never interrupted
提案チケットは https://bugs.ruby-lang.org/issues/17837 です。
その他の主要な新機能
SyntaxSuggest
-
syntax_suggest
の機能が Ruby に統合されました。syntax_suggest
は、Ruby のコードの実行時に以下の例のようにエラーが起きた場所を容易に発見する機能を提供します。Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ? 1 class Dog > 2 defbark > 4 end 5 end
ErrorHighlight
- TypeErrorとArgumentErrorの引数を下線表示するようになりました
test.rb:2:in `+': nil can't be coerced into Integer (TypeError)
sum = ary[0] + ary[1]
^^^^^^
言語機能
-
Anonymous rest and keyword rest arguments can now be passed as arguments, instead of just used in method parameters. [Feature #18351]
def foo(*) bar(*) end def baz(**) quux(**) end
-
A proc that accepts a single positional argument and keywords will no longer autosplat. [Bug #18633]
proc{|a, **k| a}.call([1, 2]) # Ruby 3.1 and before # => 1 # Ruby 3.2 and after # => [1, 2]
-
Constant assignment evaluation order for constants set on explicit objects has been made consistent with single attribute assignment evaluation order. With this code:
foo::BAR = baz
foo
is now called beforebaz
. Similarly, for multiple assignments to constants, left-to-right evaluation order is used. With this code:foo1::BAR1, foo2::BAR2 = baz1, baz2
The following evaluation order is now used:
foo1
foo2
baz1
baz2
-
Find patternが実験的機能ではなくなりました。 [Feature #18585]
-
Methods taking a rest parameter (like
*args
) and wishing to delegate keyword arguments throughfoo(*args)
must now be marked withruby2_keywords
(if not already the case). In other words, all methods wishing to delegate keyword arguments through*args
must now be marked withruby2_keywords
, with no exception. This will make it easier to transition to other ways of delegation once a library can require Ruby 3+. Previously, theruby2_keywords
flag was kept if the receiving method took*args
, but this was a bug and an inconsistency. A good technique to find the potentially-missingruby2_keywords
is to run the test suite, for where it fails find the last method which must receive keyword arguments, useputs nil, caller, nil
there, and check each method/block on the call chain which must delegate keywords is correctly marked asruby2_keywords
. [Bug #18625] [Bug #16466]def target(**kw) end # Accidentally worked without ruby2_keywords in Ruby 2.7-3.1, ruby2_keywords # needed in 3.2+. Just like (*args, **kwargs) or (...) would be needed on # both #foo and #bar when migrating away from ruby2_keywords. ruby2_keywords def bar(*args) target(*args) end ruby2_keywords def foo(*args) bar(*args) end foo(k: 1)
パフォーマンスの改善
YJIT
- YJIT now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
- This release brings support for Mac M1/M2, AWS Graviton and Raspberry Pi 4 ARM64 processors.
- Building YJIT requires Rust 1.58.0+. [Feature #18481]
- In order to ensure that CRuby is built with YJIT, please install rustc >= 1.58.0 and
run
./configure
with--enable-yjit
. - Please reach out to the YJIT team should you run into any issues.
- In order to ensure that CRuby is built with YJIT, please install rustc >= 1.58.0 and
run
- Physical memory for JIT code is lazily allocated. Unlike Ruby 3.1,
the RSS of a Ruby process is minimized because virtual memory pages
allocated by
--yjit-exec-mem-size
will not be mapped to physical memory pages until actually utilized by JIT code. - Introduce Code GC that frees all code pages when the memory consumption
by JIT code reaches
--yjit-exec-mem-size
.- RubyVM::YJIT.runtime_stats returns Code GC metrics in addition to
existing
inline_code_size
andoutlined_code_size
keys:code_gc_count
,live_page_count
,freed_page_count
, andfreed_code_size
.
- RubyVM::YJIT.runtime_stats returns Code GC metrics in addition to
existing
- Most of the statistics produced by RubyVM::YJIT.runtime_stats are now available in release builds.
- Simply run ruby with
--yjit-stats
to compute stats (incurs some run-time overhead).
- Simply run ruby with
- YJIT is now optimized to take advantage of object shapes. [[Feature #18776]]
- Take advantage of finer-grained constant invalidation to invalidate less code when defining new constants. [[Feature #18589]]
PubGrub
-
Bundler 2.4 は利用する依存解決ライブラリを Molinillo から PubGrub に変更しました。
- PubGrub は次世代の Dart 言語のパッケージマネージャである
pub
で使われている次世代の依存解決アルゴリズムです。 - この変更により、bundler を実行後に異なるライブラリの依存解決結果となる可能性があります。もし、不具合や気になる点を見つけた方は RubyGems/Bundler issues までご報告ください。
- PubGrub は次世代の Dart 言語のパッケージマネージャである
-
RubyGems は Ruby 3.2 では引き続き Molinillo ライブラリを利用しています。今後、RubyGems も PubGrub 変更し、Bundler と同じライブラリを使う予定です。
その他の注目すべき 3.1 からの変更点
- Hash
- Hash#shift now always returns nil if the hash is empty, instead of returning the default value or calling the default proc. [Bug #16908]
- MatchData
- MatchData#byteoffset has been added. [Feature #13110]
- Module
- Module.used_refinements has been added. [Feature #14332]
- Module#refinements has been added. [Feature #12737]
- Module#const_added has been added. [Feature #17881]
- Proc
- Proc#dup returns an instance of subclass. [Bug #17545]
- Proc#parameters now accepts lambda keyword. [Feature #15357]
- Refinement
- Refinement#refined_class has been added. [Feature #12737]
- RubyVM::AbstractSyntaxTree
- Add
error_tolerant
option forparse
,parse_file
andof
. [[Feature #19013]]
- Add
- Set
- Set is now available as a builtin class without the need for
require "set"
. [Feature #16989] It is currently autoloaded via theSet
constant or a call toEnumerable#to_set
.
- Set is now available as a builtin class without the need for
- String
- String#byteindex and String#byterindex have been added. [Feature #13110]
- Update Unicode to Version 15.0.0 and Emoji Version 15.0. [[Feature #18639]] (also applies to Regexp)
- String#bytesplice has been added. [Feature #18598]
- Struct
- A Struct class can also be initialized with keyword arguments
without
keyword_init: true
onStruct.new
[Feature #16806]
- A Struct class can also be initialized with keyword arguments
without
互換性に関する変更
Removed constants
The following deprecated constants are removed.
Fixnum
andBignum
[Feature #12005]Random::DEFAULT
[Feature #17351]Struct::Group
Struct::Passwd
Removed methods
The following deprecated methods are removed.
Dir.exists?
[Feature #17391]File.exists?
[Feature #17391]Kernel#=~
[Feature #15231]Kernel#taint
,Kernel#untaint
,Kernel#tainted?
[Feature #16131]Kernel#trust
,Kernel#untrust
,Kernel#untrusted?
[Feature #16131]
標準添付ライブラリの互換性に関する変更
3rd パーティライブラリのソースコード同梱廃止
-
libyaml
やlibffi
のような 3rd パーティのライブラリのソースコードの同梱を廃止しました-
Psych に同梱していた
libyaml
のソースコードは削除されました。ユーザーは自身で Ubuntu や Debian プラットフォームならlibyaml-dev
パッケージをインストールする必要があります。このパッケージ名称はプラットフォームごとに異なります。 -
Fiddle に同梱していた
libffi
のソースコードも削除されました
-
-
Psych と fiddle には特定バージョンの
libyaml
やlibffi
のソースコードを静的リンクするための機能が追加されました。libyaml-0.2.5
をリンクしてビルドする場合は以下のように実行します。$ ./configure --with-libyaml-source-dir=/path/to/libyaml-0.2.5
同様に、
libffi-3.4.4
を fiddle にリンクする場合は以下のように実行します。$ ./configure --with-libffi-source-dir=/path/to/libffi-3.4.4
C API updates
Updated C APIs
The following APIs are updated.
- PRNG update
rb_random_interface_t
updated and versioned. Extension libraries which use this interface and built for older versions. Alsoinit_int32
function needs to be defined.
Removed C APIs
The following deprecated APIs are removed.
rb_cData
variable.- “taintedness” and “trustedness” functions. [Feature #16131]
標準添付ライブラリのアップデート
- 以下の default gems のバージョンがアップデートされました。
- RubyGems 3.4.0.dev
- benchmark 0.2.1
- bigdecimal 3.1.3
- bundler 2.4.0.dev
- cgi 0.3.6
- date 3.3.0
- delegate 0.3.0
- did_you_mean 1.6.2
- digest 3.1.1
- drb 2.1.1
- erb 4.0.2
- error_highlight 0.5.1
- etc 1.4.1
- fcntl 1.0.2
- fiddle 1.1.1
- fileutils 1.7.0
- forwardable 1.3.3
- getoptlong 0.2.0
- io-console 0.5.11
- io-nonblock 0.2.0
- io-wait 0.3.0.pre
- ipaddr 1.2.5
- irb 1.5.1
- json 2.6.2
- logger 1.5.2
- mutex_m 0.1.2
- net-http 0.3.1
- net-protocol 0.2.0
- nkf 0.1.2
- open-uri 0.3.0
- openssl 3.1.0.pre
- optparse 0.3.0
- ostruct 0.5.5
- pathname 0.2.1
- pp 0.4.0
- pstore 0.1.2
- psych 5.0.0
- racc 1.6.1
- rdoc 6.5.0
- reline 0.3.1
- resolv 0.2.2
- securerandom 0.2.1
- set 1.0.3
- stringio 3.0.3
- syntax_suggest 1.0.1
- timeout 0.3.1
- tmpdir 0.1.3
- tsort 0.1.1
- un 0.2.1
- uri 0.12.0
- win32ole 1.8.9
- zlib 3.0.0
- 以下の bundled gems のバージョンがアップデートされました。
- minitest 5.16.3
- power_assert 2.0.2
- test-unit 3.5.5
- net-ftp 0.2.0
- net-imap 0.3.1
- net-pop 0.1.2
- net-smtp 0.3.3
- rbs 2.8.1
- typeprof 0.21.3
- debug 1.7.0
その他詳細については、NEWS ファイルまたはコミットログを参照してください。
なお、こうした変更により、Ruby 3.1.0 以降では 2846 個のファイルに変更が加えられ、203950 行の追加と 127153 行の削除が行われました !
ダウンロード
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-rc1.tar.gz
SIZE: 20253652 SHA1: 9b45af61ef1ae3c21ab88d7c9e30b80060116ac3 SHA256: 3bb9760c1ac1b66416aaa4899809f6ccd010e57038eaaeca19a383fd56275dac SHA512: 798157d785ebae94cb128d3c134fa35e0e90c654972e531cb6562823042f3fb68a270226f7b1cf0c42572ef2b1488a1a3e44f88389ad2a6f9ca4b280a2a8e759
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-rc1.tar.xz
SIZE: 14934012 SHA1: 5576e304786d466410f27a345dc1cb66f2c773f6 SHA256: 0d45b3af14e84337882a2021235a091ae5dcfc0baaf31dccc479b71d96dd07bc SHA512: d38fcb1e09eb9984f3b2347e65ae7406129c2578d068a25d33b5b4f021ec3b567a9abe56c2acbec6d07a3c2b4bc7b485dbd330cbfbb3a96350f60a2bb94d016e
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-rc1.zip
SIZE: 24473024 SHA1: 8fdc85363ce61e0b8f04da36e709d49028d04a75 SHA256: 7ff32473be108534548e401aaa9092c37a27f73323ea4091c33901c714c87ee5 SHA512: 07adf6a9c89fdcf420e7b131f40f2b1f4aca036aa6f28539ade26ca552f84a75e0698f77a8b774d2ea52b8c756c4982ef319bda5afa786c081a31dd9873c5ef7
Ruby とは
Rubyはまつもとゆきひろ (Matz) によって1993年に開発が始められ、今もオープンソースソフトウェアとして開発が続けられています。Rubyは様々なプラットフォームで動き、世界中で、特にWebアプリケーション開発のために使われています。