8.5 Ring Chains

# Ring Chains

In addition to the constructors such as `range` and `spread` another way of creating new rings is to manipulate existing rings.


## Chain Commands

To explore this, take a simple ring:

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

What if we wanted it backwards? Well we'd use the chain command `.reverse` to take the ring and turn it around:

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

Now, what if we wanted the first three values from the ring?

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

Finally, what if we wanted to shuffle the ring?

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

## Multiple Chains

This is already a powerful way of creating new rings. However, the *real* power comes when you chain a few of these commands together.

How about shuffling the ring, dropping 1 element and then taking the next 3?

Let's take this in stages:

1. `(ring 10, 20, 30, 40, 50)` - our initial ring
2. `(ring 10, 20, 30, 40, 50).shuffle` - shuffles - `(ring 40, 30, 10, 50, 20)`
3. `(ring 10, 20, 30, 40, 50).shuffle.drop(1)` - drop 1 - `(ring 30, 10, 50, 20)`
4. `(ring 10, 20, 30, 40, 50).shuffle.drop(1).take(3)` - take 3 - `(ring 30, 10, 50)`

Can you see how we can just create a long chain of these methods by just *sticking them together*. We can combine these in any order we want creating an extremely rich and powerful way of generating new rings from existing ones.

## Immutability

These rings have a powerful and important property. They are immutable which means that they can not change. This means that the chaining methods described in this section *do not change rings* rather they *create new rings*. This means you're free to share rings across threads and start chaining them within a thread knowing you won't be affecting any other thread using the same ring.

## Available Chain Methods

Here's a list of the available chain methods for you to play with:

* `.reverse` - returns a reversed version of the ring
* `.sort` - creates a sorted version of the ring
* `.shuffle` - creates a shuffled version of the ring
* `.pick` - returns a ring with the results of calling `.choose` once
* `.pick(3)` - returns a ring with the results of calling `.choose` 3 times
* `.take(5)` - returns a new ring containing only the first 5 elements
* `.drop(3)` - returns a new ring with everything but the first 3 elements
* `.butlast` - returns a new ring with the last element missing
* `.drop_last(3)` - returns a new ring with the last 3 elements missing
* `.take_last(6)`- returns a new ring with only the last 6 elements
* `.stretch(2)` - repeats each element in the ring twice
* `.repeat(3)` - repeats the entire ring 3 times
* `.mirror` - adds the ring to a reversed version of itself
* `.reflect` - same as mirror but doesn't duplicate middle value
* `.scale(2)` - returns a new ring with all elements multiplied by 2 (assumes ring contains numbers only)

Of course, those chain methods that take numbers can take other numbers too! So feel free to call `.drop(5)` instead of `.drop(3)` if you want to drop the first 5 elements.
