⚠️ Обращайте внимание на даты.
Этот блог больше не ведётся с 17 января 2023, и на тот момент с написания этой страницы (31.03.2014) прошло 8 лет.
Для начала расшифрую заголовок, хотя если предыдущий пост вы читали, вы уже знаете. Речь пойдёт о языке программирования Ruby. Как я уже писал, гибкость синтаксиса Ruby располагает к сооружению на его основе “новых языков” (кавычки не просто так). И именно Ruby хорош для этих целей тем, что у нового языка получается синтаксис, от которого не скручиваются мозги.
Один из показателей того, чем он лучше - “читабельность” языка, он выглядит весьма похоже на английский текст, разве что слегка сдобренный значками и скобочками (и без скобочек можно обойтись). Один из примеров я приводил в прошлом посте: аналогичный приведу и здесь, чтобы лишний раз не напрягать переходами по ссылкам. Тем не менее, прошлый пост к прочтению перед этим крайне желателен.
Это расписание. Оно взято из реальной софтины, что я пишу сейчас. И само по себе оно ничего не делает. Но стоит проехаться по проекту с расписанием с помощью whenever -w
(whenever
с флагом -w
, write, записать), и понятное на вид расписание будет преобразовано в куда менее понятный (лично мне и многим другим) синтаксис cron
(занимается запуском всякой ерунды в Linux по расписанию) и записано в соответствующее место системы. Гораздо проще работать с уже известным синтаксисом, этим и обусловлена популярность этой библиотеки (Whenever Ruby gem).
И в отличие от многих слоёв поверх других языков — мы имеем дело не с вложенным интерпретатором, а транслятором. То есть, он не будет каждый раз разбирать разметку расписания при проверке “не пора ли чего сделать”, а один раз преобразует её в разметку, понятную другой программе.
Из этого, вероятно, не очень понятно, что здесь имеется в виду под DSL. Ничего общего с модемами, нет. Речь об “узкоспециализированных языках”, которые выполняют одну узкую задачу, для которых они предназначены. В случае с Whenever это добавление задач в расписание системы, но всяческих областей же много. Некоторые даже пишут саркастические посты о том, “как сделать успешный gem для Ruby”, раскладывая разработку на последовательность вроде этой:
- Выбрать область для языка (решаемую им проблему).
- Придумать крутой синтаксис для языка.
- Придумать для итогового gem’а короткое и цепляющее название.
- Написать код.
- ???
- PROFIT
Из этого вытекает одна из самых больших проблем Ruby. И всяческих фреймворков на его основе. Проблема в том, что даже если вы знаете Ruby, пользоваться сходу произвольной библиотекой, которая вам понадобилась, вы не сможете, нужно знать ключевые слова из синтаксиса самой библиотеки. И так получилось, что языки появляются быстрее, чем их успевают документировать. Практикующих программистов больше, чем документирующих. Поэтому при работе с Ruby самая страшная проблема — отсутствие документации. Нужно быть морально готовым лезть в исходный код вашей библиотеки и читать, что она там делает, какие параметры для неё имеют смысл. Часто “документированность” является решающим фактором в выборе библиотек.
А в сущности, Ruby для удобства написания языков содержит не так много.
Возьмём, например, функции, которые принимают код. О, придумал. Давайте напишем GM-овский repeat
:
Не отличить, да? Но это только если использовать С-подобный GML, на котором пишу я. Есть ещё Pascal-подобный синтаксис с begin
и end
. Мне в голову не приходит способов их сделать, но в Ruby есть блоки do
-end
. Они на вид не хуже, но их дольше писать, и я ими не пользуюсь:
Теперь следующая фича — можно совать функции в самые неожиданные места. Раньше я просто говорил, что так можно. Но гляньте на вот такой repeat
:
Разница? Да никакой! Ну… хорошо, почти никакой, число повторов почему-то оказалось сзади. Потому что функцию повтора мы вшили прямо в число. В число?!
Подождите, давайте поднимем градус и посмотрим, какие методы там есть. Там есть +
! Бугага, давайте его переопределим:
А теперь о том, почему так делать лучше не надо. Если вы введёте это в irb
(interactive Ruby, интерпретатор, выводящий результат каждой введённой строки), он рухнет. Потому что он использует +
внутри себя, и у него разрыв шаблона оттого, что +
вернул строку. Но вам ничто не мешает определить свой класс, в котором реализовать плюс так, как вы хотите. И не только плюс. Вообще что можно переопределить? Умножение, деление, обращение а-ля массив (a[i]
), что хотите, лишь бы остальной ваш Ruby при этом не сломал всю программу — старайтесь следовать “семантике” (смыслу) методов, следующей из их названий.
В общем, Ruby чем-то похож на Linux: сильно зависит от сообщества, имеет обширную стандартную библиотеку и огромное множество библиотек дополнительных, всё это управляется мощным “менеджером пакетов”. Да и гляньте на поведение — он как Linux, делает всё, что ему скажут, к каким бы страшным последствиям это ни привело.
Я уже потерял счёт того, сколько дней этот пост пишу. Соотношение написано/опубликовано сейчас где-то около трёх. Будем считать, что тема раскрыта. Так это, или нет, без обратной связи не узнать. Дальше я буду рассказывать уже не о Ruby, а о Rails, который принёс Ruby популярность.