Learning Ruby "Advanced" Class Methods
Tags: beginners, ruby, oop
Published: 2021-05-21 17:38:35

For the last few days I have been learning about "advanced" class methods in Ruby. I am not sure if they are that advanced by a professional's standards but to me they are advanced in comparison. Basically I am learning about class constructors, self, finders, constants, class variables, etc. 

The lab I have been working on is to prep me for the big CLI music library final project in Ruby. The assignment is to create class methods to interact with class data regarding creating, finding, and storing song data including the artist name, song name, and the filename. I was given this block of code to begin with.
```ruby
class Song
  attr_accessor :name, :artist_name
  @@all = []

  def self.all
    @@all
  end

  def save
    self.class.all << self
  end
```
I was already given my reader and writer methods for song name and artist name. I was also given my empty array that these items would be stored in and a method to save them into the array. 

My first task was to create three methods that would instantiate songs using a class method instead of the previously used instance method initialize so I could have more flexibility in my program. I was told to initialize the song, save the song and/or set the name property, and then return the song. For the whole lab, I was also told to try and call on my other class methods so my code wouldn't be repetitive and not abstract. 
```ruby
  def self.create
    song = Song.new #initialize a song
    song.save #save the song using the save method
    song #return the song
  end
  
  def self.new_by_name(name)
    song = self.new #initialize a song
    song.name=name #set the name to the name property
    song #return the song
  end
  
  def self.create_by_name(name)
     song = self.create #using the create method from above 
     song.name = name #set the name to the name property
     song #return the song
  end
```
Also you can see that I have been doing more pseudocode so I am able to code more efficiently and know what steps I need to take. I have removed the rest of my pseudocode in the rest of my code so it is easier to read, but wanted to show that improvement.  

Then it was time to build some finder methods. Including one that tripped up me and the technical coaches at Flatiron. For some reason since I had created a blank method later on in the code, it was causing my tests to fail and no one knows why. Anyways, I learned that instead of building complex methods that do multiple things, it is smarter to branch complex methods into smaller chunks. Then you can call on those methods to do larger things in another method, like the `self.find_or_create_by_name` method below. Which in that method if the song is found in `self.find_by_name` then return the name if not, `self.create` the song. In the `self.find_by_name` method, I wanted to use a finder method on self.all(the array method from above) to find a song and return the song. Then to sort the array alphabetically using the sort_by method. I first wrote the code `@@all.sort {|a, b| a <=> b}` which also works but I was asked to use the sort_by method.   
```ruby
  def self.find_by_name(name) 
    self.all.find{|song| song.name == name} 
  end
  
  def self.find_or_create_by_name(name)
     self.find_by_name(name) || self.create_by_name(name) 
   end
 
  def self.alphabetical
    @@all.sort_by {|song| song.name} 
  end
```
The next challenge was what to do with a filename string like "Taylor Swift - Blank Space.mp3". I wanted to separate the artist from the song name and get rid of the .mp3. First part was easy. I just need to use the split method and split it at the "-". Getting rid of the .mp3 was something foreign to me. I was looking at everything you can do with enumerables and came across the .gsub method. I highly recommended this [article](https://www.rubyguides.com/2019/07/ruby-gsub-method/). I used this method to get rid of the pesky .mp3 and substitute in an empty string. Then set the value of the artist name and returned the song. 
```ruby
  def self.new_from_filename(filename)
    artist_name, song_name = filename.split(" - ") 
    song = self.new_by_name(song_name.gsub(".mp3", "")) 
    song.artist_name = artist_name 
    song 
  end

  def self.create_from_filename(filename)
    song = self.new_from_filename(filename) 
    song.save 
    song 
  end
```
Finally to destroy everything! 
```ruby
  def self.destroy_all
    @@all.clear #can also use @@all = []
  end 
```