DEV Community

Dorthy Thielsen
Dorthy Thielsen

Posted on

Learning OO Ruby class variables

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.

class Song

  @@count=0
  @@genres=[]
  @@artists=[] 
Enter fullscreen mode Exit fullscreen mode

@@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.

  attr_accessor :name, :artist, :genre

  def initialize(name, artist, genre)
    @name = name
    @artist = artist
    @genre = genre
    @@count += 1
    @@genres << genre
    @@artists << artist
  end
Enter fullscreen mode Exit fullscreen mode

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.

  def self.count
    @@count
  end

  def self.genres
    @@genres.uniq
  end

  def self.artists
    @@artists.uniq
  end
Enter fullscreen mode Exit fullscreen mode

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.

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
Enter fullscreen mode Exit fullscreen mode

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.

Top comments (0)