GeckoAPI - My first Ruby program intereacting with the CoinGecko API

in GEMS4 years ago

This week has been project week for my bootcamp cohort. For our assignment we are to build a Ruby CLI Gem using Nokogiri to scrape HTML or an API.

I settled on the latter and decided to use CoinGecko's free cryptocurrency API. It provides data on the 100 largest crypto projects.

Below I will be briefly going over the process I went through to make this project work.

Getting Started

I started this project off using Bundle to provide a basic project structure/skeleton. It will generate the necessary files needed for creating a Ruby Gem by running bundle gem GEM_NAME

After generating my project skeleton, I filled out the necessary information in my gemspec file and began adding dependencies I knew I'd need. There are also some fields in the gemspec that must be filled out before running your bundle install command.

After the initial setup, I began to add files that I needed such as my binary, and class files. I also set up an environment file where I can include all my dependencies in one place. It is set up like this:

/gecko_api/bin/gecko_api

#!/usr/bin/env ruby
require_relative "../lib/gecko_api"

Controller.new.call

/gecko_api/lib/gecko_api.rb

require_relative "./gecko_api/version"
require_relative "./gecko_api/controller"
require_relative "./gecko_api/market"
require_relative "./gecko_api/concerns/repeatable"
require 'json'
require 'open-uri'
require 'pry'
require 'colorize'

This makes sure all of my requirements are called upon as soon as the program launches.

One of the more difficult aspects of this project happened when I unknowingly got myself stuck in an infinite loop.

I had two loops running inside of eachother that made them run forever. This happened due to the way my menu in my controller class was set up. Below is the correct working implementation.

controller.rb

def self.menu
    puts "Type 'top' to view the top 100 projects by market cap." 
    puts "Type a number 1-100 to view detailed information about a single asset."

    input = gets.chomp
    integer_input = input.to_i

    if integer_input > 0 and integer_input < 101
        Market.coin(input)
    else
        case input.to_s
            when "back"
                Controller.clear_term
                Market.top
            when "top"
                Market.new
                Market.top  
            when "update"
                Market.update
            else
                puts "Invalid command. Please try again!".colorize(:red)
                Controller.menu

        end 
    end
end

market.rb

def self.coin(number)
    puts "Searching"
    @@market.each do |coin|
        if coin.market_cap_rank.to_s == number
            id = coin.id
            data = JSON.parse(open(BASE_URL + id).read)
            Controller.clear_term
            if data["market_data"]["price_change_percentage_24h"] > 0
                print "#{data["name"].colorize(:red)} (#{data["symbol"].upcase.colorize(:red)}) " + "$".colorize(:green) + "#{data["market_data"]["current_price"]["usd"].to_s.colorize(:green)} - #{data["market_data"]["price_change_percentage_24h"].round(2).to_s.colorize(:green)}" + "%".colorize(:green)
            else
                print "#{data["name"].colorize(:red)} (#{data["symbol"].upcase.colorize(:red)}) " + "$".colorize(:green) + "#{data["market_data"]["current_price"]["usd"].to_s.colorize(:red)} - #{data["market_data"]["price_change_percentage_24h"].round(2).to_s.colorize(:red)}" + "%".colorize(:red)
            end

            # number formatting. making more human readable. outputs X.XXX Million/Billion
            if data["market_data"]["market_cap"]["usd"].digits.length > 11 
                mktcap = "Billion"
            else
                mktcap = "Million"
            end

            # formatting the marketcap number. taking the first 6 numbers of the string.
            puts " "
            puts "Total Market Cap: $#{data["market_data"]["market_cap"]["usd"].to_s[0..5].insert(-4, ".")} #{mktcap}"

            # project description formatting. removing HTML elements but keeps links within parentheses
            description = data["description"]["en"]
            puts description.gsub(/<[^"\\] href="/, '(').gsub(/["\\]>/, ') ').gsub(/<[^<\\]a>/, '')

        else
            print "."
        end
    end
    puts " "
    Controller.menu
end

I accidently had my Controller.menu method running inside of the @@@market iterator. This had me stumped for quite awhile, but it was eventually solved.

image.png

Conclusion

Overall, this project was a great learning experience.

The beginning seemed a bit overwhelming because I was having some issues with the bundle skeleton. But, once that was solved and I was able to finally get programming, things started coming together a lot more.

I noticed that drawing out a flow-chart or some kind of visual aid can really help in the programming process. This helped me a few times when I was stuck.

Looking forward to the Sinatra project next! Thanks for reading!

What was the hardest part about your first project?