From 83bdbc14ddf7adce70793043832306d0b67020ea Mon Sep 17 00:00:00 2001 From: ola-9 Date: Fri, 21 Jun 2024 15:38:19 +0300 Subject: [PATCH] clean up new structure --- .../10-hello-world/description.ru.yml | 29 ---- modules/10-basics/10-hello-world/ru/data.yml | 1 + .../description.ru.yml | 94 ------------- .../15-ruby-as-a-second-language/ru/data.yml | 1 + .../description.ru.yml | 80 ----------- .../20-everything-is-object/ru/data.yml | 1 + .../25-first-function/description.ru.yml | 60 -------- .../10-basics/25-first-function/ru/data.yml | 1 + .../27-conditions/description.ru.yml | 75 ---------- modules/10-basics/27-conditions/ru/data.yml | 1 + modules/10-basics/30-if/description.ru.yml | 47 ------- modules/10-basics/30-if/ru/data.yml | 1 + .../10-basics/33-if-extra/description.ru.yml | 64 --------- modules/10-basics/33-if-extra/ru/data.yml | 1 + .../10-basics/35-strings/description.ru.yml | 70 ---------- modules/10-basics/35-strings/ru/data.yml | 1 + .../10-basics/40-blocks/description.ru.yml | 129 ----------------- modules/10-basics/40-blocks/ru/data.yml | 1 + .../10-basics/45-iteration/description.ru.yml | 46 ------- modules/10-basics/45-iteration/ru/data.yml | 1 + .../description.ru.yml | 48 ------- .../47-iteration-over-string/ru/data.yml | 1 + .../10-basics/50-datatypes/description.ru.yml | 80 ----------- modules/10-basics/50-datatypes/ru/data.yml | 1 + .../10-basics/60-classes/description.ru.yml | 92 ------------- modules/10-basics/60-classes/ru/data.yml | 1 + .../10-basics/65-modules/description.ru.yml | 70 ---------- modules/10-basics/65-modules/ru/data.yml | 1 + .../description.ru.yml | 48 ------- .../67-everything-is-expression/ru/data.yml | 1 + .../10-basics/70-summary/description.ru.yml | 53 ------- modules/10-basics/70-summary/ru/data.yml | 1 + .../10-arrays-basics/description.ru.yml | 65 --------- .../10-arrays-basics/ru/data.yml | 1 + .../20-arrays-methods/description.ru.yml | 77 ----------- .../20-arrays-methods/ru/data.yml | 1 + .../30-hash-basics/description.ru.yml | 76 ---------- .../20-collections/30-hash-basics/ru/data.yml | 1 + .../40-hash-methods/description.ru.yml | 130 ------------------ .../40-hash-methods/ru/data.yml | 1 + .../50-destructuring/description.ru.yml | 97 ------------- .../50-destructuring/ru/data.yml | 1 + .../description.ru.yml | 57 -------- .../10-functions-definition-splat/ru/data.yml | 1 + .../description.ru.yml | 49 ------- .../ru/data.yml | 1 + .../30-functions-pipeline/description.ru.yml | 83 ----------- .../30-functions-pipeline/ru/data.yml | 1 + .../description.ru.yml | 62 --------- .../ru/data.yml | 1 + .../description.ru.yml | 51 ------- .../ru/data.yml | 1 + .../60-functions-yield/description.ru.yml | 93 ------------- .../60-functions-yield/ru/data.yml | 1 + modules/25-functions/description.ru.yml | 1 - .../10-each-with-object/description.ru.yml | 47 ------- .../40-arrays/10-each-with-object/ru/data.yml | 1 + .../40-arrays-as-sets/description.ru.yml | 85 ------------ .../40-arrays/40-arrays-as-sets/ru/data.yml | 1 + .../50-arrays-definitions/description.ru.yml | 65 --------- .../50-arrays-definitions/ru/data.yml | 1 + .../50-hash/10-hash-fetch/description.ru.yml | 84 ----------- modules/50-hash/10-hash-fetch/ru/data.yml | 1 + .../50-hash/20-hash-new/description.ru.yml | 88 ------------ modules/50-hash/20-hash-new/ru/data.yml | 1 + 65 files changed, 32 insertions(+), 2295 deletions(-) delete mode 100644 modules/10-basics/10-hello-world/description.ru.yml delete mode 100644 modules/10-basics/15-ruby-as-a-second-language/description.ru.yml delete mode 100644 modules/10-basics/20-everything-is-object/description.ru.yml delete mode 100644 modules/10-basics/25-first-function/description.ru.yml delete mode 100644 modules/10-basics/27-conditions/description.ru.yml delete mode 100644 modules/10-basics/30-if/description.ru.yml delete mode 100644 modules/10-basics/33-if-extra/description.ru.yml delete mode 100644 modules/10-basics/35-strings/description.ru.yml delete mode 100644 modules/10-basics/40-blocks/description.ru.yml delete mode 100644 modules/10-basics/45-iteration/description.ru.yml delete mode 100644 modules/10-basics/47-iteration-over-string/description.ru.yml delete mode 100644 modules/10-basics/50-datatypes/description.ru.yml delete mode 100644 modules/10-basics/60-classes/description.ru.yml delete mode 100644 modules/10-basics/65-modules/description.ru.yml delete mode 100644 modules/10-basics/67-everything-is-expression/description.ru.yml delete mode 100644 modules/10-basics/70-summary/description.ru.yml delete mode 100644 modules/20-collections/10-arrays-basics/description.ru.yml delete mode 100644 modules/20-collections/20-arrays-methods/description.ru.yml delete mode 100644 modules/20-collections/30-hash-basics/description.ru.yml delete mode 100644 modules/20-collections/40-hash-methods/description.ru.yml delete mode 100644 modules/20-collections/50-destructuring/description.ru.yml delete mode 100644 modules/25-functions/10-functions-definition-splat/description.ru.yml delete mode 100644 modules/25-functions/20-functions-object-as-last-argument/description.ru.yml delete mode 100644 modules/25-functions/30-functions-pipeline/description.ru.yml delete mode 100644 modules/25-functions/40-functions-blocks-as-objects/description.ru.yml delete mode 100644 modules/25-functions/50-functions-symbols-to-blocks/description.ru.yml delete mode 100644 modules/25-functions/60-functions-yield/description.ru.yml delete mode 100644 modules/40-arrays/10-each-with-object/description.ru.yml delete mode 100644 modules/40-arrays/40-arrays-as-sets/description.ru.yml delete mode 100644 modules/40-arrays/50-arrays-definitions/description.ru.yml delete mode 100644 modules/50-hash/10-hash-fetch/description.ru.yml delete mode 100644 modules/50-hash/20-hash-new/description.ru.yml diff --git a/modules/10-basics/10-hello-world/description.ru.yml b/modules/10-basics/10-hello-world/description.ru.yml deleted file mode 100644 index a5610bb..0000000 --- a/modules/10-basics/10-hello-world/description.ru.yml +++ /dev/null @@ -1,29 +0,0 @@ ---- -name: Привет, Мир! -theory: | - - По традиции начнем с написания программы 'Hello, World!'. Эта программа будет выводить на экран текст: - - ```ruby - # В конце инструкции нет символа ; - # В Ruby не ставятся ; практически никогда - puts 'Hello, World!' - ``` - - `puts()` — функция печати на экран. В Ruby функции могут вызываться как со скобками, так и без них — разница только в способе записи. Код выше можно было бы записать так: - - ```ruby - puts('Hello, World!') - ``` - - Решение о том, ставить скобки или нет, зависит от предпочтений программиста и удобства в каждой конкретной ситуации. Это понимание придёт со временем. - -instructions: | - - Наберите в редакторе код из задания символ в символ и нажмите «Проверить». - - ```ruby - puts 'Hello, World!' - ``` - -tips: [] diff --git a/modules/10-basics/10-hello-world/ru/data.yml b/modules/10-basics/10-hello-world/ru/data.yml index 7640b7e..f193dbc 100644 --- a/modules/10-basics/10-hello-world/ru/data.yml +++ b/modules/10-basics/10-hello-world/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Привет, Мир! tips: [] diff --git a/modules/10-basics/15-ruby-as-a-second-language/description.ru.yml b/modules/10-basics/15-ruby-as-a-second-language/description.ru.yml deleted file mode 100644 index f3d58dc..0000000 --- a/modules/10-basics/15-ruby-as-a-second-language/description.ru.yml +++ /dev/null @@ -1,94 +0,0 @@ ---- - -name: Ruby, Ruby, Ruby -theory: | - - Ruby на нашем проекте дается как «второй язык» — это значит, что мы подразумеваем определенный багаж знаний у тех, кто учится ему здесь. В первую очередь это владение каким-либо другим языком программирования. Для понимания материала курса нужно иметь представление о типах данных, переменных, условных конструкциях, циклах, функциях, объектах (свойствах и методах) и лямбда-функциях (анонимных функциях). - - Изучение второго языка значительно проще первого, поэтому и структура материала сильно меняется. Здесь мы обзорно касаемся базовых конструкций для быстрого знакомства с синтаксисом, и переходим к интересным задачкам, ради которых, собственно, и изучается Ruby. - - ## В чём соль? - - Ruby — динамический, строго типизированный язык с глубоким уклоном в объектно-ориентированную и функциональную парадигму программирования. - - ```ruby - # Строгая типизация, число нельзя умножить на строку - 4 * 'hexlet' # TypeError (String can't be coerced into Integer) - # Всё объекты - 1.8.round # 2 - # Функции высшего порядка - ['one', 'two'].map(&:upcase) # ["ONE", "TWO"] - ``` - - Он обладает местами непривычным, но невероятно выразительным синтаксисом. Благодаря этому код на Ruby читается как английский язык и при этом остаётся компактным: - - ```ruby - # Определение конечного автомата - class Job - include AASM - - aasm do - state :sleeping, initial: true - state :running, :cleaning - - event :run do - transitions from: :sleeping, to: :running - end - - event :sleep do - transitions from: [:running, :cleaning], to: :sleeping - end - end - end - - job = Job.new - job.sleeping? # true - job.may_run? # true - job.run - job.running? # true - job.may_run? # false - ``` - - На Ruby создано большое количество решений, которые потом распространились по другим языкам. Самым ярким примером является фреймворк Ruby On Rails, который когда-то перевернул веб-разработку, и до сих пор является самым продвинутым бэкенд фреймворком для веб-разработки. И github.com, и gitlab.com написаны с использованием Rails. Даже этот сайт написан на Rails. - - В Ruby очень много метапрограммирования, встроенного во все части языка. Это значит, что программа может менять свое поведение прямо во время работы практически в любую сторону. Посмотрите, как происходит добавление методов во встроенные классы: - - ```ruby - # Этот код можно написать в любом месте программы - class String # встроенный в Ruby класс, отвечающий за строки - def wow # определение метода - 'ruby power' - end - end - - # Вызываем метод - 'hexlet'.wow # 'ruby power' - ``` - - И даже так: - - ```ruby - # Только для демонстрации - # Класс New наследуется от случайно выбранного - # класса One или Two, в зависимости от того, - # какой из них выберет метод sample на момент загрузки файла с классом - class New < [One, Two].sample - # тут код класса - end - ``` - - На этом моменте у вас возможно возникла мысль «это же ад». Как и любой мощный инструмент, Ruby можно использовать во зло — это правда, но если посмотреть на реальное положение дел, то при правильном использовании Ruby позволяет писать невероятно выразительный код. И раз вы здесь, то давайте научимся это делать. - -instructions: | - - На данном этапе мы знаем ещё слишком мало, чтобы писать какой-то интересный код, поэтому просто скопируйте и выполните код ниже. В этом коде используется библиотека ActiveSupport, которая расширяет язык некоторыми полезными возможностями. Изначально она была создана для Rails, но используется и за его пределами. - - ```ruby - # На сервере время в UTC - # Считаться будет от него - puts 1.day.ago - 1.week + 3.hours - ``` - -tips: - - | - [Ruby-комьюнити](https://t.me/hexletcommunity/9) diff --git a/modules/10-basics/15-ruby-as-a-second-language/ru/data.yml b/modules/10-basics/15-ruby-as-a-second-language/ru/data.yml index 01f44d5..2d152b1 100644 --- a/modules/10-basics/15-ruby-as-a-second-language/ru/data.yml +++ b/modules/10-basics/15-ruby-as-a-second-language/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Ruby, Ruby, Ruby tips: - | diff --git a/modules/10-basics/20-everything-is-object/description.ru.yml b/modules/10-basics/20-everything-is-object/description.ru.yml deleted file mode 100644 index b4967c5..0000000 --- a/modules/10-basics/20-everything-is-object/description.ru.yml +++ /dev/null @@ -1,80 +0,0 @@ ---- - -name: Всё есть объект -theory: | - - Ruby по своим возможностям и подходам в разработке близок к JavaScript и Python, но имеет свои особенности. Разработчики языка во многом опирались на Smalltalk, Lisp (это семейство языков), Perl и другие подобные языки. Это привело к интересному результату. Во-первых, Ruby — **очень** объектно-ориентированный язык. В Ruby всё есть объект, включая `nil` (это аналог `null`), и каждая операция — это вызов метода: - - ```ruby - 'hexlet'.reverse # telxeh - 1.7.round # 2 - nil.to_i # 0 - 1 + 1 # на самом деле 1.+(1) - ``` - - Одна из сильных сторон Ruby – [стандартная библиотека](https://ruby-doc.org/). Она решает практически все возникающие задачи. В одних только строках 185 встроенных методов! - - *Это одна из причин, почему Ruby чаще других выигрывает в [CodeBattle](https://codebattle.hexlet.io/)* - - ```ruby - # Количество методов у разных типов данных - # В примерах ниже вызывается метод methods, - # хотя кажется, что это обращение к свойству - ''.methods.count # 185 - 1.methods.count # 145 - [].methods.count # 191 - ``` - - В Ruby всё, кроме присваивания, это вызовы методов. Такой подход позволяет переопределять буквально любое поведение: - - ```ruby - # То, что на самом деле происходит, когда мы выполняем «операции» - 1.+(5) # 6 - 1.>(3) # false - ``` - - На этом основано очень много кода, особенно библиотечного. Например, у любого объекта можно определить синтаксис, аналогичный доступу к массиву `[]`. Или можно определить операции для дат, сделав работу с ними максимально простой (как в примере прошлого урока). А вот как выглядят сеттеры у объектов: - - ```ruby - # Кажется, что это прямое изменение свойства - # На самом деле это сеттер object.key=('value') - obj.key = 'value' - ``` - - Все данные в Ruby — это объекты. Например `nil`, представлен классом `NilClass`, и является единственным его объектом. `true` — объект класса `TrueClass`, а `false` — объект класса `FalseClass`. У остальных типов свои классы. - - Узнать класс любого объекта можно так: - - ```ruby - 1.class # Integer - ''.class # String - nil.class # NilClass - ``` - - С другой стороны классы в Ruby — тоже объекты, у которых есть свои классы 0_o. Но это уже совсем другая история) Есть даже такая шутка (но это не шутка): в Ruby объект это класс, а класс — это объект. Почему это так – узнаем чуть позже. - - ## Отладочная печать - - Иногда в работе приходится прибегать к отладочной печати и в Ruby есть несколько особенностей, о которых надо знать. Функция `puts()` выводит любые типы данных без необходимости преобразования их в строку. С другой стороны, такой вывод не останавливает выполнение и иногда это неудобно, если хочется посмотреть только первый вывод. Для таких ситуаций лучше использовать выброс исключения, которое и выведет на экран нужную информацию и прервёт выполнение. Делается это так: - - ```ruby - # raise – бросить исключение - # .inspect – метод, который преобразует - # любые данные в строковое представление - raise something.inspect - ``` - -instructions: | - - Напечатайте на экран следующий вызов: - - ```ruby - # Здесь выводятся на экран все методы строк, - # которые содержат знак вопроса в имени - # Фактически — это вывод списка предикатов - # То же самое можно сделать для любого типа - puts 'hexlet'.methods.grep(/\?/) - # Будет выведено около 20 имен - ``` - -tips: [] diff --git a/modules/10-basics/20-everything-is-object/ru/data.yml b/modules/10-basics/20-everything-is-object/ru/data.yml index 50eb8ef..421e167 100644 --- a/modules/10-basics/20-everything-is-object/ru/data.yml +++ b/modules/10-basics/20-everything-is-object/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Всё есть объект tips: [] diff --git a/modules/10-basics/25-first-function/description.ru.yml b/modules/10-basics/25-first-function/description.ru.yml deleted file mode 100644 index 2b9f4fd..0000000 --- a/modules/10-basics/25-first-function/description.ru.yml +++ /dev/null @@ -1,60 +0,0 @@ ---- - -name: Первая функция -theory: | - - Начнем сразу с комплексного примера, включающего в себя определение функции, переменной и простые арифметические операции. Посмотрим на синтаксис и разберём некоторые интересные особенности Ruby. Ниже дано определение функции, находящей среднее арифметическое: - - ```ruby - # def – определение функции - def find_average(a, b) - # создание переменной sum - sum = a + b - # преобразование к Float - sum.to_f / 2 - end - - find_average(3, 1) # 2.0 - find_average(1, 2) # 1.5 - - # Можно вызывать и так - find_average 3, 1 - find_average 1, 2 - - # ArgumentError (wrong number of arguments (given 1, expected 2) - find_average(1) - ``` - - Сначала пара слов о стиле. В Ruby существует ровно один общепринятый стиль оформления кода, которого [придерживается](https://ukupat.github.io/tabs-or-spaces/) все комьюнити: - - * Отступы — два пробела - * Для определения имен переменных и функций используется snake_case - * Определение классов — PascalCase, который также называют upper CamelCase - - Определение функции начинается ключевым словом `def`, за которым идёт имя функции и её параметры. В конце добавляется `end`. В отличие от своих собратьев, в Ruby не обязательно писать ключевое слово `return`. Как и в Smalltalk, в Ruby функции всегда возвращают результат последнего вычисленного выражения. Иногда `return` всё же используется, когда нужно досрочно выйти из функции. В остальных случаях его опускают. - - Определение переменных в Ruby крайне простое. Достаточно написать имя и присвоить ему любое значение. Затем переменную можно использовать и менять как угодно и где угодно в поле её видимости. - - ```ruby - sum = a + b - ``` - - Необычно в примере выше может выглядеть код `sum.to_f`. Здесь происходит вызов метода `to_f()` у числа, записанного в `sum`. Для чего это нужно? В Ruby при делении целых чисел на выходе всегда получается целое число. Если при этом была дробная часть, она отбрасывается: - - ```ruby - 3 / 2 # 1 - 3.to_f / 2 # 1.5 - ``` - - По своему смыслу функция `find_average()` должна возвращать число с плавающей точкой, поэтому такое преобразование необходимо. - -instructions: | - - Реализуйте функцию `double()`, которая удваивает любое переданное ей число и возвращает его: - - ```ruby - double(3) # 6 - double(8) # 16 - ``` - -tips: [] diff --git a/modules/10-basics/25-first-function/ru/data.yml b/modules/10-basics/25-first-function/ru/data.yml index 8b8494c..2dd6f5e 100644 --- a/modules/10-basics/25-first-function/ru/data.yml +++ b/modules/10-basics/25-first-function/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Первая функция tips: [] diff --git a/modules/10-basics/27-conditions/description.ru.yml b/modules/10-basics/27-conditions/description.ru.yml deleted file mode 100644 index f97a09e..0000000 --- a/modules/10-basics/27-conditions/description.ru.yml +++ /dev/null @@ -1,75 +0,0 @@ ---- - -name: Логический тип -theory: | - - ## Логические операторы - - Логический тип в Ruby представлен привычными значениями `true` и `false`, а также набором операторов `&&` (и), `==` (равно), `||` (или) и `!` (не): - - ```ruby - true && false # false - false || true # true - ``` - - В отличие от многих других языков сравнение с логическим значением в Ruby строгое, то есть `true` и `false` равны только самим себе: - - ```ruby - true == 1 # false - false == nil # false - ``` - - Что не отменяет возможности использовать в логических выражениях значения любых типов: - - ```ruby - 0 && 'one' # "one" - nil && false # nil - ``` - - В Ruby только `nil` и `false` рассматриваются как *falsey*, все остальные значения в логических выражениях приводятся к `true`. - - ## Значение по умолчанию - - В Ruby широко используется такой код: - - ```ruby - a ||= 'что-то' - # a = a || 'что-то' - ``` - - Он используется для задания значения по умолчанию. Такое возможно и почти всегда безопасно из-за очень ограниченного списка *falsey* значений. Единственное место, где этот способ не сработает – там, где `false` это допустимое значение. - - ## Предикаты - - В Ruby в отличие от большинства других языков принято использовать предикаты практически для всех часто встречающихся проверок. Например, как мы обычно проверяем, что число равно нулю? С помощью сравнения с нулем. В Ruby это тоже работает, но это не Ruby Way: - - ```ruby - 0.zero? # true - 1.zero? # false - 2.positive? # true - - # чётное/нечётное - 8.even? # true - 8.odd? # false - - ''.empty? # true - 'wow'.empty? # false - - something.nil? - - # не пустой массив - items.any? - # пустой массив - items.empty? - ``` - -instructions: | - - Реализуйте функцию предикат `even?`, которая проверяет, является ли переданное число чётным. Функция должна возвращать `true`, если число чётное и `false`, если не чётное. Не используйте встроенные функции для определения четности: - - ```ruby - even?(5) # false - even?(6) # true - ``` - -tips: [] diff --git a/modules/10-basics/27-conditions/ru/data.yml b/modules/10-basics/27-conditions/ru/data.yml index 2c3a791..f34ced2 100644 --- a/modules/10-basics/27-conditions/ru/data.yml +++ b/modules/10-basics/27-conditions/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Логический тип tips: [] diff --git a/modules/10-basics/30-if/description.ru.yml b/modules/10-basics/30-if/description.ru.yml deleted file mode 100644 index d7f76e5..0000000 --- a/modules/10-basics/30-if/description.ru.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- - -name: Условные конструкции -theory: | - - Условия в Ruby выглядят похожими на условия в других языках: - - ```ruby - def sentence_type(text) - # проверяем последний символ в строке - if text.end_with?('?') - 'question' # снова нет return - elsif text.end_with?('!') - 'exclamation' # и тут - else - 'statement' # и тут - end - end - - sentence_type 'anybody here?' # question - sentence_type 'Hexlet for humans' # statement - sentence_type 'boo!' # exclamation - ``` - - В Ruby условиям не нужны скобки. Выражения пишутся сразу после ключевого слова `if`. Для дополнительных условий используется ключевое словое `elsif`. И для всего остального — привычный `else`. В конце добавляется `end`. - - В примере используется предикат (функция, возвращающая `true` или `false`) `end_with?()`. Ключевое отличие Ruby от других популярных языков — в использовании знака вопроса на конце, вместо `is` и его аналогов в начале. Этот подход перекочевал из Lisp-языков. - -instructions: | - - В Ruby встроен оператор `<=>` (spaceship). Этот оператор удобно использовать в функциях сортировки для определения того, нужно менять местами два соседних элемента или нет. Всего у функции возможны три разных варианта возврата: - - ```ruby - 1 <=> 1 # 0 числа равны - 2 <=> 1 # 1 левое больше правого - 1 <=> 2 # -1 левое меньше правого - ``` - - Вашей задачей в этом задании будет написать функцию `compare()`, которая ведёт себя так же, как и spaceship-оператор: - - ```ruby - compare(1, 1) # 0 числа равны - compare(2, 1) # 1 левое больше правого - compare(1, 2) # -1 левое меньше правого - ``` - -tips: [] diff --git a/modules/10-basics/30-if/ru/data.yml b/modules/10-basics/30-if/ru/data.yml index 3edba42..553241e 100644 --- a/modules/10-basics/30-if/ru/data.yml +++ b/modules/10-basics/30-if/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Условные конструкции tips: [] diff --git a/modules/10-basics/33-if-extra/description.ru.yml b/modules/10-basics/33-if-extra/description.ru.yml deleted file mode 100644 index 2fcca42..0000000 --- a/modules/10-basics/33-if-extra/description.ru.yml +++ /dev/null @@ -1,64 +0,0 @@ ---- - -name: Условные конструкции (альтернативные варианты) -theory: | - - Ruby поддерживает множество видов условных конструкций, которые иногда способны сделать код чуть проще и прямолинейнее. Все они встречаются в реальном коде регулярно. - - ## Тернарный оператор - - Работает и выглядит аналогично другим языкам: - - ```ruby - # ? : - v = 3 == 4 ? 1 : 0 - ``` - - ## Постфиксный if - - В Ruby *if* может стоять не только в начале, но и в конце выражений: - - ```ruby - do_something() if num.zero? - ``` - - Подобную форму записи принято использовать тогда, когда все выражение помещается в одну строчку. - - ## Unless - - В дополнение к *if*, в Ruby есть конструкция *unless*, которая работает в обратную сторону: - - ```ruby - # Пока (если) something не zero? - unless something.zero? - # что-то делаем - end - ``` - - *unless* позволяет избавляться от отрицаний, но с ним нужно быть осторожным. Если в предикате используется составное логическое выражение, то *unless* становится не читаемым: - - ```ruby - # Попробуйте осознать этот код - unless a && b - end - ``` - -instructions: | - - Реализуйте функцию `get_sentence_tone()`, которая принимает строку и определяет тон предложения. Если все символы в верхнем регистре, то это вопль — `'scream'`. В ином случае — нормальное предложение — `'general'`. - - Примеры вызова: - - ```ruby - get_sentence_tone('Hello') # general - get_sentence_tone('WOW') # scream - ``` - - Алгоритм: - - 1. Сгенерируйте строку в верхнем регистре на основе строки-аргумента с помощью метода `upcase`. - 2. Сравните её с исходной строкой: - - Если строки равны, значит строка-аргумент в верхнем регистре. - - В ином случае — строка-аргумент не в верхнем регистре. - -tips: [] diff --git a/modules/10-basics/33-if-extra/ru/data.yml b/modules/10-basics/33-if-extra/ru/data.yml index 874480c..0a41183 100644 --- a/modules/10-basics/33-if-extra/ru/data.yml +++ b/modules/10-basics/33-if-extra/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Условные конструкции (альтернативные варианты) tips: [] diff --git a/modules/10-basics/35-strings/description.ru.yml b/modules/10-basics/35-strings/description.ru.yml deleted file mode 100644 index 1bc1210..0000000 --- a/modules/10-basics/35-strings/description.ru.yml +++ /dev/null @@ -1,70 +0,0 @@ ---- -name: Строки -theory: | - - Базовые операции со строками в любом языке – это интерполяция и конкатенация. Как это делается на Ruby: - - ```ruby - # Конкатенация - name = 'H' + 'e' + 'x' + 'l' + 'e' + 't' # Hexlet - # Можно даже так - name = 'H' 'e' 'x' 'l' 'e' 't' # Hexlet - # Интерполяция - greeting = "hello #{name}" # hello Hexlet - ``` - - Интерполяция выполняется только в строках с двойными кавычками. Строки, состоящие из одиночных кавычек, воспринимаются «как есть» — по аналогии с PHP. - - ```ruby - line_feed = "one line\nanother one" - # one line - # another one - ``` - - Как и в большинстве других языков, интерполяция в Ruby предпочтительнее конкатенации. - - Помимо стандартных конкатенации и интерполяции, строки в Ruby усилены срезами и большим числом полезных методов. Вот лишь некоторые примеры: - - ```ruby - name = 'ruby' - name.upcase # 'RUBY' - ''.empty? # true - name.include? 'ru' # true - name.capitalize # Ruby - name.length # 4 - ``` - - Одна из самых классных возможностей у строк – слайсы. С их помощью можно находить любую подстроку в строке. Слайс — тоже метод, но с дополнительным синтаксисом из квадратных скобок: - - ```ruby - name = 'ruby' - # второй символ (счёт идёт с нуля) - name[1] # u - # Последний символ - name[-1] # y - # два символа, начиная с нулевого индекса - name[0, 2] # ru - # от первого до второго с конца - name[0..-2] # rub - # от 4 с конца до последнего символа - name[-4..] # ruby - # и даже регулярные выражения! - name[/ru/] # ru - ``` - -instructions: | - - Номер банковской карточки является персональной и достаточно чувствительной информацией. Поэтому никакие системы не показывают его полностью даже владельцу карты (вдруг кто-то украл доступ в аккаунт). Вместо этого в интерфейсах часто показывают четыре последних символа, а остальное скрывают за зведочками. - - Реализуйте функцию `prepare_card_for_display()`, которая принимает на вход номер карты (в виде строки) и возвращает строку, в которой шесть символов. Первые два — звездочки, последние четыре соответствуют последним четырём цифрам в номере карты: - - ```ruby - prepare_card_for_display('1234789023457890') # '**7890' - prepare_card_for_display('0192837409128735') # '**8735' - ``` - -tips: - - | - [Способы определения строк](https://ruby-doc.org/core-3.0.0/doc/syntax/literals_rdoc.html#label-Strings) - - | - [Методы строк](https://ruby-doc.org/core-3.0.0/String.html) diff --git a/modules/10-basics/35-strings/ru/data.yml b/modules/10-basics/35-strings/ru/data.yml index f7d550d..c1a2935 100644 --- a/modules/10-basics/35-strings/ru/data.yml +++ b/modules/10-basics/35-strings/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Строки tips: - > diff --git a/modules/10-basics/40-blocks/description.ru.yml b/modules/10-basics/40-blocks/description.ru.yml deleted file mode 100644 index 97901a1..0000000 --- a/modules/10-basics/40-blocks/description.ru.yml +++ /dev/null @@ -1,129 +0,0 @@ ---- - -name: Блоки -theory: | - - Блоки в Ruby — очень важная концепция, которая встречается на каждом шагу. У неё нет аналогов в популярных языках, поэтому при изучении блоков сложно опираться на прошлый опыт. К счастью, их не так сложно понять, особенно если у вас есть опыт работы с лямбда-функциями (анонимными функциями). Начнём с примера: - - ```ruby - # Переводится как «пять раз». В этом весь Ruby. - 5.times do |i| - puts i - end - # => 0 - # => 1 - # => 2 - # => 3 - # => 4 - ``` - - Всего три строчки, но очень много новых смыслов. Если говорить в общем, то здесь вызывается метод `times()`, который принимает на вход блок кода и вызывает его пять раз. - - Блок кода — это конструкция *do end*. Блок очень похож на функцию, которая передается в функцию `times()`. Но передается довольно необычным способом. Ключевое слово *do* начинается после того, как закрыты вызывающие скобки у метода. Блок просто отделяется пробелом от вызова самой функции. - - ```ruby - # После пятёрки нет запятой! - 5.times() do |i| - puts i - end - - # А так не сработает - 5.times(do |i| - puts i - end) - ``` - - Как это работает? Блоки в Ruby обычно передаются в функции, как особый аргумент, который идёт вне вызова функции, что видно по примеру сверху. Внутреннюю работу блоков в функциях мы рассмотрим позже, когда немного научимся использовать блоки. - - Это довольно необычная концепция. Сама по себе она не привносит никаких новых возможностей в язык, но даёт новые визуальные возможности по оформлению кода. Именно из-за этой особенности Ruby так хорошо подходит и часто используется, как язык для построения DSL (языков предметной области). Подробнее об этом в следующих уроках. - - И, наконец, сам блок. Можно представить, что внутри функции он попадает в переменную, которая вызывается, как обычная функция. Сам блок — как функция (а он является в том числе функцией), и умеет принимать параметры. Внутрь блока они попадают через конструкцию `|i|`, идущую сразу после *do*. Этот синтаксис пришел в Ruby из Smalltalk. Если параметров несколько, то они просто перечисляются через запятую `|one, two|`. - - Блок работает как замыкание, а значит внутри него можно использовать любые переменные, определенные снаружи и выше блока: - - ```ruby - name = 'ruby' - 3.times do # а параметры блока можно опускать - puts name - end - # => ruby - # => ruby - # => ruby - ``` - - У блоков есть альтернативный синтаксис. Пример выше можно было записать так: - - ```ruby - 5.times { |i| puts i } - ``` - - Подобную запись используют в том случае, когда содержимое блока помещается на одну строку. Синтаксис `do/end` никогда не используют для однострочных блоков. - - Если быть до конца честными, то эти два синтаксиса работают немного по-разному. У `{}` приоритет выше, чем у `do/end`. Это важно, когда идёт вложенный вызов нескольких функций, и каждая из них умеет работать с блоками. Давайте разберём пример: - - ```ruby - # Обе функции вызываются и печатают на экран приветствие, если им передан блок - # Подставьте в них мысленно скобки - print_hello_f1 { "Dima" } - # => "Hello from f1, Dima" - print_hello_f2 { "Vasya" } - # => "Hello from f2, Vasya" - - # При таком вызове функции ничего не печатают, так как нет блока - print_hello_f1 - print_hello_f2 - - print_hello_f1 print_hello_f2 { "Dima" } - # => ? - - print_hello_f1 print_hello_f2 do - "Vasya" - end - # => ? - ``` - - Однострочный вариант блока будет относиться к самой правой функции. При полной форме `do ... end` блок относится к самой первой функции - - ```ruby - print_hello_f1 print_hello_f2 print_hello_f3 { 'Petya' } - # => "Hello from f3, Petya" - print_hello_f1 print_hello_f2 print_hello_f3 do 'Vasya' end - # => "Hello from f1, Vasya" - ``` - - С помощью скобок можно определить, к какой функции блок будет относиться: - - ```ruby - # Равнозначные варианты. Скобки определяют, куда будет отнесён блок - # f1(f2()) do ... end - print_hello_f1(print_hello_f2()) { 'Petya' } - # => "Hello from f1, Petya" - print_hello_f1 print_hello_f2 do - 'Petya' - end - # => "Hello from f1, Petya" - - # Равнозначные варианты - # f1(f2() do ... end) - print_hello_f1(print_hello_f2() { 'Petya' }) - # => "Hello from f2, Petya" - print_hello_f1(print_hello_f2 do - 'Petya' - end) - # => "Hello from f2, Petya" - ``` - - Не переживайте, если прямо сейчас блоки вам непонятны. Для их осознания нужно время и практика. В Ruby они встречаются повсеместно, поэтому понимание работы с блоками приходит быстро. Буквально в следующем модуле они будут уже везде. - -instructions: | - - Реализуйте функцию `show_me_numbers()`, которая выводит на экран числа от одного до переданного в функцию в обратном порядке: - - ```ruby - show_me_numbers(3) - # => 3 - # => 2 - # => 1 - ``` - -tips: [] diff --git a/modules/10-basics/40-blocks/ru/data.yml b/modules/10-basics/40-blocks/ru/data.yml index ee99d81..0d13b34 100644 --- a/modules/10-basics/40-blocks/ru/data.yml +++ b/modules/10-basics/40-blocks/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Блоки tips: [] diff --git a/modules/10-basics/45-iteration/description.ru.yml b/modules/10-basics/45-iteration/description.ru.yml deleted file mode 100644 index 6830cb0..0000000 --- a/modules/10-basics/45-iteration/description.ru.yml +++ /dev/null @@ -1,46 +0,0 @@ ---- -name: Итераторы -theory: | - - `times()` — простой метод, но слишком ограниченный. Что, например, делать, если нужно обходить какой-то конкретный диапазон чисел в прямом и обратном порядке? Для этого в Ruby есть методы `upto()` и `downto()`: - - ```ruby - 5.upto(7) do |i| - puts i - end - # => 5 - # => 6 - # => 7 - ``` - - Этот метод «поднимается» от цифры, на которой был вызван, до переданного числа. Исходное число и конечное включаются в обход. Вот как, например, посчитать сумму этих чисел: - - ```ruby - result = 0 - 5.upto(7) do |i| - result += i - end - puts result # => 18 - ``` - - Так как блок по своей сути — функция, то на него распространяются правила области видимости функций. Все, что определено внутри блока, недоступно снаружи, но блок может «замкнуть» внутри себя внешние переменные, как в примере выше. Переменные замыкаются по ссылке — это значит, что изменение переменной внутри меняет её и снаружи. - - Обратите внимание на вызов метода `upto()` и передачу блока. Блок передается внутрь метода, но происходит это вне вызывающих скобок. Пример выше можно переписать так: - - ```ruby - 5.upto 7 do |i| - ... - ``` - - Для тех, кто не привык к Ruby, такой синтаксис может показаться странным, но это быстро проходит. В какой-то момент вы почувствуете, что вас начнет раздражать ставить скобки в других языках) - -instructions: | - - Напишите функцию `average()`, считающую среднее арифметическое для всех чисел в диапазоне. Функция должна возвращать Float: - - ```ruby - average(5, 8) # (5 + 6 + 7 + 8) / 4; 26 / 4; 6.5 - average(2, 4) # (2 + 3 + 4) / 3; 9 / 3; 3.0 - ``` - -tips: [] diff --git a/modules/10-basics/45-iteration/ru/data.yml b/modules/10-basics/45-iteration/ru/data.yml index 5e0ca35..4c3df3d 100644 --- a/modules/10-basics/45-iteration/ru/data.yml +++ b/modules/10-basics/45-iteration/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Итераторы tips: [] diff --git a/modules/10-basics/47-iteration-over-string/description.ru.yml b/modules/10-basics/47-iteration-over-string/description.ru.yml deleted file mode 100644 index bd6c7fb..0000000 --- a/modules/10-basics/47-iteration-over-string/description.ru.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: Обход строки -theory: | - - Для закрепления блоков рассмотрим ещё один пример итерации – обход строки. В большинстве языков для обхода строки есть два варианта: - - * Преобразование строки в массив символов и обход этого массива - * Проход по числам от нуля до длины строки - 1. Обращение к символам по индексу. - - В таких моментах проявляется выразительность Ruby и мощь его встроенной библиотеки. Для обхода строки ничего не нужно придумывать, всё уже встроено: - - ```ruby - company_name = 'hexlet' - company_name.each_char do |c| # c – значит char - puts c - end - # => h - # => e - # => x - # => l - # => e - # => t - ``` - - Метод [each_char()](https://ruby-doc.org/core-2.7.2/String.html#method-i-each_char) определен именно на строке. - - Ниже чуть более сложный пример с агрегацией. Код, который считает количество букв *e* в строке: - - ```ruby - company_name = 'hexlet' - letters_count = 0 - company_name.each_char do |c| - if c == 'e' - letters_count += 1 - end - end - ``` - -instructions: | - - Реализуйте функцию `reverse()`, которая переворачивает строку. Не используйте в своем решении метод строки reverse - - ```ruby - reverse 'hexlet' # telxeh - reverse 'basics' # scisab - ``` - -tips: [] diff --git a/modules/10-basics/47-iteration-over-string/ru/data.yml b/modules/10-basics/47-iteration-over-string/ru/data.yml index b614e03..6ff5ab0 100644 --- a/modules/10-basics/47-iteration-over-string/ru/data.yml +++ b/modules/10-basics/47-iteration-over-string/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Обход строки tips: [] diff --git a/modules/10-basics/50-datatypes/description.ru.yml b/modules/10-basics/50-datatypes/description.ru.yml deleted file mode 100644 index 8638a69..0000000 --- a/modules/10-basics/50-datatypes/description.ru.yml +++ /dev/null @@ -1,80 +0,0 @@ ---- - -name: Типы данных Ruby -theory: | - - Большая часть типов данных в Ruby работает аналогично типам в других языках. Это относится к строкам, числам или булевым значениям: - - ```ruby - 'one' # String - true # Boolean - false - 3 # Integer - 5.2 # Float - [] # Array - {} # Hash - 1..3 # Range - ``` - - Роль `null` в ruby играет `nil`. Такое название традиционно используется в Smalltalk и семействе Lisp-языков для обозначения концепции «ничего». В остальном всё очень похоже. - - Тип Range используется для задания непрерывного диапазона чисел. Встречается не так часто, но бывает удобен, особенно при работе с датами в библиотеках. - - ```ruby - # От сейчас до +24 часа - Time.now..(Time.now + 60 * 60 * 24) - ``` - - Массивы в Ruby, как и в любом другом динамическом языке, тоже динамические. Их можно изменять, уменьшать и увеличивать прямо в процессе работы: - - ```ruby - companies = [] - # Добавление элемента - companies << 'hexlet' - ``` - - Тип данных Hash хотя и называется необычно, по сути является обычным хранилищем key-value пар. В JavaScript для этого используются объекты, в PHP — ассоциативные массивы, а в Python — словари. - - ```ruby - options = { - sanitize: true - } - options['table'] = false - ``` - - Кроме стандартных типов Ruby добавляет довольно необычный тип, называемый символом. Подобный тип есть во многих языках, включая Erlang (атом), Clojure (кейворд) и JavaScript (символ). Пример: - - ```ruby - :key - :anotherone - ``` - - Символ очень похож на строку, но он представлен в памяти в единственном экземпляре — в отличие от строк, которые создаются каждый раз заново. Это если говорить про техническую сторону. На практике символ удобен там, где строка выражает саму себя. Обычно там, где в других языках создают константы, в которые записаны строки с именем этой константы, в Ruby просто используют символ. По большому счёту символ не является чем-то жизненно необходимым — он немного сокращает количество кода и местами чуть удобнее в использовании. В остальном по смыслу — это та же строка. - - Символы — это такая концепция, которая «заходит» исключительно на практике. Чем больше примеров будет перед глазами, тем быстрее получится использовать этот тип по назначению. - - Для проверки типа в каждом объекте присутствует метод `is_a?`: - - ```ruby - 1.is_a? String # false - 1.is_a? Integer # true - - # Либо сам тип - 1.class # Integer - 'hexlet'.class # String - ``` - -instructions: | - - Реализуйте функцию `type_of_type(value)`, которая определяет, является ли тип данных составным, и возвращает символ `:complex`, если да, и `:simple` — если нет. Составным считаются только три типа: `Hash`, `Array` и `Range`. Остальные — простые. - - ```ruby - type_of_type({}) # :complex - type_of_type('') # :simple - ``` - - Для проверки условия *ИЛИ* используйте оператор `||`. - - Не забудьте при этом поставить скобки вокруг вызова методов: `1.is_a?(String)`. Иначе код выполнится не так, как задумано, из-за приоритетов операций. - -tips: [] diff --git a/modules/10-basics/50-datatypes/ru/data.yml b/modules/10-basics/50-datatypes/ru/data.yml index e8e42dd..0b9063a 100644 --- a/modules/10-basics/50-datatypes/ru/data.yml +++ b/modules/10-basics/50-datatypes/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Типы данных Ruby tips: [] diff --git a/modules/10-basics/60-classes/description.ru.yml b/modules/10-basics/60-classes/description.ru.yml deleted file mode 100644 index 1b197fe..0000000 --- a/modules/10-basics/60-classes/description.ru.yml +++ /dev/null @@ -1,92 +0,0 @@ ---- -name: Классы -theory: | - - ООП — отдельная большая тема в Ruby с миллионом своих особенностей. Сейчас мы ещё не готовы её рассматривать плотно, но как минимум нужно знать некоторые базовые конструкции, которые используются широко. В первую очередь речь про классы. Посмотрите на создание даты в Ruby: - - ```ruby - # Чтобы использовать класс даты, его необходимо подключить - require 'date' - - # Именование классов в Ruby соответствует стилю CamelCase, - # что отличает их от функций/методов и переменных - # Ниже вызовы методов - - d = Date.today - d.next # возвращает объект следующего дня - - # Создаёт дату на сегодняшний день и текущее время - time = Time.new - time.thursday? # false - ``` - - Time — это класс. А сама запись означает: вызвать метод `new()` у класса. `new` в Ruby — не отдельный оператор, а обычный метод. Конечно, не совсем обычный, но синтаксически он ничем не отличается от обычных методов. Такой синтаксис появился не просто так, ниже вы поймете почему. При этом он позволяет проще делать цепочки «по месту»: `Time.new.to_i` (возвращает unixtimestamp). Ещё немного примеров - - ```ruby - # Создаёт дату на 00:00 10-12-2020 - Time.new 2020, 12, 10 - ``` - - Как мы помним, конструктор принадлежит не объектам, а самому классу, поэтому он вызывается на классе. Но раз это метод, то что же такое класс? Посмотрите ещё на пару примеров: - - ```ruby - # now, а не new - time1 = Time.now - time2 = Time.utc # возвращает объект времени в utc - ``` - - Здесь, в зависимости от вашего бэкграунда, ответы могут отличаться друг от друга. Кто-то из PHP скажет, что `now` — статический метод, кто-то скажет, что может быть классов нет, а есть только объекты, как в JavaScript. В Ruby нет статических свойств и методов, и есть реальные классы. Но классы — это объекты, у которых есть свои методы и ... классы. - - ```ruby - Time.methods.count # 126 - Time.class # класс Time — это Class - Time.class.class # а у класса Class класс — это Class :D - Time.superclass # а у класса есть и родитель Object - Time.superclass.class # у которого класс — это Class - Time.superclass.superclass # а родитель родителя — это BasicObject - # и это мы ещё не говорим про классы объектов - # А ещё можно создать класс - Class.new ... # так как класс — это не только объект, но и класс - ``` - - То есть фразу в Ruby «все есть объект» надо понимать практически буквально, но это сильно отличается от того же JavaScript, где под объектом понимается конкретный тип данных object. Объектная модель Ruby наиболее близка языку SmallTalk. С первого взгляда она пугает, но со временем к ней не просто привыкаешь, она становится интуитивной. - - Что с этим совсем делать? Пока ничего. Знание того, как работать с классами и как их конструировать, понадобится при взаимодействии с фреймворками и библиотеками. Эта тема рассматривается в самом конце курса, а пока небольшой пример из Rails: - - ```ruby - # Просто демонстрация на подумать, понимать этот код не нужно - class User < ApplicationRecord # < – наследование - # Это вызов метода прямо в определении класса - validates :email, presence: true, uniqueness: true - - # И это вызовы методов - has_many :companies - belongs_to :company - - def to_s - # this/self не нужны - "#{first_name} #{last_name}" - end - end - ``` - -instructions: | - - Реализуйте функцию `next_day()`, которая возвращает дату начала следующего дня (12:00 a.m.). Функция должна возвращать объект типа Time. - - ```ruby - # Дата вызова: 16.12.2020 - next_day(); # 2020-12-17 00:00:00 +0000 - ``` - - Эту задачу можно реализовать разными способами. Проще всего создать сегодняшнюю дату (`Date.today`), а потом на основе данных из этого объекта создать объект времени. - - ```ruby - today = Date.today - today.day # день - today.month # месяц - today.year # год - ``` - -tips: - - Классы в Ruby загружаются автоматически через загрузчик. Их не подключают явно, как в JavaScript. diff --git a/modules/10-basics/60-classes/ru/data.yml b/modules/10-basics/60-classes/ru/data.yml index 91399bf..2c0dec3 100644 --- a/modules/10-basics/60-classes/ru/data.yml +++ b/modules/10-basics/60-classes/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Классы tips: - >- diff --git a/modules/10-basics/65-modules/description.ru.yml b/modules/10-basics/65-modules/description.ru.yml deleted file mode 100644 index dbc0653..0000000 --- a/modules/10-basics/65-modules/description.ru.yml +++ /dev/null @@ -1,70 +0,0 @@ ---- -name: Модули -theory: | - - Одна из главных концепций в любом языке – разбиение кода на независимые модули с локальным именованием. В разных языках это делается разными словами, но похожими механизмами, такими как неймспейсы, пакеты, модули. - - В Ruby для этого используется система модулей. Функции, определенные внутри модуля, локальны относительно этого модуля. То есть разные модули могут иметь внутри функции с одинаковыми именами. - - ```ruby - # file: module_name.rb - module MyModule - def self.run - 'go!' - end - end - ``` - - При определении функции внутри модуля, к ней нужно добавлять префикс `self.`, только в этом случае получится её вызвать напрямую из модуля. Без `self.` функции тоже объявляют, но только тогда, когда модуль играет роль миксина. Это очень интересная концепция, которая всё чаще встречается в других языках. Подробнее о ней в соответствующем разделе. - - ```ruby - MyModule.run # 'go!' - ``` - - Вызов функции из модуля выглядит абсолютно идентично вызову методов из класса. Является ли модуль классом? Это легко проверить: - - ```ruby - MyModule.new # undefined method `new' for MyModule:Module - # При этом модуль это объект - MyModule.class # Module - ``` - - Как понять что перед нами класс, а не модуль? Короткий ответ: никак. Обычно это не проблема, потому что из контекста понятно, с чем идёт работа. В Ruby-мире много соглашений по тому, как работают библиотеки и как организуется код. Благодаря этому резко упрощается понимание происходящего. - - Встроенных в Ruby модулей не так много. Из наиболее простого можно назвать Math, в котором лежат разные полезные математические функции: - - ```ruby - # Можно обращаться напрямую, - # встроенные модули всегда загружены - Math.sin(1) - ``` - - Из наиболее используемых — модуль Kernel. С его помощью управляют поведением процесса и интерпретатора. - - ```ruby - Kernel.exit - ``` - - Особенность этого модуля в том, что все функции модуля Kernel доступны для вызова напрямую, без указания имени модуля. Это происходит за счёт того, что модуль Kernel "подмешан" в класс Object, от которого наследуются практически все классы в Руби (неявно). - - Если смотреть дальше, то возникает множество вопросов и разных интересных ситуаций: вложенные модули, модули вложенные в классы, классы вложенные в модули и даже классы вложенные в классы. Все это возможно в Ruby. А как соотносятся файловая система и модули? А можно ли определять классы без модулей? А можно ли вызывать функции модуля из функций модуля? К сожалению, не представляется возможным разобрать все эти вопросы в рамках нашего материала. За дальнейшими подробностями добро пожаловать на Хекслет! - -instructions: | - - Создайте модуль `MyNumber`. Реализуйте внутри модуля функцию `reverse_int()`, которая переворачивает цифры в переданном числе (типа Integer) и возвращает новое число. - - ```ruby - reverse_int(13) # 31 - reverse_int(-123) # -321 - reverse_int(8900) # 98 - ``` - - Полезные методы: - - * `abs()` – возвращает модуль числа - * `to_s()` – преобразование в строку - * `to_i()` – преобразование в число - * `reverse()` – переворачивает строку - - -tips: [] diff --git a/modules/10-basics/65-modules/ru/data.yml b/modules/10-basics/65-modules/ru/data.yml index 64d54a5..45759e8 100644 --- a/modules/10-basics/65-modules/ru/data.yml +++ b/modules/10-basics/65-modules/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Модули tips: [] diff --git a/modules/10-basics/67-everything-is-expression/description.ru.yml b/modules/10-basics/67-everything-is-expression/description.ru.yml deleted file mode 100644 index c30bf7a..0000000 --- a/modules/10-basics/67-everything-is-expression/description.ru.yml +++ /dev/null @@ -1,48 +0,0 @@ ---- -name: Всё есть выражение -theory: | - - Кроме того, что в Ruby всё есть объект, практически всё — ещё и выражение. Что это значит? Возьмём для примера условные конструкции, например, `if`. `if` в большинстве языков — это конструкция языка, которая может появляться только в определенных местах. Её нельзя использовать в составе каких-то выражений. В Ruby это не так: - - ```ruby - # Так как if выражение, значит - # мы можем присваивать результат его выполнения - a = if 5 > 3 - 'yes' - else - 'no' - end - - puts a # => 'yes' - ``` - - То же самое касается любых других конструкций, вплоть до определения функций/методов, модулей, классов: - - ```ruby - # В f попадает не сама функция, а её имя в виде символа - f = def foo - end - puts f # :foo - ``` - - Зачем это нужно? Чем больше языковых конструкций реализовано в виде выражений, тем более **выразительным** является язык. В таком языке больше возможностей за счёт комбинирования конструкций, как в примере с `if`. - -instructions: | - - Реализуйте функцию `invert_case()`, которая меняет в строке регистр каждой буквы на противоположный. - - ```ruby - invert_case('Hello, World!') # hELLO, wORLD! - invert_case('I loVe JS') # i LOvE js - ``` - - Полезные методы: - - * `upcase()` – перевод строки в верхний регистр - * `downcase()` – перевод строки в нижний регистр - * [each_char()](https://ruby-doc.org/core-2.7.2/String.html#method-i-each_char) – обход строки побуквенно - -# definitions: -# Объекты первого рода - -tips: [] diff --git a/modules/10-basics/67-everything-is-expression/ru/data.yml b/modules/10-basics/67-everything-is-expression/ru/data.yml index e56fb30..b900064 100644 --- a/modules/10-basics/67-everything-is-expression/ru/data.yml +++ b/modules/10-basics/67-everything-is-expression/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Всё есть выражение tips: [] diff --git a/modules/10-basics/70-summary/description.ru.yml b/modules/10-basics/70-summary/description.ru.yml deleted file mode 100644 index aaf88a3..0000000 --- a/modules/10-basics/70-summary/description.ru.yml +++ /dev/null @@ -1,53 +0,0 @@ ---- - -name: Особенности языка -theory: | - - Ruby — мощный скриптовый язык программирования, который создавался с целью сделать программирование максимально «человечным». В этом языке очень много идиоматики, то есть принципов, как делать те или иные штуки: правильно и в стиле Ruby Way. Это очень похоже на Python с его Pythonic, но Ruby Way местами идёт в противоположную сторону. В этом месте программисты делятся на два лагеря. Одним Ruby Way приходится по душе, другие же его не принимают. - - Ruby создавался таким, чтобы одну и ту же задачу можно было сделать большим количеством способов. Например, у многих методов существуют алиасы, которые не добавляют новой функциональности — они просто существуют для логичности (стройности) языка. Пример из Rails: `1.day + 5.days`. У обоих операндов вызывается один и тот же метод, но у него разные названия — для того, чтобы можно было легко прочесть написанное. - - Ruby, благодаря лаконичному синтаксису с минимумом шума и наличию блоков, позволяет создавать DSL буквально под каждую задачу, чем программисты с удовольствием пользуются. Это одна из причин, почему язык стал популярен в DevOps-среде, где было создано множество инструментов, написанных на Ruby (Chef, Puppet и другие). - - ```ruby - # Вроде бы просто роутинг, но он не выглядит как код - Rails.application.routes.draw do - root to: "pages#main" - - resources :posts do - get :preview - - resources :comments, only: [:new, :create, :destroy] - end - end - ``` - - Подводя итог, можно сказать, что Ruby очень приятный и удобный для разработки язык. Попробуйте взять код ниже и написать на вашем текущем языке, а затем сравните: - - ```ruby - # Что делает этот код? - sentence = ' Ruby one love ' - sentence.strip.split.last.size # 4 - ``` - -instructions: | - - В мире существует множество разных билетов: на транспорт, в кино, в театр и так далее. И, как правило, у каждого билета есть свой индивидуальный номер. Считается, что билет счастливый, если сумма цифр, входящих в этот билет с самого начала и до середины, равна сумме цифр после середины этого числа. Например, если номер билета *723428*, то нам нужно сложить *7 + 2 + 3* и сравнить это с *4 + 2 + 8*. Данный билет счастливым не является. - - Напишите функцию `happy?()`, которая определяет, счастливый ли перед нами билет. Если билет счастливый, функция должна вернуть `true`, если нет — `false`. Функция должна работать только с числом, состоящим из чётного количества цифр: - - ```ruby - happy?(77) # true - happy?(7881) # false - happy?(732930) # true - ``` - - Алгоритм функции достаточно простой. Нужно превратить число в строку, поделить пополам (можно взять подстроку), и пройтись по каждой половине, считая сумму цифр. Для подсчета лучше написать отдельную функцию, чтобы не дублировать эту логику. - - Для решения этой задачи вам могут понадобится: - - * `to_s()` – метод конвертации в строку - * `to_i()` – метод конвертации в число - * [each_char()](https://ruby-doc.org/core-2.7.2/String.html#method-i-each_char) – обход строки побуквенно - -tips: [] diff --git a/modules/10-basics/70-summary/ru/data.yml b/modules/10-basics/70-summary/ru/data.yml index 03d0614..1b92476 100644 --- a/modules/10-basics/70-summary/ru/data.yml +++ b/modules/10-basics/70-summary/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Особенности языка tips: [] diff --git a/modules/20-collections/10-arrays-basics/description.ru.yml b/modules/20-collections/10-arrays-basics/description.ru.yml deleted file mode 100644 index 8c8bdd4..0000000 --- a/modules/20-collections/10-arrays-basics/description.ru.yml +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: Массивы -theory: | - - Массивы в Ruby работают так же, как и массивы в любых других динамических языках. Отличия в основном в некоторых синтаксических конструкциях и в большом количестве встроенных методов. Основные операции: - - ```ruby - items = [1, 2] - - # Добавление в конец - items << 3 # [1, 2, 3] - # Добавление в начало - items.unshift 5 # [5, 1, 2, 3] - - items.first # 5 - # Последний элемент - items.last # 3 - - items.length # 4 - # не пустой? - items.any? # true - # пустой? - items.empty? # false - - # входит ли value в items - items.include? value - - # Обращение к несуществующему элементу возвращает nil - items[5] # nil - - items.sum # 11 - ``` - - Массивы в Ruby передаются по ссылке, как в Python и JavaScript. Но в отличие от JavaScript сравнение массивов идёт по значениям: - - ```ruby - items = [1, 2] - items == [1, 2] # true - ``` - - Для обхода массивов в Ruby используется метод `each()`. По принципу работы он похож на `times()`, но применяется к коллекциям. `each()` принимает блок, который вызывается для каждого элемента коллекции. Внутрь блока передаётся текущий элемент. - - ```ruby - # Сбор в строчку - items = [1, 2, 3] - result = '' - items.each do |item| - result = "#{result}#{item}" - end - puts result # => '123' - ``` - - -instructions: | - - Напишите функцию `intersection()`, которая находит пересечение двух массивов. Под пересечением понимается новый массив, который состоит из элементов, входящих одновременно в оба исходных массива: - - ```ruby - intersection([1, 3, 8], [9, 3, 1]); # [1, 3] - intersection([8], [5, 0]) # [] - ``` - -tips: - - | - [Методы массивов](https://ruby-doc.org/core-3.0.0/Enumerator.html) diff --git a/modules/20-collections/10-arrays-basics/ru/data.yml b/modules/20-collections/10-arrays-basics/ru/data.yml index 7348d79..d32d202 100644 --- a/modules/20-collections/10-arrays-basics/ru/data.yml +++ b/modules/20-collections/10-arrays-basics/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Массивы tips: - | diff --git a/modules/20-collections/20-arrays-methods/description.ru.yml b/modules/20-collections/20-arrays-methods/description.ru.yml deleted file mode 100644 index 18851ee..0000000 --- a/modules/20-collections/20-arrays-methods/description.ru.yml +++ /dev/null @@ -1,77 +0,0 @@ ---- -name: Методы массивов -theory: | - - Помимо обычных методов, массивы содержат большое число методов, работающих с блоками. Возьмем для примера метод `sort()`. Он умеет сортировать только на основе сравнения значений. Такая сортировка сработает в случае простых массивов из чисел, но окажется бесполезной в большинстве реальных ситуаций, где процесс сортировки может быть хитрым. Пример: - - ```ruby - # Население стран - data = [ - ['france', 140_000], - ['usa', 300_000], - ['germany', 40_000] - ] - ``` - - Как отсортировать страны по количеству жителей в них? Для таких ситуаций и нужны функции высшего порядка: - - ```ruby - # Внутрь передается блок, - # который принимает на вход элемент массива - data.sort_by { |row| row[1] } - # [ - # ['germany', 40_000], - # ['france', 140_000], - # ['usa', 300_000] - # ] - - # Либо, если кода много - data.sort_by do |row| - row[1] - end - ``` - - Метод `sort_by()` ожидает, что из блока вернётся значение, по которому нужно выполнить сортировку. Затем, когда значения собраны, этот метод выполняет сортировку, сравнивая значения с помощью оператора `<=>`. - - Вот некоторые примеры подобных функций: - - * [max_by()](https://ruby-doc.org/core-3.0.0/Enumerable.html#method-i-max_by) – поиск максимального по указанному параметру в массиве - * [partition()](https://ruby-doc.org/core-3.0.0/Enumerable.html#method-i-partition) – разделяет массив на два по указанному условию - - Таких функций у массивов десятки. Единственный способ их запомнить – постоянно практиковаться и читать документацию. - -instructions: | - - Некая организация занимается аналитикой распространения COVID-19. Одна из её задач – считать ежедневное количество заболевших. Из исходных данных у неё есть ежедневное количество заболевших по странам: - - ```ruby - data = [ - ['11-9-2020', 'france', 10_000], - ['11-10-2020', 'usa', 35_000], - ['13-12-2020', 'india', 55_000], - ['12-11-2020', 'france', 13_000], - ['12-12-2020', 'usa', 22_000], - ['11-12-2020', 'india', 54_000], - ] - ``` - - Ваша задача — помочь им написать функцию `sort_cases()`, которая сортирует записи по дате в обратном порядке и возвращает наружу получившийся массив: - - ```ruby - result = sort_cases(data) - # result= [ - # ['13-12-2020', 'india', 55_000], - # ['12-12-2020', 'usa', 22_000], - # ['11-12-2020', 'india', 54_000], - # ['12-11-2020', 'france', 13_000], - # ['11-10-2020', 'usa', 35_000], - # ['11-9-2020', 'france', 10_000] - # ] - ``` - - ## Подсказки - - * Ключом сортировки в данном случае выступает unix timestamp, который можно получить из даты, преобразовав его к объекту типа [Time](https://ruby-doc.org/core-3.0.0/Time.html#class-Time-label-Examples) - * [reverse()](https://ruby-doc.org/core-3.0.0/Array.html#method-i-reverse) – метод возвращает элементы массива в обратном порядке - -tips: [] diff --git a/modules/20-collections/20-arrays-methods/ru/data.yml b/modules/20-collections/20-arrays-methods/ru/data.yml index 43f74ad..ee06374 100644 --- a/modules/20-collections/20-arrays-methods/ru/data.yml +++ b/modules/20-collections/20-arrays-methods/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Методы массивов tips: [] diff --git a/modules/20-collections/30-hash-basics/description.ru.yml b/modules/20-collections/30-hash-basics/description.ru.yml deleted file mode 100644 index 1fce5de..0000000 --- a/modules/20-collections/30-hash-basics/description.ru.yml +++ /dev/null @@ -1,76 +0,0 @@ ---- -name: Хеши -theory: | - - Hash — тип данных, предназначенный для хранения пар *ключ-значение*. Порядок ключей в хеше определен и совпадает с порядком их добавления. - - ```ruby - options = {} - # При таком определении ключ становится символом (symbol) - options = { key: 'value' } - options[:key] # 'value' - - # При таком определении ключ становится строкой (string) - options = { 'key' => 'value' } - - # Добавление/замена в хешах - options[:where] = 'code-basics' - options[:who] = 'hexlet' - - options.any? # true - options.empty? # false - - # Возвращает ключи - options.keys # ['key', :where, :who] - - # Возвращает значения - options.values # ['value', 'code-basics', 'hexlet'] - - # Обращение к несуществующему элементу возвращает nil - options[:language] # nil - - # Доступ к вложенным структурам без необходимости проверок - options.dig(:key1, :key2, :key3) - - # Если ключа нет, то будет брошено исключение - options.fetch(:key) # KeyError (key not found: :key) - - # Если ключа нет, то вернётся значение по умолчанию - options.fetch(:key, 'default value') - ``` - - ```ruby - # Проверка наличия ключа - options.key?('who') # false - options.key?(:who) # true - ``` - - Хеши в Ruby передаются по ссылке, но сравнение происходит по значению, как и в массивах. - - ```ruby - options1 = { language: 'ruby' } - options2 = { language: 'ruby' } - options1 == options2 # true - ``` - - У хешей, как и у массивов, огромное количество различных методов на все случаи жизни — включая обход и разнообразные функции высшего порядка. Частично мы их коснемся дальше, но основная часть познается уже в повседневной работе. - -instructions: | - - Реализуйте функцию `get_words_count_by_lang()`, которая считает количество слов в тексте - - ```ruby - text = 'php ruby php java javascript go go go' - get_words_count_by_lang text - # { - # 'php' => 2, - # 'ruby' => 1, - # 'java' => 1, - # 'javascript' => 1, - # 'go' => 3 - # } - ``` - -tips: - - | - [each()](https://ruby-doc.org/core-3.0.0/Enumerator.html#method-i-each) diff --git a/modules/20-collections/30-hash-basics/ru/data.yml b/modules/20-collections/30-hash-basics/ru/data.yml index 52aba96..788d0ab 100644 --- a/modules/20-collections/30-hash-basics/ru/data.yml +++ b/modules/20-collections/30-hash-basics/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Хеши tips: - | diff --git a/modules/20-collections/40-hash-methods/description.ru.yml b/modules/20-collections/40-hash-methods/description.ru.yml deleted file mode 100644 index ca7e1e5..0000000 --- a/modules/20-collections/40-hash-methods/description.ru.yml +++ /dev/null @@ -1,130 +0,0 @@ ---- - -name: Методы хешей -theory: | - - Как и у массивов, базовый метод обработки хешей это `each` (или алиас `each_pair`). Он принимает на вход блок, в который передаются и ключ, и значение: - - ```ruby - data = { - clojure: 'dynamic', - go: 'static', - kotlin: 'static' - } - - data.each do |key, value| - # логика - end - ``` - - С его помощью можно выполнить любую задачу по преообразованию хеша, но в каждой конкретной ситуации лучше пользоваться специализированными функциями, которые позволяют сократить код и сделать его понятнее. - - **[transform_values](https://ruby-doc.org/core-3.0.0/Hash.html#method-i-transform_values)** - - Этот метод позволяет преобразовать значения, оставив ключи. На выходе получается новый хеш: - - ```ruby - new_data = data.transform_values { |value| value.upcase } - # { clojure: "DYNAMIC", go: "STATIC", kotlin: "STATIC" } - ``` - - С помощью этого метода можно даже поменять тип значений и сделать их, например, массивами. Точно такой же метод есть и для ключей: [transform_keys](https://ruby-doc.org/core-3.0.0/Hash.html#method-i-transform_keys). - - **[slice](https://ruby-doc.org/core-3.0.0/Hash.html#method-i-slice)** - - Слайс позволяет извлечь из хеша только его часть по указанным ключам: - - ```ruby - data.slice(:clojure, :go) - # { clojure: "dynamic", go: "static" } - ``` - - **[select](https://ruby-doc.org/core-3.0.0/Hash.html#method-i-select)** - - Для более сложных ситуаций подходит метод `select` — он действует как фильтр и извлекает из хеша его часть, которая соответствует нужным условиям: - - ```ruby - data.select { |key, value| value == 'static' } - # { go: "static", kotlin: "static" } - ``` - - **[empty?](https://apidock.com/ruby/Hash/empty%3F)** - - **[key?](https://apidock.com/ruby/DBM/key%3F)** - - Иногда бывает полезно проверить хеш на пустоту, за это отвечает метод `empty?` и проверить в хеше наличие ключа - это метод `key?`: - - ```ruby - data.empty? # false - data.clear # метод clear очищает хеш - data.empty? # true - - data.key? :go # true - ``` - - Важно понимать, что если мы в качестве ключа передадим строку 'go' методу `key?`, то метод вернет `false`. - - **[merge](https://apidock.com/ruby/Hash/merge)** - - Метод `merge` позволяет объединить два хеша. Если в целевом хеше обнаружен дубликат, то он будет перезаписан: - - ```ruby - with_ruby = data.merge(ruby:'dynamic') - puts whith_ruby - # => { clojure: "dynamic", go: "static", kotlin: "static", ruby: "dynamic" } - new_hash = data.merge(go:'compiled') - puts new_hash - # => { clojure: "dynamic", go: "compiled", kotlin: "static", ruby: "dynamic" } - ``` - - `merge` может принимать блок, который можно использовать например для устранения коллизий: - - ```ruby - data = { password: '123456' } - new_data = { password: '123' } - data.merge(new_data) do |key, old_password, new_password| - new_password.length >= 6 ? new_password : old_password - end - ``` - - В Ruby для работы с хешами есть методы на все случаи жизни, поэтому почаще заглядывайте в документацию и экспериментируйте. - -instructions: | - - Реализуйте функцию `plainify`, которая принимает на вход список песен сгруппированных по имени группы и возвращает плоский список песен, удобный для вывода на экран. - - ```ruby - data = { - 'Queen' => [ - 'Bohemian Rhapsody', - "Don't Stop Me Now" - ], - 'Metallica' => [ - 'Nothing Else Matters' - ], - "Guns N' Roses" => [ - 'Paradise City', - 'November Rain' - ], - 'AC/DC' => [ - 'Thunderstruck', - 'Back In Black', - 'Shoot to Thrill' - ] - } - - result = plainify data - - # [ - # { band: 'Queen', song: 'Bohemian Rhapsody' }, - # { band: 'Queen', song: "Don't Stop Me Now" }, - # { band: 'Metallica', song: 'Nothing Else Matters' }, - # { band: "Guns N' Roses", song: 'Paradise City' }, - # { band: "Guns N' Roses", song: 'November Rain' }, - # { band: 'AC/DC', song: 'Thunderstruck' }, - # { band: 'AC/DC', song: 'Back In Black' }, - # { band: 'AC/DC', song: 'Shoot to Thrill' } - # ] - ``` - -tips: [] diff --git a/modules/20-collections/40-hash-methods/ru/data.yml b/modules/20-collections/40-hash-methods/ru/data.yml index d3b46d6..cd68449 100644 --- a/modules/20-collections/40-hash-methods/ru/data.yml +++ b/modules/20-collections/40-hash-methods/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Методы хешей tips: [] diff --git a/modules/20-collections/50-destructuring/description.ru.yml b/modules/20-collections/50-destructuring/description.ru.yml deleted file mode 100644 index acf4533..0000000 --- a/modules/20-collections/50-destructuring/description.ru.yml +++ /dev/null @@ -1,97 +0,0 @@ ---- - -name: Деструктуризация -theory: | - - Destructuring – синтаксический сахар для разложения составных данных на элементы. Удобная возможность языка, которая повышает читабельность кода, и немного сокращает его количество. Пример: - - ```ruby - data = ['hexlet', 'online courses', topics: ['php', 'js']] - name, description, topics = data - puts name # "hexlet" - puts description # "online courses" - puts topics # { topics: ["php", "js"] } - - # Обычный способ - # name = data[0] либо data.first - # description = data[1] - # topics = data[2] либо data.last - ``` - - Имена переменных `name` и `description` могут быть любыми, на деструктуризацию это не влияет. Стоит запомнить, что для деструктуризации вложенных массивов нам нужно знать либо количество элементов в массиве, либо пропустить их, чтобы не получить исключение. Пример: - - ```ruby - data = ['hexlet', 'online courses', ['php', 'js']] - # для доступа ко вложенному массиву используются круглые скобки - name, description, (first_topic, second_topic) = data # учли количество элементов - - # _ – используется, когда значение не важно - _, _, (first_topic, _) = data # так же все элементы учтены - - # * – указывает, что нам не важны все значения - *, (_, second_topic) = data # пропустили элементы в первом массиве, во вложенном количество учтено - - # данный пример вызовет исключение: не учли количество элементов - name, description, (first_topic) = data # Error - ``` - - Часто деструктуризацию используют для отделения первого (или первых) элемента от остальных. Для этого используется *splat-оператор* – \*. - - ```ruby - data = ['hexlet', 'online courses', ['php', 'js']] - name, *rest = data - puts rest # ["online courses", ["php", "js"]] - - # В любом месте - name, *rest, topic = data - puts rest # ["online courses"] - ``` - - Деструктуризация, к сожалению, не работает для хешей. Однако можно немного схитрить и получить похожую функциональность: - - ```ruby - data = { - name: 'hexlet', - description: 'online courses', - topic: 'programming' - } - - # values_at возвращает массив из значений для указанных ключей - name, description = data.values_at(:name, :description) - ``` - - Деструктуризация может применяться везде, включая параметры функций и блоков: - - ```ruby - # разложен первый аргумент - # обязательны скобки - def process((name, *rest)) - # логика - end - - data = ['hexlet', 'online courses', 'programming'] - process(data) - ``` - -instructions: | - - Реализуйте функцию `convert()`, которая преобразует переданные на вход данные по примеру: - - ```ruby - data = [ - ['ruby', 'dynamic', 'strong'], - ['js', 'dynamic', 'weak'], - ['c', 'static', 'weak'], - ['kotlin', 'static', 'strong'] - ] - # Удаляет вид типизации (второй элемент в массиве) - result = convert(data) - # [ - # ['ruby', 'strong'], - # ['js', 'weak'], - # ['c', 'weak'], - # ['kotlin', 'strong'] - # ] - ``` - -tips: [] diff --git a/modules/20-collections/50-destructuring/ru/data.yml b/modules/20-collections/50-destructuring/ru/data.yml index 30d41ac..0c741f7 100644 --- a/modules/20-collections/50-destructuring/ru/data.yml +++ b/modules/20-collections/50-destructuring/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Деструктуризация tips: [] diff --git a/modules/25-functions/10-functions-definition-splat/description.ru.yml b/modules/25-functions/10-functions-definition-splat/description.ru.yml deleted file mode 100644 index 3bfbe84..0000000 --- a/modules/25-functions/10-functions-definition-splat/description.ru.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- -name: Упаковка аргументов функции -theory: | - - Splat-оператор в определениях функций позволяет «сворачивать» аргументы в массив. С его помощью создают функции, которые имеют бесконечное количество параметров: - - ```ruby - def sum(*numbers) - numbers.sum - end - - # Параметры не обязательны - sum() # 0 - sum(1) # 1 - sum(1, 10) # 11 - sum(1, 10, 8, 1) # 20 - ``` - - Splat-оператор комбинируется с обычными параметрами. Например, если мы хотим требовать передачи как минимум одного параметра в функцию `sum()`, то для этого достаточно добавить обычный параметр: - - ```ruby - def sum(number, *numbers) - number + numbers.sum - end - - sum() # ArgumentError - sum(1) # 1 - ``` - - Splat-оператор может встречаться в определении функции только один раз: - - ```ruby - # Так не сработает - def sum(*numbers1, *numbers2) - - # А так сработает - def sum(*number1, number2) - def sum(number1, number2, *numbers) - ``` - -instructions: | - - Реализуйте функцию `merge_all()`, которая принимает на вход любое количество хешей и сливает (мержит) их в один хеш, который возвращается наружу: - - ```ruby - hash1 = { key: 'value' } - hash2 = { key2: 'value2' } - hash3 = { key3: 'value3', key: 'new value' } - hash = merge_all(hash1, hash2, hash3) - # { key: 'new value', key2: 'value2', key3: 'value3' } - ``` - - ## Подсказки - - * [merge()](https://ruby-doc.org/core-3.0.0/Hash.html#method-i-merge) - -tips: [] diff --git a/modules/25-functions/10-functions-definition-splat/ru/data.yml b/modules/25-functions/10-functions-definition-splat/ru/data.yml index c6c40db..87551c6 100644 --- a/modules/25-functions/10-functions-definition-splat/ru/data.yml +++ b/modules/25-functions/10-functions-definition-splat/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Упаковка аргументов функции tips: [] diff --git a/modules/25-functions/20-functions-object-as-last-argument/description.ru.yml b/modules/25-functions/20-functions-object-as-last-argument/description.ru.yml deleted file mode 100644 index f332a7b..0000000 --- a/modules/25-functions/20-functions-object-as-last-argument/description.ru.yml +++ /dev/null @@ -1,49 +0,0 @@ ---- -name: Хеш как последний параметр функции -theory: | - - Одна из идиоматических конструкций в Ruby – функция, принимающая последним параметром хеш. Обычно этот хеш содержит опции. Такое часто встречается и во встроенных функциях, и в библиотеках: - - ```ruby - # link_to(body, url, html_options = {}) - link_to 'blog', 'https://ru.hexlet.io/blog', { id: 'news', class: 'article' } - # blog - ``` - - В Ruby добавлен «синтаксический сахар», позволяющий опускать скобки в подобных ситуациях. Вызов выше в реальном коде выглядит так: - - ```ruby - link_to 'blog', 'https://ru.hexlet.io/blog', id: 'news', class: 'article' - ``` - - К такому способу записи нужно немного привыкнуть, так как может быть не сразу понятно, что к чему относится. Но потом станет видно, насколько он удобен и практичен. Это ещё одна из его «фишек», которая помогает строить [языки предметной области](https://github.com/aasm/aasm) (DSL). Из-за небольшого количества дополнительного синтаксиса код на Ruby может выглядеть просто, как текст. Ниже пример роутинга (отвечает за формирование адресов страниц сайта) из Rails: - - ```ruby - # В большинстве других языков подобная конструкция либо невозможна, - # либо получится в разы сложнее и загроможденнее символами - resources :companies, only: [:show, :edit, :update, :destroy] do - resources :orders, only: [:create] do - member do - get :payment - end - end - end - ``` - -instructions: | - - Реализуйте функцию `link_to()`, которая генерирует html-ссылки. Функция принимает на вход три параметра: - - * Текст ссылки - * Сама ссылка - * Хеш с атрибутами (не обязательный) - - ```ruby - link_to 'name', '/url' - # name - - link_to 'name', '/url', class: 'link' - # name - ``` - -tips: [] diff --git a/modules/25-functions/20-functions-object-as-last-argument/ru/data.yml b/modules/25-functions/20-functions-object-as-last-argument/ru/data.yml index 053e8f0..8fd45c1 100644 --- a/modules/25-functions/20-functions-object-as-last-argument/ru/data.yml +++ b/modules/25-functions/20-functions-object-as-last-argument/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Хеш как последний параметр функции tips: [] diff --git a/modules/25-functions/30-functions-pipeline/description.ru.yml b/modules/25-functions/30-functions-pipeline/description.ru.yml deleted file mode 100644 index fd899fa..0000000 --- a/modules/25-functions/30-functions-pipeline/description.ru.yml +++ /dev/null @@ -1,83 +0,0 @@ ---- - -name: Пайплайн -theory: | - - Функции высшего порядка — это основной способ обработки коллекций во многих языках. И Ruby здесь не исключение. Идиоматический код на Ruby выглядит, как цепочка методов, преобразующих коллекцию в какой-то нужный выход. Такая обработка строится на базе методов `map()`, `filter()`, `reduce()` и их более специфичных аналогах. - - Краткий обзор: - - ```ruby - # Обходит коллекцию и вызывает для каждого элемента блок - # Результат складывает в новую коллекцию, которая возвращается - [1, 2, 3].map { |v| v ** 2 } # [1, 4, 9] - - # Фильтрует коллекцию от элементов не удовлетворяющих условию - [1, 2, 3].filter { |v| v.odd? } # [1, 3] - - # Обходит коллекцию, накапливая в процессе аккумулятор (acc) - # После обработки каждого элемента возврат из блока становится - # новым аккумулятором. В конце он возвращается наружу - # Начальное значение аккумулятора передается первым аргументом - [1, 2, 3].reduce(0) { |acc, v| acc + v } # 6 - ``` - - При таком подходе вся обработка разбивается на множество небольших действий, которые комбинируются друг с другом, превращаясь в цепочку. Фактически это функциональное программирование на объектах. Оно популярно в большинстве современных языков, поэтому здесь не разбирается подробно. - - Рассмотрим несколько примеров разных преобразований, которые можно выполнять с помощью этих функций с данными, приближенными к реальным. - - ```ruby - users = [ - { name: 'Bronn', gender: 'male', birthday: '1973-03-23' }, - { name: 'Reigar', gender: 'male', birthday: '1973-11-03' }, - { name: 'Tisha', gender: 'female', birthday: '2012-11-03' }, - { name: 'Sansa', gender: 'female', birthday: '2012-11-03' }, - { name: 'Rick', gender: 'male', birthday: '2012-11-03' }, - ] - - # Формируем список пользователей младше 30 лет - users.filter { |u| Time.now.year - Time.new(u[:birthday]).year < 30 } - - # Формируем список тех же пользователей, но без gender - # Обратите внимание на двойные фигурные скобки — - # внешние для блока, внутренние для хеша - users.map { |u| { name: u[:name], birthday: u[:birthday] } } - - # Группируем пользователей по полу - # Аналогичного результата можно добиться с помощью group_by - users.reduce({}) do |acc, u| - acc[u[:gender]] ||= [] - acc[u[:gender]] << u - acc # обязательно вернуть новый acc - end - ``` - -instructions: | - - Реализуйте функцию `get_men_count_by_year()`, которая принимает список пользователей и возвращает объект, где ключ – это год рождения, а значение – это количество мужчин, родившихся в этот год. - - ```ruby - users = [ - { name: 'Bronn', gender: 'male', birthday: '1973-03-23' }, - { name: 'Reigar', gender: 'male', birthday: '1973-11-03' }, - { name: 'Eiegon', gender: 'male', birthday: '1963-11-03' }, - { name: 'Sansa', gender: 'female', birthday: '2012-11-03' }, - { name: 'Jon', gender: 'male', birthday: '1980-11-03' }, - { name: 'Robb', gender: 'male', birthday: '1980-05-14' }, - { name: 'Tisha', gender: 'female', birthday: '2012-11-03' }, - { name: 'Rick', gender: 'male', birthday: '2012-11-03' }, - { name: 'Joffrey', gender: 'male', birthday: '1999-11-03' }, - { name: 'Edd', gender: 'male', birthday: '1973-11-03' } - ] - - get_men_count_by_year(users) - # { - # '1973' => 3, - # '1963' => 1, - # '1980' => 2, - # '2012' => 1, - # '1999' => 1 - # } - ``` - -tips: [] diff --git a/modules/25-functions/30-functions-pipeline/ru/data.yml b/modules/25-functions/30-functions-pipeline/ru/data.yml index f79edc8..2e7093e 100644 --- a/modules/25-functions/30-functions-pipeline/ru/data.yml +++ b/modules/25-functions/30-functions-pipeline/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Пайплайн tips: [] diff --git a/modules/25-functions/40-functions-blocks-as-objects/description.ru.yml b/modules/25-functions/40-functions-blocks-as-objects/description.ru.yml deleted file mode 100644 index d92c681..0000000 --- a/modules/25-functions/40-functions-blocks-as-objects/description.ru.yml +++ /dev/null @@ -1,62 +0,0 @@ ---- -name: Блоки как объекты -theory: | - - Блоки — одна из ключевых концепций в Ruby, без которой практически не обходится ни один кусок кода. Они очень похожи на обычные лямбда-функции, но имеют свои особые черты. Для хорошего понимания языка и происходящего в коде нужно понимать, как они устроены. Здесь мы немного копнем вглубь. - - С одной стороны, у блоков есть особый синтаксис создания и передачи в функции как особого параметра. - - ```ruby - # Открытие файла на запись и добавление туда строки - File.open('log.txt', 'w') { |f| f.write "[hexlet] #{Time.now} - User logged in\n" } - ``` - - С другой стороны, сам блок — это объект, как и всё остальное в языке. Его можно как создать независимо от функции, так и использовать. За блоки в Ruby отвечает класс `Proc`: - - ```ruby - # Немного взрывает мозг то, что блок определяется через свой же синтаксис - square = Proc.new { |x| x**2 } - # Альтернативный синтаксис — proc { |x| x**2 } - square.call(4) # 16 - ``` - - С объектом-блоком можно делать всё то же самое, что и с другими объектами. В этом смысле он ведет себя как анонимная функция в любом языке. Однако, если мы захотим этот объект использовать как блок при передаче в функцию, то ничего не получится: - - ```ruby - [1, 2].map square - # ArgumentError (wrong number of arguments (given 1, expected 0)) - ``` - - Хотя мы и имеем дело с блоком, всё же в примере выше он передается в функцию как обычный объект первым параметром. Но метод `map()` не принимает на вход ничего, кроме блока, поэтому код завершается с ошибкой. Блок, созданный как объект, невозможно напрямую использовать в методах, ожидающих на вход блоки. Для этого нужен специальный синтаксис: - - ```ruby - [1, 2].map &square # [1, 4] - ``` - - Амперсанд, добавленный в начале переменной, содержащей блок, передает этот блок в функцию не как параметр, а как блок. Но тут нас ждет сюрприз: - - ```ruby - # Завершится с ошибкой - [1, 2].map() &square - - # Сработает - [1, 2].map(&square) - ``` - - Это поведение не должно вас вводить в заблуждение. Выше мы видим исключительно особенности синтаксиса. Блок выше не передается как параметр, это легко увидеть, если посмотреть на определение метода `map()`. Он не принимает на вход никаких параметров. - -instructions: | - - Реализуйте функцию `apply_blocks(data, blocks)`, которая принимает на вход данные и массив блоков. Эта функция должна по цепочке вызывать блоки, передавая туда результат предыдущего вызова блока: - - ```ruby - proc1 = proc { |x| x + 1 } - proc2 = proc { |x| x * 2 } - - apply_blocks(5, [proc1, proc2]) # 12 - # proc2.call(proc1.call(5)) - apply_blocks(5, [proc2, proc1]) # 11 - # proc1.call(proc2.call(5)) - ``` - -tips: [] diff --git a/modules/25-functions/40-functions-blocks-as-objects/ru/data.yml b/modules/25-functions/40-functions-blocks-as-objects/ru/data.yml index 2de7bdd..78e35ff 100644 --- a/modules/25-functions/40-functions-blocks-as-objects/ru/data.yml +++ b/modules/25-functions/40-functions-blocks-as-objects/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Блоки как объекты tips: [] diff --git a/modules/25-functions/50-functions-symbols-to-blocks/description.ru.yml b/modules/25-functions/50-functions-symbols-to-blocks/description.ru.yml deleted file mode 100644 index ed69eaa..0000000 --- a/modules/25-functions/50-functions-symbols-to-blocks/description.ru.yml +++ /dev/null @@ -1,51 +0,0 @@ ---- -name: Трансляция символов в блоки -theory: | - - В Ruby-коде можно встретить странную конструкцию из амперсанда, соединенного с символом: - - ```ruby - ['hexlet', 'code-basics'].map(&:upcase) # ["HEXLET", "CODE-BASICS"] - # То же самое - # ['hexlet', 'code-basics'].map { |name| name.upcase } - ``` - - Амперсанд в этом выражении обозначает передачу блока в функцию. Но символ — это не блок. Как работает такой код? Всё дело в приведении типов. У символов определен метод `to_proc()`, который преобразует символ в блок определенного вида. Он вызывается автоматически в тех случаях, когда данные используются как блоки. Это то же самое, что и интерполяция данных в строку. - - В отличие от простых типов данных, преобразование символа в блок работает не очевидно. Проще показать на примере: - - ```ruby - block = :capitalize.to_proc - # block = proc { |value| value.capitalize } - block.call('hexlet') # "Hexlet" - ``` - - То есть получившийся блок принимает на вход один параметр, у которого затем вызывается метод с именем исходного символа. Такое преобразование не случайно, его создали как раз для удобной работы с функциями высшего порядка: - - ```ruby - ['hexlet', 'code-basics'].map(&:reverse).map(&:capitalize) - # ["Telxeh", "Scisab-edoc"] - ``` - - Этот трюк работает даже для операторов, так как в Ruby большинство операторов всего лишь методы: - - ```ruby - [1, 3, 4].reduce &:+ # 8 - ``` - -instructions: | - - Реализуйте функцию `convert()`, которая принимает на вход список строк и применяет к нему следующую цепочку действий: - - * Список сортируется - * Фильтрация: удаляются строки, не заканчивающиеся на `'?'` - * Отображение: все строки приводятся к нижнему регистру - - Результат возвращается наружу: - - ```ruby - strings = ['wow?', 'One?', 'tWo!', 'THREE'] - convert(strings) # ["one?", "wow?"] - ``` - -tips: [] diff --git a/modules/25-functions/50-functions-symbols-to-blocks/ru/data.yml b/modules/25-functions/50-functions-symbols-to-blocks/ru/data.yml index 06bced0..dfa9a74 100644 --- a/modules/25-functions/50-functions-symbols-to-blocks/ru/data.yml +++ b/modules/25-functions/50-functions-symbols-to-blocks/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Трансляция символов в блоки tips: [] diff --git a/modules/25-functions/60-functions-yield/description.ru.yml b/modules/25-functions/60-functions-yield/description.ru.yml deleted file mode 100644 index 212564b..0000000 --- a/modules/25-functions/60-functions-yield/description.ru.yml +++ /dev/null @@ -1,93 +0,0 @@ ---- -name: Блоки внутри функции -theory: | - - Написать в Ruby функцию, которая принимает блок, не так страшно, как может показаться на первый взгляд. В самом простом случае нужно знать про одно ключевое слово – `yield`. Именно с его помощью происходит вызов блока: - - ```ruby - def foo() - yield - end - - # Передача блока, который не принимает аргументов - foo { puts 'code-basics for the brave' } - # => "code-basics for the brave" - - # Или так - foo do - puts 'code-basics for the brave' - end - # => "code-basics for the brave" - ``` - - Как видно из примера выше, мы не управляем блоком явно. `yield` автоматически получает доступ к блоку и вызывает его. Количество вызовов `yield` может быть любым. Каждый вызов работает, как независимый вызов блока: - - ```ruby - def foo() - yield - yield - end - - foo { puts 'Hello Hexlet' } - # => "Hello Hexlet" - # => "Hello Hexlet" - ``` - - `yield` можно воспринимать как вызов блока, который во многом ведет себя как обычная функция. Например, если блок возвращает результат, то его же вернет и `yield`. - - ```ruby - def foo() - yield - end - - # Передача блока, который не принимает аргументов - # Блок возвращает строку - result = foo { 'code-basics for the brave' } - puts result - # => "code-basics for the brave" - ``` - - Если блок содержит параметры, то они передаются в блок через `yield`, как через вызов функции: - - ```ruby - def foo(value) - yield(value) - end - - # Параметр из определения функции переходит в блок через yield - foo('Hexlet') { |v| puts v } - # => "Hexlet" - ``` - - И, собирая все вместе, так выглядит реализация `map()` внутри: - - ```ruby - // В виде функции, а не метода - def my_map(coll) - result = [] - coll.each do |elem| - result << yield(elem) - end - result - end - - my_map([1, 2, 3]) { |v| v * 2 } - # [2, 4, 6] - ``` - -instructions: | - - Реализуйте функцию `my_filter()`, которая умеет фильтровать переданную на вход коллекцию по условию в блоке: - - ```ruby - coll = [1, 2, 3] - my_filter(coll) { |v| v.even? } # [2] - my_filter(coll) { |v| v.odd? } # [1, 3] - - # Примеры выше можно записать и так - # & – преобразует символ в блок и передаст его как блок - my_filter(coll, &:even?) - my_filter(coll, &:odd?) - ``` - -tips: [] diff --git a/modules/25-functions/60-functions-yield/ru/data.yml b/modules/25-functions/60-functions-yield/ru/data.yml index 08ef8db..c9c38bc 100644 --- a/modules/25-functions/60-functions-yield/ru/data.yml +++ b/modules/25-functions/60-functions-yield/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Блоки внутри функции tips: [] diff --git a/modules/25-functions/description.ru.yml b/modules/25-functions/description.ru.yml index 6cd26d7..db0402d 100644 --- a/modules/25-functions/description.ru.yml +++ b/modules/25-functions/description.ru.yml @@ -3,4 +3,3 @@ name: Функции в Ruby description: | Продвинутые техники по работе с функциями - diff --git a/modules/40-arrays/10-each-with-object/description.ru.yml b/modules/40-arrays/10-each-with-object/description.ru.yml deleted file mode 100644 index 7a540fc..0000000 --- a/modules/40-arrays/10-each-with-object/description.ru.yml +++ /dev/null @@ -1,47 +0,0 @@ ---- - -name: each_with_object -theory: | - - В некоторых ситуациях использование `reduce()` лучше заменить на метод `each_with_object()`, который работает похоже, но не требует возврата аккумулятора. В таком случае кода получается меньше, и он чуть проще. Посмотрим на классический пример подсчёта вхождения слов в предложение: - - ```ruby - sentence = 'hexlet – work harder' - words = sentence.split - result = words.reduce({}) do |acc, word| - acc[word] ||= 0 - acc[word] += 1 - acc # <= возврат - end - ``` - - И то же самое с `each_with_object()`: - - ```ruby - sentence = 'hexlet – work harder' - words = sentence.split ' ' - result = words.each_with_object({}) do |word, acc| - acc[word] ||= 0 - acc[word] += 1 - end - ``` - - Не сказать, что код изменился кардинально, но всё же упростился. Этот метод встречается в разработке достаточно часто и, более того, рекомендуется линтером в тех случаях, где он может заменить свёртку. - -instructions: | - - Реализуйте функцию `words_by_letters()`, которая разбирает текст и группирует слова по буквам, отсортированным по алфавиту: - - ```ruby - sentence = 'hexlet helps people to become developers' - result = words_by_letters(sentence) - # { - # b: ['become'], - # d: ['developers'], - # h: ['helps', 'hexlet'], - # p: ['people'], - # t: ['to'] - # } - ``` - -tips: [] diff --git a/modules/40-arrays/10-each-with-object/ru/data.yml b/modules/40-arrays/10-each-with-object/ru/data.yml index e672ff6..f081a84 100644 --- a/modules/40-arrays/10-each-with-object/ru/data.yml +++ b/modules/40-arrays/10-each-with-object/ru/data.yml @@ -1,2 +1,3 @@ +--- name: each_with_object tips: [] diff --git a/modules/40-arrays/40-arrays-as-sets/description.ru.yml b/modules/40-arrays/40-arrays-as-sets/description.ru.yml deleted file mode 100644 index 73e801b..0000000 --- a/modules/40-arrays/40-arrays-as-sets/description.ru.yml +++ /dev/null @@ -1,85 +0,0 @@ ---- - -name: Массивы как множества -theory: | - - В работе над массивами есть особый набор операций, который пришёл к нам из математики – это операции над множествами. В Ruby для такого случая есть специальные операторы, близкие к их математическим эквивалентам. - - Представьте себе задачу поиска взаимных друзей пользователей. Для формирования такого списка на уровне кода, нужно сравнить два массива (мои друзья и друзья друга) и найти пересечение, то есть общих друзей. В данном случае массивы с друзьями — это множества, а операция поиска общих элементов – пересечение (intersection). - - Пересечение на Ruby выглядит так: - - ```ruby - friends1 = ['igor', 'anna', 'nina', 'sergey'] - friends2 = ['igor', 'petya', 'inna', 'anna'] - - # Выглядит как побитовое И, но это пересечение - friends1 & friends2 # ["igor", "anna"] - # или - # friends1.intersection(friends2) - ``` - - Такой оператор очень удобен своей естественностью. Сразу понятно, о чём идёт речь. Как и в большинстве других операторов в Ruby, мы имеем дело с вызовами методов: - - ```ruby - friends.&(friends2) - ``` - - Подобная схема позволяет не только переопределять их поведение, но и комбинировать операторы между собой: - - ```ruby - friends = ['anna', 'ivan'] - friends1 & friends2 & friends # ["anna"] - ``` - - У множеств и массивов с точки зрения математики есть одно принципиальное отличие, о котором нужно помнить. Во множествах каждый элемент представлен ровно один раз (то есть все элементы — уникальны), в то время как в массивах такого ограничения не существует. Операции над множествами рассматривают массивы не как массивы, а именно как множества. Они удаляют дубли в результирующем массиве: - - ```ruby - [1, 3, 4] & [1, 3, 3, 8] # [1, 3] - ``` - - *Объединение* - - Множество, объединяющее в себе элементы исходных множеств. - - ```ruby - [1, 3, 4] | [1, 3, 3, 8] - # [1, 3, 4, 8] - ``` - - *Дополнение* - - Множество, состоящее из элементов первого множества, за минусом элементов, совпадающих со вторым множеством. Или по простому — это разница между двумя множествами. - - ```ruby - # 4 – единственный элемент из первого множества, которого нет во втором - [1, 3, 4] - [1, 3, 3, 8] # [4] - ``` - -instructions: | - - Иногда в программировании возникает задача поиска разницы между двумя наборами данных, такими как объекты. Например, при поиске различий в json-файлах. Для этого даже существуют специальные сервисы, например, http://www.jsondiff.com/ (попробуйте нажать на ссылку sample data и кнопку Compare). - - Реализуйте функцию `gen_diff()`, которая сравнивает два объекта и возвращает результат сравнения в виде объекта. Ключами результирующего объекта будут все ключи из двух входящих объектов, а значением — строка с описанием отличий: added, deleted, changed или unchanged. - - Возможные значения: - - * added — ключ отсутствовал в первом объекте, но был добавлен во второй - * deleted — ключ был в первом объекте, но отсутствует во втором - * changed — ключ присутствовал и в первом, и во втором объектах, но значения отличаются - * unchanged — ключ присутствовал с одинаковыми значениями и в первом, и во втором объектах - - ```ruby - gen_diff( - { one: 'eon', two: 'two', four: true }, - { two: 'own', zero: 4, four: true } - ); - # { - # one: 'deleted', - # two: 'changed', - # four: 'unchanged', - # zero: 'added' - # } - ``` - -tips: [] diff --git a/modules/40-arrays/40-arrays-as-sets/ru/data.yml b/modules/40-arrays/40-arrays-as-sets/ru/data.yml index 5e295c2..6040c06 100644 --- a/modules/40-arrays/40-arrays-as-sets/ru/data.yml +++ b/modules/40-arrays/40-arrays-as-sets/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Массивы как множества tips: [] diff --git a/modules/40-arrays/50-arrays-definitions/description.ru.yml b/modules/40-arrays/50-arrays-definitions/description.ru.yml deleted file mode 100644 index ca10f82..0000000 --- a/modules/40-arrays/50-arrays-definitions/description.ru.yml +++ /dev/null @@ -1,65 +0,0 @@ ---- -name: Способы определения массивов -theory: | - - В Ruby необычно много способов создания массивов. Они помогают сделать определение короче, и достаточно часто используются на практике. Особенно любит их линтер Rubocop. - - ```ruby - # Обычное определение - ['apple', 'orange', 'melon'] - - # Сокращенное - %w[apple orange melon] - ``` - - `%w` позволяет задавать массив перечислением без использования дополнительных символов. Даже в примере выше видно, насколько код получается короче и даже читаемее. Единственное ограничение такого способа – наличие пробелов в значениях. Каждый пробел считается разделителем значений: - - ```ruby - %w[first second value third] - # ["first", "second", "value", "third"] - ``` - - Технически, слова можно экранировать, но так обычно не делают из-за резкого ухудшения читаемости: - - ```ruby - %w[first second\ value third] - # ["first", "second value", "third"] - ``` - - Похожим способом создается массив символов, только вместо `%w` используется `%i`: - - ```ruby - %i[apple orange melon] # [:apple, :orange, :melon] - ``` - - Так же массивы можно создавать из диапазонов или итераторов: - - ```ruby - (1..5).to_a # [1, 2, 3, 4, 5] - 1.upto(5).to_a # [1, 2, 3, 4, 5] - ``` - - В некоторых достаточно редких случаях можно воспользоваться динамическим созданием значений. Для этого используется конструктор Array и блок, вычисляющий значение для нужного индекса: - - ```ruby - Array.new(5) { |i| i ** 2 } - # [0, 1, 4, 9, 16] - ``` - -instructions: | - - Реализуйте функцию `valid_date?()`, которая проверяет переданную дату на допустимость по двум критериям: - - * Месяц находится между 1 и 12 - * День находится между 1 и 31 - - Дата поступает на вход всегда в формате: *dd-mm-yyyy*. Не используйте функции для работы с датами, реализуйте все с помощью обычных типов данных. - - ```ruby - valid_date?('11-11-2011') # true - valid_date?('13-11-2011') # true - valid_date?('11-13-2011') # false - valid_date?('55-11-2011') # false - ``` - -tips: [] diff --git a/modules/40-arrays/50-arrays-definitions/ru/data.yml b/modules/40-arrays/50-arrays-definitions/ru/data.yml index d6268e9..61168b9 100644 --- a/modules/40-arrays/50-arrays-definitions/ru/data.yml +++ b/modules/40-arrays/50-arrays-definitions/ru/data.yml @@ -1,2 +1,3 @@ +--- name: Способы определения массивов tips: [] diff --git a/modules/50-hash/10-hash-fetch/description.ru.yml b/modules/50-hash/10-hash-fetch/description.ru.yml deleted file mode 100644 index 09b1983..0000000 --- a/modules/50-hash/10-hash-fetch/description.ru.yml +++ /dev/null @@ -1,84 +0,0 @@ ---- - -name: Метод fetch и извлечение значений из хеша -theory: | - В Ruby значения из хеша по ключу извлекает метод `[]` и `fetch()`. В чем же принципиальное отличие между ними? - - Если запрашивать значение по несуществующему ключу, метод `[]` молча возвращает `nil`. - - ```ruby - env = { - host: 'localhost', - port: 3000 - } - puts env[:user] # -> nil - ``` - - Метод `fetch()` же действует иначе - если ключа нет, получим ошибку `КеуError`. - - ```ruby - env = { - host: 'localhost', - port: 3000 - } - puts env.fetch(:user) # -> получим ошибку key not found (KeyError) - ``` - - Но это поведение можно переопределить, так как метод `fetch()` принимает вторым параметром значение по умолчанию: - - ```ruby - env = { - host: 'localhost', - port: 3000 - } - puts env.fetch(:user, nil) # -> nil - puts env.fetch(:user, 'guest') # -> 'guest' - ``` - - И даже блок или лямбда-функцию: - - ```ruby - env = { host: 'localhost' } - - env.fetch(:user) { |key| env[key] = 'guest' } - puts env # -> { host: 'localhost', user: 'guest' } - ``` - - Пример конфигурации почтовой рассылки из приложения на Ruby on Rails: - - ```ruby - config.action_mailer.smtp_settings = { - user_name: ENV.fetch('MAIL_USERNAME', nil), - password: ENV.fetch('MAIL_PASSWORD', nil), - address: ENV.fetch('MAIL_HOST', nil), - domain: ENV.fetch('MAIL_HOST', nil), - port: ENV.fetch('SMTP_PORT', '25'), - authentication: :cram_md5 - } - ``` - - Ruby style guide советует использовать метод `fetch()` вместо метода `[]`. - -instructions: | - Реализуйте функцию `setup_env()`. - - Функция принимает: ключ, хеш и блок который тоже принимает два параметра: хеш и ключ из параметров функции. - - Если переданного ключа нет в хеше, то вызываем блок и передаем в него параметры: хеш и ключ, в результате функция должна вернуть обработанный хеш. - - Eсли ключ присутствует, то функция должна вернуть хеш в неизменном виде. - - ```ruby - env = { api_key: 123 } - setup_env(:host, env) { |env, key| env[key] = 'localhost' } # -> { api_key: 123, host: 'localhost' } - setup_env(:api_key, env) { |env, key| env[key] = 'localhost' } # -> { api_key: 123 } - env == { api_key: 123 } # -> true - ``` - - Функция не должна мутировать исходный объект. - -tips: - - | - [yield](https://apidock.com/ruby/Proc/yield) - - | - [fetch()](https://apidock.com/ruby/Hash/fetch) diff --git a/modules/50-hash/10-hash-fetch/ru/data.yml b/modules/50-hash/10-hash-fetch/ru/data.yml index 0ca5546..48f2876 100644 --- a/modules/50-hash/10-hash-fetch/ru/data.yml +++ b/modules/50-hash/10-hash-fetch/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Метод fetch и извлечение значений из хеша tips: - | diff --git a/modules/50-hash/20-hash-new/description.ru.yml b/modules/50-hash/20-hash-new/description.ru.yml deleted file mode 100644 index 79846cc..0000000 --- a/modules/50-hash/20-hash-new/description.ru.yml +++ /dev/null @@ -1,88 +0,0 @@ ---- - -name: Hash.new. Задание значений по умолчанию. -theory: | - В этом уроке мы познакомимся с альтернативными способами создания хеша. - - Вспомним как создавать хеш через литерал: - - ```ruby - env = {} # пустой хеш - env = { host: 'example.com' } - ``` - - В Ruby имеется альтернативный способ создания хеша, через вызов метода `new()` у объекта `Hash`: - - ```ruby - env = Hash.new # создали пустой хеш - puts(env[:host]) # -> nil - ``` - Такой способ имеет некоторые преимущества, давайте посмотрим какие: - - ```ruby - env = Hash.new('localhost') - puts(env[:user]) # -> 'localhost' - ``` - - Мы передаем в метод `new()` значение localhost, если мы обратимся к несуществующему ключу, то метод `[]` вернет это значение: - - Такое поведение не распространяется на метод `fetch()`: - - ```ruby - env = Hash.new('localhost') - puts(env.fetch(:host)) # -> key not found: :host (KeyError) - ``` - Как вы видите, так же будет ошибка: KeyError. - - Где же хранится значение по умолчанию? Это можно посмотреть вызвать метод `inspect()` видно, что значение не является частью хеша, а является частью экземпляра класса Hash: - - ```ruby - env = Hash.new('localhost') - puts(env.inspect) # -> {} - ``` - - `Hash.new` может принимать блок кода, который также позволяет задавать ключам значение по умолчанию. Таким образом нам не надо проверять существует ключ или нет: - - ```ruby - dependencies = Hash.new { |h, key| h[key] = [] } - dependencies[:simple_form] << 'simple_form_bootstrap' - puts(dependencies[:simple_form]) # -> ['simple_form_bootstrap'] - ``` - Так же значение по умолчанию можно задавать через метод `default()`: - - ```ruby - env = Hash.new('localhost') - puts(env[:host]) # -> localhost - env.default = 'example.com' - puts(env[:host]) # -> example.com - ``` - В этом уроке мы научились создавать хеш альтернативным способом через `Hash.new`. Это бывает полезно когда нам надо инициализировать ключи значением по умолчанию. - -instructions: | - Напишите функцию `get_adjacency_matrix()`, которая строит упрощенный вариант матрицы смежности из друзей человека в социальной сети. - - Функция принимает массив элементами которого является тоже массивы: - - ```ruby - [[Vasy, Pety], - [Vasy, Oksana], - [Vasy, Egor], - [Egor, Pety], - [Egor, Georgiy], - [Oksana, Andrey]] - ``` - Вложенный массив состоит из: имени человека - первый элемент и имени его друга - второй элемент. - - Функция должна вернуть хеш, ключем которого будет имя человека, а значением - массив из его друзей. - - ```ruby - { - 'Vasy': ['Pety', 'Oksana', 'Egor'], - 'Egor': ['Pety', 'Georgiy'], - 'Oksana': ['Andrey'] - } - ``` - -tips: - - | - [Hash.new](https://ruby-doc.org/core-2.5.1/Hash.html) diff --git a/modules/50-hash/20-hash-new/ru/data.yml b/modules/50-hash/20-hash-new/ru/data.yml index 9a602ac..d523324 100644 --- a/modules/50-hash/20-hash-new/ru/data.yml +++ b/modules/50-hash/20-hash-new/ru/data.yml @@ -1,3 +1,4 @@ +--- name: Hash.new. Задание значений по умолчанию. tips: - |