rubyrefactoringdynamic-method

How to refactor instance methods using dynamic methods in Ruby?


I want to refactor this:

class Collection
  def artists
    @songs.map { |song| song.artist }.uniq
  end
  def albums
    @songs.map { |song| song.album }.uniq
  end
  def names
    @songs.map { |song| song.name }.uniq
  end
end

into something like this:

class Collection
  song_attributes = [:artist, :album, :name]
  song_attributes.each do |song_attribute|
    define_method song_attribute do
      @songs.map { |song| song.public_send(song_attribute) }.uniq
    end
  end
end

The problem is in line define_method song_attribute do where song_attribute must be pluralized. How do I do this?

I came up only with this, but I suppose there is a better way:

song_attributes = [[:artists, :artist], [:albums, :album], [:names, :name]]
song_attributes.each do |song_attribute|
  define_method song_attribute[0] do
    @songs.map { |song| song.public_send(song_attribute[1]) }.uniq
  end
end

Solution

  • Pass the string in define_method

    .....
    song_attributes = [:artist, :album, :name]
    
    song_attributes.each do |song_attribute|
      define_method("#{song_attribute}s") do
        @songs.map { |song| song.public_send(song_attribute) }.uniq
      end
    end
    .....