1 | 2 | 3 | 4

Ruby за двадцять хвилин

Розгляньмо наш новий застосунок глибше. Зверніть увагу на перші рядки, які починаються з решітки (#). У Ruby все, що знаходиться в рядку після решітки, є коментарем і ігнорується інтерпретатором. Перший рядок файлу — особливий випадок і під Unix-подібними ОС повідомляє shell, як запускати файл. Решта коментарів потрібна лише для ясності.

Наш метод say_hi став трохи складнішим:

# Say hi to everybody
def say_hi
  if @names.nil?
    puts "..."
  elsif @names.respond_to?("each")
    # @names is a list of some kind, iterate!
    @names.each do |name|
      puts "Hello #{name}!"
    end
  else
    puts "Hello #{@names}!"
  end
end

Тепер він дивиться на змінну екземпляра @names, щоб приймати рішення. Якщо вона дорівнює nil, він просто виводить три крапки. Немає сенсу вітатися з ніким, правда?

Перебір і цикли — тобто ітерація

Якщо об’єкт @names відповідає на each, це означає, що його можна ітератувати. Отже, ми ітеруємо його і вітаємо кожну людину по черзі. Зрештою, якщо @names — це щось інше, Ruby автоматично перетворює його на рядок і виконує стандартне привітання.

Розгляньмо цей ітератор детальніше:

@names.each do |name|
  puts "Hello #{name}!"
end

each — це метод, який приймає блок коду і виконує його для кожного елемента списку; а частина між do та end — це саме такий блок. Блок схожий на анонімну функцію або lambda. Змінна між вертикальними рисками — це параметр блоку.

У цьому випадку для кожного елемента списку name прив’язується до цього елемента, після чого виконується вираз puts "Hello #{name}!".

Більшість інших мов програмування проходить список за допомогою циклу for, який у C виглядає приблизно так:

for (i=0; i<number_of_elements; i++)
{
  do_something_with(element[i]);
}

Це працює, але не дуже елегантно. Потрібна тимчасова змінна i, потрібно знати довжину списку й пояснювати, як по ньому проходити. У Ruby підхід набагато елегантніший: усі технічні деталі приховані в методі each, вам потрібно лише сказати, що робити з кожним елементом. Усередині each фактично викличе yield "Albert", потім yield "Brenda", потім yield "Charles" і так далі.

Блоки — яскравий блиск на краю Ruby

Справжня сила блоків проявляється, коли ви маєте справу зі складнішими речами, ніж списки. Окрім того, що метод приховує рутинні деталі, він може приховати підготовку, завершення та обробку помилок — усе це невидимо для користувача.

# Say bye to everybody
def say_bye
  if @names.nil?
    puts "..."
  elsif @names.respond_to?("join")
    # Join the list elements with commas
    puts "Goodbye #{@names.join(", ")}.  Come back soon!"
  else
    puts "Goodbye #{@names}.  Come back soon!"
  end
end

Метод say_bye не використовує each. Натомість він перевіряє, чи @names відповідає на метод join, і якщо так — використовує його. Інакше він просто виводить змінну як рядок. Такий підхід, коли нас не цікавить фактичний тип змінної, а лише те, які методи вона підтримує, називається “Duck Typing”, як у вислові “якщо ходить як качка і крякає як качка…”. Перевага в тому, що це не обмежує типи змінних без потреби. Якщо хтось створить новий тип класу списку й реалізує join із тією ж семантикою, що й інші списки, усе працюватиме як задумано.

Запуск скрипта

Ось і клас MegaGreeter; решта файлу просто викликає методи цього класу. Є ще одна хитрість, на яку варто звернути увагу: рядок

if __FILE__ == $0

__FILE__ — магічна змінна, що містить ім’я поточного файлу. $0 — ім’я файлу, яким запущено програму. Ця перевірка означає: “Якщо це головний використовуваний файл…”. Це дозволяє використовувати файл як бібліотеку і не виконувати код у цьому контексті, але якщо файл використовується як виконуваний — код виконується.

Вітаємо зі знайомством

Ось і все для швидкого туру Ruby. Є ще багато чого досліджувати: різні керувальні структури Ruby; використання блоків і yield; модулі як міксини; і багато іншого. Сподіваюся, це знайомство з Ruby залишило у вас бажання дізнатися більше.

Якщо так, завітайте до розділу Документація, де зібрано посилання на посібники та туторіали, які безкоштовно доступні онлайн.