10 классных особенностей языка Ruby
К написанию статьи подтолкнула статья широко известного, не только в кругах Ruby программистов, Yehuda Katz.
Динамическая типизация
Это скорее раздел их священных войн, каждый готов до последнего отставивать свою точку зрения, однако позволю осветить пару моментов.
- Статическая типизация позволяет обнаруживать значительную часть ошибок ешё на этапе компиляции, также языки такого класса обычно имеет хорошую поддержку со стороны сред разработки (просто потому, что это просто сделать)
- Однако динамическая типизация позволяет ускорить и упростить разработку, особенно в условиях быстроизменяющихся требований (привет agile): не требуется десятикратно переписывать интерфейсы, результат работы программы можно увидеть моментально.
Неявная типизация
Эффективность динамической типизации расширяется неявной типизацией. В Ruby, методам, которые ожидают объекты класса String, вовсе не обязательно делать проверку
is_a?(String). Они просто проверяют наличие методаto_srt(respond_to?(:to_str)) и выполняют его если он есть. Таким образом совершенно не важно к какому классу принадлежит объект, — важно наличие определенного поведения.Это очень широко используемая практика, в Ruby например есть метод
to_ary, который проверяется методами ожидающих массив. Rails также использует эту практику:to_paramиспользуется для преобразования модели в параметр для создания путей.Модульность
Awesome Modules
Yehuda KatzRuby предоставляет функциональность схожую с «traits» в языках Scala, Squeak, and Perl. Эффективно модули Ruby позволяют динамически добавлять новые элементы в иерархию классов прямо во время выполнения. Использование
superпозволяет во время выполнения расширять функциональность суперкласса не задумываясь о том где и как он был описан.Модуль может расширить как сам класс так и непосредственно экземпляры.
Ко всему прочему в Ruby предусмотрен перехват событий
append_featuresиincluded, что позволяет изолировать одно расширение от другого.Сообщения
Ruby так же как и Smalltalk, и Objective-C используют концепцию сообщений. То есть у объектов не вызывается метод с определенным именем, а передаётся сообщение.
Принципиальное отличие от стандартного подхода, кроется в том, что объект может обрабатывать сообщение: делегировать его, выполнить или же вызвать исключение.
В Ruby есть специальный метод
method_missing, который выполняется когда приходит сообщение, на которое объект не может ответить (метод с таким именем отсутствует). Используя такую обработку можно либо делегировать метод, либо каким то образом среагировать, либо просто пропустить обработку — вызвав исключение.Так, в ActiveRecord из Rails, помимо метода find, есть «виртуальные» методы find_by_<field_name&rt;, которые создаются при обработке method_missing.
Eval
Несомненно eval не очень хорошая идея, но в Ruby есть ряд полезных eval методов, которые убирают негативные последствия eval при этом сохраняя его достоинства.
Например
instance_evalпозволяет выполнять код блоке или строки в заданном контексте. Это ещё одна особенность позволяющая создавать ясный DSL (посмотрите хотя бы на Rake).Блоки
Лямбды, блоки и процедуры отличительная и яркая особенность Ruby. Лябмды онечно же есть также в JavaScript, Scala, Lisp, и различных функциональных языках.
Многие любят приводить пример использования блока для чтения файла:
File.open(filename, "r") do |f|f.each_line {|line| puts line }endДело в том, что блоки позволяют скрывать часть «работы», выставляя наружу «чистый» интерфейс. В данном случае когда основной блок закончится, дискриптр файла будет автоматически закрыт.
Symbols
Символ представляет литерал начинающейся с двоеточия. Являются по сути именованными числовыми константами.
Дело в том что в Ruby всё есть объект, следовательно две строки "string" уже будут разными объектами хотя и с эквивалентными значениями. Символы же создаются лишь раз независимо от того сколько раз написать :string, они всегда будет равны одному и тому же объекту. Таким образом символы идеально подходят для ключей в хешах и подобного рода задач.
Так как символы на самом деле числа, то сравнение их происходит очень быстро, а так как объект с одним и тем именем создаются только единожды это ещё и сокращает издержки на память и время создания объекта. Тут следует сделать важное замечание, дело в том что, для корректной работы подобного механизма требуется, чтобы раз созданный объект символа существовал вплоть до окончания программы, следовательно такие объекты не собираются сборщиком мусора и занимаемые ими ресурсы не освобождаются. Не следует генерировать символы вместо текста, особенно там где они не нужны.
Синтаксис
Ruby имеет хорошо сбалансированный и приятный синтаксис.
Часто используемые объекты имеет простой вариант создания: строки ("строка"), числа (5), nil, true, false.
Наличие продуманных и удобных конструкций хешей, массивов, регулярных выражений. Символы и блоки отлично дополняют эту картину.
Можно отметить наличе антонима if — конструкция unless, а также построчные условия.
Многие любят, другие ругают: в Ruby многие синтаксические конструкции могут быть опущены. Так вызов метода
foo(10, { :name => "Name" })может выглядеть какfoo 10, :name => "Name"Особенно хотел бы отметить то, что в отличие от некоторых языков, в Ruby не требуется чётко соблюдать иерархию отступов и количество пробелов в них (но обычно для Ruby используется 2 пробела на отступ).
Всё это делает написание программ не Ruby не только быстрым, но и приятным делом.
Всё есть объект, весь код исполняем и имеет self
Как уже было ни раз сказано в Ruby всё является объектом, в том числе nil и Class. Именно поэтому в Ruby создание экземпляра происходит вполне очевидным ОО способом
SomeClass.new. Соответственно методы есть и у экземпляров и у самого класса.К тому же тело класса опционально, а всё потому, что в Ruby тело класса не является каким-то особенным контекстом. Это просто контекст, в котором
selfссылается на объект класса (классы в Ruby это объекты). В Rails это частая практика, посмотрите на объявление модели:class Comment < ActiveRecord::Basevalidates_presence_of :post_idendЗдесь
validates_presence_ofне является функциональностью языка, это просто метод ActiveRecord::Base, который вызовется в контексте Comment.Так метод может выполнять код в контексте класса, включая создание новых методов или обновления текущего состояния класса. А в отличии от аннотаций Java, которые выполняются только во время компиляции, тело Ruby класса может получать информацию из среды выполнения, например дополнительные параметры или вовсе результат выполнения другого кода.
Убрав искусственные границы между кодом в разных местах, Ruby уменьшил концептуальные издержки создания абстракции. И как результат, стройная объектная модель.
Экосистема
Ruby имеет достаточно долгую историю развития, и вот с приходом XXI века стал набирать всё большую популярность. Сообщество Ruby-программистов постоянно растёт и развивается, появляются интересные и полезные приложения.
В Ruby ко всему прочему широчайшая поддержка разнородных библиотек: работа с файлами, сетевые, создание интерфейса пользователя и много других.
Для управления колоссальным количеством библиотек существует удобная и простая система на основе репозиториев — rubygems. Система аналогична системе пакетов Debian или портов FreeBSD. Достаточно выполнить
gem install <packegename>и требуемый пакет будет доставлен и установлен.Большой интерес к языку был вызван веб-каркасом Rails, который элеганто сочетает в себе различные подходы проектирования и возможности языка Ruby. Стоит отметить и про такие замечательные каркасы как Rack и Sinatra.
На данный момент Ruby можно с уверенностью считать зрелым и заслуживающим внимания языком программирования, сочетающим в себе элегантность и мощь.
