DEV Community

Cover image for Spread Operator in Ruby and Ruby Ranges
Rafał Piekara
Rafał Piekara

Posted on

Spread Operator in Ruby and Ruby Ranges

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.

[1, 2].concat(['a', 'b']) #=> [1, 2, 'a', 'b']
Enter fullscreen mode Exit fullscreen mode

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, 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.

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"]
Enter fullscreen mode Exit fullscreen mode

The password may contain uppercase letters

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

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"]
Enter fullscreen mode Exit fullscreen mode

The password may contain numbers

And Range again.

numbers = (0..9).to_a

#=>
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Enter fullscreen mode Exit fullscreen mode

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

A simple board is enough here

special_characters = ['$', '#', '*']
Enter fullscreen mode Exit fullscreen mode

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

special_characters = %w{ $ # * }

#=>
['$', '#', '*']
Enter fullscreen mode Exit fullscreen mode

The password may contain a randomly generated Wookie word

Seems like the hardest part, right?

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

#=>
["Ru", "ooma", "nng", "roooarrgh", "roooarrgh!"]
Enter fullscreen mode Exit fullscreen mode

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.

password_matrix = lowercase_letters
                      .concat(capital_letters)
                        .concat(numbers)
                        .concat(special_characters)
                        .concat(wookie_words)
Enter fullscreen mode Exit fullscreen mode

Shuffle

Let's mix it up with the bang method.

password_matrix.shuffle!
Enter fullscreen mode Exit fullscreen mode

Sample

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

password_matrix = password_matrix.sample(20).shuffle
Enter fullscreen mode Exit fullscreen mode

Join

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

password_matrix.join

#=>
"r4gP#Tsga.0aBbKc$kabukkmCYhnn-rowr"
Enter fullscreen mode Exit fullscreen mode

Spread Operator

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

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
Enter fullscreen mode Exit fullscreen mode

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

password_matrix = [ *lowercase_letters, *capital_letters, *numbers, *special_characters, *wookie_words]
Enter fullscreen mode Exit fullscreen mode

Final code looks like that:

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
Enter fullscreen mode Exit fullscreen mode

It work a treat!

Spread_Operator

Discussion (0)