Arslan Ali
6 min readApr 9, 2020

--

A brief guide to creating a command line interface application with Ruby

When you enter the world of coding, whether it’s a four year computer science degree, an arduous bootcamp program, or a self-taught Udemy course, it is more than likely that your very first trial by fire will be crafting a command line interface application. The challenge here is putting all the skills you’ve learned so far on a completely blank page and starting from there. Having been in your position, I’ll use my own project as a guideline to help you achieve your goal. I will be providing useful links to additional readings so you can better understand what to do and how to do it.

Before we begin coding, you’ll need to create a git repository on Github. Git is

  1. a version control system that allows you to safely initiate a project from your local environment to an accessible site on the internet
  2. an essential tool for gaining employment in any software company today
  3. a software that allows you to collaborate with other users to create powerful and robust projects together

You do not have to read through all those links at once; rather, visit or revisit them as you progress through the project. Let’s start on the project itself now.

In order to generate the gem itself, enter bundle gem in the command line of your text editor (I’m assuming that is Visual Studio Code, Atom, or another environment) and choose the name of the project you wish to make. In my case, I went with steadychef, as it is a project detailing entry-level cooking classes found in and around New York City. Your best bet is lowercasing and/or underscoring the name, as capitalizing and hyphenating open a host of other things you may not want.

Follow typical Ruby naming conventions here

The bundle gem input should generate a scaffold, or an outline, of the CLI app for you.

I won’t breakdown every single file and folder here, as each part can mean different things to different programmers during different projects. Primarily speaking, bin, lib, Gemfile, README.md, gemspec are where you’re going to be doing most of your work.

The bin folder is where your executables and libraries are typically going to be stored. You’ll call upon the various files here to initiate the application to walk through it yourself or for your users to, well, use. The lib folder contains all the coding you need to do in order to bring your program to life. How you structure these files is of the upmost important in the flow and deliverability, one mistake could determine a ceaseless headache or smooth sailing. The application layout itself follows a convention called the separation of concerns, and you should continue on with that by obeying the single responsibility principle.

Each one of the ruby files, denoted with a .rb, houses a single class and its accompanying methods. That single class is responsible for one single part of the application. For example, the location.rb file contains the class called Location, which is responsible for creating location instances. Staying true to both object orientation relationships and the single responsibility principle, each location has many courses (the connection being established by using attr_accessor :courses as well as @courses = []), while being solely responsible for the creation and maintenance of all location instances (attr_accessor :name, @@all = [], and@@all << self). Several methods in the Location class also invoke the Scraper class.

The Scraper class is the key to gathering and importing information from a website of my choosing to my CLI app. For steadychef I used CourseHorse and set the filters to only show beginner-level courses. Using a combination of the gems nokogiri and open-uri, I was able to scrape the information from the CSS selectors of the webpage I wanted. This involved choosing the correct parent-child objects on the page (sometimes you can’t choose exactly what makes the most sense based on your eyes alone, as scraping with nokogiri can be deceptively tricky, so practice!), iterating over the raw data, and extracting the exact text that I needed to show my users in their choice of location and courses. Let’s go into more detail by diving intoself.scrape_locations;

We set the variable page to equal a Nokogiri parser. Nokogiri::HTML is a construct that takes in the content information of the webpage and translates that into a unique Nokogiri data type (which you can run some Ruby methods on). The construct must take in the argument of open which itself should have the string argument of the website’s url you wish to scrape from. Then we set the variable neighborhoods to equal page.css and choose the css selectors from the webpage. While you may not need to do this, I had to set another variable called locations and set its value equal to an additional filter to get the specific locations I needed from the site. I then iterated over that object and assigned the name of that location to a brand new Location instant as it initialized. Remember, we set name as a required attribute for any newly created location instance object in our Location class.

The command line interface is activated by the CLI class, where we carefully craft a series of methods that invoke information from other classes and also allow the user to interface with the application using the command line. This is going to be the class where you write the most amount of code and do trial-and-error testing as well as add features while the project progresses.

The command bin/steadychef actually calls on the start method located in lib/cli. Remember, we said bin is where the executables are housed and lib is where the code is stored for your user to interact with the program.

You can see that start calls on yet another method in another class, puts various strings, and has a conditional loop based on the input from the user. Let’s go over some of the other methods.

I won’t insult your Ruby proficiency by going over every line of code in detail, but as an overview, you can see that get_locationsinvokes allfrom Location which (as shown in the Location class) invokes scrape_locations from the Scraper class. This gathers all the available locations scraped from the CourseHorse culinary webpage. Following that, list_locations does just that; lists the locations to the user. This is why it is important to give your methods, arguments, classes, modules, etc. easy to understand names. Afterwards get_user_location invokes valid_user_input, and if chosen_location matches a value found in @locations, the courses available for that location will be shown. This then leads to another series of methods regarding courses and interacting with them.

I think I had a good time designing and developing this application, as I like cooking and think we could all do more to balance our diets and budgets, and it gives a larger sense of accomplishment when making something with your own hands. Learning to scrape information from websites was a bit more tedious than I originally thought, as it takes precision and multiple tries to get it right. Still, I think I have a better handling on object oriented relationships and mitigating the number of errors by implementing failsafes into my code.

Here is a video demo of my CLI application, steadychef, in action.

Here is the Github repo where you can fork down a copy of the app and test it out. I welcome any and all questions, comments, and concerns. I hope this helped you on your coding journey.

As always, remember to floss your teeth and stay hydrated.

--

--