DEV Community

Kiana
Kiana

Posted on • Edited on

A Simple CLI

For my first project in Flatiron Software Engineering program, I had to create a command line application in Ruby. My application would be bundled into a package known as gem. My CLI uses Nokogiri to scrape facts about plants from a website and allows the user to choose a number to display a random fact.
One of the main requirements for this projects was for a user to be able to go one level deep (a user can make a choice and based on that, make another selection and so on).

This being my first CLI I wanted to keep it as simple as possible to make sure I understood the flow of creating and developing the environment. After creating a repository on github(github has plenty of information and resources on this), I created a gem by following the walkthrough on https://guides.rubygems.org/make-your-own-gem/.

From there I ran bundler and connected my repo. In the gemspec file had to add development dependencies for bundler, rake, rspec, and pry, and a general dependency for nokogiri.
gemfile
gem "nokogiri"
gem "pry"
gem "rake", "~> 13.0"
gem "rspec", "~> 3.0"

gemspec
Gem::Specification.new do |spec|
spec.name = "plantfacts"

Even with so many ideas of creating different features, the ability to create the start of the interface was the most important foundation to understand. Making sure I was solid on setting up and creating my gem and scraping the exact information is where I wanted my focus. After all of this foundation laid there is the ability to add features, separate concerns and provide more interactive functions for this CLI.

I started with a basic flow diagram on the absolute minimum.

1.prompting a user with a question
2.receiving that input
3.doing something with that input

I decided to do a simple test of my ability to create a logical flow of the basic classes and methods I would be needing. These would just be objects calling on other objects in direct flow of events. The first being located in the bin folder under a file I created called plant.
bin/plant
require ./lib/plantfacts/cli.rb
Plantfacts::CLI.new.start

In this folder I am requiring my cli.rb file which holds my class with all my app logic defined in it.
cli.rb
class Plantfacts::CLI
end

Between these two files our connection for the logic of the app is made.
The :: operator allows constants, instance methods and class methods defined within a class or module, to be accessed from anywhere outside the class or module.
With this file I am also allowing the next event to happen,

cli.rb
require_relative '../plantfacts'
require_relative 'scraper'

Just these two lines of code are essential to operating.
The first line points to the environment holding all my files.
The second points directly to file of where my scraping is taking place, defining the .rb isn't necessary since the files its being called in is in the same folder. I still decided to separate this logic out so it was easier to work with in the future for debugging as I built out my project. Within this folder I had to give access to two very important things...
scraper.rb
require 'nokogiri'
require 'open-uri'

Nokogiri to be able to scrape the webpage of my choosing as well as 'open-uri' to directly call on the url.
This small amount of code wouldn't work without requiring them both.
scraper.rb
def facts
array=[]
doc = Nokogiri::HTML(URI.open("https://www.funfactsabout.net/plant-facts/"))
doc.css("ul.facts-list li").each do |list|
array.push(list.text)
end
return array
end

With the basics of my app environment flow set up I could start writing out exactly what I wanted to happen in my cli.
Thinking back to the flow of the user experience,
I wanted to prompt a user with a question(if they wanted to learn about plants)
receiving that input, which would then envoke a case statement deciding what to do with that input.
These functions were all defined within the plantfacts class.
cli.rb
def start
puts "Hi! do you like plants?[yes/no]:"
input=gets.strip
case input
when "no"
puts goodbye
when "yes"
puts plant
end
end

from there my 'goodbye' and 'plant' methods allow the user to continue on with their experience until they are ready to exit the app.

Although I don't intend to develop this basic cli any further or reuse the website/update the information later on, I wanted to execute good practices of creating re-able and re-usable code and understanding creating an environment within an app.

Top comments (0)