5 Replies - 1041 Views - Last Post: 05 March 2014 - 05:29 AM Rate Topic: -----

#1 heaphyg  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 85
  • Joined: 30-August 13

Trying to send a message to a Song object

Posted 04 March 2014 - 02:53 PM

I am trying to iterate through an array of Song objects on line 48 and call the title method on each of those Song objects. It seems to me according to the following error that I am calling #title on an array (which can't respond to this message.) I am confused as to why the title message isn't being sent to a particular Song object in the songs array. I am not trying to send the message to the Array class.

playl.rb:49:in `block in remove': undefined method `title' for #<Array:0x007fb93b0ac110> (NoMethodError)
	from playl.rb:48:in `each'
	from playl.rb:48:in `remove'
	from playl.rb:73:in `<main>'


class Song
	attr_accessor :title, :artist

	def initialize(title, artist) 
		@title = title
		@artist = artist
		playing = false
	end

	def play
		playing  = true
	end
end

class Playlist
	attr_accessor :songs   

	def initialize(*songs)
        @songs = songs    # Ultimately an array of Song objects created on line 65
	end

	def add(*song)
		songs.push(song)
	end

	def num_of_tracks
		songs.length 
	end

	def play
		playing  = true
	end

	def play_all
		songs.each { |song| song.play  }
	end

	def stop
	    playing = false
	end

	def display
		puts songs
	end

	def remove(name)
		name = name.to_s
		songs.each { |song|   # for each of the Song objects in our songs array do the following
			if name.capitalize == song.title.capitalize   #  #title is a message that Song objects should respond to.
				songs.delete(song)
			else
				nil
			end
		}
	end
end


#### Driver Code#### 
 
one_by_one = Song.new("One by One", "Sirenia")
world_so_cold = Song.new("World So Cold", "Three Days Grace") 
going_under = Song.new("Going Under", "Evanescence")
 
my_playlist = Playlist.new(one_by_one, world_so_cold, going_under)
 
lying_from_you = Song.new("Lying From You", "Linkin Park")
angels = Song.new("Angels", "Within Temptation")
 
my_playlist.add(lying_from_you, angels)
p my_playlist.num_of_tracks == 5
going_under.play
my_playlist.remove(angels)
p my_playlist.includes?(lying_from_you) == true
my_playlist.play_all
my_playlist.display
 


This post has been edited by xclite: 04 March 2014 - 02:55 PM
Reason for edit:: Fixing code tags.


Is This A Good Question/Topic? 0
  • +

Replies To: Trying to send a message to a Song object

#2 xclite  Icon User is offline

  • LIKE A BOSS
  • member icon


Reputation: 905
  • View blog
  • Posts: 3,167
  • Joined: 12-May 09

Re: Trying to send a message to a Song object

Posted 04 March 2014 - 02:57 PM

A couple of thoughts.

First, if I had to guess, I'd say that your splat operator on line 22 is causing your "add" method to add [song] instead of song. The arguments collected by splat are grouped into an array.
This makes your array look like:
[[song1], [song2], [song3]] while your code expects [song1, song2, song3]

Secondly, I don't like that you're iterating over songs and then removing things from the collection you're iterating over. It might be better to do:

def remove(name)
  songs.delete_if{|song| song.title.capitalize == name.capitalize}
end


This post has been edited by xclite: 04 March 2014 - 02:59 PM

Was This Post Helpful? 3
  • +
  • -

#3 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2113
  • View blog
  • Posts: 3,234
  • Joined: 21-June 11

Re: Trying to send a message to a Song object

Posted 04 March 2014 - 05:04 PM

View Postheaphyg, on 04 March 2014 - 10:53 PM, said:

			else
				nil
			end



That's not necessary. An if statement without else already returns nil when the condition is false.

View Postxclite, on 04 March 2014 - 10:57 PM, said:

Secondly, I don't like that you're iterating over songs and then removing things from the collection you're iterating over.


To expand on that: Deleting an item from an array while iterating over it does not work correctly. Deleting an item changes the index of the following items, which will cause the iteration to skip over the next item. This means that if you have two consecutive items that should be deleted, only one of them will be.
Was This Post Helpful? 2
  • +
  • -

#4 heaphyg  Icon User is offline

  • D.I.C Head

Reputation: 4
  • View blog
  • Posts: 85
  • Joined: 30-August 13

Re: Trying to send a message to a Song object

Posted 04 March 2014 - 07:11 PM

I have read that if statements should always have an else. So am I poorly implementing an if statement in this example? Should I consider a different approach?
Was This Post Helpful? 0
  • +
  • -

#5 Lemur  Icon User is offline

  • Pragmatism over Dogma
  • member icon


Reputation: 1368
  • View blog
  • Posts: 3,443
  • Joined: 28-November 09

Re: Trying to send a message to a Song object

Posted 04 March 2014 - 07:13 PM

View Postheaphyg, on 04 March 2014 - 08:11 PM, said:

I have read that if statements should always have an else. So am I poorly implementing an if statement in this example? Should I consider a different approach?


In another language maybe. Ruby, no.
Was This Post Helpful? 1
  • +
  • -

#6 sepp2k  Icon User is offline

  • D.I.C Lover
  • member icon

Reputation: 2113
  • View blog
  • Posts: 3,234
  • Joined: 21-June 11

Re: Trying to send a message to a Song object

Posted 05 March 2014 - 05:29 AM

View Postheaphyg, on 05 March 2014 - 03:11 AM, said:

I have read that if statements should always have an else. So am I poorly implementing an if statement in this example?


There is absolutely no reason to give an if an else if that else doesn't do anything.
Was This Post Helpful? 2
  • +
  • -

Page 1 of 1