Ruby 3.2.0 RC 1 发布
由 naruse 于 2022 年 12 月 6 日发布
我们很高兴宣布 Ruby 3.2.0-rc1 的发布。Ruby 3.2 增加了许多新功能和性能改进。
基于 WASI 的 WebAssembly 支持
这是 WASI 的初始 WebAssembly 支持端口。这使得 CRuby 二进制文件可以在 Web 浏览器、Serverless Edge 环境或其他 WebAssembly/WASI 嵌入器中使用。目前,此端口通过了不使用 Thread API 的基本和引导测试套件。

背景
WebAssembly (Wasm) 最初是为了在 Web 浏览器中安全快速地运行程序而引入的。但其目标——在各种环境中高效、安全地运行程序——长期以来不仅是 Web 所需,也是通用应用程序所期望的。
WASI (WebAssembly 系统接口) 就是为此类用例而设计的。虽然这类应用程序需要与操作系统通信,但 WebAssembly 运行在一个没有系统接口的虚拟机上。WASI 对其进行了标准化。
Ruby 中的 WebAssembly/WASI 支持旨在利用这些项目。它使 Ruby 开发人员能够编写在这些承诺的平台上运行的应用程序。
用例
此支持鼓励开发人员在 WebAssembly 环境中使用 CRuby。一个用例是 TryRuby playground 的 CRuby 支持。现在您可以在浏览器中尝试原始 CRuby 了。
技术要点
今天的 WASI 和 WebAssembly 本身缺少实现 Fiber、异常和 GC 的一些功能,因为它们仍在发展中,也出于安全原因。因此,CRuby 通过使用 Asyncify 来填补空白,这是一种二补码转换技术,用于控制用户空间的执行。
此外,我们在 WASI 之上构建了 一个 VFS,以便我们可以轻松地将 Ruby 应用打包成单个 .wasm 文件。这使得 Ruby 应用的分发更加容易。
相关链接
Regexp 针对 ReDoS 的改进
众所周知,Regexp 匹配可能需要出乎意料的长的时间。如果您的代码尝试对不可信的输入匹配一个可能效率低下的 Regexp,攻击者可能会利用它来实现高效的拒绝服务攻击(所谓的正则表达式 DoS,或 ReDoS)。
我们引入了两项改进,可以显著缓解 ReDoS。
改进的 Regexp 匹配算法
自 Ruby 3.2 起,通过使用记忆化技术,Regexp 的匹配算法得到了极大的改进。
# This match takes 10 sec. in Ruby 3.1, and 0.003 sec. in Ruby 3.2
/^a*b?a*$/ =~ "a" * 50000 + "x"

改进后的匹配算法使大多数 Regexp 匹配(在我们实验中约占 90%)能够在线性时间内完成。
(对于预览用户:此优化可能会为每次匹配消耗与输入长度成比例的内存。我们预计不会出现实际问题,因为此内存分配通常会延迟,并且正常的 Regexp 匹配消耗的内存最多是输入长度的 10 倍。如果您在实际应用中匹配 Regexp 时遇到内存不足的问题,请报告此问题。)
原始提案是 https://bugs.ruby-lang.org/issues/19104
Regexp 超时
上述优化无法应用于某些类型的正则表达式,例如包含高级功能(如反向引用或前瞻/后顾),或具有巨大固定重复次数的正则表达式。作为一种回退措施,还引入了 Regexp 匹配的超时功能。
Regexp.timeout = 1.0
/^a*b?a*()\1$/ =~ "a" * 50000 + "x"
#=> Regexp::TimeoutError is raised in one second
请注意,Regexp.timeout 是一个全局配置。如果您想为某些特殊 Regexp 使用不同的超时设置,您可以使用 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»(以前称为 «dead_end»)的功能已集成到 Ruby 中。这有助于您找到错误的位置,例如缺失或多余的
end,从而更快地恢复工作,例如在以下示例中: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]
^^^^^^
语言
-
匿名 rest 参数和关键字 rest 参数现在可以作为参数传递,而不仅仅用于方法参数。[Feature #18351]
def foo(*) bar(*) end def baz(**) quux(**) end -
接受单个位置参数和关键字的 proc 将不再自动展开。[Bug #18633]
proc{|a, **k| a}.call([1, 2]) # Ruby 3.1 and before # => 1 # Ruby 3.2 and after # => [1, 2] -
对显式对象设置的常量的赋值求值顺序已与单属性赋值的求值顺序一致。使用此代码:
foo::BAR = baz现在
foo会在baz之前调用。同样,对于常量的多个赋值,使用从左到右的求值顺序。使用此代码:foo1::BAR1, foo2::BAR2 = baz1, baz2现在使用以下求值顺序:
foo1foo2baz1baz2
-
查找模式不再是实验性的。 [Feature #18585]
-
接受 rest 参数(如
*args)并希望通过foo(*args)委托关键字参数的方法,现在必须标记为ruby2_keywords(如果尚未标记)。换句话说,所有希望通过*args委托关键字参数的方法现在都必须标记为ruby2_keywords,没有例外。这将更容易在库可以要求 Ruby 3+ 时过渡到其他委托方式。以前,如果接收方法接受*args,则会保留ruby2_keywords标志,但这是一个 bug 和不一致之处。一种查找可能缺失的ruby2_keywords的好方法是运行测试套件,找到每个测试套件失败的地方必须接收关键字参数的最后一个方法,然后在那里使用puts nil, caller, nil。然后检查调用链中每个必须委托关键字的方法/块是否正确标记为ruby2_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 现在支持 Linux、MacOS、BSD 和其他 UNIX 平台上的 x86-64 和 arm64/aarch64 CPU。
- 此版本带来了对 Mac M1/M2、AWS Graviton 和 Raspberry Pi 4 ARM64 处理器的支持。
- 构建 YJIT 需要 Rust 1.58.0+。 [Feature #18481]
- 为了确保 CRuby 使用 YJIT 构建,请安装 rustc >= 1.58.0 并使用
--enable-yjit运行./configure。 - 如果您在 YJIT 方面遇到任何问题,请联系 YJIT 团队。
- 为了确保 CRuby 使用 YJIT 构建,请安装 rustc >= 1.58.0 并使用
- JIT 代码的物理内存是惰性分配的。与 Ruby 3.1 不同,Ruby 进程的 RSS 被最小化,因为
--yjit-exec-mem-size分配的虚拟内存页面在被 JIT 代码实际使用之前不会映射到物理内存页面。 - 引入代码 GC(垃圾回收),当 JIT 代码的内存消耗达到
--yjit-exec-mem-size时,它会释放所有代码页面。- RubyVM::YJIT.runtime_stats 返回代码 GC 指标,以及现有的
inline_code_size和outlined_code_size键:code_gc_count、live_page_count、freed_page_count和freed_code_size。
- RubyVM::YJIT.runtime_stats 返回代码 GC 指标,以及现有的
- RubyVM::YJIT.runtime_stats 产生的大部分统计信息现在可以在发布版本中获得。
- 只需使用
--yjit-stats运行 ruby 即可计算统计信息(会产生一些运行时开销)。
- 只需使用
- YJIT 现在已针对利用对象形状进行了优化。 [Feature #18776]
- 利用更细粒度的常量失效来减少定义新常量时失效的代码量。 [Feature #18589]
MJIT
- MJIT 编译器已在 Ruby 中重新实现为标准库
mjit。 - MJIT 编译器在一个 fork 出来的 Ruby 进程下执行,而不是在一个称为 MJIT worker 的原生线程中执行。[[Feature #18968]]
- 因此,不再支持 Microsoft Visual Studio (MSWIN)。
- 不再支持 MinGW。[[Feature #18824]]
- 将
--mjit-min-calls重命名为--mjit-call-threshold。 - 将默认的
--mjit-max-cache从 10000 改回 100。
PubGrub
-
Bundler 2.4 现在使用 PubGrub 解析器,而不是 Molinillo。
- PubGrub 是 Dart 编程语言的
pub包管理器使用的下一代求解算法。 - 更改后您可能会获得不同的解析结果。请将此类情况报告给 RubyGems/Bundler issues。
- PubGrub 是 Dart 编程语言的
-
RubyGems 在 Ruby 3.2 中仍使用 Molinillo 解析器。我们计划将来用 PubGrub 替换它。
自 3.1 以来的其他值得注意的更改
- Hash
- 如果哈希为空,Hash#shift 现在始终返回 nil,而不是返回默认值或调用默认 proc。 [Bug #16908]
- MatchData
- 添加了 MatchData#byteoffset。 [Feature #13110]
- Module
- 添加了 Module.used_refinements。 [Feature #14332]
- 添加了 Module#refinements。 [Feature #12737]
- 添加了 Module#const_added。 [Feature #17881]
- Proc
- Proc#dup 返回子类实例。 [Bug #17545]
- Proc#parameters 现在接受 lambda 关键字。 [Feature #15357]
- Refinement
- 添加了 Refinement#refined_class。 [Feature #12737]
- RubyVM::AbstractSyntaxTree
- 为
parse、parse_file和of添加了error_tolerant选项。[[Feature #19013]]
- 为
- Set
- Set 现在作为内置类可用,无需
require "set"。[Feature #16989] 它目前通过Set常量或调用Enumerable#to_set进行自动加载。
- Set 现在作为内置类可用,无需
- String
- 添加了 String#byteindex 和 String#byterindex。 [Feature #13110]
- 更新 Unicode 到 15.0.0 版本和 Emoji 到 15.0 版本。 [Feature #18639] (也适用于 Regexp)
- 添加了 String#bytesplice。 [Feature #18598]
- Struct
- Struct 类也可以使用关键字参数进行初始化,而无需在
Struct.new上使用keyword_init: true。[Feature #16806]
- Struct 类也可以使用关键字参数进行初始化,而无需在
兼容性问题
注意:不包括功能错误修复。
已删除的常量
已删除以下已弃用的常量。
Fixnum和Bignum[Feature #12005]Random::DEFAULT[Feature #17351]Struct::GroupStruct::Passwd
已删除的方法
以下已弃用的方法已被移除。
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]
标准库兼容性问题
不再捆绑第三方源
-
我们不再捆绑第三方源,例如
libyaml,libffi。-
libyaml 源代码已从 psych 中移除。您可能需要在 Ubuntu/Debian 平台上安装
libyaml-dev。不同平台的包名是不同的。 -
捆绑的 libffi 源代码也已从
fiddle中移除。
-
-
Psych 和 fiddle 支持使用特定版本的 libyaml 和 libffi 源代码进行静态构建。您可以使用 libyaml-0.2.5 像这样构建 psych:
$ ./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 更新
更新的 C API
已更新以下 API。
- PRNG 更新:
rb_random_interface_t已更新并版本化。使用此接口且为旧版本构建的扩展库可能需要更新。另外,需要定义init_int32函数。
已删除的 C API
已删除以下已弃用的 API。
rb_cData变量。- “taintedness” 和 “trustedness” 函数。[Feature #16131]
标准库更新
- 更新了以下默认 gem。
- 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
- 更新了以下捆绑 gem。
- 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 或 commit 记录。
自 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 (Yukihiro Matsumoto) 于 1993 年开发,现在作为开源项目进行开发。它运行在多个平台上,并在世界各地广泛使用,尤其是在 Web 开发领域。
近期新闻
Ruby 4.0.0 发布
我们很高兴地宣布 Ruby 4.0.0 的发布。Ruby 4.0 引入了“Ruby Box”和“ZJIT”,并增加了许多改进。
由 naruse 发布于 2025 年 12 月 25 日
Ruby 文档的全新外观
继 ruby-lang.org 重新设计之后,我们还有更多好消息来庆祝 Ruby 成立 30 周年:docs.ruby-lang.org 采用了 Aliki——RDoc 的新默认主题,焕然一新。
由 Stan Lo 发布于 2025 年 12 月 23 日
重新设计我们的网站标识
我们很高兴地宣布对我们的网站进行全面重新设计。此次更新的设计由 Akatsuka Taeko 创作。
由 Hiroshi SHIBATA 发布于 2025 年 12 月 22 日
Ruby 4.0.0 preview3 发布
我们很高兴地宣布 Ruby 4.0.0-preview3 的发布。Ruby 4.0 引入了 Ruby::Box 和“ZJIT”,并增加了许多改进。
由 naruse 发布于 2025 年 12 月 18 日