# Кольцевые цепи

Помимо конструкторов, таких как `range` и `spread`, есть и другой способ создания новых колец - манипулирование существующими кольцами.

## Цепные методы

Чтобы исследовать это, возьмём простое кольцо:

    (ring 10, 20, 30, 40, 50)

Что, если мы хотим перевернуть его задом наперёд? Тогда мы используем связанный метод `.reverse`, который разворачивает кольцо в обратную сторону:

    (ring 10, 20, 30, 40, 50).reverse  #=> (ring 50, 40, 30, 20, 10)

Так, а что, если мы захотим получить первые три элемента кольца?

    (ring 10, 20, 30, 40, 50).take(3)  #=> (ring 10, 20, 30)

И, наконец, что, если мы захотим перемешать элементы кольца?

    (ring 10, 20, 30, 40, 50).shuffle  #=> (ring 40, 30, 10, 50, 20)

## Множественные цепи

Это очень мощный способ создания новых колец. Однако, реальная мощь приходит, когда вы связываете несколько методов вместе.

Как на счёт перемешать кольцо, отбросить 1 элемент, а затем получить первые 3 элемента?

Давайте сделаем это в несколько этапов:

1. `(ring 10, 20, 30, 40, 50)` - наше исходное кольцо
2. `(ring 10, 20, 30, 40, 50).shuffle` - перемешиваем - `(ring 40, 30, 10, 50, 20)`
3. `(ring 10, 20, 30, 40, 50).shuffle.drop(1)` - отбрасываем 1 элемент - `(ring 30, 10, 50, 20)`
4. `(ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3)` - берём 3 первых элемента - `(ring 30, 10, 50)`

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

## Неизменяемость

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

## Доступные цепные методы

Вот список доступных для вас цепных методов:

- `.reverse` - возвращает отсортированную в обратном порядке версию кольца
- `.sort` - возвращает отсортированную версию кольца
- `.shuffle` - возвращает отсортированную в случайном порядке версию кольца
- `.pick (3)` - возвращает кольцо с результатами вызова `.choose` 3 раза
- `.pick (3)` - возвращает кольцо с результатами вызова `.choose` 3 раза
- `.take(5)` - возвращает кольцо, содержащее первые 5 элементов исходного кольца
- `.drop(3)` - возвращает кольцо, содержащее все элементы исходного кольца, кроме первых 3 элементов
- `.butlast` - возвращает новое кольцо с отсутствующим последним элементом
- `.drop_last(3)` - возвращает новое кольцо с отсутствующими 3 последними элементами
- `.take_last(6)`- возвращает кольцо, содержащее последние 6 элементов исходного кольца
- `.stretch(2)` - повторяет каждый элемент кольца дважды
- `.repeat(3)` - повторяет всё кольцо 3 раза
- `.mirror` - добавляет кольцо к перевёрнутой версии себя
- `.reflect` - то же, что и `.mirror`, но не дублирует средний элемент
- `.scale(2)` - возвращает новое кольцо все элементы которого умножены на 2 (если кольцо содержит только числа)

Конечно, цепные методы, принимающие числовые аргументы, могут принимать и другие числа! Так что не стесняйтесь вызывать `.drop(5)` вместо `.drop(3)`, если вы хотите отбросить первые 5 элементов кольца.