A Look at Ruby Methods, Loops, and Logic

As my last post noted, I am currently enrolled at Flatiron School’s Online Community-Powered Bootcamp. It has been a great experience thus far. This blog has always been a place for me to note my studies and thoughts about what I’m learning. I have discovered over the time I’ve been here that others also have come by to enhance their learning, and for that I’m grateful and happy.

As such, I will be blogging here again regularly. My last post prior to this resurgence was in 2015. I was not inactive, per se, but I slowly became more active as 2016 went on. I was embroiled in the election, and once it began wrapping up I started studying again. I went through the Web Dev Bootcamp’s Javascript section and built a few of the #Javascript30 projects but I missed Ruby on Rails. I looked at a few options before settling on the Flatiron program. While the price is a big commitment, but I am committed to make this change.

I will be mostly using this as a way to look at the code I’m writing as I complete projects for this bootcamp and explaining what I’m doing. One of the things I like is that I’m not just being told “type this” and blindly mimicking code. I actually have to sit down and write the code. So, this is all code I’ve written.

So, this first section is an intro to Ruby. I’ve learned about variables, methods, logic and conditions, boolean, and loops. I also learned, for the first time, about command line applications. So, I’m going to post the code I have written up to a lesson that looks at taking a turn in the tic tac toe app we are building and break it down. First, I’ll post the bin file, turn,

and now, the Ruby turn.rb file.

So, first and foremost, a command line application, called a CLI for command line interface, is a file that the user launches to run the application from the command line. No graphics here. This is called the bin file, and is stored in the bin directory in our application. This is the executable file we run our program from. Let’s go through this file line by line. I’ll post it again:

Ok, the first line is known as the shebang line:

This tells the interpreter to use Ruby as the language for the file.

Next, we tell the bin file to require the turn.rb file with this line:

This gives us access to methods we define in that file. This will be important in just a minute.

Now, we are going to create an array called board and set it up with some strings with a space in them:

And then greet the user and call two methods from the turn.rb file. Both will pass in board as an argument:

OK, now that we are through the bin file, let’s look at the turn.rb file in more depth. This file is located in the lib directory. I’ll put the whole thing here for reference, but then pull out each method individually as we go through it:

Let’s break this down. First, we call a method titled display_board that accepts one argument, the array we defined in the bin file. This method will build the frame of our tic tac toe board.

When we run the app, it will display like this:

Very high res, HD graphics!

Inside each puts call, you will notice these:

This is a string interpolation. Basically, this allows us to put the variable inside of the string. This in particular is pulling the data from the array. As the game is played the users will place their X and O markers in the 9 quadrants of the tic tac toe board. They will be asked to select a space numbered 1 to 9, with 1 being the top left corner and 9 being the bottom right corner. The X’s and O’s will be put inside the array in the necessary spots, and then the display_board method will interpolate the marker as it is updated.

Next, let’s look at the turn method, and as we go through it we will discuss the methods that are called from inside it. First, the method:

So, this again takes the argument of board. It asks the user, as we discussed above, to choose a space from 1 to 9 and then takes the input using the gets method. gets will take the users input, and then, using the strip method will remove any new lines or trailing whitespace. Next, this input is sent to another method defined called input_to_index:

This method will first take the argument input and turn it into an integer with the to_i method then it subtracts 1 from it. This is because the array starts counting at 0, while we are asking the user to start counting the quadrants at 1. so, while the top left square in the array is 0, the user is entering 1. Subtracting 1 fixes this. Let’s return now back to the turn method.

We are now going to define a new variable, m, and have this variable decide whether the move made by the user is a valid move. This is calling another method, valid_move?, which is below, along with it’s helper method, position_taken?:

It will probably be best to start looking at position_taken? first. This takes two arguments, the board array and the index we just created with the input_to_index method. It uses an if statement to decide whether the position the user has chosen is taken already. So, the first part of the method asks “if the spot on the board is empty then return false (the position is NOT taken), then the next part says “else, if there is an X or O already there, return true (the position IS taken). Notice here that we are using the || for the boolean for “or”.

Now, looking at this, we return to the valid_move? method. This method is deciding whether the move the user made is valid. If the user tries to take a position already taken it is not valid, hence we utilize the position_taken? method we just discussed. It also looks at a range to ensure the user is playing on the board and not in a position elsewhere. This utilizes the between? method which passes in to arguments, the start and end of the numeric range which here is 0-8. Notice also that the if statement is using && for an “and” comparison, as well as the ! in front of position_taken? to make it negative, reading instead “position is not taken.” So, this method is literally saying “if the move is between 0-8 and the position is NOT taken, its a valid move, otherwise it is not a valid move.”

So, moving forward in the turn method, the move we asked the user to make is validated through the valid_move? method. If the move is valid, which returns true, then we allow the move to proceed via the move method. Here it is:

This brings in three arguments, the board array, the index and the char argument which is the X or O for each user. Currently, the char is set to X as a default argument. Soon, it will allow the O character. This method takes the index we created from the users input and places the X on the position they chose, updating the board array.

If the move is not valid, a loop is called. Let me place this part below so we can walk through it.

So, first, m enters here as false. The loop states “until m is true, this loop will keep coming around.” The user is told the move was invalid and prompted to enter another move. The input is taken through all of the above methods we discussed again and if the move is valid, the loop ends. If not, we go through until it is valid.

Here is what we are hoping happens:

And here it is with me choosing an invalid position:

This time I showed where I called the bin using ruby bin/turn. I made the move, picking a position WAY off the board, and then the app told me the move was invalid and prompted me again. This time I got it right and the lower left hand corner had an X added to it.

I hope this helps anyone visiting to understand Ruby methods, loops, and logic a bit better. If you have questions, feel free to ask!

 

Day 38, Part 1: First App Finished

I just finished my Book Tracker app. I decided to only add a print function as I would want to put out the whole list as I go. I may go back eventually to add search, but for what it is for I believe a list function is best. I am using it to track as I go.

I created a video to detail the app and show how it works:

and here is a look at the code. You can also see the code at my GitHub profile.

First, the main file:

and the the file where I create Book.class:

and then the YAML file… where the data is stored.

OK, I am moving on to Ruby on Rails tonight. I will return shortly!

Day 37: Working on my App and Finishing Exercise 39 at Learn Ruby the Hard Way

I had a day off from work so spent a good portion of the day enjoying being off work. I am back now to finish the long lesson last night from Learn Ruby the Hard Way: Exercise 39: Hashes, Oh Lovely Hashes.

So, the second portion of the Exercise had a module, dict.rb, and then another file full of hashes to run using the module. Here is the code:

and the test file:

demosthenes131@rails-tutorial:~/workspace/LRTHW (master) $ ruby ex39_test.rb
———-
NY State has: New York
OR State has: Portland
———-
Michigan’s abbreviation is: MI
Florida’s abbreviation is: #Dict.get(states, ‘Florida’)}
———-
Michigan has: Detroit
Florida has: Jacksonville
———-
Michigan
MI
New York
NY
Florida
FL
Oregon
OR
California
CA
———-
CA
San Francisco
OR
Portland
NY
New York
MI
Detroit
FL
Jacksonville
———-
Sorry, no Texas.
The city for the state ‘TX’ is: Does not exist

And now back to my app!

I added a way to preserve added data today via YAML

Here is the BookTracker main file:

the Book class file:

and what happens when I add information:

First session:

demosthenes131@book_tracker:~/workspace (master) $ ruby book_tracker.rb
Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
a
Book title: Storm Front
Author: Jim Butcher
Genre: Urban Fantasy
Have you read it, listened to it, or is it a wish list item? Listened
Write a short, one sentence, review! Amazing
Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
e
[#]

At this point I was having a lot of trouble originally. Everytime I restarted the app and entered a new book the previous book was deleted. I fixed this by adding the open() to the run method which would then populate the array. Next session after this (also after I removed a few items that I will re-add later):

demosthenes131@book_tracker:~/workspace (master) $ ruby book_tracker.rb
Select an option from the below choices
a: Add a Book
e: Exit
a
Book title: Hounded
Author: Kevin Hearne
Genre: Urban Fantasy
Have you read it, listened to it, or is it a wish list item? Read it
Write a short, one sentence, review! Fun
Select an option from the below choices
a: Add a Book
e: Exit
e
[#, #]

And here is the YAML output file:

My plan tomorrow is to work on the search and print functions!

Day 36: Splitting Time Between Writing a New App and Learning Ruby the Hard Way

So, I want to get back to finishing Learn Ruby the Hard Way while also applying my new found knowledge to the app I am creating.

I will start with Exercise 39:

and the results:

demosthenes131@rails-tutorial:~/workspace/LRTHW (master) $ ruby ex39.rb
———-
NY state has: New York
OR state has Portland
———-
Michigan’s abbreviation is: MI.
Florida’s abbreviation is: FL
———-
Michigan has: Detroit
Florida has: Jacksonville
———-
Oregon is abbreviated OR
Florida is abbreviated FL
California is abbreviated CA
New York is abbreviated NY
Michigan is abbreviated MI
———-
Oregon has the city OR
Florida has the city FL
California has the city CA
New York has the city NY
Michigan has the city MI
———-
Oregon is abbreviated OR and has city Portland
Florida is abbreviated FL and has city Jacksonville
California is abbreviated CA and has city San Francisco
New York is abbreviated NY and has city New York
Michigan is abbreviated MI and has city Detroit
———-
Sorry, no Texas.
The city for the state ‘TX’ is: Does Not Exist

OK, I have more to do this lesson but spent the rest of my night reading through my code and trying to figure out how to get my user input to go into a hash then have that hash go into an array. I will continue tomorrow.

Day 35: Getting Closer to a Finished First App

So, i made more progress today, especially thanks to Jesus Castello of BlackBytes.info who helped me understand the difference between instance vs. local variables. So, here is how the Book Tracker is looking tonight. Also, feel free to take a look at it on GitHub.

The book class:

and the main book_tracker file:

And here are the results for this:

Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
a
Book title: Ender’s Game
Author: Orson Scott Card
Genre: SciFi
Have you read it, listened to it, or is it a wish list item? read it
Write a short, one sentence, review! Awesome
Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
a
Book title: Storm Front
Author: Jim Butcher
Genre: Urban Fantasy
Have you read it, listened to it, or is it a wish list item? listened
Write a short, one sentence, review! Amazing
Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
p
Book List
#
#
Select an option from the below choices
a: Add a Book
p: View the Books
s: Search the Books
e: Exit
e
[#, #]

I will continue hacking away tomorrow!

Day 34 Update: Working more on the App

OK, so I did some more work tonight. I am just going to post the files as they are a work in progress. Still not working 100%.

This is my new class for Book.

and the book_tracker main file. Its a mess as I am still trying to figure out how to store the data and scuh. The array is still not working, though it was earlier. I will keep working on it.

I will keep on working on it all.

Day 33: Making the Decision to Write My First App

Well, I have made a decision. I will be writing my first app over the coming days (possibly weeks).

I have decided to make an app in Ruby to track books I have read or listened to. I would like to eventually be able to assign a short, one sentence review to each. I would also like to figure out a way to mark the books as read, listened to, or wish list. Let’s get started.

Preface: I will be borrowing code from previous exercises. I will make a lot of mistakes. I will not apologize for either. I will say thanks to the previous exercises, however.

OK, here goes. The first bit of my code adds a menu that barely works and allows me to add a book.

OK, this is what happens:

demosthenes131@book_tracker:~/workspace $ ruby book_tracker.rb
Select an option from the below choices
a: Add a Book
v: View the Books
s: Search the Books
e: Exit
a
Add a book!
Ender’s Game
Select an option from the below choices
a: Add a Book
v: View the Books
s: Search the Books
e: Exit
a
Add a book!
Old Yeller
Select an option from the below choices
a: Add a Book
v: View the Books
s: Search the Books
e: Exit

Weird. It won’t keep the previously entered book. I need to create an array to collect these, I’m guessing…

And I have banged my head for an hour on this. I scrapped the whole thing and went simple:

and the results:

demosthenes131@book_tracker:~/workspace $ ruby book_tracker.rb
Add a book!
Ender
[“Ender”]
Add a book!
Shadow
[“Ender”, “Shadow”]
Add a book!
Hitchhiker
[“Ender”, “Shadow”, “Hitchhiker”]
Add a book!
Dresden
[“Ender”, “Shadow”, “Hitchhiker”, “Dresden”]
Add a book!

OK, this works. Let’s go a little more fancy. I want it to loop until I end it, and allow me to enter as many books as I decide. When I end it, I want it to print the list of books and then break. I worked it out a bit:

book_list = []

and it works! I was as surprised as you are:

demosthenes131@book_tracker:~/workspace $ ruby test.rb
Do you want to add a book? (yes or no)
yes
Add a book!
Ender’s Game
Do you want to add a book? (yes or no)
yes
Add a book!
Dresden Files
Do you want to add a book? (yes or no)
yes
Add a book!
Hitchhiker’s Guide to the Galaxy
Do you want to add a book? (yes or no)
no
[“Ender’s Game”, “Dresden Files”, “Hitchhiker’s Guide to the Galaxy”]

I also want to be able to add a one sentence review. I think a hash would work for this. Here is my attempt:

And the results:

demosthenes131@book_tracker:~/workspace $ ruby test.rb
Do you want to add a book? (yes or no)
yes
Add a book!
Ender
How about a short, one sentence review? (yes or no)
yes
Add your review!
Great book!
Do you want to add a book? (yes or no)
yes
Add a book!
Dresden
How about a short, one sentence review? (yes or no)
yes
Add your review!
Lots of fun
Do you want to add a book? (yes or no)
no
[“Ender”, “Dresden”]
{“book”=>[[“Ender”, “Dresden”]], “review”=>[[“Great book!”, “Lots of fun”]]}

I tried to work out the way to display this right. No luck as of yet. My last update:

and the result:

demosthenes131@book_tracker:~/workspace $ ruby test.rb
Do you want to add a book? (yes or no)
yes
Add a book!
Ender
How about a short, one sentence review? (yes or no)
yes
Add your review!
Awesome book
Do you want to add a book? (yes or no)
yes
Add a book!
Dresden
How about a short, one sentence review? (yes or no)
yes
Add your review!
urban fantasy fun!
Do you want to add a book? (yes or no)
no
[“Ender”, “Dresden”]
{“book”=>[[“Ender”, “Dresden”]], “review”=>[[“Awesome book”, “urban fantasy fun!”]]}
book – [[“Ender”, “Dresden”]]
review – [[“Awesome book”, “urban fantasy fun!”]]