Быстрое знакомство с Ruby

Андрей Васильев

2020

Язык Ruby

Скриптовый (интепретируемый) язык

Приложение на языке Ruby всегда выполняется с помощью интерпретатора, как во время разработки, так и во время использования конечными пользователями

Объектно-ориентированный язык

Динамически типизированный

Переменные могут содержать в себе ссылки на объекты любых типов

Запуск приложений на Ruby

Для выполнения приложения на языке Ruby потребуется:

Запуск приложения сводится к вызову интерпретатора Ruby с указанием файла, начинающего исполнение приложения

Актуальные интерпретаторы Ruby

Переменная PATH

Во всех операционных системах есть переменная окружения PATH, содержащая набор каталогов, в которых происходит поиск исполняемых файлов

Если каталога с исполняемым файлом нет в PATH, то для его запуска надо указать абсолютный путь

Руководство по настройке PATH

IRB — интерактивный интерпретатор Ruby

Вместе с обычным интерпретатором языка ruby, предназначенным для выполнения приложений, поставляется также интерактивный интерпретатор irb

Данное приложение работает по следующему принципу:

IRB позволяет

Пример из приложения

Приложение «Музыкальный автомат» должно обрабатывать данные о песнях. Опишем структуру объектов типа «песня» с помощью класса Song:

class Song
  ...
end

Создадим две переменные first_song и second_song, запишем в них ссылки на создаваемые объекты

first_song = Song.new('Калинка малинка')
second_song = Song.new('Смуглянка')

Объекты в Ruby

Модель вызова метода
Модель вызова метода

Сообщение включает название метода и набор аргументов для него

Обработка вызова метода

  1. При получении сообщения объект начинает поиск метода по имени
  2. Когда метод найден, ему передаются все аргументы

Если метод не найден или количество аргументов не совпало, то будет выброшено исключение

Более детально логику поиска методов обсудим на следующих занятиях

Примеры вызова методов

"gin joint".length
"Rick".index("c")
42.even?
sam.play(song)
num = -1234
num.abs

Базовые элементы языка

При написании кода на языке Ruby вам всегда будут доступны:

Метод puts модуля Kernel

puts выводит переданные аргументы на стандартный поток вывода

puts 'Hello, world!'
puts 42.even?
puts 2**10

Вывод в Ruby

Простейший метод

def say_goodnight(name)
  result = "Good night, " + name
  return result
end
# Вызываем метод
puts say_goodnight("John-Boy")
puts say_goodnight("Mary-Ellen")

Определение метода

def say_goodnight(name)
  result = "Good night, " + name
  return result
end

Вызов метода

puts say_goodnight("John-Boy")
puts(say_goodnight("John-Boy"))

Обычно скобки опускаются только в самых простых случаях:

Также следует использовать соглашения конкретных библиотек

Строки

Вместо конкатенации строк используйте шаблонные строки

def say_goodnight(name)
  result = "Good night, #{name.capitalize}"
  return result
end

Возвращаемое значение

def say_goodnight(name)
  "Good night, #{name.capitalize}"
end

return обычно используется когда результат становится известен заранее:

Наименования элементов

Первый символ элемента приложения описывает его назначение

Массивы и ассоциативные массивы

Массивы

a = [1, 'cat' , 3.14]
puts "Первый элемент #{a[0]}"
# Установим новое значение 3 элементу массива
a[2] = nil
puts "Массив сейчас #{a.inspect} "

Создание массивов

Объект nil

Массивы из строк

a = ['ant' , 'bee' , 'cat' , 'dog' , 'elk']
a[0] # => "ant"
a[3] # => "dog"
# Создание такого же массива из строки
a = %w{ant bee cat dog elk}
a[0] # => "ant"
a[3] # => "dog"

Ассоциативные массивы

inst_section = {
  'cello' => 'string',
  'clarinet' => 'woodwind',
  'drum' => 'percussion'
}
print inst_section['cello']

Значение по умолчанию

# Создаём массив со значением по умолчанию
histogram = Hash.new(0)
histogram['ruby'] # => 0
histogram['ruby'] = histogram['ruby'] + 1
histogram['ruby'] # => 1

Проблема уникальных значений

Часто при написании приложения нам необходимо описать уникальные значения и обращаться к ним с помощью слов

Для решения этих задач можно прибегнуть либо к константам, либо к строкам

NORTH = 1
"north"

Проблемами использования констант являются:

Проблемой использования строк является то, что под каждую из них необходимо выделить отдельную память

Символы в Ruby

В Ruby есть специальный тип данных Symbol, который позволяет описать уникальное именованное значение

Символы создаются с помощью синтаксиса :north или :"north"

walk(:north)
def walk(direction)
  if direction == :north
    ...
end

Символы как ключи хешей

Символы часто используются в качестве ключей хешей

inst_section = {
  :cello => 'string',
  :clarinet => 'woodwind'
}

Поддержка таких хешей добавлена в синтаксис языка

inst_section = {
  cello: 'string',
  clarinet: 'woodwind'
}

Управляющие конструкции

Ruby поддерживает знакомые вам конструкции

today = Time.now
if today.saturday?
  puts "Do chores around the house"
elsif today.sunday?
  puts "Relax"
else
  puts "Go to work"
end

Блок описания заканчивается ключевым словом end

Выражения в условиях

Любое выражение может являться условием. Ложными значениями являются только false и nil. Все остальные значения являются верными.

while weight < 100 && num_pallets <= 5
  pallet = next_pallet()
  weight += pallet.weight
  num_pallets += 1
end

Метод gets получает строку со стандартного потока ввода

При достижении конца потока gets возвращает nil

while line = gets
  puts line.downcase
end

Модификаторы выражений

Условные операторы могут выступать в роли модификатора выражения

if radiation > 3000
  puts "Danger, Will Robinson"
end
puts "Danger, Will Robinson" if radiation > 3000

Аналогично для операторов цикла

square = 4
while square < 1000
  square = square*square
end
square = square*square while square < 1000

Однако не стоит таким образом описывать сложные выражения

Нумерованные циклы

В Ruby также существует цикл for, который позволяет выполнить действие для элемента коллекции

for value in [1, 2, 3] do
  puts value
end

Однако для выполнения действий несколько раз удобнее воспользоваться методом times у целых чисел:

3.times do |value|
  puts value
end

Регулярные выражения

line = "Perl and Python are scripting languages"
newline = line.sub(/Perl/, 'Ruby')
newerline = newline.gsub(/Python/, 'Ruby')

Блоки и итераторы

Примеры блоков

{ puts "Hello" } # Для одного выражения
do # Для нескольких выражений
  club.enroll(person)
  person.socialize
end

Ассоциация блока с методом

Для ассоциации блока с методом его необходимо описать сразу после вызова метода

greet { puts "Hi" }
verbose_greet("Dave") { puts "Hi" }

Вызов ассоциированного блока кода

Вызов осуществляется с помощью ключевого слова yeild

def call_block
  puts "Start of the method"
  yield
  puts "End of the method"
end
call_block { puts "In the block" }

Аргументы блоков

def who_says_what
  yield ("Dave", "hello")
  yield ("Andy", "goodbye")
end

who_says_what do |person, phrase|
  puts "#{person} says #{phrase}"
end

Итераторы

Итератором называется метод коллекций, принимающий блок

Под коллекцией понимаются как встроенные классы массива и хеша, так и классы, созданные пользователями

Коллекции поддерживают множество итераторов

animals = %w(ant bee cat dog)
animals.each { |animal| puts animal }
3.upto(6) { |number| print number }
('a'..'e').each { |character| print character }

Примеры полезных итераторов

data = [5, 66, 13, 24, 46]
# Все элементы с позицией
data.each_with_index do |number, index|
    puts "#{index}: #{number}"
end
# Все ли элементы удовлетворяют условию: являются нечётными
data.all? { |number| number.odd? }
# Создать новый массив на основе текущего: квадраты чисел
data.map { |number| number**2 }
# Посчитать общую характеристику: сумму чисел
data.reduce { |memo, number| number + memo }
# Выбрать часть элементов массива
data.select { |number| number > 40 }

Обработка аргументов командной строки

Доступ к списку аргументов

Массив ARGV содержит список строк, которые были переданы в виде аргументов командной строки

puts "You gave  #{ARGV.size}  arguments"
p ARGV

Обработка файлов, переданных приложению

Если приложение ориентировано на обработку текстовых файлов, то пути к ним можно передать в качестве аргументов

В приложении к ним можно обратиться как к одному большому файлу через специальный объект ARGF