Ruby:列出数组中的所有项目

时间:2017-11-01 10:27:47

标签: arrays ruby printing

我尝试过至少5种不同的方法,目前正在使用.each方法。

我认为问题在于代码块底部的print_songs方法。

我得到的错误:

Artist #print_songs lists all of the artist's songs
     Failure/Error: expect{artist.print_songs}.to output("Dirty Diana\nBillie Jean\n").to_stdout
       expected block to output "Dirty Diana\nBillie Jean\n" to stdout, but output "#<Song:0x000000019757b0>\n#<Song:0x000000019756e8>\n"
       Diff:
       @@ -1,3 +1,3 @@
       -Dirty Diana
       -Billie Jean
       +#<Song:0x000000019757b0>
       +#<Song:0x000000019756e8>

代码:

class Artist
  attr_accessor :name, :song
  @@all = []

  def initialize(name)
    @name = name
    @songs = []
  end

  def add_song(song)
    @songs << song
  end

  def songs
    @songs
  end

  def self.all
    @@all
  end

  def save
    self.class.all << self
  end

  def self.create_by_name(name)
    artist = Artist.new(name)
  end

  def self.find_or_create_by_name(name)
    artist_name = @@all.detect{|x| x.name == name}
    if artist_name == nil
      self.create_by_name(name)
    else
      artist_name
    end
  end

  def print_songs
    @songs.each{|song| puts song}
  end

end

歌曲课程:

class Song
  attr_accessor :name, :artist

  def initialize(name)
    @name = name
  end

  # def artist=(name)
  #   self.artist = Artist.new(name)
  # end

  def self.new_by_filename(file_name)
    file_name.basename("")
  end

end

答案:

def print_songs
  @songs.each{|song| puts song.name}
end

3 个答案:

答案 0 :(得分:2)

很明显,这首歌可能不是一个字符串,而是一种某种对象。向任何对象添加to_s方法,并且puts应该自动调用它,当然,您也可以手动调用to_s。

这是我为确认此行为所做的快速测试

irb(main):001:0> class Song
irb(main):002:1> def initialize(title)
irb(main):003:2> @title = title
irb(main):004:2> end
irb(main):005:1> end
=> :initialize
irb(main):006:0> s = Song.new "scarborough fair"
=> #<Song:0x0000000030bb78 @title="scarborough fair">
irb(main):007:0> puts s
#<Song:0x0000000030bb78>
=> nil
irb(main):008:0> class Song
irb(main):009:1> def to_s
irb(main):010:2> return @title
irb(main):011:2> end
irb(main):012:1> end
=> :to_s
irb(main):013:0> puts s
scarborough fair
=> nil
irb(main):014:0>

编辑:

但为什么会这样?

简而言之,当您创建一些自定义对象类时,如上例中的Song,Ruby不知道如何将其表示为字符串。默认的to_s方法只输出类和对象ID,这对于调试是可以的,但是如果有一些明显的方法将对象表示为字符串,就像{{1}的情况一样(人们希望song.to_s返回歌曲标题),必须覆盖默认的to_s方法,或者从另一个具有更合适的Song实现的类/模块中包含/继承。

答案 1 :(得分:0)

它正在按预期工作。让我们看看试试。你能发布你尝试过的测试用例吗?

a1 = Artist.create(name: 'Lana del re')
a1.add_song('Young and Beautiful')
a1.add_song('haunted')
a1.print_songs
["Young and Beautiful", "haunted"] #output assuming song as a String object 

答案 2 :(得分:0)

默认情况下,对to_s的调用会打印对象的类名称和对象ID的编码,如下所示:"#<Song:0x007f9fd16a0770>"。也就是说,您需要覆盖to_s类的Song方法:

class Song
  def initialize(title)
    @title = title
  end

  def to_s
    @title
  end
end

然后,您需要在现有print_songs类上相应地修改Artist方法:

def print_songs
  puts @songs.each(&:to_s)
end

each(&:to_s)位基本上调用传递给块的每个to_s对象的Song方法,这与

基本相同
def print_songs
  puts @songs.each { |song| song.to_s }
end

这可能也被重写为

def print_songs
  puts @songs
end

在这种情况下,puts会隐式调用to_s元素的@songs方法。