Ruby по своим возможностям и подходам в разработке близок к JavaScript и Python, но имеет свои особенности. Разработчики языка во многом опирались на Smalltalk, Lisp (это семейство языков), Perl и другие подобные языки. Это привело к интересному результату. Во-первых, Ruby — очень объектно-ориентированный язык. В Ruby всё есть объект, включая nil
(это аналог null
), и каждая операция — это вызов метода:
'hexlet'.reverse # telxeh
1.7.round # 2
nil.to_i # 0
1 + 1 # на самом деле 1.+(1)
Одна из сильных сторон Ruby – стандартная библиотека. Она решает практически все возникающие задачи. В одних только строках 185 встроенных методов!
Это одна из причин, почему Ruby чаще других выигрывает в CodeBattle
# Количество методов у разных типов данных
# В примерах ниже вызывается метод methods,
# хотя кажется, что это обращение к свойству
''.methods.count # 185
1.methods.count # 145
[].methods.count # 191
В Ruby всё, кроме присваивания, это вызовы методов. Такой подход позволяет переопределять буквально любое поведение:
# То, что на самом деле происходит, когда мы выполняем «операции»
1.+(5) # 6
1.>(3) # false
На этом основано очень много кода, особенно библиотечного. Например, у любого объекта можно определить синтаксис, аналогичный доступу к массиву []
. Или можно определить операции для дат, сделав работу с ними максимально простой (как в примере прошлого урока). А вот как выглядят сеттеры у объектов:
# Кажется, что это прямое изменение свойства
# На самом деле это сеттер object.key=('value')
obj.key = 'value'
Все данные в Ruby — это объекты. Например nil
, представлен классом NilClass
, и является единственным его объектом. true
— объект класса TrueClass
, а false
— объект класса FalseClass
. У остальных типов свои классы.
Узнать класс любого объекта можно так:
1.class # Integer
''.class # String
nil.class # NilClass
С другой стороны классы в Ruby — тоже объекты, у которых есть свои классы 0_o. Но это уже совсем другая история) Есть даже такая шутка (но это не шутка): в Ruby объект это класс, а класс — это объект. Почему это так – узнаем чуть позже.
Иногда в работе приходится прибегать к отладочной печати и в Ruby есть несколько особенностей, о которых надо знать. Функция puts()
выводит любые типы данных без необходимости преобразования их в строку. С другой стороны, такой вывод не останавливает выполнение и иногда это неудобно, если хочется посмотреть только первый вывод. Для таких ситуаций лучше использовать выброс исключения, которое и выведет на экран нужную информацию и прервёт выполнение. Делается это так:
# raise – бросить исключение
# .inspect – метод, который преобразует
# любые данные в строковое представление
raise something.inspect
Напечатайте на экран следующий вызов:
# Здесь выводятся на экран все методы строк,
# которые содержат знак вопроса в имени
# Фактически — это вывод списка предикатов
# То же самое можно сделать для любого типа
puts 'hexlet'.methods.grep(/\?/)
# Будет выведено около 20 имен
Если вы зашли в тупик, то самое время задать вопрос в «Обсуждениях». Как правильно задать вопрос:
Тесты устроены таким образом, что они проверяют решение разными способами и на разных данных. Часто решение работает с одними входными данными, но не работает с другими. Чтобы разобраться с этим моментом, изучите вкладку «Тесты» и внимательно посмотрите на вывод ошибок, в котором есть подсказки.
Это нормально 🙆, в программировании одну задачу можно выполнить множеством способов. Если ваш код прошел проверку, то он соответствует условиям задачи.
В редких случаях бывает, что решение подогнано под тесты, но это видно сразу.
Создавать обучающие материалы, понятные для всех без исключения, довольно сложно. Мы очень стараемся, но всегда есть что улучшать. Если вы встретили материал, который вам непонятен, опишите проблему в «Обсуждениях». Идеально, если вы сформулируете непонятные моменты в виде вопросов. Обычно нам нужно несколько дней для внесения правок.
Кстати, вы тоже можете участвовать в улучшении курсов: внизу есть ссылка на исходный код уроков, который можно править прямо из браузера.
Ваше упражнение проверяется по этим тестам
1# frozen_string_literal: true
2
3require 'test_helper'
4
5describe 'function' do
6 it 'should works' do
7 _(-> { require_relative 'index' }).must_output(/respond_to/)
8 puts 'hexlet'.methods.grep(/\?/)
9 end
10end
11
Решение учителя откроется через: