In addition to the constructors such as range
and spread
another way of creating new rings is to manipulate existing rings.
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)
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:
(ring 10, 20, 30, 40, 50)
- our initial ring(ring 10, 20, 30, 40, 50).shuffle
- shuffles - (ring 40, 30, 10, 50, 20)
(ring 10, 20, 30, 40, 50).shuffle.drop(1)
- drop 1 - (ring 30, 10, 50, 20)
(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.
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.
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.