На прошой неделе вышел превью Ruby 2.3.0. Что есть интересного из изменений:
В Ruby появился оператор безопасной навигации, аналогичный оператору ‘?.’ в Groovy и некоторых других языках. Оператор применяется для сокращения выражений, где выполняется проверка существования объекта и затем обращение к методу объекта только в случае положительной проверки:
Если используется цепочка объектов и методов, то проверка может выглядеть громоздко и несколько раз впустую выполнять промежуточные методы. Например, типичный для Ruby on Rails случай безопасного получения большой картинки профиля:
Здесь метод
При этом, может оказаться не совсем корректный результат, если один из объектов в движении вглубь будет отсутствовать — тогда в image окажется
Есть также способ двигаться вглубь цепочки без проверок, перехватывая исключение, например, обычным способом:
или вызывающим всеобщее неодобрение постфиксным rescue:
ActiveSupport для решения такой проблемы поставляет методы
Эти методы добавляются в класс
По задаче #11537 для безопасной навигации в Ruby 2.3.0 добавлен сначала оператор ‘.?’, измененный позже на ‘&.’. В новом синтаксисе выражение из примеров можно записать так:
Вместе с лаконичным видом такая реализация дает быструю проверку на
Если в метод передаются аргументы, то, в отличие от
Безопасная навигация также может использоваться при присваивании значения атрибуту:
С момента появления feature request до его подтверждения и коммита с первым вариантом реализации прошло лишь чуть больше одного месяца.
Feature #11688 добавляет в
или:
на:
Доступ во вложенные хэши и массивы часто применяется при обработке параметров HTTP-запросов, получаемых Rails-приложениями, или при работе с YAML или JSON структурами. Добавление
Метод
В Ruby 3 все строковые литералы будут неизменными. По поводу неизменности споры идут давно и сейчас движение в эту сторону стало более конкретным. Выражается оно в появлении “магического” комментария
Основной аргумент в пользу неизменяемых строк — увеличение скорости работы за счет внутренних оптимизаций. В большинстве случаев строки остаются без изменений на протяжении всего жизненного цикла, и фиксирование такого поведения позволяет повысить производительность без изменения кода.
Мы подготовили хостинг Ruby-приложений в контейнерах Jet9. Как на облачном хостинге, так и на отказоустойчивом кластере.
Одна из причин, почему первым на Jet9 появляется Ruby — мы унифицируем обслуживание наших собственных внутренних сервисов и внутренних сервисов наших клиентов (сайты, биллинг, документооборот, багтрекер, тикеты и прочее). Чтобы упростить себе жизнь и сократить расходы на обновление и сопровождение зоопарка из разных дистрибутивов, HA-кластеров с разными конфигурациями и отдельных физических серверов, мы переносим все на пару типовых HA-кластеров на платформе Jet9. Большая часть написана на Ruby — используются собственные приложения и сторонние (Redmine, Gitlab). Таким образом, поддержку Ruby на Jet9 мы сделали в том числе и для себя, на себе же ее и проверяем.
Приложения работают под Nginx + Apache + mod_passenger (5.0.21), это самый удобный способ. Но можно использовать standalone Passenger или другие серверы приложений (Unicorn, Puma). Сейчас доступны версии 2.2.2 и 2.2.3, и подготавливаются другие. В связи с этим опрос:
- оператор безопасной навигации вглубь объектов (safe navigation operator), #11537
- в Hash и Array добавлен метод
dig
для доступа вглубь вложенных хэшей или массивов #11688 - движение в сторону неизменяемых (frozen) по умолчанию строковых литералов (обоснование, обсуждение #11473
Оператор безопасной навигации
В Ruby появился оператор безопасной навигации, аналогичный оператору ‘?.’ в Groovy и некоторых других языках. Оператор применяется для сокращения выражений, где выполняется проверка существования объекта и затем обращение к методу объекта только в случае положительной проверки:
obj.nil? && obj.some_method
Если используется цепочка объектов и методов, то проверка может выглядеть громоздко и несколько раз впустую выполнять промежуточные методы. Например, типичный для Ruby on Rails случай безопасного получения большой картинки профиля:
image = user && user.profile && user.profile.thumbnails && user.profile.thumbnails.large
Здесь метод
profile
будет выполнен три раза и два раза будет выполнен метод thumbnails
. Оптимизированный вариант будет выглядеть еще сложнее:image = user && (profile = user.profile) && (thumbnails = profile.thumbnails) && thumbnails.large
При этом, может оказаться не совсем корректный результат, если один из объектов в движении вглубь будет отсутствовать — тогда в image окажется
false
, а не nil
. А если проверять на nil?
, то код будет выглядеть еще запутаннее.Есть также способ двигаться вглубь цепочки без проверок, перехватывая исключение, например, обычным способом:
image = begin
user.profile.thumbnails.large
rescue NoMethodError
nil
end
или вызывающим всеобщее неодобрение постфиксным rescue:
image = user.profile.thumbnails.large rescue nil
ActiveSupport для решения такой проблемы поставляет методы
try
и try!
:image = user.try(:profile).try(:thumbnails).try(:large)
Эти методы добавляются в класс
Object
и при вызове проверяют сначала существование вызываемого метода и если он отсутствует, то возвращают nil
. В случае, если user
имеет метод #profile
, он будет выполнен и на его результате дальше по цепочке будет вызван try(:thumbnails)
. Если user
будет nil
, то #try
вернет nil
и так по цепочке #try
будет вызван у nil
еще два раза. Медленно? Зато коротко.Что делает новоявленный safe navigation operator в Ruby
По задаче #11537 для безопасной навигации в Ruby 2.3.0 добавлен сначала оператор ‘.?’, измененный позже на ‘&.’. В новом синтаксисе выражение из примеров можно записать так:
image = user&.profile&.thumbnails&.large
Вместе с лаконичным видом такая реализация дает быструю проверку на
nil
, так как изменения реализованы на уровне парсера и ruby-код в проверках не участвует. После того, как встретился nil
, дальнейшее выполнение цепочки прерывается. Проверка выполняется именно на nil
, а не на логическое условие, поэтому если результатом окажется false
, то выполнение будет успешно продолжено по цепочке дальше.Если в метод передаются аргументы, то, в отличие от
try
, они вычисляются только в том случае, если объект существует и метод реально вызывается. Например, для ActiveSupport в выражении obj.try(:foo, bar())
всегда будет выполняться bar()
, даже если obj
не существует. Но в выражении obj&.foo(bar())
, аргумент bar()
будет вычислен только тогда, когда ojb
не равен nil
.Безопасная навигация также может использоваться при присваивании значения атрибуту:
obj&.attr += 1
С момента появления feature request до его подтверждения и коммита с первым вариантом реализации прошло лишь чуть больше одного месяца.
Навигация вглубь вложенных хэшей и массивов с помощью #dig.
Feature #11688 добавляет в
Hash
и Array
метод dig
, который используется для безопасного получения значения из вложенных хэшей и массивов. Этот метод заменяет выражение:value = hash[:a].nil? ? nil : hash[:a][:b].nil? ? nil : hash[:a][:b][:c]
или:
value = hash[:a][:b][:c] rescue nil
на:
value = hash.dig(:a, :b, :c)
Доступ во вложенные хэши и массивы часто применяется при обработке параметров HTTP-запросов, получаемых Rails-приложениями, или при работе с YAML или JSON структурами. Добавление
dig
для обращения вглубь не только предоставляет удобный метод доступа, но и ускоряет его в несколько десятков раз.Метод
dig
также на днях добавлен в Struct
, но в первое превью 2.3.0 попасть не успел.Неизменяемость строк
В Ruby 3 все строковые литералы будут неизменными. По поводу неизменности споры идут давно и сейчас движение в эту сторону стало более конкретным. Выражается оно в появлении “магического” комментария
frozen-string-literal
, присутствие которого включает по умолчанию неизменность для всех строковых литералов, и в добавлении --enable/--disable=frozen-string-literal
для управления таким поведением.Основной аргумент в пользу неизменяемых строк — увеличение скорости работы за счет внутренних оптимизаций. В большинстве случаев строки остаются без изменений на протяжении всего жизненного цикла, и фиксирование такого поведения позволяет повысить производительность без изменения кода.
А у нас небольшой опрос
Мы подготовили хостинг Ruby-приложений в контейнерах Jet9. Как на облачном хостинге, так и на отказоустойчивом кластере.
Одна из причин, почему первым на Jet9 появляется Ruby — мы унифицируем обслуживание наших собственных внутренних сервисов и внутренних сервисов наших клиентов (сайты, биллинг, документооборот, багтрекер, тикеты и прочее). Чтобы упростить себе жизнь и сократить расходы на обновление и сопровождение зоопарка из разных дистрибутивов, HA-кластеров с разными конфигурациями и отдельных физических серверов, мы переносим все на пару типовых HA-кластеров на платформе Jet9. Большая часть написана на Ruby — используются собственные приложения и сторонние (Redmine, Gitlab). Таким образом, поддержку Ruby на Jet9 мы сделали в том числе и для себя, на себе же ее и проверяем.
Приложения работают под Nginx + Apache + mod_passenger (5.0.21), это самый удобный способ. Но можно использовать standalone Passenger или другие серверы приложений (Unicorn, Puma). Сейчас доступны версии 2.2.2 и 2.2.3, и подготавливаются другие. В связи с этим опрос:
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой Ruby вы используете в продакшене
4.11% MRI 1.8.713
10.13% MRI 1.9.332
9.81% MRI 2.0.*31
27.53% MRI 2.1.*87
57.28% MRI 2.2.*181
12.97% MRI 2.3.*41
0% Rubinius 1.40
0% Rubinius 2.40
1.27% Rubinius 2.54
0.32% JRuby 1.61
1.9% JRuby 1.76
2.53% JRuby 9.0.0.08
0.63% IronRuby2
1.27% Maglev4
Проголосовали 316 пользователей. Воздержались 197 пользователей.
Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Какой Ruby вы хотите использовать в продакшене
1.5% MRI 1.8.74
0.38% MRI 1.9.31
1.88% MRI 2.0.*5
3.01% MRI 2.1.*8
28.95% MRI 2.2.*77
78.95% MRI 2.3.*210
0% Rubinius 1.40
0.38% Rubinius 2.41
5.26% Rubinius 2.514
0% JRuby 1.60
0.75% JRuby 1.72
7.52% JRuby 9.0.0.020
0% IronRuby0
0.38% Maglev1
Проголосовали 266 пользователей. Воздержались 229 пользователей.