Чего нам ждать от Ruby 2.1?

от автора

Несколько дней назад Константин Хаасе, один из ключевых людей в сообществе Ruby, опубликовал запись в своём блоге, посвящённую анонсу предварительной версии Ruby 2.1. Изменений между версиями 2.0 и 2.1 накопилось достаточно, чтобы вчитаться в его изложение, и лучше — на русском языке.

NB: разумеется, Ruby 2.1 содержит все замечательные возможности предыдущей версии — 2.0. Изменения предыдущих версий упоминаться не будут.

Механизм уточнений

Известно, что в Ruby 2.0 введён механим уточнений. Реализация данного механизма оказалась достаточно противоречивой, поэтому в версии 2.0 его функциональность была несколько ограничена и помечена как экспериментальная.

Стоит напомнить, что уточнения позволяют применять манки патчи в рамках единственного Ruby-файла:

module Foo   refine String do     def foo       self + "foo"     end   end end  using Foo puts "bar".foo 

За пределами данного файла экземпляры класса String не будут отвечать на метод foo.

В новой версии Ruby уточнения не будут являться экспериментальной возможностью. Более того, их можно будет применять не только к области видимости верхнего уровня, но и к отдельным модулям.

module Foo   refine String do     def foo       self + "foo"     end   end end  module Bar   using Foo   puts "bar".foo end 

Важно иметь в виду, что чрезмерное увлечение уточнениями может привести к написанию достаточно запутанного кода. Разработчики некоторых реализаций Ruby уже заявили, что могут отказаться поддерживать уточнения.

Десятичные литералы

При работе с Ruby можно заметить, что значения с плавающей запятой ведут себя не лучшим образом, когда над ними выполняются вычисления, привычные по работе с десятичными дробями:

irb(main):001:0> 0.1 * 3 => 0.30000000000000004 

Подобное поведение приводит к тому, что большое количество Ruby-разработчиков начинает использовать целые числа, имитируя заданное количество знаков после запятой при представлении результата. Безусловно, такой способ работает хорошо при строго заданном количестве знаков после запятой. В противном случае приходится использовать рациональные дроби — это не очень плохо, но язык не обладает достаточно удобным синтаксисом для работы с ними.

Новая версия Ruby представляет суффикс r для описания десятичных и рациональных дробей:

irb(main):001:0> 0.1r => (1/10) irb(main):002:0> 0.1r * 3 => (3/10) 

Замороженные строковые литералы

Если в коде содержится объявление строкового литерала, то каждый раз при исполнении содержащей его строки кода Ruby создаёт новый объект класса String. Это обусловлено мутабельностью строк. В таких случаях символы ведут себя гораздо эффективнее, так как инициализируются всего один раз. Тем не менее, для сравнения символа со строкой нужно провести преобразование строки в символ или символа в строку. Выполнение таких преобразований — рискованная операция, открывающую потенциальную возможность для DoS-атаки, так как символы не освобождаются при сборке мусора, а любое преобразование символа в строку создаёт новую строку.

Единственный способ уберечь себя от негативных последствий в данном случае — хранить и использоваться строку в виде константы:

class Foo   BAR = "bar"    def bar?(input)     input == BAR   end end 

Часто, чтобы избавиться от мутабельности, выполняют заморозку строки. Заморозка объекта предотвращает его изменение со стороны кода на Ruby, однако не даёт никаких прибавок к производительности:

class Foo   BAR = "bar".freeze    def bar?(input)     input == BAR   end end 

Это выглядит достаточно нелепо и громоздко. К счастью, Ruby 2.1 предлагает новый синтаксис для решения данной задачи:

class Foo   def bar?(input)     input == "bar"f   end end 

В приведённом коде будет создан замороженный объект класса String, и где бы он не использовался — он будет инициализирован всего один раз.

Не исключено, что такой синтаксис может показаться странным. Тот же самый фрагмент кода можно переписать эквивалентно:

class Foo   def bar?(input)     input == %q{bar}f   end end 

Вообще, вопрос применения суффикса f к массивам и хэшам остаётся открытым.

Обязательные ключевые аргументы

Почему-то в анонсе Ruby 2.0 не были упомянуты обязательные ключевые аргументы. Итак, Ruby 2.0 представляет обязательные ключевые аргументы:

def foo(a: 10)   puts a end  foo(a: 20) # 20 foo        # 10 

При таком подходе к объявлению методов приходится указывать значения аргументов по-умолчанию. Это не всегда возможно, поэтому Ruby 2.1 позволяет задать обязательные ключевые аргументы:

def foo(a:)   puts a end  foo(a: 20) # 20 foo        # ArgumentError: missing keyword: a 

Объявление метода возвращает имя метода

В предыдущих версиях Ruby объявление метода при помощи def возвращало nil.

def foo() end # => nil 

Теперь это поведение изменилось и имя метода возвращается как символ:

def foo() end # => :foo 

Это полезно при метапрограммировании и выполнении подобных трюков. Например, все ли знают, что метод private может принимать аргументы?

# приватным будет только метод foo class Foo   def foo   end    private :foo    # метод bar останется незатронутым   def bar   end end 

Теперь, когда def возвращает имя объявленного метода, можно легко делать методы приватными:

# приватными будут только методы foo и bar class Foo   private def foo   end    private \   def bar   end    def baz   end end 

Удаление лишних байт из строк

Теперь Ruby имеет удобный метод для удаление лишних байт из строк:

some_string.scrub("") 

Раньше было сложно добиться одинакового поведения такого метода для всех существующих реализаций Ruby, поэтому также доступна библиотека для этого.

StringScanner поддерживает именованные захваты

Многим нравится класс StringScanner из стандартной библиотеки языка. В частности, он используется в Rails для разбора шаблонов маршрутов. То же самое будет делать Sinatra 2.0.

В версии 1.9 была добавлена поддержка именованных захватов, однако StringScanner их не поддерживал:

require 'strscan' s = StringScanner.new("foo") s.scan(/(?<bar>.*)/) puts s[:bar] 

При запуске данного кода на Ruby 2.0 будет получено исключение:

TypeError: no implicit conversion of Symbol into Integer 

Зато при запуске на Ruby 2.1:

foo 

Работа с сетевыми интерфейсами

Теперь можно получить доступ к сетевыми интерфейсам при помощи метода Socket.getifaddrs:

require 'socket'  Socket.getifaddrs.each do |i|   puts "#{i.name}: #{i.addr.ip_address}" if i.addr.ip? end 

Пример вывода такой программы:

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 

Быстрая работа с числами для вычислительных задач

Ruby 2.1 ведёт себя быстрее при работе с большими числами благодаря использованию 128-битных целых чисел в качестве внутреннего представления объектов класса Bignum. Более того, применение GNU Multiple Precision Arithmetic Library даёт дополнительный прирост к производительности.

Изменения в виртуальной машине

Теперь виртуальная машина Ruby наряду с использованием глобального кэша методов выполняет кэширование по месту вызова функции. Про это есть отдельные слайды.

RGenGC

Новая версия Ruby частично оснащена сборщиком мусора на основе поколений. Благодаря этому сборка мусора будет происходить быстрее. До этого использовался консервативный сборщик мусора, работающий по схеме «stop the world — mark — sweep».

На самом деле, старый сборщик никуда не исчез. Такие вещи сложно менять из-за особенностей внутреннего и внешнего программного интерфейса Ruby для языка Си.

Тем не менее, виртуальная машина Ruby 2.1 выполняет классификацию объектов на светлые и тёмные. В зависимости от присвоенного класса определяется поведение сборщика мусора. Имеются операции, которые делают светлый объект тёмным. Например, работа с ним из расширения на языке Си. Такие объекты, как открытые файлы, являются тёмными изначально.

Новый сборщик мусора работает только со светлыми объектами.

Обновление RubyGems

RubyGems получили обновление до версии 2.2.0, которая приносит несколько незначительных усовершенствований.

И это лишь предварительная версия!

Не стоит забывать, что недавний релиз является лишь предварительной версией, и всё вышеописанное может измениться.

ссылка на оригинал статьи http://habrahabr.ru/post/195844/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *