Learning OO Ruby class variables
Tags: ruby, oop, beginners
Published: 2021-05-19 22:57:13

Today I learned about `@@class_variables` which are accessible to the entire class.  For the assignment to help me learn this, I was given the task to create the class Song and keep track of the name, artist, genre, and counts all song instances. 

First things first, creating the class and creating my class variables which would hold all the data about all the instances.
```ruby
class Song
  
  @@count=0
  @@genres=[]
  @@artists=[] 
```
`@@count` is going to be used to create a counter for everytime a song instance is born. `@@genres` is going to house all of the genres in this now empty array. Keep in mind that this will be storing duplicates if there is more than one song in each genre. `@@artists` is going to store all of the artists just like `@@genres`. 

Now to create the variables/attributes that all the song will be born with. Which means using my favorite `attr_acessor`. Then creating the initialize method that will run on creation of each instance to give it all the attributes required. This includes pushing data into the previously created arrays and assigning instance variables.
```ruby 
  attr_accessor :name, :artist, :genre

  def initialize(name, artist, genre)
    @name = name
    @artist = artist
    @genre = genre
    @@count += 1
    @@genres << genre
    @@artists << artist
  end
```   
With all of this I also learned about self, which just means referring to the class. It is pretty self explanatory...yes, time to roll your eyes at my lame joke. Now the task is to create class methods that will allow me to access the class variables outside of the method. Also to create unique arrays of the artist and genre arrays so there are no repeats using the handy `.uniq`. I first made the mistake of using the bang operator and then remembered that I don't want to change my array because I need both arrays for one of the later tasks. 
```ruby
  def self.count
    @@count
  end
  
  def self.genres
    @@genres.uniq
  end
  
  def self.artists
    @@artists.uniq
  end
```
Everything was going great up until now. No major issues and then the last task threw me off and it took me a long time to figure it out. The last task was to return a hash with the keys set to the genres and artists and the values to be the count of each. Ex. `{"rap" => 3, "pop" => 5, "metal" => 1}`. I knew the first thing was to create an empty array and I would need to return the array. I also knew that I needed to do some iterating. Great... but the rest was lost to me. 
```ruby
def self.genre_count
    genre_hash= {}
    
    self.genres.each do |genre| 
      genre_hash[genre] = @@genres.count{|g| g == genre} 
    end
     
     genre_hash
  end
  
  def self.artist_count
    artist_hash={}
    
    self.artists.each do |artist|
      artist_hash[artist] = @@artists.count{|a| a == artist}
    end
    
    artist_hash
  end
end
```
The solution was to iterate through the `self.genres` aka the unique array of genres. Then set the key in the hash equal to genre via `genre_hash[genre]`. Now to set the value which is a count. As I mentioned earlier, I initially still had the bang operator in my `self.genres` method. Which meant there was nothing to count. Once I fixed that then it became clearer to use the initial `@@genres` array that had the duplicates and `.count`. The great thing about `.count` that I didn't know before was that it could take a block of code. In the block of code I set a local variable of `|g|` as to not overwrite the genre variable. I set `g == genre`. For every time this returns true, the count will increase! How cool is that? Then I just applied the same thing to artist and viola! Lab was passed.