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