My Ruby CLI Application — Learning to work with APIs and Metaprogamming (Jan 2020)

Harry Wilson
4 min readJul 13, 2020

--

This week I completed my first project, a Ruby CLI Application. I wanted to create something which I would personally use as I knew this would drive me to work harder on implementing new features and completing the application in a timely manner. I have created an NBA Fantasy Basketball application which gives the user access to biographical and fantasy draft information on all current NBA players as well as some basic information on NBA teams. My hope is that this app will improve people’s ability to draft great fantasy basketball teams.

This week was also the first time I learned the power of APIs. An API is a set of functions and procedures which allows you to create powerful applications which have access to large amounts of data stored in another application or operating system. There are thousands of APIs, some free, some rather expensive and when it comes to the code required to gain access to the data, the number of lines ranges massively. The API I chose comes from the fantastic website https://www.fantasybasketballnerd.com/ and is completely free to use and requires no key. A key is a unique set of characters given to you (normally) upon registration to the website and is used when making your API call.

In my API class I used a gem called HTTParty to access the data from this website and I then stored the result of this method in a variable. The variable contains an array of over 500 hashes, each hash containing information on each individual NBA Player.

def get_player
doc = HTTParty.get(“https://www.fantasybasketballnerd.com/service/players")
players = doc[“FantasyBasketballNerd”][“Player”]
end

When the user inputted that they would like to learn more information about a player. I would iterate over this collection and for each hash within this array (which represented an NBA player) I would send this to my Player class and create an instance of that class.

player_generator = FantasyNBA::API.new.get_player 
player_generator.each do |player|
FantasyNBA::Player.new(player)

The advantages of creating all the players at once means that I could store them within my application and when a user asks for another player, I do not need to make unnecessary additional API calls. This vastly speeds up my application as API calls (as they are calling on an external source of data) naturally take longer than finding something within your application.

So how exactly did I take the data found in each player’s hash and turn it into an instance of a player class. Some clean metaprogramming, that’s how! When iterating over the player_generator variable stored above, each |player| was formatted as follows:

{“playerId”=>”2", “name”=>”Avery Bradley”, “team”=>”LAL”, “position”=>”SG”, “height”=>”6–2", “weight”=>”180", “dob”=>”1969–12–31", “school”=>”Texas”}

Each of these hashes (and there were around 550) is then sent to my initialize method in the Player class to be magically (not really) transformed into an instance of my Player class. In the initialize method, which takes in a hash as an argument, I passed a key and a value into my block, allowing me to iterate over each key/value pair in the hash. For each key that I want to have as an attribute for my player, I created an attribute accessor. I then use the .send method which allows me to call a method even though I won’t know it’s name until runtime and use it on the recipient, in this case self which here is the specific instance of my class. I pass that method two arguments, one is the key= setter and then the value will be what I want that key to be assigned to.

attr_accessor :name, :team, :position, :height, :weight, :school, :rankPos, :rankOverall@@all = []def initialize(player_hash)
player_hash.each do |key, value|
begin
self.send(“#{key}=”, value)
rescue
end
end
@@all << self
end

My method therefore goes through each key in the hash and if there is an attr_accessor for that key, it will assign the value found in the hash to that attribute of my player. The begin rescue block is there so that when it finds an attribute in the hash which isn’t an attr_accessor, it will simply pass over it and move onto the next key/value pair. For example, the date of birth key/value pairs in this dataset were not filled out correctly, so I chose to ignore those and not assign them to my players. At the end of this method all instances of my player class are stored in my @@all class variable and this allows me to easily access them using a find_by_name class method in my player class. This drastically speeds up my application after the search of an initial player.

I use the exact same method for accessing, creating and storing information about NBA teams and I also have a third API call to add two extra pieces of information to my player instances using a slightly different url in an API call which gives me fantasy ranking information on NBA players.

Overall, learning about the powerful combination of API calls and metaprogramming to speed up my application as well as create an incredibly clean and streamlined process has been fascinating. I’ve only just begun my journey with Flatiron and I’m excited to see what powerful tools we will be looking at next!

--

--