1 | 2 | 3 | 4

Ruby за двадцать минут

Итак, приглядимся повнимательнее к нашей новой программе. Обратите внимание на первые строки, начинающиеся с хэш символа (#). В Ruby все, что в одной строке идет после хэш символа является комментарием и игнорируется интерпретатором. Первая строка файла – особый случай, и под Unix-подобными операционными системами говорит шеллу (shell) как запускать данный файл. Остальные комментарии служат лишь для пояснений кода.

Наш say_hi метод стал немного более сложным:

# Сказать всем привет
def say_hi
  if @names.nil?
    puts "..."
  elsif @names.respond_to?("each")
    # @names это некий список, итерируй!
    @names.each do |name|
      puts "Hello #{name}!"
    end
  else
    puts "Hello #{@names}!"
  end
end

Теперь он смотрит на переменную @names, чтобы принять решение. Если ее значение nil, он просто печатает три точки. Нет смысла приветствовать несуществующее, верно?

Циклы и повторы – так же известные как итерации

Если объект, записанный в переменной @names откликается на метод each, значит он является объектом на котором вы можете итерировать. И итерируя по нему вы можете приветствовать каждого человека за раз. И наконец, если @names является чем-то совсем другим, просто превратим ее в строку автоматически и поприветствуем.

Давайте взглянем на итератор повнимательнее:

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

each – это метод, который принимает блок кода и запускает этот блок кода для каждого элемента в списке. И в примере выше, код между do и end, это просто некий блок. Блок это что-то вроде анонимной функции или лямбды. Переменная между знаками (|) – это параметр для данного блока, как раз тот самый элемент списка, на которым будет производится действие в блоке кода.

Что происходит здесь, это то, что каждая запись в списке, 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”` и так далее с остальными именами.

Блоки, прекрасные блестки на грани Ruby

Реальная сила блоков видна, когда вы работаете с более сложными сущностями, чем списки. За выполнением простых деталей внутри метода, вы также можете осуществлять там некую настройку, декомпозицию, отлавливать ошибки – все может быть скрыто от пользователя.

# Сказать всем пока
def say_bye
  if @names.nil?
    puts "..."
  elsif @names.respond_to?("join")
    # Объединить все значения из списка через запятую
    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 и вы захотите узнать его еще лучше!

Если так, пожалуйста просмотрите нашу Документацию, которая содержит в себе ссылки на руководства и введения, все они бесплатно доступны онлайн.