A few days ago, Konstantin Haase, one of the key people in the Ruby community, posted an
entry in his blog about the preview version of Ruby 2.1. Changes between versions 2.0 and 2.1 have accumulated enough to read into his presentation, and better in Russian.
NB: Of course, Ruby 2.1 contains all the great features of the previous version - 2.0. Changes from previous versions will not be mentioned.Refinement mechanism
It is known that the
refinement engine is introduced in Ruby 2.0. The implementation of this mechanism turned out to be rather inconsistent, therefore, in version 2.0, its functionality was somewhat limited and marked as experimental.
It is worth recalling that the refinements allow you to apply decoys patches in a single Ruby file:
')
module Foo refine String do def foo self + "foo" end end end using Foo puts "bar".foo
Outside this file, instances of the String
class will not respond to the foo
method.
In the new version of Ruby, updates will not be an experimental feature. Moreover, they can be applied not only to the top-level scope, but also to individual modules.
module Foo refine String do def foo self + "foo" end end end module Bar using Foo puts "bar".foo end
It is important to keep in mind that overreliance on clarifications may lead to the writing of rather confusing code. The developers of some implementations of Ruby have already stated that they may refuse to support the refinement.
Decimal Literals
When working with Ruby, you can see that the floating-point values ​​do not behave in the best way when they are performed on calculations that are familiar with working with decimal fractions:
irb(main):001:0> 0.1 * 3 => 0.30000000000000004
This behavior leads to the fact that a large number of Ruby-developers begin to use whole numbers, imitating a given number of decimal places when presenting the result. Of course, this method works well with a strictly specified number of decimal places. Otherwise, you have to use rational fractions - this is not very bad, but the language does not have a sufficiently convenient syntax to work with them.
The new version of Ruby introduces the
r
suffix to describe decimal and rational fractions:
irb(main):001:0> 0.1r => (1/10) irb(main):002:0> 0.1r * 3 => (3/10)
Immune strings
If the code contains a string declaration, then each time the line containing the code is executed, Ruby creates a new object of the
String
class. This is due to string
mutability . In such cases,
characters behave much more efficiently, since they are initialized only once. However, to compare a character with a string, you need to convert a string to a symbol or a character to a string. Performing such transformations is a risky operation, opening up the potential for a DoS attack, since the characters are not released during garbage collection, and any character-to-string conversion creates a new string.
The only way to protect yourself from negative consequences in this case is to store and use the string as a constant:
class Foo BAR = "bar" def bar?(input) input == BAR end end
Often, to get rid of mutability, perform line freezing. Freezing the object prevents it from being modified by the Ruby code, but does not give any performance gains:
class Foo BAR = "bar".freeze def bar?(input) input == BAR end end
It looks quite ridiculous and cumbersome. Fortunately, Ruby 2.1 offers a new syntax for solving this problem:
class Foo def bar?(input) input == "bar"f end end
In the above code, an
immutable String
object will be created, and wherever it is used, it will be initialized only once.
It is possible that this syntax may seem strange. The same code snippet can be rewritten equivalently:
class Foo def bar?(input) input == %q{bar}f end end
In general, the question of applying the suffix
f
to arrays and hashes remains open.
Mandatory Key Arguments
For some reason, the
obligatory key arguments were not mentioned in the announcement of Ruby 2.0. So Ruby 2.0 introduces the required key arguments:
def foo(a: 10) puts a end foo(a: 20)
With this approach to declaring methods, you have to specify the default values ​​of the arguments. This is not always possible, so Ruby 2.1 allows you to specify the required key arguments:
def foo(a:) puts a end foo(a: 20)
Method declaration returns method name
In previous versions of Ruby, a method declaration with
def
returned
nil
.
def foo() end
Now this behavior has changed and the method name is returned as a symbol:
def foo() end
This is useful for metaprogramming and performing such tricks. For example, does everyone know that the
private
method can take arguments?
Now, when
def
returns the name of the declared method, you can easily make the methods private:
Remove extra bytes from strings
Ruby now has a convenient method for removing extra bytes from strings:
some_string.scrub("")
It used to be difficult to achieve the same behavior of this method for all existing Ruby implementations, so a
library is also available for this.
StringScanner supports named captures
Many people like the
StringScanner
class from the standard language library. In particular, it is used in Rails to parse route patterns. Sinatra 2.0 will do the same.
In version 1.9, support for named captures was added, but
StringScanner
did not support them:
require 'strscan' s = StringScanner.new("foo") s.scan(/(?<bar>.*)/) puts s[:bar]
In Ruby 2.0, this code will throw an exception:
TypeError: no implicit conversion of Symbol into Integer
But when launched on Ruby 2.1, everything will be fine:
foo
Work with network interfaces
You can now access network interfaces using the
Socket.getifaddrs
method:
require 'socket' Socket.getifaddrs.each do |i| puts "#{i.name}: #{i.addr.ip_address}" if i.addr.ip? end
An example of the output of such a program:
lo0: fe80::1%lo0 lo0: 127.0.0.1 lo0: ::1 en0: fe80::1240:f3ff:fe7e:594e%en0 en0: 192.168.178.30 en2: fe80::3e07:54ff:fe6f:147a%en2
Quick work with numbers for computational tasks
Ruby 2.1 behaves faster when working with large numbers by using 128-bit integers as the internal representation of
Bignum
objects. Moreover, the use of the GNU Multiple Precision Arithmetic Library provides an additional boost to performance.
Changes in the virtual machine
Now the Ruby virtual machine, along with the use of the global method cache, performs
caching at the place of the function call . There are
separate slides about it.
Rgenc
The new version of Ruby uses a new
generational generation of garbage . Due to this, garbage collection will be faster. Prior to this, a conservative garbage collector was used, which operates according to the “stop the world - mark - sweep” scheme.
In fact, the old collector has not disappeared anywhere. Such things are difficult to change due to the characteristics of the internal and external Ruby C program interface.
However, the Ruby 2.1 virtual machine classifies objects into
light and
dark . Depending on the assigned class, the behavior of the garbage collector is determined. There are operations that make a
bright object
dark . For example, working with it from an extension in the C language. Objects such as open files are
dark initially.
The new garbage collector works only with
light objects.
RubyGems Update
RubyGems received an upgrade to version 2.2.0, which brings several minor improvements.
Nothing is eternal
Do not forget that the recent release is only a preliminary version, and all of the above may change.