10

6 changes you might have missed coming in Ruby 2.7

 3 years ago
source link: https://sourcediving.com/less-known-changes-in-ruby-2-7-8d5db660370f
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

6 changes you might have missed coming in Ruby 2.7

As part of the recent Ruby Hack Challenge held at Cookpad’s Global HQ in Bristol, some people submitted patches to Ruby Core, some others decided to learn more about Ruby by exploring what’s coming in the next release.

Image for post
Image for post
Ruby commiters having fun at the event

The following are some interesting changes that might not be as striking as pattern matching or the pipeline operator but are still useful to know about.

Navigating to previously executed lines in IRB

If you enjoy trying out your code in IRB, you probably have found yourself pressing the up arrow key (↑) multiple times to bring back a method definition into your IRB prompt only to find out it loads one line at a time.

Ruby 2.7 introduces a neat change to how that works. It will now load the whole method definition and even allow you to edit it as if you were on a text editor.

Image for post
Image for post
New IRB navigation

There are probably more uses for this and even changes in IRB that are not documented yet.

Introducing Module#const_source_location

Using Method#source_location made finding the location of any method fairly easy. Unfortunately, there wasn’t an equivalent for constants. This meant that unless the constant you needed to find was defined in your codebase, finding its source location was not easy.

That is why Ruby 2.7 introduces Module#const_source_locationwhich will make finding the source location of a constant as easy as finding it for a method.

To illustrate that, let’s say we have the following class:

Whenever we want to find where MY_CONSTANT was last defined, we can now do the following:

> Module.const_source_location(:MyClass)
=> ["my_class.rb", 1]

> MyClass.const_source_location(:MY_CONSTANT)
=> ["my_class.rb", 2]

This method also receives the constant as a String if you prefer it that way.

> Module.const_source_location("MyClass")
=> ["my_class.rb", 1]

Introducing FrozenError#receiver

When FrozenError is raised, it is usually difficult to determine from the context which was the frozen object that a modification was attempted on.

Ruby 2.7 introduces FrozenError#receiver which will return the frozen object that modification was attempted on, similar to NameError#receiver. This can help pinpoint exactly what is the frozen object.

In your Ruby code, the frozen object can be set when raising FrozenError by passing it as the second argument to FrozenError.new.

> FrozenError.new("error message", "frozen string".freeze).receiver
=> "frozen string"
> _.frozen?
=> true

Combining non-Symbol and Symbol keys is allowed again

Before Ruby 2.6, if we had a method that received keyword arguments by using the double splat operator like this:

def method_with_keyword_args(opt=nil, **keyword_args)
keyword_args
end

We could call it using a Hash as a parameter even if some of its keys were not symbols and it would treat them as the first optional argument.

> method_with_keyword_args(a: 1, "b" => 2, "c" => 3)
=> {:a=>1}

In 2018 Matz started a discussion on Twitter in favor of removing support for non-symbol keys which ended up with an experimental feature being introduced in Ruby 2.6.0.

That meant that calling the method in the same way demonstrated before would raise an ArgumentError.

> method_with_keyword_args(a: 1, "b" => 2, "c" => 3)
ArgumentError (non-symbol key in keyword arguments: "b")

Fortunately, it seems that Ruby commiters later decided to revert the decision. So in 2.7 (actually as early as 2.6.2) the behavior was reverted and is now the same as in pre-2.6.0 Ruby versions.

Using Proc and lambda without a block

Let’s start with proc. When Proc.new or proc are called without a block inside of a method and such method is called with a block, a deprecation warning will be printed out.

To illustrate that, let’s say we have the following method:

def proc_without_block
proc
end

Calling the method with a block will just send call to the block that was passed as a parameter in Ruby 2.6:

> proc_without_block { "in here!" }.call
=> "in here!"

That changes in 2.7. Although the method will still behave the same, a deprecation warning will be printed out.

> proc_without_block { "in here!" }.call
warning: Capturing the given block using Proc.new is deprecated; use `&block` instead
=> "in here!"

Now let’s talk about lambda. In Ruby 2.7, when lambda is called without a block inside of a method and that method is called with a block, an errorwill be raised . To illustrate that, let’s say we have the following method:

def lambda_without_block
lambda
end

As mentioned, in Ruby 2.7 this will no longer work and an ArgumentError will be raised.

> lambda_without_block { :in_here }
ArgumentError (tried to create Proc object without a block)

Calling such method with a block in Ruby 2.6 would return the Proc and print out a deprecation warning:

> lambda_without_block { :in_here }
warning: tried to create Proc object without a block
=> #<Proc:0x00007fa527865d70 (lambda)>

Discouraging use of $; and $, special variables

As Matz has mentioned several times. One of the things that Ruby copied from Perl is the definition of a few special variables. Those variables begin with the $ character so they are globally available.

As in Perl the special variables have special meanings in Ruby. Both $;and $, are used for input and output formatting. In particular:

  • $;: Default separator for String#split
  • $,: Item to be emitted between the parameters of print and Array#join

Ruby 2.7 discourages us from using those globals by a deprecation warning that’s printed out when setting them to a non-nil value and using them with Array#split and Array#join respectively.

> $; = " "
warning: non-nil $; will be deprecate
=> " "
> "hello world!".split
warning: $; is set to non-nil value
=> ["hello", "world!"]
> $, = " "
warning: non-nil $, will be deprecated
=> " "
> ["hello", "world!"].join
warning: non-nil $, will be deprecated
=> "hello world!"

Doing the same using Ruby 2.6 wouldn’t trigger any warnings when setting them to a non-nil value:

> $; = " "
=> " "
> "hello world!".split
=> ["hello", "world!"]
> $, = " "
=> " "
> ["hello", "world!"].join
=> "hello world!"

What other changes are coming in Ruby?

Checking out the NEWS file in Ruby’s repository is a great way to learn more about other changes coming in the next Ruby version. It can also be helpful in finding the issue that started the discussion for each change.

Special thanks to Roberto Miranda who helped writting this blog post.


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK