Posted by naruse on 11 Nov 2022
Ruby 3.2系のプレビューリリースである、Ruby 3.2.0 Preview 3 が公開されました。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 です。
その他の主要な新機能
言語機能
- Find patternが実験的機能ではなくなりました。
3rd パーティライブラリのソースコード同梱廃止
-
libyaml
やlibffi
のような 3rd パーティのライブラリのソースコードの同梱を廃止しました-
Psych に同梱していた
libyaml
のソースコードは削除されました。ユーザーは自身で Ubuntu や Debian プラットフォームならlibyaml-dev
パッケージをインストールする必要があります。このパッケージ名称はプラットフォームごとに異なります。 -
Fiddle に同梱していた
libffi
のソースコードも削除されました
-
パフォーマンスの改善
YJIT
- Support arm64 / aarch64 on UNIX platforms.
- Building YJIT requires Rust 1.58.1+. [Feature #18481]
その他の注目すべき 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 14.0.0 and Emoji Version 14.0. [Feature #18037] (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
標準添付ライブラリのアップデート
-
SyntaxSuggest
syntax_suggest
(旧名:dead_end
)という機能がRuby本体に統合されました。[Feature #18159]
-
ErrorHighlight
- TypeErrorとArgumentErrorの引数を下線表示するようになりました
test.rb:2:in `+': nil can't be coerced into Integer (TypeError)
sum = ary[0] + ary[1]
^^^^^^
-
以下の default gems のバージョンがアップデートされました。
- TBD
-
以下の bundled gems のバージョンがアップデートされました。
- TBD
-
以下のライブラリが新たに bundled gems になりました。Bundler から利用する場合は Gemfile に明示的に指定してください。
- TBD
その他詳細については、NEWS ファイルまたはコミットログを参照してください。
なお、こうした変更により、Ruby 3.1.0 以降では 2719 個のファイルに変更が加えられ、191269 行の追加と 120315 行の削除が行われました !
ダウンロード
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview3.tar.gz
SIZE: 20086542 SHA1: dafca8116d36ceaa32482ab38359768de8c3ae5e SHA256: c041d1488e62730d3a10dbe7cf7a3b3e4268dc867ec20ec991e7d16146640487 SHA512: 860634d95e4b9c48f18d38146dfbdc3c389666d45454248a4ccdfc3a5d3cd0c71c73533aabf359558117de9add1472af228d8eaec989c9336b1a3a6f03f1ae88
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview3.tar.xz
SIZE: 14799804 SHA1: c94e2add05502cb5c39afffc995b7c8f000f7df0 SHA256: d3f5619de544240d92a5d03aa289e71bd1103379622c523a0e80ed029a74b3bb SHA512: c1864e2e07c3711eaa17d0f85dfbcc6e0682b077782bb1c155315af45139ae66dc4567c73682d326975b0f472111eb0a70f949811cb54bed0b3a816ed6ac34df
-
https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview3.zip
SIZE: 24426893 SHA1: 346c051c4be7ab8d0b551fd2ff8169785697db62 SHA256: cf49aa70e7ebd8abebffd5e49cd3bd92e5b9f3782d587cc7ed88c98dd5f17069 SHA512: 4f22b5ea91be17ef5f68cf0acb1e3a226dcc549ad71cc9b40e623220087c4065ca9bea942710f668e5c94ca0323da8d2ccd565f95a9085c1a0e38e9c0543b22f
Ruby とは
Rubyはまつもとゆきひろ (Matz) によって1993年に開発が始められ、今もオープンソースソフトウェアとして開発が続けられています。Rubyは様々なプラットフォームで動き、世界中で、特にWebアプリケーション開発のために使われています。