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.
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.
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.
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. 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.
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!
def self.destroy_all
@@all.clear #can also use @@all = []
end
Top comments (0)