📜 ⬆️ ⬇️

What's new in Ruby 2.3

Last week came out a preview of Ruby 2.3.0 . What is interesting from the changes:


Safe navigation operator


In Ruby, a safeguarding operator appeared, similar to the operator '?.' in Groovy and some other languages. The operator is used to shorten expressions, where you check the existence of an object and then refer to the object's method only in the case of a positive test:

 obj.nil? && obj.some_method 

If a chain of objects and methods is used, then the check may look cumbersome and several times useless to perform intermediate methods. For example, a typical case for Ruby on Rails to securely retrieve a large profile picture:
')
 image = user && user.profile && user.profile.thumbnails && user.profile.thumbnails.large 

Here the profile method will be executed three times and the thumbnails method will be executed twice. The optimized version will look even harder:

 image = user && (profile = user.profile) && (thumbnails = profile.thumbnails) && thumbnails.large 

At the same time, the result may not be entirely correct, if one of the objects in motion will be absent - then the image will be false , not nil . And if you check for nil? then the code will look even more confusing.

There is also a way to move deeper into the chain without checking, catching an exception, for example, in the usual way:

 image = begin user.profile.thumbnails.large rescue NoMethodError nil end 

or causing general disapproval of postfix rescue:

 image = user.profile.thumbnails.large rescue nil 

ActiveSupport to solve this problem delivers try and try! methods try! :

 image = user.try(:profile).try(:thumbnails).try(:large) 

These methods are added to the Object class and when they are called, they first check for the existence of the called method and, if it is absent, return nil . If the user has the #profile method, it will be executed and on its result further along the chain will be called try(:thumbnails) . If user is nil , then #try will return nil and so on the chain #try will be called from nil two more times. Slow? But short.

What does the newly appeared safe navigation operator in Ruby


According to task # 11537 for safe navigation in Ruby 2.3.0, the '.?' Operator was added, changed later to '&.'. In the new syntax, the expression from the examples can be written as:

 image = user&.profile&.thumbnails&.large 

Together with a concise look, such an implementation gives a quick check for nil , since the changes are implemented at the parser level and the ruby ​​code is not involved in the checks. After nil encountered, further execution of the chain is interrupted. The check is performed precisely on nil , and not on a logical condition, so if the result is false , then the execution will continue successfully along the chain.

If arguments are passed to the method, then, in contrast to try , they are calculated only if the object exists and the method is actually called. For example, for ActiveSupport, the obj.try(:foo, bar()) expression will always execute bar() , even if obj does not exist. But in the obj&.foo(bar()) expression, the obj&.foo(bar()) argument will be evaluated only when ojb not nil .

Safe navigation can also be used when assigning a value to an attribute:

 obj&.attr += 1 

From the moment of the appearance of the feature request to its confirmation and commit with the first implementation variant, only slightly more than one month passed.

Navigation into embedded hashes and arrays with #dig.


Feature # 11688 adds the dig method to Hash and Array , which is used to safely derive values ​​from nested hashes and arrays. This method replaces the expression:

 value = hash[:a].nil? ? nil : hash[:a][:b].nil? ? nil : hash[:a][:b][:c] 

or:

 value = hash[:a][:b][:c] rescue nil 

on:

 value = hash.dig(:a, :b, :c) 

Access to nested hashes and arrays is often used when processing the parameters of HTTP requests received by Rails applications, or when working with YAML or JSON structures. Adding dig to the depth not only provides a convenient access method, but also accelerates it several dozen times.

The dig method was also recently added to Struct , but did not have time to get into the first preview 2.3.0.

String immutability


In Ruby 3, all string literals will be unchanged. Regarding the immutability of the disputes are long and now the movement in this direction has become more specific. It is expressed in the appearance of the “magic” commentary frozen-string-literal , whose presence includes by default immutability for all string literals, and in the addition - --enable/--disable=frozen-string-literal to control this behavior.

The main argument in favor of immutable strings is an increase in the speed of work due to internal optimizations. In most cases, strings remain unchanged throughout the life cycle, and fixing this behavior improves performance without changing the code.

And we have a small survey


We have prepared a hosting of Ruby applications in Jet9 containers. Both on cloud hosting and failover cluster .

One of the reasons why Ruby is the first to appear on Jet9 is to unify our own internal services and our customers' internal services (websites, billing, workflow, bugtracker, tickets, etc.). To simplify our life and reduce the cost of updating and maintaining the zoo from different distributions, HA-clusters with different configurations and individual physical servers, we transfer everything to a couple of typical HA-clusters on the Jet9 platform. Most of it is written in Ruby — its own applications and third-party applications (Redmine, Gitlab) are used. Thus, we have done support for Ruby on Jet9, including for ourselves, we check it for ourselves.

Applications run under Nginx + Apache + mod_passenger (5.0.21), this is the most convenient way. But you can use standalone Passenger or other application servers (Unicorn, Puma). Versions 2.2.2 and 2.2.3 are now available, and others are being prepared. In this regard, the survey:

Source: https://habr.com/ru/post/271301/


All Articles