Beautifully Spaced Columns in Ruby
Tags: beginners, ruby
Published: 2021-01-19 04:51:19

Recently I was working on a CLI application (nothing crazy, just a fun little Superhero API project), and I wanted to spruce up the way I was outputting my list of all the available heroes.

I'm still new to programming, so I try to focus on function over form as much as possible while I'm learning. I'm also not trying to shout from the rooftops about my training wheels though, you know?

And that'd pretty much what this feels like: 
![Screen Shot 2021-01-17 at 10.17.08 PM](https://dev-to-uploads.s3.amazonaws.com/i/hyxs9wvvy1sj7efxuklo.png)
...pretty rough, especially considering there are over 700 characters in that list.

So obviously I needed to take advantage of a little more horizontal real estate, but I was having trouble finding a straight-forward way to accomplish that without really knowing what to search for. I get that there are tons of command line tools out there that will format everything up and make it look dynamite, but I'm trying to learn the fundamentals. What's a guy gotta do to get a basic column out here?? 

So that brings us here, to `.rjust` and `.ljust`, two super easy methods (which for some reason are hiding in the comments of Stack Overflow with not enough upvotes) to help format your output into columns in regular ol' Ruby.     

As you probably guessed, those stand for 'right justify' and 'left justify', and there are a couple key things to note here if you're having trouble using them.
    
## These methods take an argument for the desired length of the new string *not* how much whitespace to add 

If you try an example in IRB, you can see that `.rjust` is actually just padding the left side of the string and `.ljust` is padding the right ride of the string:
```
:001 > "apple".rjust(10)
 => "     apple"
:002 > a = "apple".ljust(10)
 => "apple     "
:003 > a.length
 => 10
```
These methods also take the optional second argument of a string to use for padding instead of whitespace
```
:004 > "banana".rjust(10, "*")
 => "****banana"

# You can also use a pattern for padding
:005 > "apple".rjust(20, "!?") + "peach".rjust(20, " -")
 => "!?!?!?!?!?!?!?!apple - - - - - - - peach"
```
Honestly, I can't think of too many practical applications for using something other than whitespace, but at least we're getting closer to understanding how to build out our columns. 

**NOTE: Make sure you aren't asking your string to be *shorter* than it started.** 

**Calling `"Grapefruits".rjust(10)` isn't going to get you anywhere, because you're telling an 11 character string to pad itself on the left with enough spaces to become a 10 character string...**    

Now, if you're working with an array of arrays, this is pretty much as far as you need to go, since it's easy enough to iterate over your group and right or left justify each one.
```
dynamic_duos = [ ["Tom", "Jerry", "1940"], ["Scooby", "Shaggy", "1969"], ["Ketchup", "Mustard", "1812"] ] 

dynamic_duos.each{ |duo| 
    puts duo[0].rjust(10) + duo[1].rjust(10) + duo[2].rjust(10)
}

    # Prints these columns
       Tom     Jerry      1940
    Scooby    Shaggy      1969
   Ketchup   Mustard      1812
```
Not bad! Why are my years strings though? That's not very realistic, especially if I wanted to order my columns by year or something. That's because of the second common mistake with these methods. 

## `.rjust` and `.ljust` are methods from the String class

Calling these methods on an integer (like those years up there should be) will raise an error, but this actually isn't a big deal. There are plenty of easy solutions, like...

Interpolation
```
dynamic_duos = [ ["Tom", "Jerry", 1940], ["Scooby", "Shaggy", 1969], ["Ketchup", "Mustard", 1812] ]

dynamic_duos.each{ |duo| puts duo[0].rjust(10) + duo[1].rjust(10) + "#{duo[2]}".rjust(10)}

    # Prints the same columns from before
       Tom     Jerry      1940
    Scooby    Shaggy      1969
   Ketchup   Mustard      1812
```
If your arrays have a mixture of data types, you can interpolate all of the elements to be safe. There are lots of other options, like explicitly converting your value to a string first with `.to_s.rjust(10)`, but I won't get into all those here.

## What if I'm working with a normal array?

That's right, I almost forgot that the whole reason we're doing this is to print out a list of 731 superheroes without making our users scroll for five straight minutes. 

Here's a shorter example of what I ended up doing:
```
fifteen_hockey_players = ["Lemieux", "Crosby", "Jágr", "Malkin", "Fleury", "Murray", "Jarry", "Letang", "Kessel", "Guentzel", "Rust", "McCann", "Dumoulin", "Hagelin", "Pettersson"]   
    # Totally not biased for any particular team  

count = 0
number = (fifteen_hockey_players.length/3) 
    # Divided by three because I want three columns

number.times do
    puts fifteen_hockey_players[count].rjust(15) + fifteen_hockey_players[count+1].rjust(15) + fifteen_hockey_players[count+2].rjust(15)
    count += 3
end         

    # Prints these lovely, lovely columns 
        Lemieux         Crosby           Jágr
         Malkin         Fleury         Murray
          Jarry         Letang         Kessel
       Guentzel           Rust         McCann
       Dumoulin        Hagelin     Pettersson            
```
As long as I up my counter by the number of columns I have, I can print out as long a list as I like, in as many columns as I like. 

----------------------------------------------------------
Thanks to everyone who read this far! It's a little long, but I hope this will help some people like myself, who didn't have much experience with `.rjust` and `.ljust`. If anyone has anything to add or critique, please let me know in the comments.

**Things to play around with on your own if you're interested:** `.center`, chaining `.rjust.ljust`, and using the length of your string as the argument ex. `.rjust(x.length + 5)`.