CLI Project Flatiron by Danny Reina

Hello world!

Danny Reina
6 min readJan 17, 2020

“Hello World!”

Seemingly a person’s baptism into the world of programming starts with this piece of string. My programming baptism was 32 days ago and yet someway somehow I have managed to build my very own CLI program/ruby gem.

My CLI called “Romantic Restaurants” was conceptualized as a birthday gift for my gf (hi dushi ❤), the intent for the CLI was for her to be provided a numbered list of romantic restaurants in NYC and a colorful description of each restaurant with contact information. From there the desired end result was to make a reservation from her selected option for our Valentine’s dinner. I completed the first step, conceptualize and visualize what I want my program to do, small victory!

The next step was to actually start, it is here where I encountered perhaps my most difficult step. Staring at a blank gem template I was suddenly battling the demon that is setting up your dependencies in the Learn IDE. My initial thoughts were, I wish I were doing this in a local environment but alas the project has to be done in the provided Learn IDE sandbox.

Guided by Avi Flombaum’s “Building a CLI Gem Walkthrough,” I first tackle setting up my environment and file structure. Bundle gem sets me on the right path. Under the steadfast guidance of Avi, I create my gem and then I see the awful wall of red errors.

just a representation, not accurate

After some troubleshooting and feedback from my terrific cohort lead Dalia and fellow classmates, I conquer the red wall by installing the missing gems pry and Nokogiri. Pry to peek into what my code is doing and Nokogiri to scrape my webpage.

Great my environment is set up and here I go. First, start metaprogramming my cli interface. I use my notes to guide me which ends up resulting in me writing three methods. The call method will be used to kickoff my program. The list_restaurants method will be where the user will see the list of restaurants scraped from my selected webpage. The restaurant_description method will be there to provide the user with an option to select a restaurant if he or she desires more information. Additionally, I made sure to include conditions within my restaurant_description method to carry out functions if a user wants to view the list again after viewing a description or to exit the program which would kickoff the last method in my cli file which is called goodbye. I believe this helps in providing a seamless experience for the user.

With the basic function of the cli method set, although refining it later on is imperative, I look towards creating the basic function of scraping and creating a new object that will represent my restaurant with its appropriate attributes: name, and description. Thanks to Nokogiri, I am able to scrape my webpage while properly identifying which tags I need to pull, however, I encounter a problem.

After a lengthy process prying into everything and losing my new updates (git commit novice here), I discover that my return value for doc.css(url)is not returning what I need. Instead of getting only the name of the restaurant I am getting an array of strings that look like this “1.restaurant, 2.restaurant.” To rectify this problem I call upon good ole collect, in-line syntax, to iterate over each element and use .css(‘ID’)[1].text.strip to return the correct string values in an array. All that's left to do is set that end value to my variable restaurant_name and boom first attribute is set.

The second attribute, restaurant_description, ends up being much simpler thanks to the simple design/layout provided by my selected webpage. All that is needed is to call .css on my doc variable, doc is storing my Nokogiri value, and iterate over each element to remove the blank spaces, using .strip, at the beginning of each string. The blank spaces were discovered when I ran ./bin/romantic_restaurants which kicks off my CLI.

Perfect, now I have my two attributes, confirmed through pry. Now I am ready to create my restaurants object and apply its appropriate attributes. I use self.new and assign it to a variable called restaurant. Then I give my object its name and description attributes. After, I store my object in my self.all method which allows me to access it in my CLI.

At this point, I need to create a class variable that will allow me to assign the value of self.all to it so that its scope is accessible for my entire cli file. The next step was a bit challenging however pry saved me! With tremendous gratitude for Avi’s walkthrough video material I am convinced to use each.with_index. It's worth noting the difference between each.with_index and each_with_index. However, I ask myself what am I iterating over? It has to be an array so where are my arrays? I have two arrays in my object. I need to puts the names of the restaurant where are the names? They are in the names attribute in my object or in my case @restaurant.name. Eureka! I can iterate over @restaurant.name and puts out my list. The ecstasy that consumed me when I saw my list neatly printed in my terminal was surreal.

The next task to do was list the description for a restaurant based on the user's selection. For this, I knew I would need gets and somehow return the description based on the user’s input. However, a few critical things to be made aware of. The descriptions are in an array but the indices of an array always start at 0 which means somewhere I have to do input -1 to accommodate for the nature of array indices. Also, gets returns a string which means if I want to satisfy the condition that the user receives a description based on their provided integer I need to convert gets to an integer via the to_i method. Great, all that's left to do to list the description is to create my condition. I use handy dandy if and tell my method to puts a variable called restaurant that will be assigned the value of the index.to_i -1 of the @restaurant.description array if that input.to_i is greater than 0 since no items in our list will be marked as 0. However, I did account for human error. What if the user did type 0 or anything else that would seemingly break the program well I included as the last portion in my condition to puts “Not sure what you want, type list or exit.” list would kickoff the method list_restaurants which would display the restaurants and exit would activate the last method in my cli called goodbye which simply ends the program by saying “See you later.”

All in all, I very much enjoyed this project. The toughest part for me was starting with a blank canvas. I have taken special note to refactor my code later on and am contemplating on separating my scraper function and object into two different classes. That is a task that will be done after I present this finished CLI program to my girlfriend as one of her many birthday gifts :)

--

--

Danny Reina
Danny Reina

No responses yet