NEWS for Ruby 2.7.0
本文档是除 bug 修复之外,在版本发布之间所做的用户可见功能更改的列表。
请注意,每个条目都保持得非常简短,不提供原因或参考信息。要查看所有信息的完整更改列表,请参阅 ChangeLog 文件或 Redmine (例如 https://bugs.ruby-lang.org/issues/$FEATURE_OR_BUG_NUMBER)。
自 2.6.0 发布以来的更改
语言更改
模式匹配
-
模式匹配作为一项实验性功能引入。[Feature #14912]
case [0, [1, 2, 3]] in [a, [b, *c]] p a #=> 0 p b #=> 1 p c #=> [2, 3] end case {a: 0, b: 1} in {a: 0, x: 1} :unreachable in {a: 0, b: var} p var #=> 1 end case -1 in 0 then :unreachable in 1 then :unreachable end #=> NoMatchingPatternError json = <<END { "name": "Alice", "age": 30, "children": [{ "name": "Bob", "age": 2 }] } END JSON.parse(json, symbolize_names: true) in {name: "Alice", children: [{name: name, age: age}]} p name #=> "Bob" p age #=> 2 JSON.parse(json, symbolize_names: true) in {name: "Alice", children: [{name: "Charlie", age: age}]} #=> NoMatchingPatternError
-
更多详情请参阅以下幻灯片
-
可以通过 -W:no-experimental 选项 来抑制有关模式匹配的警告。
关键字参数的规范已为 3.0 进行了更改
-
关键字参数和位置参数的自动转换已被弃用,将在 Ruby 3 中移除。[Feature #14183]
-
当方法调用在最后一个参数传递一个
Hash,并且不传递关键字参数,而被调用的方法又接受关键字参数时,会发出警告。为了继续将 hash 作为关键字参数处理,请添加一个双星号(double splat)运算符,以避免警告并确保 Ruby 3 中的正确行为。def foo(key: 42); end; foo({key: 42}) # warned def foo(**kw); end; foo({key: 42}) # warned def foo(key: 42); end; foo(**{key: 42}) # OK def foo(**kw); end; foo(**{key: 42}) # OK
-
当方法调用向接受关键字参数的方法传递关键字参数,但未传递足够必需的位置参数时,关键字参数将被视为最后的必需位置参数,并会发出警告。将参数作为 hash 而不是关键字参数传递,以避免警告并确保 Ruby 3 中的正确行为。
def foo(h, **kw); end; foo(key: 42) # warned def foo(h, key: 42); end; foo(key: 42) # warned def foo(h, **kw); end; foo({key: 42}) # OK def foo(h, key: 42); end; foo({key: 42}) # OK
-
当一个方法接受特定的关键字参数但不支持关键字参数拆包(keyword splat),并且传递给该方法的 hash 或关键字参数拆包同时包含
Symbol和非 Symbol 键时,该 hash 将继续被拆分,并会发出警告。您需要更新调用代码,单独传递 hash 以确保 Ruby 3 中的正确行为。def foo(h={}, key: 42); end; foo("key" => 43, key: 42) # warned def foo(h={}, key: 42); end; foo({"key" => 43, key: 42}) # warned def foo(h={}, key: 42); end; foo({"key" => 43}, key: 42) # OK
-
如果一个方法不接受关键字参数,并且使用关键字参数调用,关键字参数仍被视为位置 hash,不会发出警告。此行为将在 Ruby 3 中继续有效。
def foo(opt={}); end; foo( key: 42 ) # OK
-
-
如果方法接受任意关键字参数,则允许非 Symbol 作为关键字参数的键。[Feature #14183]
-
在 2.6.0 中禁止将非 Symbol 键用作关键字参数 hash 的键,但现在又允许了。[Bug #15658]
def foo(**kw); p kw; end; foo("str" => 1) #=> {"str"=>1}
-
-
**nil可用于方法定义中,以明确表示该方法不接受关键字参数。调用此类方法时使用关键字参数将导致ArgumentError。[Feature #14183]def foo(h, **nil); end; foo(key: 1) # ArgumentError def foo(h, **nil); end; foo(**{key: 1}) # ArgumentError def foo(h, **nil); end; foo("str" => 1) # ArgumentError def foo(h, **nil); end; foo({key: 1}) # OK def foo(h, **nil); end; foo({"str" => 1}) # OK
-
向不接受关键字参数的方法传递一个空的关键字参数拆包(empty keyword splat)将不再传递一个空的 hash,除非该空的 hash 对于必需参数是必需的,在这种情况下将发出警告。删除双星号(double splat)以继续传递位置 hash。[Feature #14183]
h = {}; def foo(*a) a end; foo(**h) # [] h = {}; def foo(a) a end; foo(**h) # {} and warning h = {}; def foo(*a) a end; foo(h) # [{}] h = {}; def foo(a) a end; foo(h) # {}
-
上述警告也可以通过 -W:no-deprecated 选项 来抑制。
编号参数
-
作为默认块参数的编号参数被引入。[Feature #4475]
[1, 2, 10].map { _1.to_s(16) } #=> ["1", "2", "a"] [[1, 2], [3, 4]].map { _1 + _2 } #=> [3, 7]
您仍然可以定义一个名为
_1等的局部变量,并且当它存在时会被识别,但会产生警告。_1 = 0 #=> warning: `_1' is reserved for numbered parameter; consider another name [1].each { p _1 } # prints 0 instead of 1
没有块的 proc/lambda 已弃用
-
在被调用时传递了块的方法中,使用没有块的
Proc.new和Kernel#proc现在会显示警告。def foo proc end foo { puts "Hello" } #=> warning: Capturing the given block using Kernel#proc is deprecated; use `&block` instead
此警告可以通过 -W:no-deprecated 选项 抑制。
-
在被调用时传递了块的方法中,没有块的
Kernel#lambda会引发异常。def bar lambda end bar { puts "Hello" } #=> tried to create Proc object without a block (ArgumentError)
其他杂项更改
-
无起始范围(beginless range)作为实验性功能引入。它可能在
case语句、Comparable#clamp的新调用序列、常量和 DSL 中很有用。[Feature #14799]ary[..3] # identical to ary[0..3] case RUBY_VERSION when ..."2.4" then puts "EOL" # ... end age.clamp(..100) where(sales: ..100)
-
将
$;设置为非 nil 值现在会显示警告。[Feature #14240] 这包括在String#split中的用法。此警告可以通过 -W:no-deprecated 选项 抑制。 -
将
$,设置为非 nil 值现在会显示警告。[Feature #14240] 这包括在Array#join中的用法。此警告可以通过 -W:no-deprecated 选项 抑制。 -
引用的 here-document 标识符必须在同一行内结束。
<<"EOS " # This had been warned since 2.4; Now it raises a SyntaxError EOS
-
flip-flop 语法弃用已恢复。[Feature #5400]
-
注释行现在可以放置在链式点(fluent dot)之间。
foo # .bar .baz # => foo.baz
-
现在允许使用字面量 `self` 作为接收者来调用私有方法。[Feature #11297] [Feature #16123]
-
修改器 rescue(Modifier rescue)现在对于多重赋值和单赋值的操作方式相同。[Bug #8279]
a, b = raise rescue [1, 2] # Previously parsed as: (a, b = raise) rescue [1, 2] # Now parsed as: a, b = (raise rescue [1, 2])
-
单例类语法中的 `yield` 现在会显示警告。此行为即将被弃用。[Feature #15575]。
def foo class << Object.new yield #=> warning: `yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575] end end foo { p :ok }此警告可以通过 -W:no-deprecated 选项 抑制。
-
引入了通过
(...)进行参数转发。[Feature #16253]def foo(...) bar(...) end
传递给
foo的所有参数都会转发给bar,包括关键字参数和块参数。请注意,括号是强制的。bar ...会被解析为无尽范围。 -
对
$SAFE的访问和设置现在总是会显示警告。$SAFE将在 Ruby 3.0 中成为普通全局变量。[Feature #16131] -
Object#{taint,untaint,trust,untrust}以及 C-API 中的相关函数不再有效果(所有对象始终被视为未污染),现在在详细模式(verbose mode)下会显示警告。此警告在 Ruby 3.0 中甚至在非详细模式下都会被禁用,方法和 C 函数将在 Ruby 3.2 中移除。[Feature #16131] -
Refinements 应用于
Object#method和Module#instance_method。[Feature #15373]
命令行选项
Warning 选项
-W 选项已扩展为后面带有 :,用于管理分类警告。[Feature #16345] [Feature #16420]
-
抑制弃用警告
$ ruby -e '$; = ""' -e:1: warning: `$;' is deprecated $ ruby -W:no-deprecated -e '$; = //'
-
它与
RUBYOPT环境变量一起工作$ RUBYOPT=-W:no-deprecated ruby -e '$; = //'
-
抑制实验性功能警告
$ ruby -e '0 in a' -e:1: warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby! $ ruby -W:no-experimental -e '0 in a'
-
要通过
RUBYOPT抑制两者,请设置空格分隔的值$ RUBYOPT='-W:no-deprecated -W:no-experimental' ruby -e '($; = "") in a'
另请参阅 Core classes updates 中的 Warning。
核心类更新(仅列出重要的更新)
Array- 新方法
-
添加了
Array#intersection。[Feature #16155] -
添加了
Array#minmax,其实现比Enumerable#minmax更快。[Bug #15929]
-
Comparable- 修改的方法
-
Comparable#clamp现在接受Range参数。[Feature #14784]-1.clamp(0..2) #=> 0 1.clamp(0..2) #=> 1 3.clamp(0..2) #=> 2 # With beginless and endless ranges: -1.clamp(0..) #=> 0 3.clamp(..2) #=> 2
-
Complex- 新方法
-
添加了
Complex#<=>。因此0 <=> 0i不会引发NoMethodError。[Bug #15857]
-
DirEncoding- 新编码
-
添加了新编码 CESU-8。[Feature #15931]
-
Enumerable- 新方法
-
添加了
Enumerable#filter_map。[Feature #15323][1, 2, 3].filter_map {|x| x.odd? ? x.to_s : nil } #=> ["1", "3"]
-
添加了
Enumerable#tally。[Feature #11076]["A", "B", "C", "B", "A"].tally #=> {"A"=>2, "B"=>2, "C"=>1}
-
Enumerator- 新方法
-
添加了
Enumerator.produce,用于从任何自定义数据转换生成Enumerator。[Feature #14781]require "date" dates = Enumerator.produce(Date.today, &:succ) #=> infinite sequence of dates dates.detect(&:tuesday?) #=> next Tuesday
-
添加了
Enumerator::Lazy#eager,用于从惰性枚举器(lazy enumerator)生成一个非惰性枚举器。[Feature #15901]a = %w(foo bar baz) e = a.lazy.map {|x| x.upcase }.map {|x| x + "!" }.eager p e.class #=> Enumerator p e.map {|x| x + "?" } #=> ["FOO!?", "BAR!?", "BAZ!?"]
-
添加了
Enumerator::Yielder#to_proc,这样 Yielder 对象可以直接作为块参数传递给另一个方法。[Feature #15618] -
添加了
Enumerator::Lazy#with_index以使其成为惰性。之前,Enumerator::Lazy#with_index未定义,因此它会继承Enumerator的默认实现,而该实现不是惰性的。[Bug #7877]("a"..).lazy.with_index(1) { |it, index| puts "#{index}:#{it}" }.take(3).force # => 1:a # 2:b # 3:c
-
Fiber- 新方法
-
添加了
Fiber#raise,其行为类似于Fiber#resume,但在恢复的协程(fiber)上引发异常。[Feature #10344]
-
File- 新方法
-
添加了
File.absolute_path?,以便以可移植的方式检查路径是否为绝对路径。[Feature #15868]File.absolute_path?("/foo") # => true (on *nix) File.absolute_path?("C:/foo") # => true (on Windows) File.absolute_path?("foo") # => false
-
- 修改的方法
-
在非 Windows 平台上,
File.extname现在对于以点结尾的名称返回一个点字符串。[Bug #15267]File.extname("foo.") #=> "."
-
FrozenError- 新方法
-
添加了
FrozenError#receiver,用于返回尝试修改的对象。要在 Ruby 代码中引发FrozenError时设置此对象,FrozenError.new接受一个:receiver选项。[Feature #15751]
-
GC- 新方法
-
添加了 `GC.compact` 方法来压缩堆。此函数压缩堆中的活动对象,以便使用更少的页面,并且堆更易于进行 CoW(写时复制)。[Feature #15626]
有关算法和注意事项的详细信息,请访问:bugs.ruby-lang.org/issues/15626
-
IO- 新方法
-
添加了
IO#set_encoding_by_bom来检查 BOM 并设置外部编码。[Bug #15210]
-
Integer- 修改的方法
-
Integer#[]现在支持范围操作。[Feature #8842]0b01001101[2, 4] #=> 0b0011 0b01001100[2..5] #=> 0b0011 0b01001100[2...6] #=> 0b0011 # ^^^^
-
- Method
- 修改的方法
-
Method#inspect显示更多信息。[Feature #14145]
-
- Module
- 新方法
-
添加了
Module#const_source_location,用于检索常量定义的位置。[Feature #10771] -
添加了
Module#ruby2_keywords,用于将方法标记为通过常规参数拆包(argument splat)传递关键字参数,在将所有参数委托给另一个方法时非常有用,并且可以与旧版 Ruby 向后兼容。[Bug #16154]
-
- 修改的方法
-
Module#autoload?现在接受一个可选参数inherit,类似于Module#const_defined?。[Feature #15777] -
Module#name现在总是返回一个冻结的String。对于给定的 Module,返回的String始终是相同的。此更改是实验性的。[Feature #16150]
-
NilClass/TrueClass/FalseClass- 修改的方法
-
NilClass#to_s、TrueClass#to_s和FalseClass#to_s现在总是返回一个冻结的String。对于这些值中的每一个,返回的String总是相同的。此更改是实验性的。[Feature #16150]
-
ObjectSpace::WeakMap- 修改的方法
-
ObjectSpace::WeakMap#[]=现在接受特殊对象作为键或值。[Feature #16035]
-
Proc- 新方法
-
添加了
Proc#ruby2_keywords,用于将 proc 标记为通过常规参数拆包(argument splat)传递关键字参数,在将所有参数委托给另一个方法或 proc 时非常有用,并且可以与旧版 Ruby 向后兼容。[Feature #16404]
-
Range- 新方法
-
添加了
Range#minmax,其实现比Enumerable#minmax更快。它返回的最大值现在对应于Range#max。[Bug #15807]
-
- 修改的方法
-
Range#===现在也对String参数使用Range#cover?(在 Ruby 2.6 中,它从Range#include?更改为所有类型(除了字符串))。[Bug #15449]
-
RubyVM- 移除的方法
-
RubyVM.resolve_feature_path已移动到$LOAD_PATH.resolve_feature_path。[Feature #15903] [Feature #15230]
-
String- Unicode
-
将 Unicode 版本和 Emoji 版本从 11.0.0 更新到 12.0.0。[Feature #15321]
-
将 Unicode 版本更新到 12.1.0,增加了对 U+32FF SQUARE ERA NAME REIWA 的支持。[Feature #15195]
-
将 Unicode Emoji 版本更新到 12.1。[Feature #16272]
-
Symbol- 新方法
-
添加了
Symbol#start_with?和Symbol#end_with?方法。[Feature #16348]
-
Time- 新方法
-
添加了
Time#ceil方法。[Feature #15772] -
添加了
Time#floor方法。[Feature #15653]
-
- 修改的方法
-
Time#inspect已与Time#to_s分离,并显示时间的亚秒部分。[Feature #15958]
-
UnboundMethod- 新方法
-
添加了
UnboundMethod#bind_call方法。[Feature #15955]umethod.bind_call(obj, ...)在语义上等同于umethod.bind(obj).call(...)。这种习惯用法在一些库中用于调用被覆盖的方法。添加的方法在不分配中间 Method 对象的情况下完成相同的操作。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
-
Warning- 新方法
-
添加了
Warning.[]和Warning.[]=来管理发出/抑制某些类别的警告。[Feature #16345] [Feature #16420]
-
- $LOAD_PATH
- 新方法
-
添加了
$LOAD_PATH.resolve_feature_path。[Feature #15903] [Feature #15230]
-
标准库更新(仅列出重要的更新)
Bundler-
升级到
Bundler2.1.2。请参阅 github.com/bundler/bundler/releases/tag/v2.1.2
-
CGI-
当至少有一个字符需要转义时,
CGI.escapeHTML的速度提高了 2~5 倍。请参阅 github.com/ruby/ruby/pull/2226
-
- CSV
-
升级到 3.1.2。请参阅 github.com/ruby/csv/blob/master/NEWS.md。
-
Date-
Date.jisx0301、Date#jisx0301和Date.parse支持新的日本年号。[Feature #15742]
-
Delegator-
Object#DelegateClass接受一个块,并在返回的类上下文中对其进行 module_eval,类似于Class.new和Struct.new。
-
ERB-
禁止 marshaling ERB 实例。
-
- IRB
-
引入了受 Pry gem 启发的语法高亮,用于 Binding#irb 的源行、REPL 输入以及某些核心类对象的 inspect 输出。
-
引入了由 Reline 提供的多行编辑模式。
-
在补全时显示文档。
-
默认启用自动缩进和历史记录的保存/加载。
-
JSON-
升级到 2.3.0。
-
- Net::FTP
-
添加了 `Net::FTP#features` 来检查可用功能,以及 `Net::FTP#option` 来启用/禁用每个功能。[Feature #15964]
-
Net::HTTP-
向
Net::HTTP#start添加了 `ipaddr` 可选参数,用于替换 TCP/IP 连接的地址。[Feature #5180]
-
- Net::IMAP
-
添加了服务器名称指示 (SNI) 支持。[Feature #15594]
-
- open-uri
OptionParser-
现在会显示未知选项的“您是否指...”提示。[Feature #16256]
test.rb
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!
示例
$ ruby test.rb --baa Traceback (most recent call last): test.rb:7:in `<main>': invalid option: --baa (OptionParser::InvalidOption) Did you mean? baz bar
-
Pathname-
Pathname.glob现在将 3 个参数委托给Dir.glob以接受 `base` 关键字参数。[Feature #14405]
-
- Racc
-
合并了上游存储库的 1.4.15 版本,并添加了 racc 的 cli。
-
- Reline
-
新的标准库,与 readline 标准库兼容,但用纯 Ruby 实现。它还提供多行编辑模式。
-
- REXML
-
升级到 3.2.3。请参阅 github.com/ruby/rexml/blob/master/NEWS.md。
-
- RSS
-
升级到 RSS 0.2.8。请参阅 github.com/ruby/rss/blob/master/NEWS.md。
-
- RubyGems
StringScanner-
升级到 1.0.3。请参阅 github.com/ruby/strscan/blob/master/NEWS.md。
-
兼容性问题(不包括功能性 bug 修复)
-
以下库不再是捆绑 gem。请安装相应的 gem 来使用这些功能。
-
CMath (cmath gem)
-
Scanf (scanf gem)
-
Shell (shell gem)
-
Synchronizer (sync gem)
-
ThreadsWait (thwait gem)
-
E2MM (e2mmap gem)
-
Proc-
Proc#to_s的格式已更改。[Feature #16101]
-
Range-
Range#minmax以前会迭代范围来确定最大值。现在它使用与Range#max相同的算法。在极少数情况下(例如,Float 或 String 的范围),这可能会产生不同的结果。[Bug #15807]
-
标准库兼容性问题(不包括功能 bug 修复)
-
将标准库提升为默认 gem
-
以下默认 gem 已在 rubygems.org 上发布
-
benchmark
-
cgi
-
delegate
-
getoptlong
-
net-pop
-
net-smtp
-
open3
-
pstore
-
readline
-
readline-ext
-
singleton
-
-
以下默认 gem 仅在 ruby-core 中推广,但尚未在 rubygems.org 上发布。
-
monitor
-
observer
-
timeout
-
tracer
-
uri
-
yaml
-
-
-
did_you_mean gem 已从捆绑 gem 提升为默认 gem
- pathname
-
当使用
Pathname参数调用Kernel#Pathname时,它现在返回参数而不是创建一个新的Pathname。这与其他Kernel方法更相似,但可能会破坏修改返回值并期望参数不被修改的代码。
-
- profile.rb, Profiler__
-
已从标准库中移除。它自 Ruby 2.0.0 起就无人维护。
-
C API 更新
-
已添加了许多 `*_kw` 函数,用于设置是否应将传递的最后一个参数视为关键字参数。您可能需要切换到这些函数以避免关键字参数分离警告,并确保 Ruby 3 中的正确行为。
-
rb_scan_args 格式字符串中的 `:` 字符现在被视为关键字参数。传递位置 hash 而不是关键字参数将发出弃用警告。
-
带有 `ANYARGS` 的 C API 声明已更改为不使用 `ANYARGS`。请参阅 github.com/ruby/ruby/pull/2404
实现改进
Fiber-
允许使用
--with-coroutine=选择不同的协程实现,例如:$ ./configure --with-coroutine=ucontext $ ./configure --with-coroutine=copy
-
用 fiber 池缓存替换了之前的堆栈缓存。fiber 池在一个内存区域中分配了许多堆栈。堆分配变为 O(log N),fiber 创建摊销为 O(1)。在微基准测试中测量到大约 10 倍的性能提升。github.com/ruby/ruby/pull/2224
-
File-
在许多平台上,
File.realpath使用 realpath(3),这可以显著提高性能。[Feature #15797]
-
Hash-
更改了小型
Hash对象的内部数据结构。[Feature #15602]
-
Monitor-
Monitor类是用 C 扩展编写的。[Feature #16255]
-
Thread-
VM 堆栈内存分配现在与原生线程堆栈合并,提高了线程分配性能并减少了与分配相关的失败。在微基准测试中测量到大约 10 倍的性能提升。
-
- JIT
-
当优化假设无效时,JIT 编译的代码会被重新编译为优化程度较低的代码。
-
当一个方法被认为是纯粹(pure)的时,会执行方法内联。此优化仍是实验性的,许多方法尚未被视为纯粹。
-
--jit-max-cache的默认值从 1,000 更改为 100。 -
--jit-min-calls的默认值从 5 更改为 10,000。
-
RubyVM-
每个调用站点的方法缓存(自 1.9 版本左右以来一直存在)得到了改进:缓存命中率从 89% 提高到 94%。请参阅 github.com/ruby/ruby/pull/2583
-
RubyVM::InstructionSequence-
RubyVM::InstructionSequence#to_binary方法生成编译后的二进制代码。二进制文件大小已减小。[Feature #16163]
-
杂项更改
-
已移除对 IA64 架构的支持。测试硬件难以获取,原生 fiber 代码难以实现,并且增加了解释器不必要的复杂性。[Feature #15894]
-
要求编译器支持 C99。[Misc #15347]
-
Ruby 的上游存储库已从 Subversion 更改为 Git。
-
RUBY_DESCRIPTION 包含 Git 修订版本而不是 Subversion 的。
-
使用
_builtin语法支持 Ruby 中的内置方法。[Feature #16254]一些方法定义在 *.rb 文件中(例如 trace_point.rb)。例如,很容易定义一个接受关键字参数的方法。