Ruby 3.2.0 Preview 2 发布

naruse 于 2022 年 9 月 9 日发布

我们很高兴地宣布 Ruby 3.2.0-preview2 的发布。Ruby 3.2 增加了很多新特性和性能改进。

基于 WASI 的 WebAssembly 支持

这是 WASI 支持的 WebAssembly 的初步移植。它使得 CRuby 二进制文件可以在 Web 浏览器、无服务器边缘环境和其他 WebAssembly/WASI 嵌入器上可用。目前,此移植通过了不使用 Thread API 的基本和引导测试套件。

背景

WebAssembly (Wasm) 最初是为了在 Web 浏览器中安全快速地运行程序而引入的。但它的目标——在各种环境中高效安全地运行程序——不仅被 Web 应用所需要,也被通用应用程序长期渴望。

WASI (WebAssembly 系统接口) 就是为此类用例而设计的。虽然这类应用程序需要与操作系统通信,但 WebAssembly 运行在一个没有系统接口的虚拟机上。WASI 对其进行了标准化。

Ruby 中的 WebAssembly/WASI 支持旨在利用这些项目。它使 Ruby 开发者能够编写运行在这些承诺的平台上的应用程序。

用例

这项支持鼓励开发者在 WebAssembly 环境中利用 CRuby。其中一个用例是 TryRuby 游乐场对 CRuby 的支持。现在你可以在浏览器中试用原生的 CRuby 了。

技术要点

今天的 WASI 和 WebAssembly 本身在实现 Fiber、异常和 GC 方面存在一些缺失的功能,因为它们仍在发展中,也出于安全原因。因此,CRuby 通过使用 Asyncify 来弥补这一差距,Asyncify 是一种用于控制用户空间执行的二进制转换技术。

此外,我们在 WASI 之上构建了 一个 VFS,以便我们可以轻松地将 Ruby 应用打包成单个 .wasm 文件。这使得 Ruby 应用的分发更加容易。

Regexp 超时

引入了 Regexp 匹配的超时功能。

Regexp.timeout = 1.0

/^a*b?a*$/ =~ "a" * 50000 + "x"
#=> Regexp::TimeoutError is raised in one second

众所周知,Regexp 匹配可能需要意想不到的长的时间。如果您的代码尝试将一个可能效率低下的 Regexp 与不可信的输入进行匹配,攻击者可能会利用它进行高效的拒绝服务攻击(所谓的正则表达式 DoS,或 ReDoS)。

通过根据你的 Ruby 应用程序的需求配置 Regexp.timeout,可以预防或显著减轻 DoS 风险。请在你的应用程序中尝试并欢迎提供反馈。

请注意,Regexp.timeout 是全局配置。如果您想为一些特殊的 Regexps 使用不同的超时设置,您可能想在 Regexp.new 中使用 timeout 关键字。

Regexp.timeout = 1.0

# This regexp has no timeout
long_time_re = Regexp.new("^a*b?a*$", timeout: nil)

long_time_re =~ "a" * 50000 + "x" # never interrupted

原始提案是 https://bugs.ruby-lang.org/issues/17837

其他值得注意的新特性

不再捆绑第三方源

  • 我们不再捆绑第三方源,例如 libyaml, libffi

    • libyaml 的源代码已从 psych 中移除。你可能需要在 Ubuntu/Debian 平台上安装 libyaml-dev。不同平台的包名称可能不同。

    • libffi 将在 preview2 中从 fiddle 中移除

语言

  • 匿名 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
    

    现在使用以下求值顺序:

    1. foo1
    2. foo2
    3. baz1
    4. baz2

    [Bug #15928]

  • 查找模式不再是实验性的。[特性 #18585]

  • 接收剩余参数(如 *args)并希望通过 foo(*args) 委托关键字参数的方法,现在必须用 ruby2_keywords 标记(如果尚未标记)。换句话说,所有希望通过 *args 委托关键字参数的方法,现在都必须用 ruby2_keywords 标记,没有例外。这将使在库可以要求 Ruby 3+ 时更易于过渡到其他委托方式。之前,如果接收方法接受 *args,则 ruby2_keywords 标志会被保留,但这是一种错误和不一致。查找可能缺失的 ruby2_keywords 的好方法是运行测试套件,当失败时,找到必须接收关键字参数的最后一个方法,并在那里使用 puts nil, caller, nil,然后检查调用链上必须委托关键字参数的每个方法/块是否正确标记为 ruby2_keywords。[错误 #18625] [错误 #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

  • 支持 UNIX 平台上的 arm64 / aarch64。
  • 构建 YJIT 需要 Rust 1.58.1+。[特性 #18481]

自 3.1 以来的其他值得注意的更改

  • Hash
    • 如果哈希为空,Hash#shift 现在始终返回 nil,而不是返回默认值或调用默认 proc。 [Bug #16908]
  • MatchData
  • Module
  • Proc
  • Refinement
  • Set
    • Set 现在作为内置类可用,无需 require "set"。[Feature #16989] 它目前通过 Set 常量或调用 Enumerable#to_set 进行自动加载。
  • String
    • 添加了 String#byteindex 和 String#byterindex。 [Feature #13110]
    • 更新 Unicode 到 14.0.0 版本和 Emoji 14.0 版本。[特性 #18037](也适用于 Regexp)
    • 添加了 String#bytesplice。 [Feature #18598]
  • Struct
    • Struct 类也可以使用关键字参数进行初始化,而无需在 Struct.new 上使用 keyword_init: true。[Feature #16806]

兼容性问题

注意:不包括功能错误修复。

已删除的常量

已删除以下已弃用的常量。

已删除的方法

以下已弃用的方法已被移除。

标准库兼容性问题

  • Psych 不再捆绑 libyaml 源代码。用户需要通过包管理系统自行安装 libyaml 库。[特性 #18571]

C API 更新

已删除的 C API

已删除以下已弃用的 API。

  • rb_cData 变量。
  • “taintedness” 和 “trustedness” 函数。[Feature #16131]

标准库更新

  • 以下默认 gem 已更新。

    • 待定
  • 更新了以下捆绑 gem。

    • 待定
  • 以下默认 gem 现在是捆绑 gem。您需要在 bundler 环境下的 Gemfile 中添加以下库。

    • 待定

更多详情请参阅 NEWS提交日志

与 Ruby 3.1.0 相比,这次改动了 2393 个文件,新增 168931 行,删除 113411 行

下载

  • https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview2.tar.gz

    SIZE: 19816780
    SHA1: 2106c77fc1600daf41ae137ecc4cf7937e27f67f
    SHA256: 8a78fd7a221b86032f96f25c1d852954c94d193b9d21388a9b434e160b7ed891
    SHA512: 5e9ddcb1a43cff449b0062cc716bfb80a9ebbb14a1b063f34005e2998c2c5033badb44e882232db9b2fceda9376f6615986e983511fda2575d60894752b605cc
    
  • https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview2.tar.xz

    SIZE: 14578112
    SHA1: 538b3ea4dc0d99f60f8bd6f71e65a56ceeb41c18
    SHA256: 01fac0929dccdabc0686c1109da6c187897a401da9ff8851242befa92f7fd430
    SHA512: 0f4cc919284fdfa1a42b6381760d1b3a4660da4b0fcdd2adf01ea04a425548b3c5ac090866915675db73964a1055090e54dd97cf4628cbb69403e541c71c28ff
    
  • https://cache.ruby-lang.org/pub/ruby/3.2/ruby-3.2.0-preview2.zip

    SIZE: 24150109
    SHA1: 69ffffc52cad626166f73f21f25c29c9d73fe0e8
    SHA256: 67f9ad3110be1975b3ce547c0a6e2c910dfc1945fd6e9bb1bd340568897c6554
    SHA512: 1447e099e7a8da0ff206fda6f4e466640d6e86e9da8148315ab0154684b1fd22c02c0022b5a2f4d3fc00103b4e8cef8e35a770174921fd8c6abeca9ad41c1818
    

什么是 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 日

更多新闻...