This document is a list of user visible feature changes made between releases except for bug fixes.
Note that each entry is kept so brief that no reason behind or reference information is supplied with. For a full list of changes with all sufficient information, see the ChangeLog file or Redmine (e.g. https://bugs.ruby-lang.org/issues/$FEATURE_OR_BUG_NUMBER
).
Pattern matching is introduced as an experimental feature. [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
See the following slides for more details:
speakerdeck.com/k_tsj/pattern-matching-new-feature-in-ruby-2-dot-7
Note that the slides are slightly obsolete.
The warning against pattern matching can be suppressed with -W:no-experimental option.
Automatic conversion of keyword arguments and positional arguments is deprecated, and conversion will be removed in Ruby 3. [Feature #14183]
When a method call passes a Hash
at the last argument, and when it passes no keywords, and when the called method accepts keywords, a warning is emitted. To continue treating the hash as keywords, add a double splat operator to avoid the warning and ensure correct behavior in 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
When a method call passes keywords to a method that accepts keywords, but it does not pass enough required positional arguments, the keywords are treated as a final required positional argument, and a warning is emitted. Pass the argument as a hash instead of keywords to avoid the warning and ensure correct behavior in 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
When a method accepts specific keywords but not a keyword splat, and a hash or keywords splat is passed to the method that includes both Symbol
and non-Symbol keys, the hash will continue to be split, and a warning will be emitted. You will need to update the calling code to pass separate hashes to ensure correct behavior in 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
If a method does not accept keywords, and is called with keywords, the keywords are still treated as a positional hash, with no warning. This behavior will continue to work in Ruby 3.
def foo(opt={}); end; foo( key: 42 ) # OK
Non-symbols are allowed as keyword argument keys if the method accepts arbitrary keywords. [Feature #14183]
Non-Symbol keys in a keyword arguments hash were prohibited in 2.6.0, but are now allowed again. [Bug #15658]
def foo(**kw); p kw; end; foo("str" => 1) #=> {"str"=>1}
**nil
is allowed in method definitions to explicitly mark that the method accepts no keywords. Calling such a method with keywords will result in an 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
Passing an empty keyword splat to a method that does not accept keywords no longer passes an empty hash, unless the empty hash is necessary for a required parameter, in which case a warning will be emitted. Remove the double splat to continue passing a positional 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) # {}
Above warnings can be suppressed also with -W:no-deprecated option.
Numbered parameters as default block parameters are introduced. [Feature #4475]
[1, 2, 10].map { _1.to_s(16) } #=> ["1", "2", "a"] [[1, 2], [3, 4]].map { _1 + _2 } #=> [3, 7]
You can still define a local variable named _1
and so on, and that is honored when present, but renders a warning.
_1 = 0 #=> warning: `_1' is reserved for numbered parameter; consider another name [1].each { p _1 } # prints 0 instead of 1
Proc.new
and Kernel#proc
with no block in a method called with a block will now display a warning.
def foo proc end foo { puts "Hello" } #=> warning: Capturing the given block using Kernel#proc is deprecated; use `&block` instead
This warning can be suppressed with -W:no-deprecated option.
Kernel#lambda
with no block in a method called with a block raises an exception.
def bar lambda end bar { puts "Hello" } #=> tried to create Proc object without a block (ArgumentError)
A beginless range is experimentally introduced. It might be useful in case
, new call-sequence of the Comparable#clamp
, constants and DSLs. [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)
Setting $;
to a non-nil value will now display a warning. [Feature #14240] This includes the usage in String#split
. This warning can be suppressed with -W:no-deprecated option.
Setting $,
to a non-nil value will now display a warning. [Feature #14240] This includes the usage in Array#join
. This warning can be suppressed with -W:no-deprecated option.
Quoted here-document identifiers must end within the same line.
<<"EOS " # This had been warned since 2.4; Now it raises a SyntaxError EOS
The flip-flop syntax deprecation is reverted. [Feature #5400]
Comment lines can be placed between fluent dot now.
foo # .bar .baz # => foo.baz
Calling a private method with a literal self
as the receiver is now allowed. [Feature #11297] [Feature #16123]
Modifier rescue now operates the same for multiple assignment as single assignment. [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
in singleton class syntax will now display a warning. This behavior will soon be deprecated. [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 }
This warning can be suppressed with -W:no-deprecated option.
Argument forwarding by (...)
is introduced. [Feature #16253]
def foo(...) bar(...) end
All arguments to foo
are forwarded to bar
, including keyword and block arguments. Note that the parentheses are mandatory. bar ...
is parsed as an endless range.
Access and setting of $SAFE
will now always display a warning. $SAFE
will become a normal global variable in Ruby 3.0. [Feature #16131]
Object#{taint,untaint,trust,untrust}
and related functions in the C-API no longer have an effect (all objects are always considered untainted), and will now display a warning in verbose mode. This warning will be disabled even in non-verbose mode in Ruby 3.0, and the methods and C functions will be removed in Ruby 3.2. [Feature #16131]
Refinements take place at Object#method
and Module#instance_method
. [Feature #15373]
Warning
option¶ ↑The -W
option has been extended with a following :
, to manage categorized warnings. [Feature #16345] [Feature #16420]
To suppress deprecation warnings:
$ ruby -e '$; = ""' -e:1: warning: `$;' is deprecated $ ruby -W:no-deprecated -e '$; = //'
It works with the RUBYOPT
environment variable:
$ RUBYOPT=-W:no-deprecated ruby -e '$; = //'
To suppress experimental feature warnings:
$ 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'
To suppress both by using RUBYOPT
, set space separated values:
$ RUBYOPT='-W:no-deprecated -W:no-experimental' ruby -e '($; = "") in a'
See also Warning
in Core classes updates.
Array
Added Array#intersection
. [Feature #16155]
Added Array#minmax
, with a faster implementation than Enumerable#minmax
. [Bug #15929]
Comparable
Comparable#clamp
now accepts a Range
argument. [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
Added Complex#<=>. So 0 <=> 0i
will not raise NoMethodError
. [Bug #15857]
Dir
Encoding
Added new encoding CESU-8. [Feature #15931]
Enumerable
Added Enumerable#filter_map
. [Feature #15323]
[1, 2, 3].filter_map {|x| x.odd? ? x.to_s : nil } #=> ["1", "3"]
Added Enumerable#tally
. [Feature #11076]
["A", "B", "C", "B", "A"].tally #=> {"A"=>2, "B"=>2, "C"=>1}
Enumerator
Added Enumerator.produce
to generate an Enumerator
from any custom data transformation. [Feature #14781]
require "date" dates = Enumerator.produce(Date.today, &:succ) #=> infinite sequence of dates dates.detect(&:tuesday?) #=> next Tuesday
Added Enumerator::Lazy#eager
that generates a non-lazy enumerator from a 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!?"]
Added Enumerator::Yielder#to_proc
so that a Yielder object can be directly passed to another method as a block argument. [Feature #15618]
Fiber
Added Fiber#raise
that behaves like Fiber#resume
but raises an exception on the resumed fiber. [Feature #10344]
File
Added File.absolute_path?
to check whether a path is absolute or not in a portable way. [Feature #15868]
File.absolute_path?("/foo") # => true (on *nix) File.absolute_path?("C:/foo") # => true (on Windows) File.absolute_path?("foo") # => false
File.extname
now returns a dot string for names ending with a dot on non-Windows platforms. [Bug #15267]
File.extname("foo.") #=> "."
FrozenError
Added FrozenError#receiver
to return the frozen object on which modification was attempted. To set this object when raising FrozenError
in Ruby code, FrozenError.new
accepts a :receiver
option. [Feature #15751]
GC
Added GC.compact
method for compacting the heap. This function compacts live objects in the heap so that fewer pages may be used, and the heap may be more CoW (copy-on-write) friendly. [Feature #15626]
Details on the algorithm and caveats can be found here: bugs.ruby-lang.org/issues/15626
IO
Added IO#set_encoding_by_bom
to check the BOM and set the external encoding. [Bug #15210]
Integer
Integer#[]
now supports range operations. [Feature #8842]
0b01001101[2, 4] #=> 0b0011 0b01001100[2..5] #=> 0b0011 0b01001100[2...6] #=> 0b0011 # ^^^^
Method
Method#inspect
shows more information. [Feature #14145]
Module
Added Module#const_source_location
to retrieve the location where a constant is defined. [Feature #10771]
Added Module#ruby2_keywords
for marking a method as passing keyword arguments through a regular argument splat, useful when delegating all arguments to another method in a way that can be backwards compatible with older Ruby versions. [Bug #16154]
Module#autoload?
now takes an inherit
optional argument, like Module#const_defined?
. [Feature #15777]
Module#name
now always returns a frozen String
. The returned String
is always the same for a given Module
. This change is experimental. [Feature #16150]
NilClass
/ TrueClass
/ FalseClass
NilClass#to_s
, TrueClass#to_s
, and FalseClass#to_s
now always return a frozen String
. The returned String
is always the same for each of these values. This change is experimental. [Feature #16150]
ObjectSpace::WeakMap
ObjectSpace::WeakMap#[]=
now accepts special objects as either key or values. [Feature #16035]
Proc
Added Proc#ruby2_keywords
for marking the proc as passing keyword arguments through a regular argument splat, useful when delegating all arguments to another method or proc in a way that can be backwards compatible with older Ruby versions. [Feature #16404]
Range
Added Range#minmax
, with a faster implementation than Enumerable#minmax
. It returns a maximum that now corresponds to Range#max
. [Bug #15807]
Range#===
now uses Range#cover?
for String
arguments, too (in Ruby 2.6, it was changed from Range#include?
for all types except strings). [Bug #15449]
RubyVM
RubyVM.resolve_feature_path
moved to $LOAD_PATH.resolve_feature_path
. [Feature #15903] [Feature #15230]
String
Update Unicode version and Emoji version from 11.0.0 to 12.0.0. [Feature #15321]
Update Unicode version to 12.1.0, adding support for U+32FF SQUARE ERA NAME REIWA. [Feature #15195]
Update Unicode Emoji version to 12.1. [Feature #16272]
Symbol
Added Symbol#start_with?
and Symbol#end_with?
methods. [Feature #16348]
Time
Added Time#ceil
method. [Feature #15772]
Added Time#floor
method. [Feature #15653]
Time#inspect
is separated from Time#to_s
and it shows the time's sub second. [Feature #15958]
UnboundMethod
Added UnboundMethod#bind_call
method. [Feature #15955]
umethod.bind_call(obj, ...)
is semantically equivalent to umethod.bind(obj).call(...)
. This idiom is used in some libraries to call a method that is overridden. The added method does the same without allocation of an intermediate Method
object.
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
Added Warning.[]
and Warning.[]=
to manage emitting/suppressing some categories of warnings. [Feature #16345] [Feature #16420]
Added $LOAD_PATH.resolve_feature_path
. [Feature #15903] [Feature #15230]
Bundler
Upgrade to Bundler
2.1.2. See github.com/bundler/bundler/releases/tag/v2.1.2
CGI
CGI.escapeHTML
becomes 2~5x faster when there is at least one escaped character. See github.com/ruby/ruby/pull/2226
CSV
Upgrade to 3.1.2. See github.com/ruby/csv/blob/master/NEWS.md.
Date
Date.jisx0301
, Date#jisx0301
, and Date.parse
support the new Japanese era. [Feature #15742]
Delegator
Object#DelegateClass accepts a block and module_evals it in the context of the returned class, similar to Class.new
and Struct.new
.
ERB
Prohibit marshaling ERB
instance.
Introduce syntax highlighting inspired by the Pry gem to Binding#irb
source lines, REPL input, and inspect output of some core-class objects.
Introduce multiline editing mode provided by Reline
.
Show documentation when completion.
Enable auto indent and save/load history by default.
JSON
Upgrade to 2.3.0.
Add Net::FTP#features to check available features, and Net::FTP#option to enable/disable each of them. [Feature #15964]
Net::HTTP
Add ipaddr
optional parameter to Net::HTTP#start
to replace the address for the TCP/IP connection. [Feature #5180]
Add Server Name Indication (SNI) support. [Feature #15594]
OptionParser
Now show “Did you mean?” for unknown options. [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!
example:
$ 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
now delegates 3 arguments to Dir.glob
to accept base
keyword. [Feature #14405]
Racc
Merge 1.4.15 from upstream repository and added cli of racc.
Reline
New stdlib that is compatible with the readline stdlib but is implemented in pure Ruby. It also provides a multiline editing mode.
Upgrade to 3.2.3. See github.com/ruby/rexml/blob/master/NEWS.md.
Upgrade to RSS 0.2.8. See github.com/ruby/rss/blob/master/NEWS.md.
StringScanner
Upgrade to 1.0.3. See github.com/ruby/strscan/blob/master/NEWS.md.
The following libraries are no longer bundled gems. Install corresponding gems to use these features.
CMath (cmath gem)
Scanf (scanf gem)
Shell (shell gem)
Synchronizer (sync gem)
ThreadsWait (thwait gem)
E2MM (e2mmap gem)
Proc
The Proc#to_s
format was changed. [Feature #16101]
Range
Range#minmax
used to iterate on the range to determine the maximum. It now uses the same algorithm as Range#max
. In rare cases (e.g. ranges of Floats or Strings), this may yield different results. [Bug #15807]
Promote stdlib to default gems
The following default gems were published on rubygems.org
benchmark
cgi
delegate
getoptlong
net-pop
net-smtp
open3
pstore
readline
readline-ext
singleton
The following default gems were only promoted at ruby-core, but not yet published on rubygems.org.
monitor
observer
timeout
tracer
uri
yaml
The did_you_mean
gem has been promoted up to a default gem from a bundled gem
Removed from standard library. It was unmaintained since Ruby 2.0.0.
Many *_kw
functions have been added for setting whether the final argument being passed should be treated as keywords. You may need to switch to these functions to avoid keyword argument separation warnings, and to ensure correct behavior in Ruby 3.
The :
character in rb_scan_args format string is now treated as keyword arguments. Passing a positional hash instead of keyword arguments will emit a deprecation warning.
C API declarations with ANYARGS
are changed not to use ANYARGS
. See github.com/ruby/ruby/pull/2404
Fiber
Allow selecting different coroutine implementations by using --with-coroutine=
, e.g.
$ ./configure --with-coroutine=ucontext $ ./configure --with-coroutine=copy
Replace previous stack cache with fiber pool cache. The fiber pool allocates many stacks in a single memory region. Stack allocation becomes O(log N) and fiber creation is amortized O(1). Around 10x performance improvement was measured in micro-benchmarks. github.com/ruby/ruby/pull/2224
File
File.realpath
now uses realpath(3) on many platforms, which can significantly improve performance. [Feature #15797]
Hash
Change data structure of small Hash
objects. [Feature #15602]
Monitor
Monitor
class is written in C-extension. [Feature #16255]
Thread
VM stack memory allocation is now combined with native thread stack, improving thread allocation performance and reducing allocation related failures. Around 10x performance improvement was measured in micro-benchmarks.
JIT-ed code is recompiled to less-optimized code when an optimization assumption is invalidated.
Method
inlining is performed when a method is considered as pure. This optimization is still experimental and many methods are NOT considered as pure yet.
The default value of --jit-max-cache
is changed from 1,000 to 100.
The default value of --jit-min-calls
is changed from 5 to 10,000.
RubyVM
Per-call-site method cache, which has been there since around 1.9, was improved: cache hit rate raised from 89% to 94%. See github.com/ruby/ruby/pull/2583
RubyVM::InstructionSequence
RubyVM::InstructionSequence#to_binary
method generates compiled binary. The binary size is reduced. [Feature #16163]
Support for IA64 architecture has been removed. Hardware for testing was difficult to find, native fiber code is difficult to implement, and it added non-trivial complexity to the interpreter. [Feature #15894]
Require compilers to support C99. [Misc #15347]
Details of our dialect: bugs.ruby-lang.org/projects/ruby-master/wiki/C99
Ruby's upstream repository is changed from Subversion to Git.
RUBY_DESCRIPTION includes Git revision instead of Subversion's one.
Support built-in methods in Ruby with the __builtin_
syntax. [Feature #16254]
Some methods are defined in *.rb (such as trace_point.rb). For example, it is easy to define a method which accepts keyword arguments.