Wine Spectator's Top 100 Wines - Ruby CLI Project

For the first project in Flatiron School's Software Engineering Bootcamp, students are asked to build a Command Line Interface (CLI) to an external data source. The CLI should be composed of an Object Oriented Ruby application, and demonstrate knowledge gained during the Ruby Module of the program.
For my project, I scraped data from Wine Spectator's list of Top 100 Wines of 2020 and created an app that allows users to interact with the information provided.
PLAN
Being that this was my first full-scale project build, I spent a considerable amount of time in the planning phase. I studied the requirements, watched live build videos, and explored code from other projects to visualize how I wanted to structure my own.
REQUIREMENTS
  • Provide a CLI
  • CLI application must provide access to data from a web page
  • The data provided must go one level deep - where a user can make a choice and receive detailed information on their selection
  • Use strong Object Oriented design patterns - data should be stored in a collection of objects, not hashes
  • OUTLINE
    The goal of the Top 100 Wines CLI App is to output a numbered list of wines by rank, allow the user to select a wine that they're interested in, provide the details of that wine, and then either loop back to the list or exit the program based on user input.
    BUILD
    After creating the skeleton of my application (bin files, gemspec, environment, etc.), I focused on the structure and responsibilities of my Class files.
    SCRAPER CLASS
    The Scraper Class is responsible for scraping data from the Wine Spectator website.
    class TopWines::Scraper
    def self.scrape_wines
    doc = Nokogiri::HTML(open("https://top100.winespectator.com/lists/"))
    wine_block = doc.css("tbody tr")
    wine_block.each do |block|
    wine = TopWines::Wine.new
    wine.rank = block.css(".rank").text
    wine.winery = block.css("span.sort-text").text
    wine.name = block.css("div.table-name span.wineName").children[1].text.strip
    wine.vintage = block.css(".vintage").text
    wine.score = block.css(".score").text
    wine.price = block.css(".price").text
    wine.full_description = block.css("div.tabel-note").children[0].text.strip.chomp(' —')
    end
    end
    end
    view raw scraper hosted with ❤ by GitHub
    WINE CLASS
    The Wine Class is responsible for creating and storing wine objects.
    class TopWines::Wine
    attr_accessor :rank, :winery, :name, :vintage, :score, :price, :full_description
    @@all = []
    def initialize(rank = nil, winery = nil, name = nil, vintage = nil, score = nil, price = nil, full_description = nil)
    @rank = rank
    @winery = winery
    @name = name
    @vintage = vintage
    @score = score
    @price = price
    @full_description = full_description
    @@all << self
    end
    def self.all
    @@all
    end
    def self.find(id)
    self.all[id-1]
    end
    end
    view raw wine hosted with ❤ by GitHub
    CLI CLASS
    The CLI Class is responsible for all operational functionality. In addition to listing the wines numerically by rank, I implemented a method asking the user which group of wines they would like to view in intervals of 20. I also utilized the Colorize gem to add some visual depth to the program.
    class TopWines::CLI
    def call
    TopWines::Scraper.scrape_wines
    puts "\nWelcome to Wine Spectator's Top 100 Wines of 2020!".white.on_black
    @input = ""
    until @input == "exit"
    start
    select_wine
    next_move
    end
    end
    def start
    puts "\nPlease select the group of wines you would like to see: \n1-20 \n21-40 \n41-60 \n61-80 \n81-100".black.on_light_white
    input = gets.strip.to_i
    print_wines(input)
    select_wine
    next_move
    end
    def select_wine
    puts "\nPlease select the corresponding number of the wine of your choice for more details.".black.on_light_white
    input = gets.strip
    wine = TopWines::Wine.find(input.to_i)
    print_wine(wine)
    end
    def next_move
    puts "\nWould you like to view another wine? Enter Y or N".black.on_light_white
    @input = gets.strip.downcase
    if @input == "y"
    start
    elsif @input == "n"
    puts "\nCheers!".white.on_black
    exit
    elsif @input == "exit"
    puts "\nCheers!".white.on_black
    exit
    else
    puts "\nI'm not sure what you mean. Keep exploring wines, or type 'exit' to leave.".black.on_light_white
    next_move
    end
    end
    def print_wines(from_number)
    puts "\nWINES RANKED #{from_number} - #{from_number+19}".black.on_light_white
    TopWines::Wine.all[from_number-1, 20].each.with_index(from_number) do |wine, index|
    puts "\n#{index}. #{wine.winery} - #{wine.name}"
    end
    end
    def print_wine(wine)
    puts "\n#{wine.rank}. #{wine.winery.upcase} - #{wine.name.upcase}".black.on_light_white
    puts "RANK: #{wine.rank}"
    puts "WINERY: #{wine.winery}"
    puts "NAME: #{wine.name}"
    puts "VINTAGE: #{wine.vintage}"
    puts "SCORE: #{wine.score}"
    puts "PRICE: #{wine.price}"
    puts "FULL DESCRIPTION: #{wine.full_description}"
    end
    end
    view raw cli hosted with ❤ by GitHub
    EXECUTE
    The video below demos the app at runtime.
    [cover photo by Mathilde Langevin on Unsplash]

    27

    This website collects cookies to deliver better user experience

    Wine Spectator's Top 100 Wines - Ruby CLI Project