2020
Для отладки работы исходного кода на Ruby существуют следующие способы:
irb для запуска методовirb — интерактивный интерпретатор Ruby, позволяющий выполнять код построчно (REPL, Read-Eval-Print Loop)
Для подключения собственных файлов в irb:
Запустите irb:
irb -I .Подключите файл в вашу сессию require ...
prypry — альтернативная реализация интерактивного интерпретатора Ruby
pry не входит в поставку Ruby, его необходимо поставить отдельно:
$ gem install pry
Желательно также установить пакет pry-byebug
$ gem install pry-byebug
pry и pry-byebugКомбинация pry и pry-byebug позволяет реализовать интерактивную отладку приложения. Для включения отладки достаточно в нужное место добавить следующий код:
Для навигации следует использовать следующие команды:
break — управлять списком точек остановкиstep — сделать 1 или несколько шагов выполненияnext — сделать 1 или несколько шагов в данном фреймеfinish — выполнить код до завершения фреймаcontinue — продолжить выполнение и выйти из pryДокументация на byebug: https://github.com/deivid-rodriguez/pry-byebug
Обычно массивы создаются с помощью литералов
Но можно и с помощью создания объекта
#size, также известный как #length, возвращает число элементов в массиве#size, а для строк — #lengthДля доступа к элементам массива используется метод #[]
-1nilМетод #[] может принимать два аргумента: начало и количество. Однако лучше использовать метод #slice
nila = [3, 6, 9, 12, 15]
a.slice(1, 3) # => [6, 9, 12]
a.slice(3, 1) # => [12]
a.slice(-3, 2) # => [9, 12]
a.slice(-2, 3) # => [12, 15]В Ruby есть встроенный тип Range, диапазон. Для его создания существуют 2 литерала: .. (включающий границы) и ... (исключающий границу справа)
Их можно использовать для выборок массивов
a = [3, 6, 9, 12, 15]
a.silce(0..2) # => [3, 6, 9]
a.slice(0...2) # => [3, 6]
a.slice(-3..-1) # => [9, 12, 15]
a.slice(-1..-3) # => []Для записи значений в массив использется метод #[]=
a = [3, 6, 9, 12, 15] # => [3, 6, 9, 12, 15]
a[1] = 'lemon' # a => [3, "lemon", 9, 12, 15]
a[-2] = 'orange' # a => [3, "lemon", 9,
# "orange", 15]
a[0] = [1, 2] # a => [[1, 2], "lemon", 9,
# "orange", 15]
b = [3, 6] # => [3, 6]
b[5] = 15 # b => [3, 6, nil, nil, nil, 15]При присвоении к несуществующему элементу пропуски заполняются nil
Метод []= также принимает набор
a = [3, 6, 9, 12, 1] #=> [3, 6, 9, 12, 1]
a[2, 2] = 'fly' # a => [3, 6, "fly", 1]
a[2, 0] = 'bot' # a => [3, 6, "bot", "fly", 1]
a[1, 1] = [2, 5] # a => [3, 2, 5, "bot", "fly"..
a[0..3] = [] # a => ["fly", 1]
a[5..6] = 98, 99 # a => ["fly", 1, nil, nil,
# nil, 98, 99]Такой код невозможно воспринимать ни при каких обстоятельствах, поэтому использовать такую нотацию не рекомендуется
Официальная документация описывает множество методов класса Array, например:
#push, #append — добавить в конец массива#pop — извлечь элемент из конца массива#shift — извлечь элемент с начала массива#unshift, #prepend — добавить в начало массива#first(n) — получить n первых элементов#last(n) — получить n последних элементов#drop(n) — получить элементы массива с позиции n#shuffle — создать новый массив, перемешав элементы#delete(obj) — удалить все вхождения объекта objХеши описывают соответствие между наборами из двух объектов. Первый объект называется ключом и должен быть уникальным среди всех ключей. Второй объект — значение
Хеши обычно создаются с помощью литералов
h = {'dog' => 'canine', 'cat' => 'feline'}
h.length # => 2
h['dog'] # => "canine"
h[12] = 'dodecine'
h['cat'] = 99Часто ключами хешей являются символы
Подсчитаем, насколько часто встречаются слова в тексте. Для решения этой задачи необходимо:
#downcase преобразует строку к нижнему регистру#scan возвращает массив строк, совпадающих с переданным регулярным выражениемcounts = {}
for word in word_list
if counts.has_key?(word)
counts[word] += 1
else
counts[word] = 1
end
endПары ключ-значение сохраняют свой порядок в Хешах, что позволяет их сортировать
Для сортировки можно использовать метод #sort_by, который принимает блок и использует его значения для сортировки
Вывод 5 наиболее часто встречающихся слов
top_five = sorted.last(5)
for i in 0...5
word = top_five[i][0]
count = top_five[i][1]
puts "#{word}: #{count}"
end#has_key? — проверка на наличие ключа#has_value? — проверка на наличие значения#last — получение последних элементов#sort_by — сортировка элементов#length — количество элементов#delete — удалить пару ключ-значениеПривычный императивный стиль
С применением итераторов исходный код становится легче к восприятию, следовательно содержит меньше ошибок
begin и end или фигурными скобкамиПеременные блока маскируют внешние переменные
Можно определить список локальных переменных
square = "some shape"
sum = 0
[1, 2, 3, 4].each do |value; square|
square = value * value # локальная переменная
sum += square
end
puts sum
puts squareНо не надо так делать
yieldМетод вызывает ассоциированный блок два раза
def fib_up_to(max)
i1, i2 = 1, 1 # Паралельное присваивание
while i1 <= max
yield i1
i1, i2 = i2, i1+i2
end
end
fib_up_to(1000) {|f| print f, " "}Блоку передаются параметр — следующее число последовательности Фибоначи. Блок будет вызываться столько раз, сколько необходимо для выполнения условия цикла
class Array
def find # Вариант реализации find
each do |value|
return value if yield(value)
end
nil
end
end
[1, 3, 5, 7, 9].find {|v| v*v > 30} # => 7#find возвращает значение элемента#find ничего не знает об условии, но эффективно обходит все элементы массива и предоставляет общую структуру для решения задачиreturn не имеет специального смысла в блоках, связан только с методомbreak заканчивает выполнение блока, а также метода, который его вызвалnext завершает текущую итерацию, цикл продолжается со следующейКлючевое слово break принимает аргумент, значение которого становится результатом вызова метода с блоком
Будьте аккуратны при использовании break, так как выполнение метода прерывается
#map#map (или #collect) позволяет создать новый массив на основе значений текущего массиваМетод String#succ возвращает «преемника» для данной строки, начиная с правого символа строки
Классы ввода-вывода предоставляют итераторы для чтения по линиям или байтам
Итераторы могут быть использованы для решения множества задач
with_indexf = File.open("testfile")
f.each.with_index do |line, index|
puts "Line #{index} is: #{line}"
end
f.closeДанная функциональность основана на работе нумераторов, которые разберём в следующих лекциях
Данные итераторы предполагают, что блок будет возвращать логические значения
#any? — есть ли хотя бы один элемент, удовлетворяющий условию#all? — все ли элементы удовлетворяют условию#one? — только один элемент удовлетворяет условию#none? — ни один элемент не удовлетворяет условию#find — найти первый элемент, удовлетворяющий условию#find_all — найти все элементы, удовлетворяющие условию#find_index — найти номер первого элемента, удовлетворяющего условию#delete_if — удалить из массива все элементы, удовлетворяющие условиюЧасто необходимо вычислить значение, основываясь на всех элементах массива. Итератор #reduce (или #inject) позволяет решить данную задачу
Можно не указывать начальное значение, тогда первый элемент массива — начальное значение
Можно просто указать метод, который необходимо вызывать у элементов массива
#tap и #yield_self#tapДанный итератор позволяет встроиться в цепочку по обработке данных, не изменяя её содержимое. Он передаёт self в качестве аргумента блока и возвращает его в качестве значения вызова метода
#then, #yield_selfДанный итератор был добавлен в Ruby 2.5 с целью структурировать обработку данных. В версии 2.6 данный метод был переименован в #then