Одна из главных концепций в любом языке – разбиение кода на независимые модули с локальным именованием. В разных языках это делается разными словами, но похожими механизмами, такими как неймспейсы, пакеты, модули.
В Ruby для этого используется система модулей. Функции, определенные внутри модуля, локальны относительно этого модуля. То есть разные модули могут иметь внутри функции с одинаковыми именами.
# file: module_name.rb
module MyModule
def self.run
'go!'
end
end
При определении функции внутри модуля, к ней нужно добавлять префикс self.
, только в этом случае получится её вызвать напрямую из модуля. Без self.
функции тоже объявляют, но только тогда, когда модуль играет роль миксина. Это очень интересная концепция, которая всё чаще встречается в других языках. Подробнее о ней в соответствующем разделе.
MyModule.run # 'go!'
Вызов функции из модуля выглядит абсолютно идентично вызову методов из класса. Является ли модуль классом? Это легко проверить:
MyModule.new # undefined method `new' for MyModule:Module
# При этом модуль это объект
MyModule.class # Module
Как понять что перед нами класс, а не модуль? Короткий ответ: никак. Обычно это не проблема, потому что из контекста понятно, с чем идёт работа. В Ruby-мире много соглашений по тому, как работают библиотеки и как организуется код. Благодаря этому резко упрощается понимание происходящего.
Встроенных в Ruby модулей не так много. Из наиболее простого можно назвать Math, в котором лежат разные полезные математические функции:
# Можно обращаться напрямую,
# встроенные модули всегда загружены
Math.sin(1)
Из наиболее используемых — модуль Kernel. С его помощью управляют поведением процесса и интерпретатора.
Kernel.exit
Особенность этого модуля в том, что все функции модуля Kernel доступны для вызова напрямую, без указания имени модуля. Это происходит за счёт того, что модуль Kernel "подмешан" в класс Object, от которого наследуются практически все классы в Руби (неявно).
Если смотреть дальше, то возникает множество вопросов и разных интересных ситуаций: вложенные модули, модули вложенные в классы, классы вложенные в модули и даже классы вложенные в классы. Все это возможно в Ruby. А как соотносятся файловая система и модули? А можно ли определять классы без модулей? А можно ли вызывать функции модуля из функций модуля? К сожалению, не представляется возможным разобрать все эти вопросы в рамках нашего материала. За дальнейшими подробностями добро пожаловать на Хекслет!
Создайте модуль MyNumber
. Реализуйте внутри модуля функцию reverse_int()
, которая переворачивает цифры в переданном числе (типа Integer) и возвращает новое число.
reverse_int(13) # 31
reverse_int(-123) # -321
reverse_int(8900) # 98
Полезные методы:
abs()
– возвращает модуль числаto_s()
– преобразование в строкуto_i()
– преобразование в числоreverse()
– переворачивает строкуЕсли вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1# frozen_string_literal: true
2
3require 'test_helper'
4require_relative 'index'
5
6describe 'function' do
7 it 'should works' do
8 assert { MyNumber.reverse_int(123) == 321 }
9 assert { MyNumber.reverse_int(-34) == -43 }
10 end
11end
12
Решение учителя откроется через: