⚠️ Обращайте внимание на даты.
Этот блог больше не ведётся с 17 января 2023, и на тот момент с написания этой страницы (31.03.2014) прошло 8 лет.
Жил да был когда-то человек, называвший себя в интернете Matz
, и вывели его как-то раз разные языки программирования из себя настолько, что он решил создать свой язык, с чаем и плюшками. Так появился Ruby. И никто бы о нём не узнал, если бы не нашумевший фреймворк Rails, написанный на этом языке. Как ни странно, эти вещи появились почти независимо друг от друга: язык разработал один человек, а взрыв популярности ему обеспечил совсем другой. Зададимся вопросом — стоит ли язык изучения, даже если вы не планируете строить веб-приложения?
Коротко говоря, мой вердикт — да, стоит. Во многом потому, что это просто интересный язык, в котором элегантно применили множество идей, имеющихся ныне во многих разных языках. То есть, у языка нет существенных преимуществ перед такими гигантами, как C++, Java и C#, если говорить о возможностях. Но если говорить об удобстве разработки — Ruby способен обойти многие из этих языков в большинстве задач. Цена всему этому — интерпретируемость. Это интерпретируемый язык, и поэтому не стоит ожидать от него космических скоростей. Годится он, таким образом, для обучения и решения задач, не требующих скорости. Если вы хотите проверить, работает ли спланированный алгоритм, хотите собрать болванку-отвечалку для вашего сетевого приложения (с целью проверки или отладки) — это ваш выбор.
На данный момент я разобрал учебник Майкла Хартла по Rails и заканчиваю книгу “Beginning Ruby” Питера Купера, а также собрал пару работающих поделок на Ruby и Rails. И я впечатлён. В основном я впечатлён аккуратностью, с которой можно писать программы на Ruby. Во многом мне тут помогает Light Table, обеспечивая правильные отступы, если я потерял нить происходящего. Это же частенько позволяет находить ошибки синтаксиса — я частенько забываю закрывать блоки по одной команде, считая это излишеством после C и GML.
Итак, первая забавная особенность, обычная для интерпретируемых языков — reflection, возможность получать информацию о стуктурах работающей программы в виде, пригодном для обработки этой же программой. Разумеется, у reflection есть смысл только в объектно-ориентированных языках, поскольку только в них исполняемый код структурируется настолько сильно, чтобы пользоваться им было полезно. Скажем, взяв произвольный объект, вы можете быстро узнать, какие методы у него есть:
Чуть поясню: это вызов у объекта метода methods
без параметров, он возвращает массив названий методов, который я склеиваю с помощью join
, разделив их пробелами. Многовато вышло, да? Но если присмотреться, большинство методов связаны именно с получением и изменением структуры объекта: на какие методы отвечает, какой к ним доступ… Такие методы есть у всех классов в Ruby, ну или почти всех. Поэтому нет смысла обращать на них много внимания. Вы можете существенно менять структуру программы прямо в процессе работы.
У этого есть очень забавные побочные эффекты. И под “забавными” я понимаю класс шуток, пригодных на 1 апреля (которое, кстати, настанет совсем скоро). Вот пример. Какая длина у слова "Hello"
? 20
. Инфа 100%. irb
(интерактивный Ruby) подтвердит:
Счастливой отладки!
Читерство? Может быть. Но такая вот реализация полиморфизма в Ruby. Разумеется, её можно использовать и в мирных целях. Прямо так, конечно, делать не рекомендуют (на уровне за такое бьют по рукам или около того). Для существующих классов полагается разве что добавлять новые методы, а если обязательно нужна другая реализация именно такого метода, всегда можно создать класс-наследник. Кстати, возможность добавлять новые методы в системные классы весьма полезна. Это часть куда более интересной особенности Ruby. Но об этом дальше.
Вторая особенность Ruby — наличие гигантского набора библиотек (просто откройте RubyGems) для широчайшего набора задач. Насколько широчайшего? Есть библиотека, позволяющая встраивать в Ruby кусочки компилируемых языков, вроде С или С++. Есть библиотеки для обработки разметки, вроде Markdown, этот пост отформатирован библиотекой redcarpet
. Есть библиотеки для работы с сетью, с которыми можно в десяток строк написать простенький клиент (или сервер?) для протокола UDP. Это, в сочетании с широким кругом разработчиков, называется “экосистемой Ruby”. Она во многом базируется на философии “ПО с открытым кодом”, отсюда и места базирования — например, Github. “Решил сам, помоги другим — возможно, твоё решение нужно не только тебе, и могут найтись желающие его улучшить”. Это, во многом, следствие возникновения Rails, но этим не объясняются обёртки для Ruby таких штук, как Qt и wxWidgets, с помощью которых можно собирать приличные программки с обычными для вашей ОС элементами управления. Списки, галочки, кнопочки, окошки, сообщения. Не вебом единым. Но я увлёкся. Просто я пытался вникнуть в то, что из этого мне реально может быть полезно, и я быстро утонул в разнообразии.
Третья особенность Ruby — изменяемый синтаксис. В сущности, от вас требуется заключение команд в блоки, что полезно почти для всех языков. Почти всё остальное вы можете написать сами, создав собственный язык. Занимается ли этим кто-либо всерьёз? Да сплошь и рядом! Есть такая штука, DSL, в вольном переводе “узкоспециализированный язык”. Здесь пример кода библиотеки Whenever
объяснит лучше меня:
Немного подробностей о том, что происходит. hours
— метод встроенного класса “число” (Fixnum
), и он возвращает указанное в часах время в более подходящих здесь единицах измерения, в секундах. every
- функция, принимающая момент времени или интервал, а также блок кода, который она в соответствующее время (или с указанным интервалом) исполняет. Очень удобно и хорошо читается. Но посмотрим на более “приземлённый” пример. Вы же знаете, насколько тяжело многим даются циклы в языках программирования. Скажем, вам надо сделать 5 шагов с числами 1-5 внутри цикла. Тёртые программисты это могут сделать не задумываясь. А в Ruby — даже не сомневаясь, что это будет работать именно так:
Это “новое поколение циклов”, грубо говоря. Зовётся “итератор” и активно используется в известных мне ООП-шных языках: точно в Java, C++ и C#. Ах да, почему это работает? upto
— метод класса “число”, который исполняет данный ему блок кода, увеличивая каждый шаг данное число на 1
, пока оно не станет больше 5
. В итоге и выходит, что действие_с i
выполнится, при i
равном 1
, 2
, 3
, 4
и 5
. Пугающе просто, наверное. Но не ново. Это, как говорится, “синтаксический сахар”. Во многих других языках подобное тоже можно провернуть, но настолько крутой и короткий синтаксис для этого действа не встретить почти нигде. Причём он короткий с обеих сторон — и использование, и реализация upto
довольно просто записываются.
Четвёртая особенность… опишу кратко. Название переменной напрямую определяет о ней некоторые факты. “Мягко”. К примеру, Переменная (с большой буквы) считается константой. Из-за большой первой буквы названия, да. И вы будете смеяться, но эту “константу” можно будет менять! Только Ruby это не понравится, и он выведет предупреждение о том, что вы несёте чушь. Тем не менее, он сделает, что вы просите.
На этом, пожалуй, свернусь. Дело в том, что я до сих пор дочитываю вторую книжку по Ruby, и я хочу ещё. Напоследок отмечу, что с Ruby хорошо работать в Linux, там проще всего добиться работы большинства библиотек, взять хотя бы RubyInline
, который позволяет писать части программы на C. Дистрибутивы Linux обычно больше предрасположены к готовности собирать нужные программы из исходного кода, и компилятор в дистрибутивах обычно уже есть. К тому же, есть немало особенностей, которых в Windows просто нет из-за неприязни к POSIX: например, fork
, позволяющего одному процессу разделиться в два. Из Ruby это можно сделать.
…но, конечно, для этого уже сделали специальную библиотеку. Это можно сказать почти обо всех задачах, что типично возникают. Да, экосистема настолько обширна, поэтому я в ней и потерялся. Но это непередаваемое ощущение, когда язык хоть и медленно (и то не факт!), но делает всё, что я скажу… многие люди из-за этого ощущения и подались в программисты. Для меня же это ощущение оказалось приятным бонусом к принятому решению.