Write specs for new Ruby 2.7 features and changes
ruby/spec already contains some specs for 2.7, but we should aim to cover all new features and important changes. This will improve the test coverage of these features (and maybe discover a few bugs along the way), allow other Ruby implementations to implement the changes faster with more confidence and document clearly the new behavior.
The new specs should be within a version guard block:
ruby_version_is "2.7" do
# New specs
end
NOTE: https://rubyreferences.github.io/rubychanges/2.7.html gives more details for many features and changes.
From https://github.com/ruby/ruby/blob/v2_7_0/NEWS:
NEWS for Ruby 2.7.0
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).
Changes since the 2.6.0 release
Language changes
Pattern matching
- [x] 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:
- https://speakerdeck.com/k_tsj/pattern-matching-new-feature-in-ruby-2-dot-7
- Note that the slides are slightly obsolete.
- [x] The warning against pattern matching can be suppressed with {-W:no-experimental option}[#label-Warning+option].
The spec of keyword arguments is changed towards 3.0
-
[x] 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}
- [x]
**nilis 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
- [x] 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) # {}
- [x] Above warnings can be suppressed also with {-W:no-deprecated option}[#label-Warning+option].
Numbered parameters
-
[x] 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
_1and 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/lambda without block is deprecated
-
[x] Proc.new and Kernel#proc with no block in a method called with a block is warned now.
def foo proc end foo { puts "Hello" } #=> warning: Capturing the given block using Kernel#proc is deprecated; use `&block` insteadThis warning can be suppressed with {-W:no-deprecated option}[#label-Warning+option].
-
[x] 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)
Other miscellaneous changes
-
[x] A beginless range is experimentally introduced. It might be useful in
case, new call-sequence of theComparable#clamp, constants and DSLs. Feature #14799ary[..3] # identical to ary[0..3] case RUBY_VERSION when ..."2.4" then puts "EOL" # ... end age.clamp(..100) where(sales: ..100) -
[x] Quoted here-document identifiers must end within the same line.
<<"EOS " # This had been warned since 2.4; Now it raises a SyntaxError EOS -
[x] The flip-flop syntax deprecation is reverted. Feature #5400
-
[x] Comment lines can be placed between fluent dot now.
foo # .bar .baz # => foo.baz -
[x] Calling a private method with a literal
selfas the receiver is now allowed. Feature #11297 Feature #16123 -
[x] 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]) -
[x]
yieldin singleton class syntax is warned and will be deprecated later. Feature #15575.def foo class << Object.new yield #=> warning: `yield' in class syntax will not be supported from Ruby 3.0. [Feature #15575](https://bugs.ruby-lang.org/issues/15575) end end foo { p :ok }This warning can be suppressed with {-W:no-deprecated option}[#label-Warning+option].
-
[x] Argument forwarding by
(...)is introduced. Feature #16253def foo(...) bar(...) endAll arguments to
fooare forwarded tobar, including keyword and block arguments. Note that the parentheses are mandatory.bar ...is parsed as an endless range. -
[x] Access and setting of
$SAFEis now always warned.$SAFEwill become a normal global variable in Ruby 3.0. Feature #16131 -
[x]
Object#{taint,untaint,trust,untrust}and related functions in the C-API no longer have an effect (all objects are always considered untainted), and are now warned 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 -
[x] Refinements take place at
Object#methodandModule#instance_method. Feature #15373
Command line options
Warning option
The -W option has been extended with a following :, to manage categorized
warnings. Feature #16345 Feature #16420
-
[x] To suppress deprecation warnings:
$ ruby -e '$; = ""' -e:1: warning: `$;' is deprecated $ ruby -W:no-deprecated -e '$; = //' -
[x] It works with the
RUBYOPTenvironment variable:$ RUBYOPT=-W:no-deprecated ruby -e '$; = //' -
[x] 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' -
[x] 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}[#label-Core+classes+updates+-28outstanding+ones+only-29].
Core classes updates (outstanding ones only)
Array
-
[x] Added Array#intersection. Feature #16155
-
[x] Added Array#minmax, with a faster implementation than Enumerable#minmax. Bug #15929
Comparable
-
[x] Comparable#clamp now accepts a Range argument. Feature #14784
```ruby -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
- [x] Added Complex#<=>.
So
0 <=> 0iwill not raise NoMethodError. Bug #15857
Dir
- [x] Dir.glob and Dir.[] no longer allow NUL-separated glob pattern. Use Array instead. Feature #14643
Encoding
- [x] Added new encoding CESU-8. Feature #15931
Enumerable
-
[x] Added Enumerable#filter_map. Feature #15323
[1, 2, 3].filter_map {|x| x.odd? ? x.to_s : nil } #=> ["1", "3"] -
[x] Added Enumerable#tally. Feature #11076
["A", "B", "C", "B", "A"].tally #=> {"A"=>2, "B"=>2, "C"=>1}
Enumerator
-
[x] 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 -
[x] 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!?"] -
[x] Added Enumerator::Yielder#to_proc so that a Yielder object can be directly passed to another method as a block argument. Feature #15618
Fiber
- [x] Added Fiber#raise that behaves like Fiber#resume but raises an exception on the resumed fiber. Feature #10344
File
-
[x] File.extname now returns a dot string for names ending with a dot on non-Windows platforms. Bug #15267
File.extname("foo.") #=> "."
FrozenError
- [x] 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
:receiveroption. Feature #15751
GC
-
[x] (MRI-specific) 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: https://bugs.ruby-lang.org/issues/15626
IO
- [x] Added IO#set_encoding_by_bom to check the BOM and set the external encoding. Bug #15210
Integer
-
[x] Integer#[] now supports range operations. Feature #8842
0b01001101[2, 4] #=> 0b0011 0b01001100[2..5] #=> 0b0011 0b01001100[2...6] #=> 0b0011 # ^^^^
Method
- [x] Method#inspect shows more information. Feature #14145
Module
-
[x] Added Module#const_source_location to retrieve the location where a constant is defined. Feature #10771
-
[x] 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
-
[x] Module#autoload? now takes an
inheritoptional argument, like Module#const_defined?. Feature #15777 -
[x] 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
- [x] 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
- [x] ObjectSpace::WeakMap#[]= now accepts special objects as either key or values. Feature #16035
Proc
- [x] 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
-
[x] Added Range#minmax, with a faster implementation than Enumerable#minmax. It returns a maximum that now corresponds to Range#max. Bug #15807
-
[x] 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
String
-
[x] Update Unicode version and Emoji version from 11.0.0 to 12.0.0. Feature #15321
-
[x] Update Unicode version to 12.1.0, adding support for U+32FF SQUARE ERA NAME REIWA. Feature #15195
-
[x] Update Unicode Emoji version to 12.1. Feature #16272
Symbol
- [x] Added Symbol#start_with? and Symbol#end_with? methods. Feature #16348
Time
-
[x] Added Time#ceil method. Feature #15772
-
[x] Added Time#floor method. Feature #15653
-
[x] Time#inspect is separated from Time#to_s and it shows the time's sub second. Feature #15958
UnboundMethod
-
[x] Added UnboundMethod#bind_call method. Feature #15955
<code>umethod.bind_call(obj, ...)</code> is semantically equivalent to <code>umethod.bind(obj).call(...)</code>. 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
- [x] Added Warning.[] and Warning.[]= to manage emitting/suppressing some categories of warnings. Feature #16345 Feature #16420
$LOAD_PATH
- [x] Added
$LOAD_PATH.resolve_feature_path. Feature #15903 Feature #15230
Stdlib updates (outstanding ones only)
- [x] Pathname.glob now delegates 3 arguments to Dir.glob
to accept
basekeyword. Feature #14405
Compatibility issues (excluding feature bug fixes)
- [x] 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
- [x] The Proc#to_s format was changed. Feature #16101
Range
- [x] #777 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
Stdlib compatibility issues (excluding feature bug fixes)
- 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 following default gems were published on rubygems.org
- [x] The
did_you_meangem has been promoted up to a default gem from a bundled gem
pathname
- [x] Kernel#Pathname when called with a Pathname argument now returns the argument instead of creating a new Pathname. This is more similar to other Kernel methods, but can break code that modifies the return value and expects the argument not to be modified.
C API updates
-
[ ] Many
*_kwfunctions 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 inrb_scan_argsformat string is now treated as keyword arguments. Passing a positional hash instead of keyword arguments will emit a deprecation warning. -
[x] C API declarations with
ANYARGSare changed not to useANYARGS. See https://github.com/ruby/ruby/pull/2404
@andrykonchin I tried to keep the ones you checked after my last fix for links to issues. Should be fine but would be good if you can double-check.
@eregon Checked 👍
Note for contributors: please mention here which item/checkbox you'd like to add specs for, in order to avoid duplicated work.
Hi @eregon
I believe you can mark this as completed
- [ ] "Added Symbol#start_with? and Symbol#end_with? methods."
Symbol#end_with?: https://github.com/ruby/spec/commit/c51c102ceb1966839e8febca927771ab9d04829f
Symbol#start_with?: https://github.com/ruby/spec/commit/7377c2b0ad8bee9603646b5a7bc4db2176918c4a
And this looks like completed too
The Proc#to_s format was changed. Feature #16101
https://github.com/ruby/spec/commit/d3c12442817a4f2582659d43eba0017e81d5159b
@eregon
How could I cover this one?
- [ ] Added Array#minmax, with a faster implementation than Enumerable#minmax. Bug #15929
As far as I understand there's already a Enumerable#minmax spec which uses Arrays... so it's already tested?
@lxxxvi In that case we could just add a new file and check Array.should have_instance_method(:minmax), and a comment saying the behavior is tested in the core/enumerable/minmax_spec.rb.
I don't see Arrays being used (as receivers) in https://github.com/ruby/spec/blob/bc1942130ba064d7759f4e91e84ff6b126b2c721/core/enumerable/minmax_spec.rb though, so I think best is to copy that file and adapt to use Arrays. And check Array.should have_instance_method(:minmax) in 2.7+.
The flip-flop syntax deprecation is reverted. Feature #5400
And this one completed: https://github.com/ruby/spec/commit/61092f3c9e3e66b27c780ae274fc7c855cfbbfc7 https://github.com/ruby/spec/commit/574b5c05fa17955abecfe0cd4cfe3e1866b2063d
ObjectSpace::WeakMap#[]= now accepts special objects as either key or values. Feature #16035
It seems this case has already been covered in this commit https://github.com/ruby/spec/commit/47be917309aba997f3e353046a28296a41f95e46, can you please check?
@kuei0221 Indeed, I now checked the box.
^ PR for
[ ] Object#{taint,untaint,trust,untrust} and related functions in the C-API no longer have an effect (all objects are always considered untainted), and are now warned 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
61/70 done, we're almost there!
@eregon Is it time for new Ruby3-related issue?
I'll try to make one soon. It would be great to finish the last 5 items for this issue.
Only 2 items left under C API updates now.
Issue for Ruby 3.0 specs: https://github.com/ruby/spec/issues/823