Spread Operator in Ruby and Ruby Ranges
Tags: ruby, rails, programming, beginners
Published: 2022-01-30 11:06:44

We all remember the revolutionary in JavaScript world turned out to be the introduction of `spread operator` with the ES6 standard. Working with the collection has become pleasant and easy. Joining arrays has become very simple. You might think that this makes JS unique in this regard… but no. **We used the spread operator in Ruby before it became fashionable.** So, if you want to know what the spread operator in Ruby and Ruby Ranges looks like (a very interesting object), I invite you to read it.

I've learned from experience that Ruby language has a well-developed API when it comes to operations on collections. All thanks to `the Enumerable` module and `the Array` class, which provide all interesting functionalities.

##Concat

And so Ruby has a `concat` method that is used to join arrays together, so, to actions very often used in JS.

```ruby
[1, 2].concat(['a', 'b']) #=> [1, 2, 'a', 'b']
```

##Ruby Magic

Let me show you an example that proves how great a language Ruby is. We'll use a few less obvious array methods and another cool tool such as Ruby Ranges.

##Fake password generator

Let's write a simple password generator that we can use to seed the database, mock test data, or generate a password for the user.

**Business requirements:**

- the password may contain lowercase letters

- password may contain uppercase letters

- the password may contain numbers

- the password may contain special characters: $, #, *

- the password may contain a randomly generated [Wookie word](https://starwars.fandom.com/wiki/Wookiee), we will use the Faker gem

Let’s do this!

##The password may contain lowercase letters

You don't need to install anything, we will use `the Range` object which allows us to generate a set of characters or numbers from a specified range. Then we'll convert this object to an array using the `to_a` method.

```ruby
lowercase_letters = ('a'..'z').to_a

#=>
["a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z"]
```

##The password may contain uppercase letters

Here we will also use `Range` all we need to do is to change parameters to uppercase.

```ruby
capital_letters = ('A'..'Z').to_a

#=>
["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z"]
```

##The password may contain numbers

And `Range` again.

```ruby
numbers = (0..9).to_a

#=>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
```

##The password may contain special characters: $, #, *

A simple board is enough here

```ruby
special_characters = ['$', '#', '*']
```

It's easy to make a typo and forget the apostrophe, let's use more fancy syntax.

```ruby
special_characters = %w{ $ # * }

#=>
['$', '#', '*']
```

##The password may contain a randomly generated Wookie word

Seems like the hardest part, right?

```ruby
wookie_words = Faker::Movies::StarWars.wookiee_sentence.split

#=>
["Ru", "ooma", "nng", "roooarrgh", "roooarrgh!"]
```

I use `the split` method, which takes space as a default separator and breaks the generated sentence into an array of words understood by Chewbacci.

##Password generation

Now we have the components, it's time to create a password. First, let's sort all the criteria into one array.

```ruby
password_matrix = lowercase_letters
			          .concat(capital_letters)
				        .concat(numbers)
				        .concat(special_characters)
				        .concat(wookie_words)
```

##Shuffle

Let's mix it up with **the bang method**.

```ruby
password_matrix.shuffle!
```

##Sample

Let's pick 20 random pieces and mix it up again.

```ruby
password_matrix = password_matrix.sample(20).shuffle
```

##Join

Now we have to connect and we have the password ready.

```ruby
password_matrix.join

#=>
"r4gP#Tsga.0aBbKc$kabukkmCYhnn-rowr"
```

##Spread Operator 

All the code, with a small, refactor to simplify the steps, looks like this:

```ruby
def fake_password
  lowercase_letters = ('a'..'z').to_a
  capital_letters = ('A'..'Z').to_a
  numbers = (0..9).to_a
  special_characters = %w{ $ # * }
  wookie_words = Faker::Movies::StarWars.wookiee_sentence.split

  password_matrix = lowercase_letters
				.concat(capital_letters)
				.concat(capital_letters)
				.concat(numbers)
				.concat(special_characters)
				.concat(wookie_words)
				.shuffle
				.sample(20)
				.shuffle
				.join
end
```

A lot of this code, and I promised you a spread operator. Well, to combine arrays into one, all you need is `*`.

```ruby
password_matrix = [ *lowercase_letters, *capital_letters, *numbers, *special_characters, *wookie_words]
```

Final code looks like that:

```ruby
def fake_password
  lowercase_letters = ('a'..'z').to_a
  capital_letters = ('A'..'Z').to_a
  numbers = (0..9).to_a
  special_characters = %w{ $ # * }
  wookie_words = Faker::Movies::StarWars.wookiee_sentence.split

  password_matrix = [*lowercase_letters, *capital_letters, *numbers, *special_characters, *wookie_words]

  password_matrix
    .shuffle
    .sample(20)
    .shuffle
    .join
end
```

##It work a treat!


![Spread_Operator](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/xddula3sqr14rxq9r3vi.gif)