Skip to main content
3 of 4
Formatting
Flambino
  • 33.3k
  • 2
  • 46
  • 90

Creating a Wrapper for CSV Data

I am trying to complete a Ruby coding exercise. The specifics of the excercise can be found on a the level_up_exercises GitHub repo. This repo also contains the CSV file used in the exercise.

I would like you to comment on how well you think I met the requirements with the exception of

  1. loading the African dinosaur data
  2. exporting the data to JSON (the reason I have not completed these is because I am pretty sure I can do the first one, and I need to do further homework before I can do the second one)

I have put my code below, but I think a run-down of how it works might make it easier for you to comment on the code.

First, I created a Dinosaur class. Most of the attributes are readable (except for the @period instance variable). I've created a custom Dinosaur#to_s method in order to print the dinosaur object. I've also created Dinosaur#carnivorous, Dinosaur#big, and Dinosaur#small. These methods return Booleans, but I didn't name them with an ending "?" for reasons that might be clear in the implementation of the filter method.

Secondly, I created a Dinodex class. This class holds Dinosaur objects in an array. Because the internal data structure is an array, I've defined Dinodex#<<(Dinosaur). Dinodex#to_s merely aggregates the strings returned calls to Dinosaur#to_s, for all the dinosaurs in the dinodex.

The interesting part about the Dinodex (or at least the one I had the most trouble with), is the Dinodex#filter method. The Dinodex#filter method takes an options hash, where (ideally) the keys are attributes of the Dinosaur class, and the values are what the user is selecting for.

NOTE: I am just realizing now that I am writing this out that the else branch in the Dinodex#filter method that I should check if param is valid. I would do this by using the respond_to?(param) method.

I had a tough time figuring out how to make the Dinodex#filters method recursive, until I realized I can just update what the local variable selection points to. Once the right dinosaurs have been selected, a new Dinodex object is returned, so that chaining is possible.

require 'csv'

class Dinosaur
  attr_reader :name, :continent, :diet, :weight, :locomotion, :description

  def initialize(name, period, continent, diet, weight, locomotion, description)
    @name = name
    @period = period
    @continent = continent
    @diet = diet
    @weight = weight
    @locomotion = locomotion
    @description = description
  end

  def carnivorous
    carnivorous = ["Yes", "Carnivore", "Insectivore", "Piscivore"]
    carnivorous.include?(@diet)
  end

  def period(timespan)
    @period.downcase.include?(timespan.downcase)
  end

  def big
    (@weight > 2000 ? true : false) if @weight
  end

  def small
    not big
  end

  def to_s
    justification = 15

    representation = ''

    representation << "-" * 30 + "\n"
    representation << "Name:".ljust(justification) + "#{@name}\n" if @name
    representation << "Period:".ljust(justification) + "#{@period}\n" if @period
    representation << "Continent:".ljust(justification) + "#{@continent}\n" if @continent
    representation << "Diet:".ljust(justification) + "#{@diet}\n" if @diet
    representation << "Weight:".ljust(justification) + "#{@weight}\n" if @weight
    representation << "Locomotion:".ljust(justification) + "#{@locomotion}\n" if @locomotion
    representation << "Description:".ljust(justification) + "#{@description}\n" if @description

    representation
  end
end

class Dinodex
  def initialize(dinosaurs = [])
    @dinosaurs = dinosaurs
  end

  def <<(dino)
    @dinosaurs << dino
  end

  def filter(options = {})
    selection = @dinosaurs

    options.each do |param, value|
      case param
      when "period"
        selection = selection.select { |dino| dino.send(param, value) }
      when "big"
        selection = selection.select { |dino| dino.big }
      when "small"
        selection = selection.select { |dino| dino.small }
      when "carnivore"
        selection = selection.select { |dino| dino.carnivore }
      else
        selection = selection.select { |dino| dino.send(param) == value }
      end
    end

    Dinodex.new(selection)
  end

  private

  def to_s
    string_rep = ''

    @dinosaurs.each do |dino|
      string_rep << dino.to_s
    end

    string_rep << "-" * 30

    string_rep
  end
end


# Load Data Into dinodex

dinodex = Dinodex.new

OPTIONS = { :headers => true, :converters => :all }

CSV.foreach("dinodex.csv", OPTIONS) do |row|
  name = row["NAME"]
  period = row["PERIOD"]
  continent = row["CONTINENT"]
  diet = row["DIET"]
  weight =  row["WEIGHT_IN_LBS"]
  locomotion = row["WALKING"]
  description = row["DESCRIPTION"]

  dinodex << Dinosaur.new(name, period, continent, diet, weight, locomotion,
                          description)
end

puts dinodex.filter({ "period" => "Late"})
Steven L.
  • 425
  • 2
  • 8