{"id":21815577,"url":"https://github.com/arbox/ruby-style-guide","last_synced_at":"2025-04-04T13:13:47.848Z","repository":{"id":2105079,"uuid":"21326855","full_name":"arbox/ruby-style-guide","owner":"arbox","description":":blue_book:  Russian Version: A community-driven Ruby coding style guide.","archived":false,"fork":false,"pushed_at":"2023-03-11T21:08:24.000Z","size":1820,"stargazers_count":412,"open_issues_count":0,"forks_count":120,"subscribers_count":38,"default_branch":"master","last_synced_at":"2025-03-28T12:09:58.005Z","etag":null,"topics":["bbatsov","rubocop","ruby","russian","style","style-guide"],"latest_commit_sha":null,"homepage":"https://github.com/arbox/ruby-style-guide","language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/arbox.png","metadata":{"files":{"readme":"README-ruRU.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null},"funding":{"github":["arbox"]}},"created_at":"2014-06-29T16:06:40.000Z","updated_at":"2024-12-05T11:48:22.000Z","dependencies_parsed_at":"2023-07-05T20:03:28.073Z","dependency_job_id":null,"html_url":"https://github.com/arbox/ruby-style-guide","commit_stats":{"total_commits":647,"total_committers":141,"mean_commits":4.588652482269503,"dds":0.6615146831530139,"last_synced_commit":"ad79e003dd86f12560513927e236097a94b5c64e"},"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Fruby-style-guide","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Fruby-style-guide/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Fruby-style-guide/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/arbox%2Fruby-style-guide/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/arbox","download_url":"https://codeload.github.com/arbox/ruby-style-guide/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247182420,"owners_count":20897381,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bbatsov","rubocop","ruby","russian","style","style-guide"],"created_at":"2024-11-27T15:20:01.491Z","updated_at":"2025-04-04T13:13:47.824Z","avatar_url":"https://github.com/arbox.png","language":null,"funding_links":["https://github.com/sponsors/arbox"],"categories":[],"sub_categories":[],"readme":"# Вступление\n\n\u003e Ролевые модели важны. \u003cbr/\u003e\n\u003e -- Офицер Алекс Мёрфи / Робот-полицейский\n\nОдин из вопросов, который меня всегда беспокоил как разработчика на Руби,\n\u0026mdash; это то, что у разработчиков на Питоне есть великолепное руководство\nпо стилю оформления ([PEP-8][]), а у нас\nникогда не было официального руководства, описывавшего бы стиль оформления кода\nна Руби и дающего примеры его успешного применения. Я же уверен, что стиль\nоформления крайне важен. Также я верю, что такое замечательное сообщество\nразработчиков, которое есть у Руби, вполне имеет силы создать этот давно\nназревший документ.\n\nЭто наставление появилось на свет в нашей фирме в виде внутреннего руководства\nпо оформлению кода на Руби (составленного вашим покорным слугой). И в какой-то\nмомент я решил, что данная работа, которой я тогда занимался, может быть\nинтересной и другим членам сообщества программистов на Руби и что миру вовсе\nне нужно еще одно руководство для внутреннего пользования: окружающий мир может\nполучить пользу от совместно создаваемого и одобренного сообществом набора\nпрактик, идиом и стилистических предписаний для программирования на Руби.\n\nСо времени опубликования этого руководства я получил многочисленные отклики\nот членов сообщества программистов на Руби из разных уголков со всего мира. Я\nочень благодарен им за полезные предложения и поддержку! Нашими общими усилиями\nмы сможем сделать этот ресурс полезным для всех и каждого разработчика на Руби.\n\nИ кстати, если вы работаете с Rails, вы можете взглянуть на дополняющее это\nруководство [Ruby on Rails 3 \u0026 4: Руководство по стилю оформления][rails-style-guide].\n\n# :blue_book: Руби: руководство по стилю оформления\n\nЭто руководство по оформлению кода на Руби дает передовые рекомендации, так что\nобычный программист на Руби сможет создавать код, который с легкостью смогут\nподдерживать другие обычные программисты на Руби. Руководство по оформлению,\nкоторое отражает повседневную практику, будет применяться постоянно, а руководство,\nстремящееся к идеалу, который не принимается обычными людьми, подвергается риску\nвообще быть забытым \u0026mdash; не важно, насколько хорошим оно является.\n\nДанное руководство разделено на несколько частей, состоящих из связанных по смыслу\nправил. В каждом случае я попытался обосновать появление этих правил (объяснение\nопущено в ситуациях, когда я посчитал его очевидным).\n\nВсе эти правила не появились из пустоты, они по большей части основываются на моем\nсобственном обширном профессиональном опыте в качестве разработчика ПО, отзывах\nи предложениях других членов сообщества программистов на Руби и различных\nобщепризнанных источниках по программированию на Руби, например,\n[\"Programming Ruby\"][pickaxe] и [\"Язык программирования Ruby\"][trpl]\n(в оригинале [\"The Ruby Programming Language\"][entrpl]).\n\nВо многих областях до сих пор нет единого мнения в среде разработчиков на Руби\nотносительно конкретных аспектов стиля оформления (например, оформление строк\nв кавычках, пробелы при оформлении хешей, месторасположение точки при\nмногострочном последовательном вызове методов и т.д.). В таких ситуациях мы\nрассматривали все распространенные стили, вам же решать, какой из этих стилей\nвы будете применять последовательно в вашем коде.\n\nЭто руководство все еще находится в процессе создания: у многих правил нет\nпримеров, у других нет примеров, достаточно ясно объясняющих эти правила. В свое\nвремя каждое правило найдет свое объяснение, а пока просто примите их к сведению.\n\nВы можете создать копию этого руководства в форматах PDF или HTML при помощи\n[Pandoc][].\n\n[RuboCop][] \u0026mdash; это анализатор кода, основывающийся на правилах этого\nруководства по оформлению.\n\nПереводы данного руководства доступны на следующих языках:\n\n* [английский (исходная версия)](https://github.com/rubocop-hq/ruby-style-guide)\n* [арабский (египетский)](https://github.com/HassanTC/ruby-style-guide/blob/master/README-EgAr.md)\n* [вьетнамский](https://github.com/CQBinh/ruby-style-guide/blob/master/README-viVN.md)\n* [испанский](https://github.com/alemohamad/ruby-style-guide/blob/master/README-esLA.md)\n* [китайский традиционный](https://github.com/JuanitoFatas/ruby-style-guide/blob/master/README-zhTW.md)\n* [китайский упрощенный](https://github.com/JuanitoFatas/ruby-style-guide/blob/master/README-zhCN.md)\n* [корейский](https://github.com/dalzony/ruby-style-guide/blob/master/README-koKR.md)\n* [французский](https://github.com/gauthier-delacroix/ruby-style-guide/blob/master/README-frFR.md)\n* [португальский (бразильский)](https://github.com/rubensmabueno/ruby-style-guide/blob/master/README-PT-BR.md)\n* [русский (данный документ)](https://github.com/arbox/ruby-style-guide/blob/master/README-ruRU.md)\n* [японский](https://github.com/fortissimo1997/ruby-style-guide/blob/japanese/README.ja.md)\n\n## Оглавление\n\n* [Организация исходного кода](#Организация-исходного-кода)\n* [Синтаксис](#Синтаксис)\n* [Наименование](#Наименование)\n* [Комментарии](#Комментарии)\n  * [Пометки в комментариях](#Пометки-в-комментариях)\n  * [Магические комментарии](#Магические-комментарии)\n* [Классы и модули](#Классы-и-модули)\n* [Исключения](#Исключения)\n* [Коллекции](#Коллекции)\n* [Числа](#Числа)\n* [Строки](#Строки)\n* [Даты и время](#Даты-и-время)\n* [Регулярные выражения](#Регулярные-выражения)\n* [Процентные литералы](#Процентные-литералы)\n* [Метапрограммирование](#Метапрограммирование)\n* [Разное](#Разное)\n* [Инструментарий](#Инструментарий)\n\n## Организация исходного кода\n\n\u003e Почти все убеждены, что любой стиль кроме их собственного ужасен и нечитаем.\n\u003e Уберите отсюда \"кроме их собственного\" \u0026mdash; и они будут, наверное, правы... \u003cbr\u003e\n\u003e -- Джерри Коффин (Jerry Coffin) об отступах\n\n* \u003ca name=\"utf-8\"\u003e\u003c/a\u003e\n  Используйте `UTF-8` в качестве кодировки для исходного кода.\n  \u003csup\u003e[[ссылка](#utf-8)]\u003c/sup\u003e\n\n* \u003ca name=\"spaces-indentation\"\u003e\u003c/a\u003e\n  Используйте два **пробела** на уровень отступа (т.е. мягкую табуляцию).\n  Никаких знаков табуляции!\n  \u003csup\u003e[[ссылка](#spaces-indentation)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (четыре пробела)\n  def some_method\n      do_something\n  end\n\n  # хорошо\n  def some_method\n    do_something\n  end\n  ```\n\n* \u003ca name=\"crlf\"\u003e\u003c/a\u003e\n  Используйте стиль Unix для строк (пользователи \\*BSD/Solaris/Linux/macOS\n  используют его по умолчанию, пользователям Windows нужно обратить особое\n  внимание).\n  \u003csup\u003e[[ссылка](#crlf)]\u003c/sup\u003e\n\n  * Если вы используете Git, вы можете добавить следующие настройки\n    в вашу конфигурацию, чтобы предотвратить ненамеренное проникновение в ваш\n    код строк, оканчивающихся в стиле Windows:\n\n    ```bash\n    $ git config --global core.autocrlf true\n    ```\n\n* \u003ca name=\"no-semicolon\"\u003e\u003c/a\u003e\n  Не используйте `;` для разделения директив и выражений. Отсюда непосредственно\n  следует, что каждая директива должна занимать свою отдельную строку.\n  \u003csup\u003e[[ссылка](#no-semicolon)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (точка с запятой избыточна)\n  puts 'foobar';\n\n  puts 'foo'; puts 'bar' # две директивы на одной строке\n\n  # хорошо\n  puts 'foobar'\n\n  puts 'foo'\n  puts 'bar'\n\n  puts 'foo', 'bar' # это частное правило для `puts`\n  ```\n\n* \u003ca name=\"single-line-classes\"\u003e\u003c/a\u003e\n  Используйте преимущественно однострочный формат для определений классов\n  с пустым телом.\n  \u003csup\u003e[[ссылка](#single-line-classes)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class FooError \u003c StandardError\n  end\n\n  # сносно\n  class FooError \u003c StandardError; end\n\n  # хорошо\n  FooError = Class.new(StandardError)\n  ```\n\n* \u003ca name=\"no-single-line-methods\"\u003e\u003c/a\u003e\n  Избегайте однострочных методов. И хотя они достаточно популярны в среде\n  программистов, существует множество неприятных мелочей, связанных\n  с синтаксисом их определения, которые делают применение таких методов\n  нежелательным. В любом случае однострочные методы не должны содержать больше\n  одного выражения.\n  \u003csup\u003e[[ссылка](#no-single-line-methods)]\u003c/sup\u003e\n\n\n  ```ruby\n  # плохо\n  def too_much; something; something_else; end\n\n  # сносно (обратите внимание, что первая `;` обязательна)\n  def no_braces_method; body end\n\n  # сносно (обратите внимание, что вторая `;` опциональна)\n  def no_braces_method; body; end\n\n  # сносно (корректный синтаксис, но отсутствие `;` создает трудности при прочтении)\n  def some_method() body end\n\n  # хорошо\n  def some_method\n    body\n  end\n  ```\n\n  Одним исключением в этом правиле являются методы с пустым телом.\n\n  ```ruby\n  # хорошо\n  def no_op; end\n  ```\n\n* \u003ca name=\"spaces-operators\"\u003e\u003c/a\u003e\n  Вставляйте пробелы вокруг операторов, после запятых, двоеточий и\n  точек с запятыми.  Пробелы (по большей части) игнорируются\n  интерпретатором Руби, но их правильное использование является ключом\n  к написанию легко читаемого кода.\n  \u003csup\u003e[[ссылка](#spaces-operators)]\u003c/sup\u003e\n\n  ```ruby\n  sum = 1 + 2\n  a, b = 1, 2\n  class FooError \u003c StandardError; end\n  ```\n\n  Из этого правила есть несколько исключений. Одним из них является оператор возведения в степень:\n\n  ```ruby\n  # плохо\n  e = M * c ** 2\n\n  # хорошо\n  e = M * c**2\n  ```\n\n  Другим исключением является косая черта в литералах дробей:\n\n  ```ruby\n  # плохо\n  o_scale = 1 / 48r\n\n  # хорошо\n  o_scale = 1/48r\n  ```\n\n  \u003c!--- @FIXME: look for a better translation ---\u003e\n  Еще одним исключением является \"safe navigation operator\":\n\n  ```ruby\n  # плохо\n  foo \u0026. bar\n  foo \u0026.bar\n  foo\u0026. bar\n\n  # хорошо\n  foo\u0026.bar\n  ```\n\n* \u003ca name=\"spaces-braces\"\u003e\u003c/a\u003e\n  Не используйте пробел после `(`, `[` или перед `]`, `)`. Вставляйте\n  пробелы вокруг `{` и перед `}`.\n  \u003csup\u003e[[ссылка](#spaces-braces)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  some( arg ).other\n  [ 1, 2, 3 ].each{|e| puts e}\n\n  # хорошо\n  some(arg).other\n  [1, 2, 3].each { |e| puts e }\n  ```\n\n  Скобки `{` и `}` заслуживают некоторого пояснения, так как они\n  используются для обозначения блоков и литералов хешей, а также при\n  интерполяции строк.\n\n  Для литералов хешей два стиля являются общепринятыми. Первый\n  вариант несколько проще для чтения и, по всей вероятности, более\n  распространен среди членов сообщества программистов на Руби.  Второй\n  вариант имеет преимущество в том, что создается видимое различие\n  между блоками и литералами хешей. Какой бы стиль вы ни выбрали,\n  применяйте его единообразно.\n\n  ```ruby\n  # хорошо (пробел после { и до })\n  { one: 1, two: 2 }\n\n  # хорошо (пробелы отсутствуют после { и перед })\n  {one: 1, two: 2}\n  ```\n\n  В выражениях с интерполяцией избегайте лишних пробелов внутри скобок.\n\n  ```ruby\n  # плохо\n  \"From: #{ user.first_name }, #{ user.last_name }\"\n\n  # хорошо\n  \"From: #{user.first_name}, #{user.last_name}\"\n  ```\n\n* \u003ca name=\"no-space-bang\"\u003e\u003c/a\u003e\n  Не используйте пробел после `!`.\n  \u003csup\u003e[[ссылка](#no-space-bang)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  ! something\n\n  # хорошо\n  !something\n  ```\n* \u003ca name=\"no-space-inside-range-literals\"\u003e\u003c/a\u003e\n  Записывайте литералы диапазонов без пробелов.\n  \u003csup\u003e[[ссылка](#no-space-inside-range-literals)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  1 .. 3\n  'a' ... 'z'\n\n  # хорошо\n  1..3\n  'a'...'z'\n  ```\n\n* \u003ca name=\"indent-when-to-case\"\u003e\u003c/a\u003e\n  Делайте отступ для `when` таким же, как и для `case`. Этот стиль\n  предписывается как [\"Языком программирования Ruby\"][trpl], так и [\"Programming Ruby\"][pickaxe].\n  \u003csup\u003e[[ссылка](#indent-when-to-case)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  case\n    when song.name == 'Misty'\n      puts 'Not again!'\n    when song.duration \u003e 120\n      puts 'Too long!'\n    when Time.now.hour \u003e 21\n      puts \"It's too late\"\n    else\n      song.play\n  end\n\n  # хорошо\n  case\n  when song.name == 'Misty'\n    puts 'Not again!'\n  when song.duration \u003e 120\n    puts 'Too long!'\n  when Time.now.hour \u003e 21\n    puts \"It's too late\"\n  else\n    song.play\n  end\n  ```\n\n* \u003ca name=\"indent-conditional-assignment\"\u003e\u003c/a\u003e\n  Присваивая результат условного выражения переменной, сохраняйте соответствие\n  уровней отступа.\n  \u003csup\u003e[[ссылка](#indent-conditional-assignment)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (слишком запутано)\n  kind = case year\n  when 1850..1889 then 'Blues'\n  when 1890..1909 then 'Ragtime'\n  when 1910..1929 then 'New Orleans Jazz'\n  when 1930..1939 then 'Swing'\n  when 1940..1950 then 'Bebop'\n  else 'Jazz'\n  end\n\n  result = if some_cond\n    calc_something\n  else\n    calc_something_else\n  end\n\n  # хорошо (намерения очевидны)\n  kind = case year\n         when 1850..1889 then 'Blues'\n         when 1890..1909 then 'Ragtime'\n         when 1910..1929 then 'New Orleans Jazz'\n         when 1930..1939 then 'Swing'\n         when 1940..1950 then 'Bebop'\n         else 'Jazz'\n         end\n\n  result = if some_cond\n             calc_something\n           else\n             calc_something_else\n           end\n\n  # хорошо (и не так расточительно)\n  kind =\n    case year\n    when 1850..1889 then 'Blues'\n    when 1890..1909 then 'Ragtime'\n    when 1910..1929 then 'New Orleans Jazz'\n    when 1930..1939 then 'Swing'\n    when 1940..1950 then 'Bebop'\n    else 'Jazz'\n    end\n\n  result =\n    if some_cond\n      calc_something\n    else\n      calc_something_else\n    end\n  ```\n\n* \u003ca name=\"empty-lines-between-methods\"\u003e\u003c/a\u003e\n  Используйте пустые строки для разделения определений методов и выделения\n  логических частей определений внутри них.\n  \u003csup\u003e[[ссылка](#empty-lines-between-methods)]\u003c/sup\u003e\n\n  ```ruby\n  def some_method\n    data = initialize(options)\n\n    data.manipulate!\n\n    data.result\n  end\n\n  def some_method\n    result\n  end\n  ```\n\n* \u003ca name=\"two-or-more-empty-lines\"\u003e\u003c/a\u003e\n  Не используйте несколько пустых строк подряд.\n  \u003csup\u003e[[ссылка](#two-or-more-empty-lines)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (две пустые строки)\n  some_method\n\n\n  some_method\n\n  # хорошо\n  some_method\n\n  some_method\n  ```\n\n* \u003ca name=\"empty-lines-around-access-modifier\"\u003e\u003c/a\u003e\n  Отделяйте макросы доступа к данным пустой строкой.\n  \u003csup\u003e[[ссылка](#empty-lines-around-access-modifier)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Foo\n    attr_reader :foo\n    def foo\n      # некоторый код\n    end\n  end\n\n  # хорошо\n  class Foo\n    attr_reader :foo\n\n    def foo\n      # некоторый код\n    end\n  end\n  ```\n\n* \u003ca name=\"empty-lines-around-bodies\"\u003e\u003c/a\u003e\n  Не оставляйте пустые строки вокруг тел методов, классов, модулей и блоков.\n  \u003csup\u003e[[ссылка](#empty-lines-around-bodies)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Foo\n\n    def foo\n\n      begin\n\n        do_something do\n\n          something\n\n        end\n\n      rescue\n\n        something\n\n      end\n\n    end\n\n  end\n\n  # хорошо\n  class Foo\n    def foo\n      begin\n        do_something do\n          something\n        end\n      rescue\n        something\n      end\n    end\n  end\n  ```\n\n* \u003ca name=\"no-trailing-params-comma\"\u003e\u003c/a\u003e\n  Избегайте запятых после последнего параметра в вызове метода, особенно когда\n  параметры расположены в отдельных строках.\n  \u003csup\u003e[[ссылка](#no-trailing-params-comma)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (хотя перемещать/добавлять/удалять строки проще)\n  some_method(\n    size,\n    count,\n    color,\n  )\n\n  # плохо\n  some_method(size, count, color, )\n\n  # хорошо\n  some_method(size, count, color)\n  ```\n\n* \u003ca name=\"spaces-around-equals\"\u003e\u003c/a\u003e\n  Вставляйте пробелы вокруг оператора присваивания `=`, когда назначаете\n  параметрам метода значения по умолчанию:\n  \u003csup\u003e[[ссылка](#spaces-around-equals)]\u003c/sup\u003e\n\n\n  ```ruby\n  # плохо\n  def some_method(arg1=:default, arg2=nil, arg3=[])\n    # некоторый код\n  end\n\n  # хорошо\n  def some_method(arg1 = :default, arg2 = nil, arg3 = [])\n    # некоторый код\n  end\n  ```\n\n  Хотя в некоторых книгах по Ruby рекомендуют первый стиль, второй\n  гораздо более нагляден.\n\n* \u003ca name=\"no-trailing-backslash\"\u003e\u003c/a\u003e\n  Не используйте символ продления строк `\\` везде, где можно обойтись без него.\n  Практически не используйте его нигде, кроме как при конкатенации строк.\n  \u003csup\u003e[[ссылка](#no-trailing-backslash)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  result = 1 - \\\n           2\n\n  # возможно (но ужасно)\n  result = 1 \\\n           - 2\n\n  long_string = 'First part of the long string' \\\n                ' and second part of the long string'\n  ```\n\n* \u003ca name=\"consistent-multi-line-chains\"\u003e\u003c/a\u003e\n  Используйте единый стиль многострочных последовательных цепочек вызовов методов.\n  В сообществе Руби популярны два взаимоисключающих стиля их оформления:\n  с точкой в начале (вариант A) и с точкой в конце (вариант B).\n  \u003csup\u003e[[ссылка](#consistent-multi-line-chains)]\u003c/sup\u003e\n\n  * **A** Когда продолжаете цепочку вызовов методов на\n  следующую строку, начинайте её с точки.\n\n    ```ruby\n    # плохо (нужно посмотреть на предыдущую строку, чтобы понять\n    # смысл последующей\n    one.two.three.\n      four\n\n    # хорошо (сразу ясно, что происходит во второй строке)\n    one.two.three\n      .four\n    ```\n\n  * **B** Соответственно, наоборот, когда продолжаете цепочку\n  вызовов на следующей строке, завершайте строку точкой `.`, давая\n  понять, что продолжение выражения следует\n\n    ```ruby\n    # плохо (чтобы понять, что выражение не окончено, необходимо\n    # посмотреть на следующую строку)\n    one.two.three\n      .four\n\n    # хорошо (сразу видно, что выражение будет продолжено на\n    # следующей строке)\n    one.two.three.\n      four\n    ```\n\n  C аргументами за и против обоих стилей можно ознакомиться в дискуссии\n  [здесь](https://github.com/rubocop-hq/ruby-style-guide/pull/176).\n\n* \u003ca name=\"no-double-indent\"\u003e\u003c/a\u003e\n  Выравнивайте параметры вызова метода, если вызов занимает более одной строки.\n  Если выравнивание невозможно из-за ограничений на длину строки, то используйте\n  одинарный отступ.\n  \u003csup\u003e[[ссылка](#no-double-indent)]\u003c/sup\u003e\n\n  ```ruby\n  # первоначальный вариант (строка слишком длинная)\n  def send_mail(source)\n    Mailer.deliver(to: 'bob@example.com', from: 'us@example.com', subject: 'Important message', body: source.text)\n  end\n\n  # плохо (двойной отступ)\n  def send_mail(source)\n    Mailer.deliver(\n        to: 'bob@example.com',\n        from: 'us@example.com',\n        subject: 'Important message',\n        body: source.text)\n  end\n\n  # хорошо\n  def send_mail(source)\n    Mailer.deliver(to: 'bob@example.com',\n                   from: 'us@example.com',\n                   subject: 'Important message',\n                   body: source.text)\n  end\n\n  # хорошо (одинарный отступ)\n  def send_mail(source)\n    Mailer.deliver(\n      to: 'bob@example.com',\n      from: 'us@example.com',\n      subject: 'Important message',\n      body: source.text\n    )\n  end\n  ```\n\n* \u003ca name=\"align-multiline-arrays\"\u003e\u003c/a\u003e\n  Выравнивайте элементы литералов массива, если они занимают несколько строк.\n  \u003csup\u003e[[ссылка](#align-multiline-arrays)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  menu_item = %w[Spam Spam Spam Spam Spam Spam Spam Spam\n    Baked beans Spam Spam Spam Spam Spam]\n\n  # хорошо\n  menu_item = %w[\n    Spam Spam Spam Spam Spam Spam Spam Spam\n    Baked beans Spam Spam Spam Spam Spam\n  ]\n\n  # хорошо\n  menu_item =\n    %w[Spam Spam Spam Spam Spam Spam Spam Spam\n       Baked beans Spam Spam Spam Spam Spam]\n  ```\n\n* \u003ca name=\"underscores-in-numerics\"\u003e\u003c/a\u003e\n  Добавляйте символ подчеркивания в большие числовые константы для улучшения\n  их восприятия.\n  \u003csup\u003e[[ссылка](#underscores-in-numerics)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (Сколько тут нолей?)\n  num = 1000000\n\n  # хорошо (число воспринимается гораздо легче)\n  num = 1_000_000\n  ```\n\n* \u003ca name=\"numeric-literal-prefixes\"\u003e\u003c/a\u003e\n  Используйте строчные буквы в префиксах числовых записей: `0o` для\n  восьмеричных, `0x` для шестнадцатеричных и `0b` для двоичных чисел.\n  Не используйте `0d` префикс для десятичных литералов.\n  \u003csup\u003e[[ссылка](#numeric-literal-prefixes)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  num = 01234\n  num = 0O1234\n  num = 0X12AB\n  num = 0B10101\n  num = 0D1234\n  num = 0d1234\n\n  # хорошо (проще визуально отделить числа от префикса)\n  num = 0o1234\n  num = 0x12AB\n  num = 0b10101\n  num = 1234\n  ```\n\n* \u003ca name=\"rdoc-conventions\"\u003e\u003c/a\u003e\n  Используйте устоявшиеся правила [RDoc][rdoc] для описания интерфейсов.\n  Не отделяйте блок комментария от начала определения метода `def` пустой строкой.\n  \u003csup\u003e[[ссылка](#rdoc-conventions)]\u003c/sup\u003e\n\n* \u003ca name=\"80-character-limits\"\u003e\u003c/a\u003e\n  Ограничивайте длину строк 80-ю символами.\n  \u003csup\u003e[[ссылка](#80-character-limits)]\u003c/sup\u003e\n\n* \u003ca name=\"no-trailing-whitespace\"\u003e\u003c/a\u003e\n  Не оставляйте пробелы в конце строки.\n  \u003csup\u003e[[ссылка](#no-trailing-whitespace)]\u003c/sup\u003e\n\n* \u003ca name=\"newline-eof\"\u003e\u003c/a\u003e\n  Завершайте каждый файл переводом строки.\n  \u003csup\u003e[[ссылка](#newline-eof)]\u003c/sup\u003e\n\n* \u003ca name=\"no-block-comments\"\u003e\u003c/a\u003e\n  Не пользуйтесь блочными комментариями. Их нельзя разместить на необходимом\n  уровне отступа. К тому же их сложнее воспринимать, чем обычные комментарии.\n  \u003csup\u003e[[ссылка](#no-block-comments)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  =begin\n  строка комментария\n  еще одна строка комментария\n  =end\n\n  # хорошо\n  # строка комментария\n  # другая строка комментария\n  ```\n\n## Синтаксис\n\n* \u003ca name=\"double-colons\"\u003e\u003c/a\u003e\n  Используйте `::` только для обращения к константам \u0026mdash; в том числе к именам\n  классов и модулей \u0026mdash; и конструкторам класса (например, `Array()` или\n  `Nokogiri::HTML()`). Никогда не используйте `::` для обычного вызова методов.\n  \u003csup\u003e[[ссылка](#double-colons)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  SomeClass::some_method\n  some_object::some_method\n\n  # хорошо\n  SomeClass.some_method\n  some_object.some_method\n  SomeModule::SomeClass::SOME_CONST\n  SomeModule::SomeClass()\n  ```\n\n* \u003ca name=\"colon-method-definition\"\u003e\u003c/a\u003e\n  Не используйте `::` при определении методов класса.\n  \u003csup\u003e[[ссылка](#colon-method-definition)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Foo\n    def self::some_method\n    end\n  end\n\n  # хорошо\n  class Foo\n    def self.some_method\n    end\n  end\n  ```\n\n\n* \u003ca name=\"method-parens\"\u003e\u003c/a\u003e\n  Используйте `def` со скобками, когда у метода есть параметры. Опускайте\n  скобки, когда метод не принимает параметров.\n  \u003csup\u003e[[ссылка](#method-parens)]\u003c/sup\u003e\n\n   ```ruby\n   # плохо\n   def some_method()\n     # некоторый код\n   end\n\n   # хорошо\n   def some_method\n     # некоторый код\n   end\n\n   # плохо\n   def some_method_with_parameters param1, param2\n     # некоторый код\n   end\n\n   # хорошо\n   def some_method_with_parameters(param1, param2)\n     # некоторый код\n   end\n   ```\n\n* \u003ca name=\"method-invocation-parens\"\u003e\u003c/a\u003e\n  Используйте круглые скобки вокруг аргументов при вызове метода,\n  в особенности если первый аргумент начинается с символа `(`\n  (как например тут: `f((3 + 2) + 1)`)\n  \u003csup\u003e[[ссылка](#method-invocation-parens)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  x = Math.sin y\n  # хорошо\n  x = Math.sin(y)\n\n  # плохо\n  array.delete e\n  # хорошо\n  array.delete(e)\n\n  # плохо\n  temperance = Person.new 'Temperance', 30\n  # хорошо\n  temperance = Person.new('Temperance', 30)\n  ```\n\n  Всегда опускайте скобки в случаях,\n\n  * когда метод вызывается без аргументов:\n\n    ```ruby\n    # плохо\n    Kernel.exit!()\n    2.even?()\n    fork()\n    'test'.upcase()\n\n    # хорошо\n    Kernel.exit!\n    2.even?\n    fork\n    'test'.upcase\n    ```\n\n  * когда методы являются частью внутреннего DSL (т.е. `Rake`, `Rails`, `RSpec`):\n\n    ```ruby\n    # плохо\n    validates(:name, presence: true)\n    # хорошо\n    validates :name, presence: true\n    ```\n\n  * когда методы имеют статусы ключевых слов в Руби:\n\n    ```ruby\n    class Person\n      # плохо\n      attr_reader(:name, :age)\n      # хорошо\n      attr_reader :name, :age\n\n      # некоторый код\n    end\n    ```\n\n  Скобки можно опускать,\n\n  * когда методы имеют в Руби статус ключевого слова, но не являются декларативными:\n\n    ```ruby\n    # хорошо\n    puts(temperance.age)\n    system('ls')\n    # тоже хорошо\n    puts temperance.age\n    system 'ls'\n    ```\n\n* \u003ca name=\"optional-arguments\"\u003e\u003c/a\u003e\n  Определяйте необязательные аргументы в конце списка аргументов.\n  Способ, каким Руби обрабатывает необязательные аргументы при вызове метода,\n  может показаться вам неоднозначным, если они заданы в начале списка.\n  \u003csup\u003e[[ссылка](#optional-arguments)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  def some_method(a = 1, b = 2, c, d)\n    puts \"#{a}, #{b}, #{c}, #{d}\"\n  end\n\n  some_method('w', 'x') # =\u003e '1, 2, w, x'\n  some_method('w', 'x', 'y') # =\u003e 'w, 2, x, y'\n  some_method('w', 'x', 'y', 'z') # =\u003e 'w, x, y, z'\n\n  # хорошо\n  def some_method(c, d, a = 1, b = 2)\n    puts \"#{a}, #{b}, #{c}, #{d}\"\n  end\n\n  some_method('w', 'x') # =\u003e '1, 2, w, x'\n  some_method('w', 'x', 'y') # =\u003e 'y, 2, w, x'\n  some_method('w', 'x', 'y', 'z') # =\u003e 'y, z, w, x'\n  ```\n\n* \u003ca name=\"parallel-assignment\"\u003e\u003c/a\u003e\n  Избегайте параллельного присвоения значений переменным. Параллельное\n  присвоение разрешается тогда, когда присваивается возвращаемое методом\n  значение совместно с оператором разобщения или значения переменных\n  взаимно переопределяются. Параллельное присвоение сложнее воспринимается, чем\n  обычная его форма записи.\n  \u003csup\u003e[[ссылка](#parallel-assignment)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  a, b, c, d = 'foo', 'bar', 'baz', 'foobar'\n\n  # хорошо\n  a = 'foo'\n  b = 'bar'\n  c = 'baz'\n  d = 'foobar'\n\n  # хорошо (взаимное переопределение)\n  # Взаимное переопределение является особым случаем, так как помогает заместить\n  # оба задействованных значения.\n  a = 'foo'\n  b = 'bar'\n\n  a, b = b, a\n  puts a # =\u003e 'bar'\n  puts b # =\u003e 'foo'\n\n  # хорошо (возвращаемое значение)\n  def multi_return\n    [1, 2]\n  end\n\n  first, second = multi_return\n\n  # хорошо (применение оператора разобщения)\n  # first = 1, list = [2, 3, 4]\n  first, *list = [1, 2, 3, 4]\n\n  # ['Hello']\n  hello_array = *'Hello'\n\n  # [1, 2, 3]\n  a = *(1..3)\n  ```\n* \u003ca name=\"trailing-underscore-variables\"\u003e\u003c/a\u003e\n  Избегайте ненужного использования нижних подчеркиваний в именах переменных\n  в конце параллельного присваивания. Именованные нижние подчеркивания\n  предпочтительнее безымянных, поскольку помогают понять контекст. Использовать\n  нижние подчеркивания в конце параллельного присваивания есть смысл, когда\n  в начале присваивания вы используете оператор разобщения в переменную\n  и хотите исключить какие-то значения.\n  \u003csup\u003e[[ссылка]](#trailing-underscore-variables)\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  foo = 'one,two,three,four,five'\n  # Ненужное присваивание, не несущее к тому же полезной информации.\n  first, second, _ = foo.split(',')\n  first, _, _ = foo.split(',')\n  first, *_ = foo.split(',')\n\n\n  # хорошо\n  foo = 'one,two,three,four,five'\n  # Нижнее подчеркивание нужно, чтобы показать, что нам нужны все элементы\n  # кроме некоторого количества последних элементов.\n  *beginning, _ = foo.split(',')\n  *beginning, something, _ = foo.split(',')\n\n  a, = foo.split(',')\n  a, b, = foo.split(',')\n  # Ненужное присваивание значения неиспользуемой переменной, но это\n  # присваивание дает нам полезную информацию о данных.\n  first, _second = foo.split(',')\n  first, _second, = foo.split(',')\n  first, *_ending = foo.split(',')\n  ```\n\n* \u003ca name=\"no-for-loops\"\u003e\u003c/a\u003e\n  Используйте оператор `for` только в случаях, когда вы точно знаете, зачем вы\n  это делаете. В подавляющем большинстве остальных случаев стоит применять\n  итераторы. Оператор `for` реализуется при помощи `each` (таким образом вы\n  добавляете еще один уровень абстракции), но с некоторыми отличиями:\n  не создается отдельная область видимости (в отличии от `each`) и переменные,\n  объявленные в теле `for`, будут видны за пределами блока.\n  \u003csup\u003e[[ссылка](#no-for-loops)]\u003c/sup\u003e\n\n  ```ruby\n  arr = [1, 2, 3]\n\n  # плохо\n  for elem in arr do\n    puts elem\n  end\n\n  # Учтите, elem доступен за пределами цикла\n  elem #=\u003e 3\n\n  # хорошо\n  arr.each { |elem| puts elem }\n\n  # elem недоступен за пределами блока each\n  elem #=\u003e NameError: undefined local variable or method `elem'\n  ```\n\n* \u003ca name=\"no-then\"\u003e\u003c/a\u003e\n  Не используйте `then` для условий `if`/`unless`,\n  объявленных на нескольких строках.\n  \u003csup\u003e[[ссылка](#no-then)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if some_condition then\n    # некоторое действие\n  end\n\n  # хорошо\n  if some_condition\n    # некоторое действие\n  end\n  ```\n\n\n* \u003ca name=\"same-line-condition\"\u003e\u003c/a\u003e\n  Всегда записывайте условие для `if/unless` на той же строке, что содержит\n  `if/then` в многострочном условии.\n  \u003csup\u003e[[ссылка](#same-line-condition)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if\n    x \u003e 1\n    # некоторые действия\n  end\n\n  # хорошо\n  if x \u003e 1\n    # некоторые действия\n  end\n  ```\n\n* \u003ca name=\"ternary-operator\"\u003e\u003c/a\u003e\n  Предпочитайте тернарный оператор (`?:`) конструкциям с `if/then/else/end`.\n  Он используется чаще и по определению более краток.\n  \u003csup\u003e[[ссылка](#ternary-operator)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  result = if some_condition then something else something_else end\n\n  # хорошо\n  result = some_condition ? something : something_else\n  ```\n\n* \u003ca name=\"no-nested-ternary\"\u003e\u003c/a\u003e\n  Используйте только одно выражение в каждой ветви тернарного оператора.\n  Отсюда следует, что лучше избегать вложенных тернарных операторов.\n  При возникновении такой необходимости применяйте конструкции с `if/else`.\n  \u003csup\u003e[[ссылка](#no-nested-ternary)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  some_condition ? (nested_condition ? nested_something : nested_something_else) : something_else\n\n  # хорошо\n  if some_condition\n    nested_condition ? nested_something : nested_something_else\n  else\n    something_else\n  end\n  ```\n\n* \u003ca name=\"no-1.8-if-syntax\"\u003e\u003c/a\u003e\n  Не используйте `if x: ...`, в Руби 1.9 эту синтаксическую конструкцию удалили,\n  используйте вместо нее тернарные операторы.\n  \u003csup\u003e[[ссылка](#no-1.8-if-syntax)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  result = if some_condition: something else something_else end\n\n  # хорошо\n  result = some_condition ? something : something_else\n  ```\n\n* \u003ca name=\"no-semicolon-ifs\"\u003e\u003c/a\u003e\n  Не используйте точку с запятой в `if x; ...`. Применяйте тернарные операторы.\n  \u003csup\u003e[[ссылка](#no-semicolon-ifs)]\u003c/sup\u003e\n\n* \u003ca name=\"use-if-case-returns\"\u003e\u003c/a\u003e\n  Извлекайте пользу из такого факта, что `if` и `case` являются выражениями,\n  возвращающими результирующие значения.\n  \u003csup\u003e[[ссылка](#use-if-case-returns)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if a == 1\n    result = x\n  else\n    result = y\n  end\n\n  # хорошо\n  result =\n    if a == 1\n      x\n    else\n      y\n    end\n  ```\n\n* \u003ca name=\"one-line-cases\"\u003e\u003c/a\u003e\n  Применяйте `when x then ...` для однострочных выражений. Вариант записи\n  `when x: ...` был удален, начиная с Руби 1.9.\n  \u003csup\u003e[[ссылка](#one-line-cases)]\u003c/sup\u003e\n\n* \u003ca name=\"no-when-semicolons\"\u003e\u003c/a\u003e\n  Не используйте `when x; ...` по аналогии с предыдущим правилом.\n  \u003csup\u003e[[ссылка](#no-when-semicolons)]\u003c/sup\u003e\n\n* \u003ca name=\"bang-not-not\"\u003e\u003c/a\u003e\n  Используйте `!` вместо `not`.\n  \u003csup\u003e[[ссылка](#bang-not-not)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (необходимы скобки из-за неоднозначности приоритетов операторов)\n  x = (not something)\n\n  # хорошо\n  x = !something\n  ```\n\n* \u003ca name=\"no-bang-bang\"\u003e\u003c/a\u003e\n  Не используйте `!!`.\n  \u003csup\u003e[[ссылка](#no-bang-bang)]\u003c/sup\u003e\n\n  `!!` преобразует значение в логическое, однако зачастую в явном\n  преобразовании просто нет необходимости в контексте управляющего\n  выражения, его использование делает ваше намерение неявным.\n  Если вы хотите сделать проверку на `nil`, лучше используйте `nil?`.\n\n  ```ruby\n  # плохо\n  x = 'test'\n  # неявная проверка на nil\n  if !!x\n    # некоторое выражение\n  end\n\n  # хорошо\n  x = 'test'\n  if x\n    # некоторое выражение\n  end\n  ```\n\n* \u003ca name=\"no-and-or-or\"\u003e\u003c/a\u003e\n  Ключевые слова `and` и `or` следует забыть. Минимальное улучшение ясности\n  написанного кода достигается за счет высокой вероятности сделать\n  сложнонаходимые ошибки. Для логических выражений всегда используйте `\u0026\u0026` и `||`\n  вместо них. Для управления ветвлением применяйте `if` и `unless`; `\u0026\u0026` и `||`\n  также допустимы, хотя и менее понятны.\n  \u003csup\u003e[[ссылка](#no-and-or-or)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  # булево выражение\n  ok = got_needed_arguments and arguments_are_valid\n\n  # управление ветвлением\n  document.save or raise(\"Failed to save document!\")\n\n  # хорошо\n  # булево выражение\n  ok = got_needed_arguments \u0026\u0026 arguments_are_valid\n\n  # управление ветвлением\n  raise(\"Failed to save document!\") unless document.save\n\n  # сойдет\n  # управление ветвлением\n  document.save || raise(\"Failed to save document!\")\n  ```\n\n* \u003ca name=\"no-multiline-ternary\"\u003e\u003c/a\u003e\n  Избегайте многострочных тернарных операторов `? :`.\n  Используйте вместо них `if`/`unless`.\n  \u003csup\u003e[[ссылка](#no-multiline-ternary)]\u003c/sup\u003e\n\n* \u003ca name=\"if-as-a-modifier\"\u003e\u003c/a\u003e\n  Для однострочных выражений по возможности используйте модификатор\n  `if`/`unless`. Другим хорошим вариантом являются операторы управления\n  потоком исполнения `\u0026\u0026`/`||`.\n  \u003csup\u003e[[ссылка](#if-as-a-modifier)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if some_condition\n    do_something\n  end\n\n  # хорошо\n  do_something if some_condition\n\n  # еще хороший вариант\n  some_condition \u0026\u0026 do_something\n  ```\n\n* \u003ca name=\"no-multiline-if-modifiers\"\u003e\u003c/a\u003e\n  Избегайте `if`/`unless` в конце нетривиального многострочного блока.\n  \u003csup\u003e[[ссылка](#no-multiline-if-modifiers)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  10.times do\n    # некоторый код в несколько строк\n  end if some_condition\n\n  # хорошо\n  if some_condition\n    10.times do\n      # некоторый код в несколько строк\n    end\n  end\n  ```\n\n* \u003ca name=\"no-nested-modifiers\"\u003e\u003c/a\u003e\n  Избегайте вложенных модификаторов `if`/`unless`/`while`/`until`.\n  Используйте `\u0026\u0026`/`||` по необходимости.\n  \u003csup\u003e[[ссылка](#no-nested-modifiers)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  do_something if other_condition if some_condition\n\n  # хорошо\n  do_something if some_condition \u0026\u0026 other_condition\n  ```\n* \u003ca name=\"unless-for-negatives\"\u003e\u003c/a\u003e\n  Используйте `unless` вместо `if` для отрицательных условий (или `||` для управления потоком исполнения).\n  \u003csup\u003e[[ссылка](#unless-for-negatives)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  do_something if !some_condition\n\n  # плохо\n  do_something if not some_condition\n\n  # хорошо\n  do_something unless some_condition\n\n  # тоже хорошо\n  some_condition || do_something\n  ```\n\n* \u003ca name=\"no-else-with-unless\"\u003e\u003c/a\u003e\n  Не используйте `unless` вместе с `else`.\n  Перепишите такие выражение с положительной проверкой.\n  \u003csup\u003e[[ссылка](#no-else-with-unless)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  unless success?\n    puts 'failure'\n  else\n    puts 'success'\n  end\n\n  # хорошо\n  if success?\n    puts 'success'\n  else\n    puts 'failure'\n  end\n  ```\n\n* \u003ca name=\"no-parens-around-condition\"\u003e\u003c/a\u003e\n  Не используйте скобки вокруг условных выражений в управляющих конструкциях.\n  \u003csup\u003e[[ссылка](#no-parens-around-condition)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if (x \u003e 10)\n    # код опущен для краткости\n  end\n\n  # хорошо\n  if x \u003e 10\n    # код опущен для краткости\n  end\n  ```\n  Однако в этом правиле есть некоторые исключения, например,\n  [надежные присвоения в условных выражениях](#safe-assignment-in-condition).\n\n* \u003ca name=\"no-multiline-while-do\"\u003e\u003c/a\u003e\n  Не используйте `while/until УСЛОВИЕ do` для многострочных циклов с `while/until`.\n  \u003csup\u003e[[ссылка](#no-multiline-while-do)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  while x \u003e 5 do\n    # код опущен для краткости\n  end\n\n  until x \u003e 5 do\n    # код опущен для краткости\n  end\n\n  # хорошо\n  while x \u003e 5\n    # код опущен для краткости\n  end\n\n  until x \u003e 5\n    # код опущен для краткости\n  end\n  ```\n\n* \u003ca name=\"while-as-a-modifier\"\u003e\u003c/a\u003e\n  Используйте `while`/`until` в постпозиции для однострочных выражений.\n  \u003csup\u003e[[ссылка](#while-as-a-modifier)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  while some_condition\n    do_something\n  end\n\n  # хорошо\n  do_something while some_condition\n  ```\n* \u003ca name=\"until-for-negatives\"\u003e\u003c/a\u003e\n  Используйте `until` вместо `while` для условий на отрицания.\n  \u003csup\u003e[[ссылка](#until-for-negatives)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  do_something while !some_condition\n\n  # хорошо\n  do_something until some_condition\n  ```\n* \u003ca name=\"infinite-loop\"\u003e\u003c/a\u003e\n  Используйте `Kernel#loop` вместо `while/until` для бесконечного цикла.\n  \u003csup\u003e[[ссылка](#infinite-loop)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  while true\n    do_something\n  end\n\n  until false\n    do_something\n  end\n\n  # хорошо\n  loop do\n    do_something\n  end\n  ```\n\n* \u003ca name=\"loop-with-break\"\u003e\u003c/a\u003e\n  Используйте `Kernel#loop` с `break` вместо `begin/end/until` или\n  `begin/end/while` для циклов с постусловием.\n  \u003csup\u003e[[ссылка](#loop-with-break)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  begin\n    puts val\n    val += 1\n  end while val \u003c 0\n\n  # хорошо\n  loop do\n    puts val\n    val += 1\n    break unless val \u003c 0\n  end\n  ```\n\n* \u003ca name=\"no-braces-opts-hash\"\u003e\u003c/a\u003e\n  Не используйте фигурные скобки для ограничения хешей, передаваемых методу.\n  \u003csup\u003e[[ссылка](#no-braces-opts-hash)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  user.set({ name: 'John', age: 45, permissions: { read: true } })\n\n  # хорошо\n  user.set(name: 'John', age: 45, permissions: { read: true })\n  ```\n\n* \u003ca name=\"no-dsl-decorating\"\u003e\u003c/a\u003e\n  Не используйте фигурные скобки для ограничения хешей, передаваемых методу, и\n  скобки вокруг параметров для методов, являющихся частью DSL.\n  \u003csup\u003e[[ссылка](#no-dsl-decorating)]\u003c/sup\u003e\n\n  ```ruby\n  class Person \u003c ActiveRecord::Base\n    # плохо\n    validates(:name, { presence: true, length: { within: 1..10 } })\n\n    # хорошо\n    validates :name, presence: true, length: { within: 1..10 }\n  end\n  ```\n\n* \u003ca name=\"single-action-blocks\"\u003e\u003c/a\u003e\n  Используйте краткую форму для вызова `proc`, если вызываемый метод является\n  единственным в блоке.\n  \u003csup\u003e[[ссылка](#single-action-blocks)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  names.map { |name| name.upcase }\n\n  # хорошо\n  names.map(\u0026:upcase)\n  ```\n\n* \u003ca name=\"single-line-blocks\"\u003e\u003c/a\u003e\n  Используйте преимущественно скобки `{...}` в случае однострочных\n  блоков, а `do...end` в случае многострочных блоков (многострочные\n  последовательности вызовов методов всегда выглядят\n  ужасно). Старайтесь применять `do...end` для логических операций и\n  определений методов (например, для Rakefile и некоторых DSL). Не\n  используйте `do...end` в цепочках вызовов.\n  \u003csup\u003e[[ссылка](#single-line-blocks)]\u003c/sup\u003e\n\n  ```ruby\n  names = %w[Bozhidar Steve Sarah]\n\n  # плохо\n  names.each do |name|\n    puts name\n  end\n\n  # хорошо\n  names.each { |name| puts name }\n\n  # плохо\n  names.select do |name|\n    name.start_with?('S')\n  end.map { |name| name.upcase }\n\n  # хорошо\n  names.select { |name| name.start_with?('S') }.map(\u0026:upcase)\n  ```\n\n  Некоторые из нас поспорят, что многострочные последовательные вызовы с блоками\n  при использовании {...} выглядят неплохо, но тогда стоит себя спросить, а\n  читается ли такой код и не стоит ли выделить эти блоки в отдельные специальные\n  методы.\n\n* \u003ca name=\"block-argument\"\u003e\u003c/a\u003e Попробуйте использовать блоки напрямую в виде\n  аргумента в случае, когда блок просто передает свои аргументы в другой блок.\n  В этом случае обратите внимание на падение производительности, так как\n  аргументы будут преобразованы в объект класса `Proc`.\n  \u003csup\u003e[[ссылка](#block-argument)]\u003c/sup\u003e\n\n  ```ruby\n  require 'tempfile'\n\n  # плохо\n  def with_tmp_dir\n    Dir.mktmpdir do |tmp_dir|\n      # блок просто передает аргументы дальше\n      Dir.chdir(tmp_dir) { |dir| yield dir }\n    end\n  end\n\n  # хорошо\n  def with_tmp_dir(\u0026block)\n    Dir.mktmpdir do |tmp_dir|\n      Dir.chdir(tmp_dir, \u0026block)\n    end\n  end\n\n  with_tmp_dir do |dir|\n    puts \"dir доступен в виде параметра, и pwd имеет значение: #{dir}\"\n  end\n  ```\n\n* \u003ca name=\"no-explicit-return\"\u003e\u003c/a\u003e\n  Избегайте ключевого слова `return` везде, где это не нужно для управления ветвлением.\n  \u003csup\u003e[[ссылка](#no-explicit-return)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  def some_method(some_arr)\n    return some_arr.size\n  end\n\n  # хорошо\n  def some_method(some_arr)\n    some_arr.size\n  end\n  ```\n\n* \u003ca name=\"no-self-unless-required\"\u003e\u003c/a\u003e\n  Избегайте ключевого слова `self` везде, где оно не требуется. Оно необходимо\n  только при вызове методов доступа для записи, методов, совпадающих с ключевыми\n  словами, и перегружаемых операторов.\n  \u003csup\u003e[[ссылка](#no-self-unless-required)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  def ready?\n    if self.last_reviewed_at \u003e self.last_updated_at\n      self.worker.update(self.content, self.options)\n      self.status = :in_progress\n    end\n    self.status == :verified\n  end\n\n  # хорошо\n  def ready?\n    if last_reviewed_at \u003e last_updated_at\n      worker.update(content, options)\n      self.status = :in_progress\n    end\n    status == :verified\n  end\n  ```\n\n* \u003ca name=\"no-shadowing\"\u003e\u003c/a\u003e\n  В качестве бездоказательного утверждения: избегайте маскирования методов\n  локальными переменными, если они не эквивалентны.\n  \u003csup\u003e[[ссылка](#no-shadowing)]\u003c/sup\u003e\n\n  ```ruby\n  class Foo\n    attr_accessor :options\n\n    # сносно\n    # как options, так и self.options здесь эквивалентны\n    def initialize(options)\n      self.options = options\n    end\n\n    # плохо\n    def do_something(options = {})\n      unless options[:when] == :later\n        output(self.options[:message])\n      end\n    end\n\n    # хорошо\n    def do_something(params = {})\n      unless params[:when] == :later\n        output(options[:message])\n      end\n    end\n  end\n  ```\n\n* \u003ca name=\"safe-assignment-in-condition\"\u003e\u003c/a\u003e\n  Используйте возвращаемое оператором присваивания (`=`) значение только\n  в случаях, когда все выражение стоит в скобках. Эта идиома достаточно\n  распространена среди программистов на Руби и часто называется\n  *надежное присваивание в логических выражениях*.\n  \u003csup\u003e[[ссылка](#safe-assignment-in-condition)]\u003c/sup\u003e\n\n\n  ```ruby\n  # плохо (к тому же вызывает предупреждение)\n  if v = array.grep(/foo/)\n    do_something(v)\n    # некоторый код\n  end\n\n  # хорошо (MRI выдаст предупреждение, но Рубокоп допускает такой синтаксис)\n  if (v = array.grep(/foo/))\n    do_something(v)\n    # некоторый код\n  end\n\n  # хорошо\n  v = array.grep(/foo/)\n  if v\n    do_something(v)\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"self-assignment\"\u003e\u003c/a\u003e\n  По возможности используйте сокращенные операторы присваивания.\n  \u003csup\u003e[[ссылка](#self-assignment)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  x = x + y\n  x = x * y\n  x = x**y\n  x = x / y\n  x = x || y\n  x = x \u0026\u0026 y\n\n  # хорошо\n  x += y\n  x *= y\n  x **= y\n  x /= y\n  x ||= y\n  x \u0026\u0026= y\n  ```\n\n* \u003ca name=\"double-pipe-for-uninit\"\u003e\u003c/a\u003e\n  Используйте оператор `||=` для инициализации переменных, только если\n  переменная еще не инициализирована.\n  \u003csup\u003e[[ссылка](#double-pipe-for-uninit)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  name = name ? name : 'Bozhidar'\n\n  # плохо\n  name = 'Bozhidar' unless name\n\n  # хорошо (присвоить переменной `name` значение 'Bozhidar', только если ее\n  # значение `nil` или `false`)\n  name ||= 'Bozhidar'\n  ```\n\n* \u003ca name=\"no-double-pipes-for-bools\"\u003e\u003c/a\u003e\n  Не используйте оператор `||=` для инициализации логических переменных.\n  Это вызовет проблемы, если текущим значением переменной будет `false`.\n  \u003csup\u003e[[ссылка](#no-double-pipes-for-bools)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (назначит переменной enabled значение true, даже если оно было false)\n  enabled ||= true\n\n  # хорошо\n  enabled = true if enabled.nil?\n  ```\n\n* \u003ca name=\"double-amper-preprocess\"\u003e\u003c/a\u003e\n  Используйте оператор `\u0026\u0026=` для предварительной работы с переменными, которые\n  уже или еще не инициализированы. Использование оператора `\u0026\u0026=` изменит\n  значение переменной, только если она инициализирована. При этом отпадает\n  необходимость в проверке с `if`.\n  \u003csup\u003e[[ссылка](#double-amper-preprocess)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if something\n    something = something.downcase\n  end\n\n  # плохо\n  something = something ? something.downcase : nil\n\n  # сносно\n  something = something.downcase if something\n\n  # хорошо\n  something = something \u0026\u0026 something.downcase\n\n  # еще лучше\n  something \u0026\u0026= something.downcase\n  ```\n\n* \u003ca name=\"no-case-equality\"\u003e\u003c/a\u003e\n  Избегайте явного использования оператора равенства в case `===`. Как\n  подсказывает его имя, этот оператор предназначен для имплицитного\n  применения в выражениях `case`, в отрыве от них он приводит только к\n  разночтениям в коде.\n  \u003csup\u003e[[ссылка](#no-case-equality)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  Array === something\n  (1..100) === 7\n  /something/ === some_string\n\n  # хорошо\n  something.is_a?(Array)\n  (1..100).include?(7)\n  some_string =~ /something/\n  ```\n* \u003ca name=\"eql\"\u003e\u003c/a\u003e\n  Не используйте `eql?`, если будет достаточно `==`. Более строгая семантика\n  сравнения, реализованная в `eql?`, достаточно редко нужна на практике.\n  \u003csup\u003e[[ссылка](#eql)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (`eql?` работает для строк, как и  `==`)\n  'ruby'.eql? some_str\n\n  # хорошо\n  'ruby' == some_str\n  1.0.eql? x # здесь `eql?` имеет смысл, если вы хотите различать классы числа: `Integer` vs. `Float`\n  ```\n\n* \u003ca name=\"no-cryptic-perlisms\"\u003e\u003c/a\u003e\n  Избегайте специальных переменных, заимствованных из языка Перл, например, `$:`,\n  `$;` и т.д. Они сложно воспринимаются, и их использование приветствуется\n  только в однострочных скриптах. В остальных случаях применяйте легкие для\n  восприятия варианты этих переменных из библиотеки `English`.\n  \u003csup\u003e[[ссылка](#no-cryptic-perlisms)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  $:.unshift File.dirname(__FILE__)\n\n  # хорошо\n  require 'English'\n  $LOAD_PATH.unshift File.dirname(__FILE__)\n  ```\n\n* \u003ca name=\"parens-no-spaces\"\u003e\u003c/a\u003e\n  Не оставляйте пробел между именем метода и открывающей скобкой.\n  \u003csup\u003e[[ссылка](#parens-no-spaces)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  f (3 + 2) + 1\n\n  # хорошо\n  f(3 + 2) + 1\n  ```\n\n* \u003ca name=\"always-warn-at-runtime\"\u003e\u003c/a\u003e\n  Всегда вызывайте интерпретатор Руби с ключом `-w`, чтобы получать напоминания о\n  правилах, описанных выше, даже если вы о них забываете.\n  \u003csup\u003e[[ссылка](#always-warn-at-runtime)]\u003c/sup\u003e\n\n* \u003ca name=\"lambda-multi-line\"\u003e\u003c/a\u003e\n  Используйте новый синтаксис лямбда-выражений для однострочных блоков. Используйте\n  метод `lambda` для многострочных блоков.\n  \u003csup\u003e[[ссылка](#lambda-multi-line)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  l = lambda { |a, b| a + b }\n  l.call(1, 2)\n\n  # верно, но выглядит очень странно\n  l = -\u003e(a, b) do\n    tmp = a * 7\n    tmp * b / 50\n  end\n\n  # хорошо\n  l = -\u003e(a, b) { a + b }\n  l.call(1, 2)\n\n  l = lambda do |a, b|\n    tmp = a * 7\n    tmp * b / 50\n  end\n  ```\n* \u003ca name=\"stabby-lambda-with-args\"\u003e\u003c/a\u003e\n  Используйте скобки при определении `lambda` с аргументами.\n  \u003csup\u003e[[ссылка](#stabby-lambda-with-args)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  l = -\u003ex, y { something(x, y) }\n\n  # хорошо\n  l = -\u003e(x, y) { something(x, y) }\n  ```\n* \u003ca name=\"stabby-lambda-no-args\"\u003e\u003c/a\u003e\n  Не используйте скобки при определении `lambda` без аргументов.\n  \u003csup\u003e[[ссылка](#stabby-lambda-no-args)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  l = -\u003e() { something }\n\n  # хорошо\n  l = -\u003e { something }\n  ```\n\n* \u003ca name=\"proc\"\u003e\u003c/a\u003e\n  Используйте `proc` вместо `Proc.new`.\n  \u003csup\u003e[[ссылка](#proc)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  p = Proc.new { |n| puts n }\n\n  # хорошо\n  p = proc { |n| puts n }\n  ```\n\n* \u003ca name=\"proc-call\"\u003e\u003c/a\u003e\n  Используйте `proc.call()` вместо `proc[]` или `proc.()` для\n  лямбда-выражений и блоков.\n  \u003csup\u003e[[ссылка](#proc-call)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (выглядит как доступ к энумератору)\n  l = -\u003e(v) { puts v }\n  l[1]\n\n  # тоже плохо (редкая формулировка)\n  l = -\u003e(v) { puts v }\n  l.(1)\n\n  # хорошо\n  l = -\u003e(v) { puts v }\n  l.call(1)\n  ```\n\n* \u003ca name=\"underscore-unused-vars\"\u003e\u003c/a\u003e\n  Начинайте неиспользуемые параметры блока с подчеркивания `_`. Также допустимо\n  использовать только подчеркивание `_`, хотя это и менее информативно. Эта\n  договоренность распознается интерпретатором Руби и Рубокопом и уберет\n  предупреждения о неиспользуемых переменных.\n  \u003csup\u003e[[ссылка](#underscore-unused-vars)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  result = hash.map { |k, v| v + 1 }\n\n  def something(x)\n    unused_var, used_var = something_else(x)\n    # некоторый код\n  end\n\n  # хорошо\n  result = hash.map { |_k, v| v + 1 }\n\n  def something(x)\n    _unused_var, used_var = something_else(x)\n    # некоторый код\n  end\n\n  # хорошо\n  result = hash.map { |_, v| v + 1 }\n\n  def something(x)\n    _, used_var = something_else(x)\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"global-stdout\"\u003e\u003c/a\u003e\n  Используйте переменные `$stdout/$stderr/$stdin` вместо констант\n  `STDOUT/STDERR/STDIN`. `STDOUT/STDERR/STDIN` являются константами, поэтому при\n  их переопределении (вы это можете сделать, например, для перенаправления\n  ввода-вывода) интерпретатор будет выдавать предупреждения.\n  \u003csup\u003e[[ссылка](#global-stdout)]\u003c/sup\u003e\n\n* \u003ca name=\"warn\"\u003e\u003c/a\u003e\n  Используйте `warn` вместо `$stderr.puts`. Это не только короче, но и позволит\n  вам скрыть все предупреждения, если вам это понадобится (для этого задайте\n  уровень предупреждений равный `0` при помощи опции `-W0`).\n  \u003csup\u003e[[ссылка](#warn)]\u003c/sup\u003e\n\n* \u003ca name=\"sprintf\"\u003e\u003c/a\u003e\n  Используйте `sprintf` и его алиас `format` вместо довольно запутанного метода\n  `String#%`.\n  \u003csup\u003e[[ссылка](#sprintf)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  '%d %d' % [20, 10]\n  # =\u003e '20 10'\n\n  # хорошо\n  sprintf('%d %d', 20, 10)\n  # =\u003e '20 10'\n\n  # хорошо\n  sprintf('%\u003cfirst\u003ed %\u003csecond\u003ed', first: 20, second: 10)\n  # =\u003e '20 10'\n\n  format('%d %d', 20, 10)\n  # =\u003e '20 10'\n\n  # хорошо\n  format('%\u003cfirst\u003ed %\u003csecond\u003ed', first: 20, second: 10)\n  # =\u003e '20 10'\n  ```\n\n* \u003ca name=\"named-format-tokens\"\u003e\u003c/a\u003e\n  Используйте формат `%\u003cname\u003es` вместо `%{name}` для поименованных\n  переменных в шаблонах, это даст информацию о типе используемого значения.\n  \u003csup\u003e[[ссылка](#named-format-tokens)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  format('Hello, %{name}', name: 'John')\n\n  # хорошо\n  format('Hello, %\u003cname\u003es', name: 'John')\n  ```\n\n* \u003ca name=\"array-join\"\u003e\u003c/a\u003e\n  Используйте `Array#join` вместо достаточно неочевидного `Array#*` со строковым\n  аргументом.\n  \u003csup\u003e[[ссылка](#array-join)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  %w[one two three] * ', '\n  # =\u003e 'one, two, three'\n\n  # хорошо\n  %w[one two three].join(', ')\n  # =\u003e 'one, two, three'\n  ```\n\n* \u003ca name=\"array-coertion\"\u003e\u003c/a\u003e\n  Используйте явное приведение типов `Array()` (вместо явной проверки\n  на принадлежность к `Array` или `[*var]`), когда вам приходится\n  работать с переменной, которая по вашим ожиданиям должна быть\n  массивом, но вы в этом не полностью уверены.\n  \u003csup\u003e[[ссылка](#array-coertion)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  paths = [paths] unless paths.is_a? Array\n  paths.each { |path| do_something(path) }\n\n  # плохо (всегда создает новый объект `Array`)\n  [*paths].each { |path| do_something(path) }\n\n  # хорошо (и более читаемо)\n  Array(paths).each { |path| do_something(path) }\n  ```\n\n* \u003ca name=\"ranges-or-between\"\u003e\u003c/a\u003e\n  Используйте интервалы или метод `Comparable#between?` вместо сложной логики\n  для сравнения, когда это возможно.\n  \u003csup\u003e[[ссылка](#ranges-or-between)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  do_something if x \u003e= 1000 \u0026\u0026 x \u003c= 2000\n\n  # хорошо\n  do_something if (1000..2000).include?(x)\n\n  # хорошо\n  do_something if x.between?(1000, 2000)\n  ```\n\n* \u003ca name=\"predicate-methods\"\u003e\u003c/a\u003e\n  Используйте предикативные методы вместо явного сравнения с использованием\n  `==`. Сравнение чисел можно проводить явно.\n  \u003csup\u003e[[ссылка](#predicate-methods)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  if x % 2 == 0\n  end\n\n  if x % 2 == 1\n  end\n\n  if x == nil\n  end\n\n  if x == 0\n  end\n\n  # хорошо\n  if x.even?\n  end\n\n  if x.odd?\n  end\n\n  if x.nil?\n  end\n\n  if x.zero?\n  end\n  ```\n\n* \u003ca name=\"no-non-nil-checks\"\u003e\u003c/a\u003e\n  Проводите явную проверку на значение `nil`, только если вы работаете\n  с логическими значениями.\n  \u003csup\u003e[[ссылка](#no-non-nil-checks)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  do_something if !something.nil?\n  do_something if something != nil\n\n  # хорошо\n  do_something if something\n\n  # хорошо (логическое значение)\n  def value_set?\n    !@some_boolean.nil?\n  end\n  ```\n\n* \u003ca name=\"no-BEGIN-blocks\"\u003e\u003c/a\u003e\n  Старайтесь не использовать блоки `BEGIN`.\n  \u003csup\u003e[[ссылка](#no-BEGIN-blocks)]\u003c/sup\u003e\n\n* \u003ca name=\"no-END-blocks\"\u003e\u003c/a\u003e\n  Никогда не используйте блоки `END`. Используйте метод `Kernel#at_exit`.\n  \u003csup\u003e[[ссылка](#no-END-blocks)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  END { puts 'Goodbye!' }\n\n  # хорошо\n  at_exit { puts 'Goodbye!' }\n  ```\n\n* \u003ca name=\"no-flip-flops\"\u003e\u003c/a\u003e\n  Избегайте переменных-перевертышей (flip-flops).\n  \u003csup\u003e[[ссылка](#no-flip-flops)]\u003c/sup\u003e\n\n* \u003ca name=\"no-nested-conditionals\"\u003e\u003c/a\u003e\n  Избегайте вложенных условий для управления ветвлением. Используйте проверочные\n  выражения (guard clauses). Проверочные выражения - это условные выражения\n  в самом начале функции, которые срабатывают при первой же возможности.\n  \u003csup\u003e[[ссылка](#no-nested-conditionals)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  def compute_thing(thing)\n    if thing[:foo]\n      update_with_bar(thing[:foo])\n      if thing[:foo][:bar]\n        partial_compute(thing)\n      else\n        re_compute(thing)\n      end\n    end\n  end\n\n  # хорошо\n  def compute_thing(thing)\n    return unless thing[:foo]\n    update_with_bar(thing[:foo])\n    return re_compute(thing) unless thing[:foo][:bar]\n    partial_compute(thing)\n  end\n  ```\n\n  В циклах используйте `next` вместо блоков с условием.\n\n  ```ruby\n  # плохо\n  [0, 1, 2, 3].each do |item|\n    if item \u003e 1\n      puts item\n    end\n  end\n\n  # хорошо\n  [0, 1, 2, 3].each do |item|\n    next unless item \u003e 1\n    puts item\n  end\n  ```\n\n## Наименование\n\n\u003e Единственными настоящими сложностями в программировании являются очистка кэша\n\u003e и выбор наименований. \u003cbr\u003e\n\u003e -- Фил Карлтон (Phil Karlton)\n\n* \u003ca name=\"english-identifiers\"\u003e\u003c/a\u003e\n  Используйте английский язык, называя идентификаторы.\n  \u003csup\u003e[[ссылка](#english-identifiers)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (идентификатор использует символы вне ASCII)\n  зарплата = 1_000\n\n  # плохо (идентификатор - это русское слово, набранное латиницей вместо\n  # кириллицы)\n  zarplata = 1_000\n\n  # хорошо\n  salary = 1_000\n  ```\n\n* \u003ca name=\"snake-case-symbols-methods-vars\"\u003e\u003c/a\u003e\n  Используйте `snake_case` при наименовании символов, методов и переменных.\n  \u003csup\u003e[[ссылка](#snake-case-symbols-methods-vars)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  :'some symbol'\n  :SomeSymbol\n  :someSymbol\n\n  someVar = 5\n  var_10 = 10\n\n  def someMethod\n    # некоторый код\n  end\n\n  def SomeMethod\n   # некоторый код\n  end\n\n  # хорошо\n  :some_symbol\n\n  some_var = 5\n  var10    = 10\n\n  def some_method\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"snake-case-symbols-methods-vars-with-numbers\"\u003e\u003c/a\u003e\n  Не разделяйте числа и буквы в именах символов, методов и переменных.\n  \u003csup\u003e[[ссылка](#snake-case-symbols-methods-vars-with-numbers)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  :some_sym_1\n\n  some_var_1 = 1\n\n  def some_method_1\n    # некоторый код\n  end\n\n  # хорошо\n  :some_sym1\n\n  some_var1 = 1\n\n  def some_method1\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"camelcase-classes\"\u003e\u003c/a\u003e\n  Используйте `CamelCase` для имен классов и модулей. Сокращения вроде `HTTP`,\n  `RFC`, `XML` набирайте заглавными буквами.\n  \u003csup\u003e[[ссылка](#camelcase-classes)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Someclass\n    # некоторый код\n  end\n\n  class Some_Class\n    # некоторый код\n  end\n\n  class SomeXml\n    # некоторый код\n  end\n\n  class XmlSomething\n    # некоторый код\n  end\n\n  # хорошо\n  class SomeClass\n    # некоторый код\n  end\n\n  class SomeXML\n    # некоторый код\n  end\n\n  class XMLSomething\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"snake-case-files\"\u003e\u003c/a\u003e\n  Используйте `snake_case`, называя файлы, например, `hello_world.rb`.\n  \u003csup\u003e[[ссылка](#snake-case-files)]\u003c/sup\u003e\n\n* \u003ca name=\"snake-case-dirs\"\u003e\u003c/a\u003e\n  Используйте `snake_case`, называя каталоги, например, `lib/hello_world/hello_world.rb`.\n  \u003csup\u003e[[ссылка](#snake-case-dirs)]\u003c/sup\u003e\n\n* \u003ca name=\"one-class-per-file\"\u003e\u003c/a\u003e\n  Старайтесь сохранять только один класс или модуль в каждом файле исходного кода.\n  Называйте эти файлы по имени класса или модуля, изменив запись в форме\n  `CamelCase` на `snake_case`.\n  \u003csup\u003e[[ссылка](#one-class-per-file)]\u003c/sup\u003e\n\n* \u003ca name=\"screaming-snake-case\"\u003e\u003c/a\u003e\n  Используйте `SCREAMING_SNAKE_CASE` для всех других констант кроме имен классов и модулей.\n  \u003csup\u003e[[ссылка](#screaming-snake-case)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  SomeConst = 5\n\n  # хорошо\n  SOME_CONST = 5\n  ```\n\n* \u003ca name=\"bool-methods-qmark\"\u003e\u003c/a\u003e\n  Идентификаторы предикативных методов, т.е. методов, возвращающих логическое\n  значение, должны оканчиваться вопросительным знаком. Например, `Array#empty?`.\n  Имена методов, не возвращающих логическое значение, не должны оканчиваться\n  вопросительным знаком.\n  \u003csup\u003e[[ссылка](#bool-methods-qmark)]\u003c/sup\u003e\n\n* \u003ca name=\"bool-methods-prefix\"\u003e\u003c/a\u003e\n  Не используйте избыточные наименования предикатных методов вроде\n  `is_`, `does_` или `can_`. Такие префиксы не соответствуют\n  конвенциям, принятым в стандартной библиотеке Руби (`#empty?` или\n  `#include?`, например).\n  \u003csup\u003e[[ссылка](#bool-methods-prefix)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Person\n    def is_tall?\n      true\n    end\n\n    def can_play_basketball?\n      false\n    end\n\n    def does_like_candy?\n      true\n    end\n  end\n\n  # хорошо\n  class Person\n    def tall?\n      true\n    end\n\n    def basketball_player?\n      false\n    end\n\n    def likes_candy?\n      true\n    end\n  end\n  ```\n\n* \u003ca name=\"dangerous-method-bang\"\u003e\u003c/a\u003e\n  Идентификаторы потенциально *опасных* методов, т.е. таких методов, которые\n  могут изменить `self` или его аргументы, должны оканчиваться восклицательным\n  знаком, если есть соответствующий *безопасный* вариант такого метода.\n  Например, `exit!`, который не вызывает завершающий скрипт в отличии от `exit`,\n  выполняющего финализацию.\n  \u003csup\u003e[[ссылка](#dangerous-method-bang)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (нет соответствующего безопасного аналога)\n  class Person\n    def update!\n    end\n  end\n\n  # хорошо\n  class Person\n    def update\n    end\n  end\n\n  # хорошо\n  class Person\n    def update!\n    end\n\n    def update\n    end\n  end\n  ```\n\n* \u003ca name=\"safe-because-unsafe\"\u003e\u003c/a\u003e\n  Определяйте безопасный метод (вариант без восклицательного знака) при помощи\n  вызова опасного метода (с восклицательным знаком), если это возможно.\n  \u003csup\u003e[[ссылка](#safe-because-unsafe)]\u003c/sup\u003e\n\n  ```ruby\n  class Array\n    def flatten_once!\n      res = []\n\n      each do |e|\n        [*e].each { |f| res \u003c\u003c f }\n      end\n\n      replace(res)\n    end\n\n    def flatten_once\n      dup.flatten_once!\n    end\n  end\n  ```\n\n* \u003ca name=\"other-arg\"\u003e\u003c/a\u003e\n  При определении бинарных операторов называйте параметр `other`. Исключение\n  составляют методы `#\u003c\u003c` и  `#[]`, так как их семантика сильно отличается.\n  \u003csup\u003e[[ссылка](#other-arg)]\u003c/sup\u003e\n\n  ```ruby\n  def +(other)\n    # некоторый код\n  end\n  ```\n\n* \u003ca name=\"map-find-select-reduce-size\"\u003e\u003c/a\u003e\n  Используйте `#map` вместо `#collect`, `#find` вместо `#detect`, `#select`\n  вместо  `#find_all`, `#reduce` вместо `#inject` и `#size` вместо `#length`.\n  Это требование не сложно реализовать. Если использование альтернатив улучшит\n  восприятие кода, то можно использовать и их. Все описанные варианты были взяты\n  из языка Smalltalk и не распространены в других языках программирования.\n  Причиной, почему не следует использовать `#find_all` вместо `#select`,\n  является хорошая сочетаемость с методом `#reject`, и эти наименования очевидны.\n  \u003csup\u003e[[ссылка](#map-find-select-reduce-size)]\u003c/sup\u003e\n\n* \u003ca name=\"count-vs-size\"\u003e\u003c/a\u003e\n  Не используйте `#count` в качестве замены для `#size()`. Для объектов классов\n  с включенным `Enumerable` (кроме класса`Array`) это приведет к затратному\n  полному обходу всех элементов для определения размера.\n  \u003csup\u003e[[ссылка](#count-vs-size)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  some_hash.count\n\n  # хорошо\n  some_hash.size\n  ```\n\n* \u003ca name=\"flat-map\"\u003e\u003c/a\u003e\n  Используйте `#flat_map` вместо `#map` + `#flatten`. Это правило не относится\n  к массивам с глубиной больше 2, например, если\n  `users.first.songs == ['a', ['b', 'c']]`, то используйте `#map` + `#flatten`,\n  а не `#flat_map`. Метод `#flat_map` уменьшает глубину на один уровень. Метод\n  `#flatten` сглаживает вложенность любого уровня.\n  \u003csup\u003e[[ссылка](#flat-map)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  all_songs = users.map(\u0026:songs).flatten.uniq\n\n  # хорошо\n  all_songs = users.flat_map(\u0026:songs).uniq\n  ```\n\n* \u003ca name=\"reverse-each\"\u003e\u003c/a\u003e\n  Используйте метод `#reverse_each` вместо `#reverse.each`, так как некоторые\n  классы, включающие в себя модуль `Enumerable`, дадут вам очень эффективную\n  реализацию. Даже в худшем случае, когда класс не реализует этот метод\n  отдельно, наследуемая реализация из модуля `Enumerable` будет по меньшей мере\n  такой же эффективной, как и для `#reverse.each`.\n  \u003csup\u003e[[ссылка](#reverse-each)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  array.reverse.each { ... }\n\n  # хорошо\n  array.reverse_each { ... }\n  ```\n\n## Комментарии\n\n\u003e Хороший код является лучшей документацией для себя. Каждый раз, когда вы\n\u003e готовитесь добавить комментарий, спросите себя: \"Как я могу улучшить код,\n\u003e чтобы это комментарий стал ненужным?\" Улучшите код и добавьте комментарий,\n\u003e чтобы сделать его еще понятнее. \u003cbr\u003e\n\u003e -- Стив Макконнел (Steve McConnell)\n\n* \u003ca name=\"no-comments\"\u003e\u003c/a\u003e\n  Пишите говорящий за себя код и смело пропускайте все остальное в этом разделе.\n  Серьезно!\n  \u003csup\u003e[[ссылка](#no-comments)]\u003c/sup\u003e\n\n* \u003ca name=\"english-comments\"\u003e\u003c/a\u003e\n  Пишите комментарии по-английски.\n  \u003csup\u003e[[ссылка](#english-comments)]\u003c/sup\u003e\n\n* \u003ca name=\"hash-space\"\u003e\u003c/a\u003e\n  Используйте один пробел между символом `#` в начале и текстом самого\n  комментария.\n  \u003csup\u003e[[ссылка](#hash-space)]\u003c/sup\u003e\n\n* \u003ca name=\"english-syntax\"\u003e\u003c/a\u003e\n  Комментарии длиной больше одного слова должны оформляться в виде законченных\n  предложений (с большой буквы и со знаками препинания).\n  Разделяйте предложения [одним пробелом](https://en.wikipedia.org/wiki/Sentence_spacing).\n  \u003csup\u003e[[ссылка](#english-syntax)]\u003c/sup\u003e\n\n* \u003ca name=\"no-superfluous-comments\"\u003e\u003c/a\u003e\n  Избегайте избыточного комментирования.\n  \u003csup\u003e[[ссылка](#no-superfluous-comments)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  counter += 1 # Увеличивает счетчик на единицу.\n  ```\n\n* \u003ca name=\"comment-upkeep\"\u003e\u003c/a\u003e\n  Актуализируйте существующие комментарии. Устаревший комментарий гораздо хуже\n  отсутствующего комментария.\n  \u003csup\u003e[[ссылка](#comment-upkeep)]\u003c/sup\u003e\n\n\u003e Хороший код подобен хорошей шутке: он не нуждается в пояснениях. \u003cbr\u003e\n\u003e -- Рус Ольсен (Russ Olsen)\n\u003e \u0026mdash; афоризм старого программиста, взято у [Руса Ольсена](http://eloquentruby.com/blog/2011/03/07/good-code-and-good-jokes/)\n\n* \u003ca name=\"refactor-dont-comment\"\u003e\u003c/a\u003e\n  Не пишите комментарии для объяснения плохого кода. Перепишите код, чтобы он\n  говорил сам за себя.\n  \u003csup\u003e[[ссылка](#refactor-dont-comment)]\u003c/sup\u003e\n\n\u003e Делай или не делай, тут нет места попыткам. \u003cbr\u003e\n\u003e -- Мастер Йода\n\n### Пометки в комментариях\n\n* \u003ca name=\"annotate-above\"\u003e\u003c/a\u003e\n  Обычно пометки следует записывать на предшествующей описываемому коду строке.\n  \u003csup\u003e[[ссылка](#annotate-above)]\u003c/sup\u003e\n\n* \u003ca name=\"annotate-keywords\"\u003e\u003c/a\u003e\n  Пометка отделяется двоеточием и пробелом, потом следует примечание,\n  описывающее проблему.\n  \u003csup\u003e[[ссылка](#annotate-keywords)]\u003c/sup\u003e\n\n* \u003ca name=\"indent-annotations\"\u003e\u003c/a\u003e\n  Если для описания проблемы потребуются несколько строк, то на каждой\n  последующей строке следует сделать отступ в три пробела после символа `#`.\n  \u003csup\u003e[[ссылка](#indent-annotations)]\u003c/sup\u003e\n\n  ```ruby\n  def bar\n    # FIXME: This has crashed occasionally since v3.2.1. It may\n    #   be related to the BarBazUtil upgrade.\n    baz(:quux)\n  end\n  ```\n\n* \u003ca name=\"rare-eol-annotations\"\u003e\u003c/a\u003e\n  В тех случаях, когда проблема настолько очевидна, что любые описания покажутся\n  избыточными, пометки можно поставить в конце вызывающей проблему строки.\n  Однако такое применение должно быть исключением, а не правилом.\n  \u003csup\u003e[[ссылка](#rare-eol-annotations)]\u003c/sup\u003e\n\n  ```ruby\n  def bar\n    sleep 100 # OPTIMIZE\n  end\n  ```\n\n* \u003ca name=\"todo\"\u003e\u003c/a\u003e\n  Используйте `TODO`, чтобы пометить отсутствующие возможности или функционал,\n  которые должны быть добавлены позже.\n  \u003csup\u003e[[ссылка](#todo)]\u003c/sup\u003e\n\n* \u003ca name=\"fixme\"\u003e\u003c/a\u003e\n  Используйте `FIXME`, чтобы пометить код с ошибками, который должен быть\n  исправлен.\n  \u003csup\u003e[[ссылка](#fixme)]\u003c/sup\u003e\n\n* \u003ca name=\"optimize\"\u003e\u003c/a\u003e\n  Используйте `OPTIMIZE`, чтобы пометить медленный или неэффективный код,\n  который может вызвать проблемы с производительностью.\n  \u003csup\u003e[[ссылка](#optimize)]\u003c/sup\u003e\n\n* \u003ca name=\"hack\"\u003e\u003c/a\u003e\n  Используйте `HACK`, чтобы пометить код \"с душком\", который должен быть\n  переработан и использует сомнительные практики разработки.\n  \u003csup\u003e[[ссылка](#hack)]\u003c/sup\u003e\n\n* \u003ca name=\"review\"\u003e\u003c/a\u003e\n  Используйте `REVIEW`, чтобы пометить все, что должно быть проверено на\n  работоспособность. Например, `REVIEW: Are we sure this is how the client does\n  X currently?`.\n  \u003csup\u003e[[ссылка](#review)]\u003c/sup\u003e\n\n* \u003ca name=\"document-annotations\"\u003e\u003c/a\u003e\n  Используйте персональные пометки, если это подходит по месту, но обязательно\n  опишите их смысл в файле `README` (или похожем) для вашего проекта.\n  \u003csup\u003e[[ссылка](#document-annotations)]\u003c/sup\u003e\n\n### Магические комментарии\n\u003c!--- See https://en.wikipedia.org/wiki/Magic_number_(programming) ---\u003e\n\u003c!--- @FIXME: look for a better translation ---\u003e\n\n* \u003ca name=\"magic-comments-first\"\u003e\u003c/a\u003e\n  Размещайте \"магические\" комментарии над всем кодом и документацией. Исключением\n  является только строка вызовом интерпретатора (Shebang), о чем речь пойдет далее.\n  \u003csup\u003e[[ссылка](#magic-comments-first)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  # Some documentation about Person\n\n  # frozen_string_literal: true\n  class Person\n  end\n\n  # хорошо\n  # frozen_string_literal: true\n\n  # Some documentation about Person\n  class Person\n  end\n  ```\n* \u003ca name=\"below-shebang\"\u003e\u003c/a\u003e\n  Размещайте магические комментарии под строкой вызова интерпретатора (Shebang),\n  если она есть в тексте.\n  \u003csup\u003e[[ссылка](#below-shebang)]\u003c/sup\u003e\n\n  ```ruby\n  # хорошо\n  #!/usr/bin/env ruby\n  # frozen_string_literal: true\n\n  App.parse(ARGV)\n\n  # плохо\n  # frozen_string_literal: true\n  #!/usr/bin/env ruby\n\n  App.parse(ARGV)\n  ```\n\n* \u003ca name=\"one-magic-comment-per-line\"\u003e\u003c/a\u003e\n  Каждый \"магический\" комментарий должен быть на отдельной строке.\n  \u003csup\u003e[[ссылка](#one-magic-comment-per-line)]\u003c/sup\u003e\n\n  ```ruby\n  # хорошо\n  # frozen_string_literal: true\n  # encoding: ascii-8bit\n\n  # плохо\n  # -*- frozen_string_literal: true; encoding: ascii-8bit -*-\n  ```\n\n* \u003ca name=\"separate-magic-comments-from-code\"\u003e\u003c/a\u003e\n  Отделяйте \"магические\" комментарии пустой строкой от последующего кода или\n  комментариев.\n  \u003csup\u003e[[ссылка](#separate-magic-comments-from-code)]\u003c/sup\u003e\n\n  ```ruby\n  # хорошо\n  # frozen_string_literal: true\n\n  # Some documentation for Person\n  class Person\n    # Some code\n  end\n\n  # плохо\n  # frozen_string_literal: true\n  # Some documentation for Person\n  class Person\n    # Some code\n  end\n  ```\n\n## Классы и модули\n\n* \u003ca name=\"consistent-classes\"\u003e\u003c/a\u003e\n  Придерживайтесь единообразной структуры классов.\n  \u003csup\u003e[[ссылка](#consistent-classes)]\u003c/sup\u003e\n\n  ```ruby\n  class Person\n    # extend и include в начале\n    extend SomeModule\n    include AnotherModule\n\n    # вложенные классы\n    CustomError = Class.new(StandardError)\n\n    # после этого константы\n    SOME_CONSTANT = 20\n\n    # после этого макросы методов доступа к атрибутам\n    attr_reader :name\n\n    # и все прочие макросы (если имеются)\n    validates :name\n\n    # следующими по списку будут публичные методы класса\n    def self.some_method\n    end\n\n    # инициализация объекта стоит между методами класса и экземпляров\n    def initialize\n    end\n\n    # и следующие за ними публичные методы экземпляров этого класса\n    def some_method\n    end\n\n    # защищенные и частные методы нужно собрать ближе к концу\n    protected\n\n    def some_protected_method\n    end\n\n    private\n\n    def some_private_method\n    end\n  end\n  ```\n\n* \u003ca name=\"mixin-grouping\"\u003e\u003c/a\u003e\n  Каждый включаемый модуль должен быть включен отдельным выражением.\n  \u003csup\u003e[[ссылка](#mixin-grouping)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Person\n    include Foo, Bar\n  end\n\n  # хорошо\n  class Person\n    # каждый миксин включается отдельным выражением\n    include Foo\n    include Bar\n  end\n  ```\n\n* \u003ca name=\"file-classes\"\u003e\u003c/a\u003e\n  Если определение класса занимает несколько строк, постарайтесь вынести такой\n  класс в отдельный файл. Файл с определением стоит поместить в директорию,\n  названную по имени родительского класса, внутри которого определяется\n  вложенный класс.\n  \u003csup\u003e[[ссылка](#file-classes)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n\n  # foo.rb\n  class Foo\n    class Bar\n      # 30 методов внутри\n    end\n\n    class Car\n      # 20 методов внутри\n    end\n\n    # 30 методов внутри\n  end\n\n  # хорошо\n\n  # foo.rb\n  class Foo\n    # 30 методов внутри\n  end\n\n  # foo/bar.rb\n  class Foo\n    class Bar\n      # 30 методов внутри\n    end\n  end\n\n  # foo/car.rb\n  class Foo\n    class Car\n      # 20 методов внутри\n    end\n  end\n  ```\n\n* \u003ca name=\"namespace-definition\"\u003e\u003c/a\u003e\n  Определяйте (и открывайте заново) классы и модули, определенные в некотором\n  пространстве имен, с помощью явного вложения. Оператор разрешения пространства\n  (scope resolution) может создать трудные для понимания ситуации из-за\n  [лексического определения пространств имен](https://cirw.in/blog/constant-lookup.html)\n  в Руби. Пространство имен зависит для модуля от места его определения.\n  \u003csup\u003e[[ссылка](#namespace-definition)]\u003c/sup\u003e\n\n  ```ruby\n  module Utilities\n    class Queue\n    end\n  end\n\n  # плохо\n  class Utilities::Store\n    Module.nesting # =\u003e [Utilities::Store]\n\n    def initialize\n      # Refers to the top level ::Queue class because Utilities isn't in the\n      # current nesting chain.\n      @queue = Queue.new\n    end\n  end\n\n  # хорошо\n  module Utilities\n    class WaitingList\n      Module.nesting # =\u003e [Utilities::WaitingList, Utilities]\n\n      def initialize\n        @queue = Queue.new # Refers to Utilities::Queue\n      end\n    end\n  end\n  ```\n\n* \u003ca name=\"modules-vs-classes\"\u003e\u003c/a\u003e\n  Если класс определяет только методы класса, то трансформируйте такой класс\n  в модуль. Использовать классы логично в тех ситуациях, когда нужно создавать\n  экземпляры класса.\n  \u003csup\u003e[[ссылка](#modules-vs-classes)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class SomeClass\n    def self.some_method\n      # некоторый код\n    end\n\n    def self.some_other_method\n      # некоторый код\n    end\n  end\n\n  # хорошо\n  module SomeModule\n    module_function\n\n    def some_method\n      # некоторый код\n    end\n\n    def some_other_method\n      # некоторый код\n    end\n  end\n  ```\n\n* \u003ca name=\"module-function\"\u003e\u003c/a\u003e\n  Используйте `module_function` вместо `extend self`, когда вам нужно\n  преобразовать включаемые методы модуля в методы модуля.\n  \u003csup\u003e[[ссылка](#module-function)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  module Utilities\n    extend self\n\n    def parse_something(string)\n      # здесь реализуется логика\n    end\n\n    def other_utility_method(number, string)\n      # здесь реализуется дополнительная логика\n    end\n  end\n\n  # хорошо\n  module Utilities\n    module_function\n\n    def parse_something(string)\n      # здесь реализуется логика\n    end\n\n    def other_utility_method(number, string)\n      # здесь реализуется дополнительная логика\n    end\n  end\n  ```\n\n* \u003ca name=\"liskov\"\u003e\u003c/a\u003e\n  Создавая иерархии классов, проверяйте их на соответствие [принципу подстановки Барбары Лисков][Liskov].\n  \u003csup\u003e[[ссылка](#liskov)]\u003c/sup\u003e\n\n* \u003ca name=\"solid-design\"\u003e\u003c/a\u003e\n  Проверяйте дизайн ваших классов на соответствие принципу [SOLID][SOLID],\n  если такая возможность есть.\n  \u003csup\u003e[[ссылка](#solid-design)]\u003c/sup\u003e\n\n* \u003ca name=\"define-to-s\"\u003e\u003c/a\u003e\n  Для описывающих предметные области объектов всегда определяйте метод `#to_s`.\n  \u003csup\u003e[[ссылка](#define-to-s)]\u003c/sup\u003e\n\n  ```ruby\n  class Person\n    attr_reader :first_name, :last_name\n\n    def initialize(first_name, last_name)\n      @first_name = first_name\n      @last_name = last_name\n    end\n\n    def to_s\n      \"#{@first_name} #{@last_name}\"\n    end\n  end\n  ```\n\n* \u003ca name=\"attr_family\"\u003e\u003c/a\u003e\n  Применяйте макросы из семейства `attr_` для тривиальных методов доступа к объекту.\n  \u003csup\u003e[[ссылка](#attr_family)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Person\n    def initialize(first_name, last_name)\n      @first_name = first_name\n      @last_name = last_name\n    end\n\n    def first_name\n      @first_name\n    end\n\n    def last_name\n      @last_name\n    end\n  end\n\n  # хорошо\n  class Person\n    attr_reader :first_name, :last_name\n\n    def initialize(first_name, last_name)\n      @first_name = first_name\n      @last_name = last_name\n    end\n  end\n  ```\n\n* \u003ca name=\"accessor_mutator_method_names\"\u003e\u003c/a\u003e\n  Для методов доступа и назначения переменных избегайте наименований с\n  префиксами `get_` and `set_`. В Руби принято называть методы\n  доступа по именам соответствующих переменных, а методы назначения с\n  использованием `=`, например `attr_name=`.\n  \u003csup\u003e[[ссылка](#accessor_mutator_method_names)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо\n  class Person\n    def get_name\n      \"#{@first_name} #{@last_name}\"\n    end\n\n    def set_name(name)\n      @first_name, @last_name = name.split(' ')\n    end\n  end\n\n  # хорошо\n  class Person\n    def name\n      \"#{@first_name} #{@last_name}\"\n    end\n\n    def name=(name)\n      @first_name, @last_name = name.split(' ')\n    end\n  end\n  ```\n\n* \u003ca name=\"attr\"\u003e\u003c/a\u003e\n  Не используйте обобщенную форму `attr`. Используйте `attr_reader` и\n  `attr_accessor` вместо нее.\n  \u003csup\u003e[[ссылка](#attr)]\u003c/sup\u003e\n\n  ```ruby\n  # плохо (создает единый метод доступа атрибуту, объявлено нежелательным в Руби \u003e= 1.9)\n  attr :something, true\n  attr :one, :two, :three # ведет себя как attr_reader\n\n  # хорошо\n  attr_accessor :something\n  attr_reader :one, :two, :three\n  ```\n\n* \u003ca name=\"struct-new\"\u003e\u003c/a\u003e\n  Подумайте об использовании `Struct.new`, эта конструкция автоматически даст вам\n  простейшие методы доступа к объекту, метод инициализации и методы сравнения.\n  \u003csup\u003e[[ссылка](#struct-new)]\u003c/sup\u003e\n\n  ```ruby\n  # хорошо\n  class Person\n    attr_accessor :first_name, :last_name\n\n    def initialize(first_name, last_name)\n      @first_name = first_name\n      @last_name = last_name\n    end\n  end\n\n  # лучше\n  Person = Struct.new(:first_name, :last_name) do\n  end\n  ```\n\n* \u003ca name=\"no-extend-struct-new\"\u003e\u003c/a\u003e\n  Не дополняйте `Struct.new` при помощи `#extend`. В этом случае уже создается\n  новый класс. При дополнении вы создадите избыточный уровень абстракции, это\n  может п","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farbox%2Fruby-style-guide","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Farbox%2Fruby-style-guide","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Farbox%2Fruby-style-guide/lists"}