jimmy_jukebox 0.4.2 → 0.4.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,48 +1,69 @@
1
1
  module Artists
2
2
 
3
- JAZZ_ARTISTS = {
4
- :acb => "archibald_camp_banjo",
5
- :at => "art_tatum",
6
- :as => "artie_shaw",
7
- :bg => "benny_goodman",
8
- :bh => "billie_holiday",
9
- :bb => "bix_beiderbecke",
10
- :bm => "bennie_moten",
11
- :cc => "charlie_christian",
12
- :cp => "charlie_parker",
13
- :ch => "coleman_hawkins",
14
- :chjb => "clifford_hayes_jug_blowers",
15
- :cb => "count_basie",
16
- :dx => "dixieland",
17
- :dg => "dizzy_gillespie",
18
- :dr => "django_reinhardt",
19
- :de => "duke_ellington",
20
- :eh => "earl_hines",
21
- :fh => "fletcher_henderson",
22
- :jj => "james_p_johnson",
23
- :jrm => "jelly_roll_morton",
24
- :ko => "king_oliver",
25
- :la => "louis_armstrong",
26
- :lh => "lionel_hampton",
27
- :md => "miles_davis",
28
- :odjb => "original_dixieland_jazz_band",
29
- :rt => "ragtime",
30
- :rn => "red_norvo",
31
- :sb => "sidney_bechet"
3
+ ARTISTS = {
4
+ acb: { genre: 'BANJO', name: "archibald_camp_banjo" },
5
+ at: { genre: 'JAZZ', name: "art_tatum" },
6
+ as: { genre: 'JAZZ', name: "artie_shaw"},
7
+ bg: { genre: 'JAZZ', name: "benny_goodman"},
8
+ bh: { genre: 'JAZZ', name: "billie_holiday"},
9
+ bb: { genre: 'JAZZ', name: "bix_beiderbecke"},
10
+ bm: { genre: 'JAZZ', name: "bennie_moten"},
11
+ cc: { genre: 'JAZZ', name: "charlie_christian"},
12
+ cp: { genre: 'JAZZ', name: "charlie_parker"},
13
+ ch: { genre: 'JAZZ', name: "coleman_hawkins"},
14
+ chjb: { genre: 'JAZZ', name: "clifford_hayes_jug_blowers"},
15
+ cb: { genre: 'JAZZ', name: "count_basie"},
16
+ dx: { genre: 'JAZZ', name: "dixieland"},
17
+ dg: { genre: 'JAZZ', name: "dizzy_gillespie"},
18
+ dr: { genre: 'JAZZ', name: "django_reinhardt"},
19
+ de: { genre: 'JAZZ', name: "duke_ellington"},
20
+ eh: { genre: 'JAZZ', name: "earl_hines"},
21
+ fh: { genre: 'JAZZ', name: "fletcher_henderson"},
22
+ jj: { genre: 'JAZZ', name: "james_p_johnson"},
23
+ jrm: { genre: 'JAZZ', name: "jelly_roll_morton"},
24
+ ko: { genre: 'JAZZ', name: "king_oliver"},
25
+ la: { genre: 'JAZZ', name: "louis_armstrong"},
26
+ lh: { genre: 'JAZZ', name: "lionel_hampton"},
27
+ lvb: { genre: 'CLASSICAL', name: "beethoven"},
28
+ md: { genre: 'JAZZ', name: "miles_davis"},
29
+ odjb: { genre: 'JAZZ', name: "original_dixieland_jazz_band"},
30
+ rt: { genre: 'JAZZ', name: "ragtime"},
31
+ rn: { genre: 'JAZZ', name: "red_norvo"},
32
+ sb: { genre: 'JAZZ', name: "sidney_bechet"}
32
33
  }
33
34
 
34
- def key_to_subdir_name(key)
35
- value_to_subdir_name(JAZZ_ARTISTS[key.to_sym])
35
+ def artist_genre(key)
36
+ ARTISTS[key][:genre]
36
37
  end
37
38
 
38
- def value_to_subdir_name(value)
39
- return '/JAZZ/' + value.to_s.capitalize unless value.to_s.match(/_/)
40
- '/JAZZ/' + value.to_s.split("_").map! { |name_component| name_component.capitalize }.join("_")
39
+ def artist_name(key)
40
+ ARTISTS[key][:name]
41
41
  end
42
42
 
43
- def value_to_yaml_file(value)
44
- return value.to_s.capitalize + '.yml' unless value.to_s.match(/_/)
45
- value.to_s.split("_").map! { |name_component| name_component.capitalize }.join("") + '.yml'
43
+ def artist_name_to_genre(name)
44
+ p "looking for #{name}"
45
+ artists = ARTISTS.select { |k,v| v[:name] == name }
46
+ p artists
47
+ key, value = artists.first
48
+ value[:genre]
49
+ end
50
+
51
+ def artist_name_to_subdir_name(name)
52
+ return "/#{artist_name_to_genre(name)}/" + name.to_s.capitalize unless name.to_s.match(/_/)
53
+ "/#{artist_name_to_genre(name)}/" + name.to_s.split("_").map! { |name_component| name_component.capitalize }.join("_")
54
+ end
55
+
56
+ def artist_key_to_subdir_name(key)
57
+ artist_name_to_subdir_name(artist_name(key))
58
+ end
59
+
60
+ def artist_key_to_yaml_file(key)
61
+ artist_name_to_yaml_file(artist_name(key))
62
+ end
63
+
64
+ def artist_name_to_yaml_file(name)
65
+ return name.to_s.capitalize + '.yml' unless name.to_s.match(/_/)
66
+ name.to_s.split("_").map! { |name_component| name_component.capitalize }.join("") + '.yml'
46
67
  end
47
68
 
48
69
  end
@@ -4,6 +4,7 @@ module JimmyJukebox
4
4
 
5
5
  class Jukebox
6
6
 
7
+ class NoSongsException < Exception; end
7
8
  class NoNewSongException < Exception; end
8
9
  class NoCurrentSongException < Exception; end
9
10
  class NoPreviousSongException < Exception; end
@@ -14,6 +15,7 @@ module JimmyJukebox
14
15
  def initialize(new_user_config = UserConfig.new, continuous_play = true)
15
16
  self.user_config = new_user_config
16
17
  self.continuous_play = continuous_play
18
+ raise NoSongsException if songs.empty?
17
19
  end
18
20
 
19
21
  def play_loop
@@ -121,7 +123,7 @@ module JimmyJukebox
121
123
  self.songs_played << song
122
124
  current_song.play(user_config, self)
123
125
  p "Finished playing"
124
- p "Songs played: " + songs_played.to_s
126
+ #p "Songs played: " + songs_played.to_s
125
127
  self.current_song = nil
126
128
  self.playing = false
127
129
  rescue Song::SongTerminatedPrematurelyException
@@ -22,6 +22,9 @@ def invalid_artist
22
22
  end
23
23
 
24
24
  no_argv0 unless ARGV[0]
25
- invalid_artist unless JAZZ_ARTISTS.has_key?(ARGV[0].to_sym)
26
- JimmyJukebox::SongLoader.send(JAZZ_ARTISTS[ARGV[0].to_sym])
27
25
 
26
+ if ARTISTS.has_key?(ARGV[0].to_sym)
27
+ JimmyJukebox::SongLoader.send(ARTISTS[ARGV[0].to_sym][:name])
28
+ else
29
+ invalid_artist
30
+ end
@@ -94,6 +94,23 @@ module JimmyJukebox
94
94
  end
95
95
  end
96
96
 
97
+ def spawn_method
98
+ if $running_jruby
99
+ lambda { |command, arg| Spoon.spawnp(command, arg) }
100
+ else
101
+ begin
102
+ lambda { |command, arg| POSIX::Spawn::spawn(command + ' ' + arg) }
103
+
104
+ # posix/spawn is much faster than fork-exec
105
+ #pid = Process.fork do
106
+ # exec(command + ' ' + arg)
107
+ #end
108
+ rescue NotImplementedError
109
+ raise CannotSpawnProcessException, "*** Cannot play music because we found neither Spoon.spawnp (for JRuby) nor Process.fork (for MRI) ***"
110
+ end
111
+ end
112
+ end
113
+
97
114
  def play(user_config, jukebox)
98
115
  set_player(user_config)
99
116
  process_status = play_with_player
@@ -114,21 +131,7 @@ module JimmyJukebox
114
131
 
115
132
  def run_command(command, arg)
116
133
  # make system call and get pid so you can pause/terminate process
117
- if $running_jruby
118
- pid = Spoon.spawnp(command,arg)
119
- else
120
- begin
121
- pid = POSIX::Spawn::spawn(command + ' ' + arg)
122
-
123
- # posix/spawn is much faster than fork-exec
124
- #pid = Process.fork do
125
- # exec(command + ' ' + arg)
126
- # exit! 127 # should never be reached
127
- #end
128
- rescue NotImplementedError
129
- raise CannotSpawnProcessException, "*** Cannot play music because we found neither Spoon.spawnp (for JRuby) nor Process.fork (for MRI) ***"
130
- end
131
- end
134
+ pid = spawn_method.call(command, arg)
132
135
  self.playing_pid = pid
133
136
  end
134
137
 
@@ -27,14 +27,14 @@ module JimmyJukebox
27
27
  def self.define_artist(name,user_config)
28
28
  metaclass.instance_eval do
29
29
  define_method(name) do
30
- save_dir = user_config.default_music_dir + value_to_subdir_name(name)
31
- songs = YAML::load_file(File.dirname(__FILE__) + "/songs/#{value_to_yaml_file(name)}")
30
+ save_dir = user_config.default_music_dir + artist_name_to_subdir_name(name.to_s)
31
+ songs = YAML::load_file(File.dirname(__FILE__) + "/songs/#{artist_name_to_yaml_file(name.to_s)}")
32
32
  download_songs(songs, save_dir)
33
33
  end
34
34
  end
35
35
  end
36
36
 
37
- JAZZ_ARTISTS.values.each { |v| define_artist v.to_sym, @user_config }
37
+ ARTISTS.values.each { |artist| define_artist artist[:name].to_sym, @user_config }
38
38
 
39
39
  def self.sample(num_songs)
40
40
  # create array of all possible songs
@@ -80,14 +80,24 @@ module JimmyJukebox
80
80
  end
81
81
  end
82
82
 
83
- def self.download_song(song_url, save_dir)
84
- song_savename = File.basename(song_url)
85
- if version_of_song_in_any_dir?(song_savename, save_dir)
86
- puts "#{song_savename} already exists in #{save_dir}"
87
- return
83
+ def self.song_savename(song_url)
84
+ File.basename(song_url)
85
+ end
86
+
87
+ def self.song_already_exists?(savename, save_dir)
88
+ if version_of_song_in_any_dir?(savename, save_dir)
89
+ puts "#{savename} already exists in #{save_dir}"
90
+ true
91
+ else
92
+ false
88
93
  end
89
- puts "Downloading #{song_savename}"
90
- song_pathname = File.join(save_dir,song_savename)
94
+ end
95
+
96
+ def self.download_song(song_url, save_dir)
97
+ savename = song_savename(song_url)
98
+ return if song_already_exists?(savename, save_dir)
99
+ puts "Downloading #{savename}"
100
+ song_pathname = File.join(save_dir, savename)
91
101
  open(song_pathname, 'wb') do |dst|
92
102
  open(song_url) do |src|
93
103
  dst.write(src.read)
@@ -97,7 +107,7 @@ module JimmyJukebox
97
107
  rescue OpenURI::HTTPError
98
108
  p "Warning: Could not download #{song_url}"
99
109
  File.delete(song_pathname) if File.exists?(song_pathname)
100
- return nil
110
+ nil
101
111
  end
102
112
 
103
113
  def self.check_downloaded_song_size(song_pathname)
@@ -0,0 +1,51 @@
1
+ ---
2
+ - http://archive.org/download/BeethovenSymphonyNo.1/1.mp3
3
+ - http://archive.org/download/BBCSymphony2Beethoven/symphony2_beethoven_radio3.mp3
4
+ - http://archive.org/download/bbcSymphony3Beethoven_2/symphony3_beethoven_radio3.mp3
5
+ - http://archive.org/download/BeethovenSymphonyNo.3walter/I.AllegroConBrio.mp3
6
+ - http://archive.org/download/BeethovenSymphonyNo.3walter/Ii.MarciaFunebreAdagioAssai.mp3
7
+ - http://archive.org/download/BeethovenSymphonyNo.3walter/Iii.Scherzo-AllegroVivaceTrio.mp3
8
+ - http://archive.org/download/BeethovenSymphonyNo.3walter/Iv.Finale-AllegroMoltoPocoAndante.mp3
9
+ - http://archive.org/download/BeethovenSymphonyNo.4/I.Adagio_AllegroVivace.mp3
10
+ - http://archive.org/download/BeethovenSymphonyNo.4/Ii.Adagio.mp3
11
+ - http://archive.org/download/BeethovenSymphonyNo.4/Iii.Scherzo-AllegroVivace_Trio-UnPocoMenoAllegro.mp3
12
+ - http://archive.org/download/BeethovenSymphonyNo.4/Iv.AllegroMaNonTroppo.mp3
13
+ - http://archive.org/download/Beethovens5th/01SymphonyNo.5InCMinor.mp3
14
+ - http://archive.org/download/BeethovenSymphonyNo.5/ToscaniniBeethoven5.mp3
15
+ - http://archive.org/download/BBCSymphony6Beethoven/symphony6_beethoven_radio3.mp3
16
+ - http://archive.org/download/BeethovenSymphonyNo.7-ormandy/I.PocoSostenutoVivace.mp3
17
+ - http://archive.org/download/BeethovenSymphonyNo.7-ormandy/Ii.Allegretto.mp3
18
+ - http://archive.org/download/BeethovenSymphonyNo.7-ormandy/Iii.Presto.mp3
19
+ - http://archive.org/download/BeethovenSymphonyNo.7-ormandy/Iv.AllegroConMoto.mp3
20
+ - http://archive.org/download/BBCSymphony8Beethoven/symphony8_beethoven_radio3.mp3
21
+ - http://archive.org/download/BeethovenSymphonyNo.8/01.allegroVivaceEConBrio.mp3
22
+ - http://archive.org/download/BeethovenSymphonyNo.8/02.scherzandoAllegretto.mp3
23
+ - http://archive.org/download/BeethovenSymphonyNo.8/03.tempoDiMenuetto.mp3
24
+ - http://archive.org/download/BeethovenSymphonyNo.8/04.allegroVivace.mp3
25
+ - http://archive.org/download/BeethovenViolinConcertoheifetz/I.AllegroMaNonTroppo.mp3
26
+ - http://archive.org/download/BeethovenViolinConcertoheifetz/Ii.Larghetto.mp3
27
+ - http://archive.org/download/BeethovenViolinConcertoheifetz/Iii.Rondoallegro.mp3
28
+ - http://archive.org/download/BeethovenViolinConcerto-Szigeti/01I.AllegroMaNonTroppo.mp3
29
+ - http://archive.org/download/BeethovenViolinConcerto-Szigeti/02Ii.LarghettoIii.Rondo.mp3
30
+ - http://archive.org/download/BeethovenFrElise-Schnabel/Beethoven-FrEliseWoo59.mp3
31
+ - http://archive.org/download/BeethovenRondoInG/Beethoven-RondoInGMajor.mp3
32
+ - http://archive.org/download/BeethovenElevenVienneseDances/Beethoven-ElevenVienneseDancesWoo17.mp3
33
+ - http://archive.org/download/BeethovenCoriolanOverture/Beethoven-CoriolonOverture.mp3
34
+ - http://archive.org/download/MoonlightSonata_755/Beethoven-MoonlightSonata.mp3
35
+ - http://archive.org/download/BeethovenPianoSonataNo.2/BeethovenSonata2.ogg
36
+ - http://archive.org/download/BeethovenPianoSonataNo.3/BeethovenSonata3.ogg
37
+ - http://archive.org/download/BeethovenPianoSonataNo.6/BeethovenSonata6.mp3
38
+ - http://archive.org/download/BeethovenPianoSonata13/BeethovenPianoSonata13.mp3
39
+ - http://archive.org/download/BeethovenPianoSonata15/BeethovenPianoSonata15.mp3
40
+ - http://archive.org/download/BeethovenPianoSonata16/BeethovenPianoSonata16.mp3
41
+ - http://archive.org/download/BeethovenPianoSonata17/BeethovenPianoSonata17.mp3
42
+ - http://archive.org/download/BeethovenPianoSonata22/BeethovenPianoSonata22.mp3
43
+ - http://archive.org/download/BeethovenPianoSonataNo.25/BeethovenPianoSonata25.mp3
44
+ - http://archive.org/download/BeethovenSonata31Opus110/KatieAconeBeethovenSonata31Opus110.mp3
45
+ - http://archive.org/download/BeethovenTripleConcerto/01I.Allegro.mp3
46
+ - http://archive.org/download/BeethovenTripleConcerto/02Ii.LargoIii.RondoAllaPolacca.mp3
47
+ - http://archive.org/download/BeethovenTrioOp.11-Adagio/BeethovenTrio.mp3
48
+ - http://archive.org/download/GlennGould-BeethovenPianoSonatas/01-Beethoven-SonataNo.1InFMinorOp.2No.1-I.Allegro-GlennGould.mp3
49
+ - http://archive.org/download/GlennGould-BeethovenPianoSonatas/05-Beethoven-SonataNo.2InAMajorOp.2No.2-I.AllegroVivace-GlennGould.mp3
50
+ - http://archive.org/download/GlennGould-BeethovenPianoSonatas/09-Beethoven-SonataNo.3InCMajorOp.2No.3-I.AllegroConBrio-GlennGould.mp3
51
+
@@ -1,5 +1,13 @@
1
1
  ---
2
2
  - http://archive.org/download/CharlieChristian-SevenComeEleven/02.SevenComeEleven.mp3
3
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-BennysBugle.mp3
4
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-BoyMeetsGoygrandSlam.mp3
5
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-BreakfastFeudsecondVersion.mp3
6
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-FlyingHomealternateTake.mp3
7
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-GoneWithwhatWindalternateTake.mp3
8
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-GoodEnoughToKeepairMailSpecialfirstVersion--AlternateTak.mp3
9
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-SevenComeEleven.mp3
10
+ - http://archive.org/download/Daddy_GS_CHARLIE_CHRISTIAN_Guitar_Hero/ChristianCharlieoriginalGuitarHero-WhollyCats.mp3
3
11
  #- http://www.archive.org/download/CharlieChristian-01-08/CharlieChristian-AirmailSpecial.mp3
4
12
  #- http://www.archive.org/download/CharlieChristian-01-08/CharlieChristian-BluesInB.mp3
5
13
  #- http://www.archive.org/download/CharlieChristian-01-08/CharlieChristian-HoneysuckleRose1939.mp3
@@ -69,8 +69,6 @@ module JimmyJukebox
69
69
  # return
70
70
  #elsif (require 'rbconfig') && ['mac','darwin'].include?(RbConfig::CONFIG['host_os'])
71
71
  # ogg_player = "afplay"
72
- else
73
- raise NoOggPlayerFoundException, "Could not find an Ogg Vorbis player"
74
72
  end
75
73
  end
76
74
 
@@ -96,8 +94,6 @@ module JimmyJukebox
96
94
  # return
97
95
  #elsif (require 'rbconfig') && ['mac','darwin'].include?(RbConfig::CONFIG['host_os'])
98
96
  # mp3_player = "afplay"
99
- else
100
- raise NoMP3PlayerFoundException, "Could not find an MP3 player"
101
97
  end
102
98
  end
103
99
 
@@ -147,8 +143,8 @@ module JimmyJukebox
147
143
  # puts "ARGV: " + ARGV.inspect + " (" + ARGV.class.to_s + ")"
148
144
  if ARGV.empty?
149
145
  music_directories << default_music_dir
150
- elsif JAZZ_ARTISTS.keys.include?(ARGV[0].to_sym)
151
- music_directories << default_music_dir + key_to_subdir_name(ARGV[0].to_sym)
146
+ elsif ARTISTS.keys.include?(ARGV[0].to_sym)
147
+ music_directories << default_music_dir + artist_key_to_subdir_name(ARGV[0].to_sym)
152
148
  elsif is_a_txt_file?(ARGV[0])
153
149
  set_music_directories_from_file
154
150
  elsif is_a_directory?(ARGV[0])
@@ -185,10 +181,16 @@ module JimmyJukebox
185
181
  end
186
182
  end
187
183
 
184
+ def all_subdirectories(dir)
185
+ Dir.glob(File.join(dir,"**/","*/"))
186
+ .delete_if {|dir_name| !File.directory?(dir_name)}
187
+ .map { |dir_name| File.expand_path(dir_name) }
188
+ end
189
+
188
190
  def add_all_subdirectories
189
191
  new_dirs = []
190
192
  music_directories.each do |dir|
191
- new_dirs = new_dirs + Dir.glob(File.join(dir,"**/")).map { |dir_name| File.expand_path(dir_name) }
193
+ new_dirs = new_dirs + all_subdirectories(dir)
192
194
  end
193
195
  self.music_directories = music_directories + new_dirs
194
196
  end
@@ -1,4 +1,4 @@
1
1
  module JimmyJukebox
2
- VERSION = '0.4.2'
3
- DATE = '2013-02-22'
2
+ VERSION = '0.4.3'
3
+ DATE = '2013-02-25'
4
4
  end
@@ -0,0 +1,71 @@
1
+ require 'spec_helper'
2
+ require_relative '../lib/jimmy_jukebox/artists'
3
+ include Artists
4
+
5
+ #describe Jukebox do
6
+
7
+ describe Artists do
8
+
9
+ describe "::ARTISTS" do
10
+ it "has the correct keys" do
11
+ Artists::ARTISTS.keys.should include(:ch)
12
+ end
13
+
14
+ it "has the correct values for each key" do
15
+ Artists::ARTISTS[:eh].should == { genre: 'JAZZ', name: 'earl_hines' }
16
+ end
17
+ end
18
+
19
+ describe "#artist_genre" do
20
+ it "provides the artist's genre" do
21
+ artist_genre(:lvb).should == 'CLASSICAL'
22
+ artist_genre(:jrm).should == 'JAZZ'
23
+ end
24
+ end
25
+
26
+ describe "#artist_name" do
27
+ it "provides the artist's name" do
28
+ artist_name(:lh).should == 'lionel_hampton'
29
+ artist_name(:bg).should == 'benny_goodman'
30
+ end
31
+ end
32
+
33
+ describe "#artist_name_to_genre" do
34
+ it "provides the artist's genre" do
35
+ artist_name_to_genre('sidney_bechet').should == 'JAZZ'
36
+ artist_name_to_genre('beethoven').should == 'CLASSICAL'
37
+ end
38
+ end
39
+
40
+ describe "#artist_name_to_subdir_name" do
41
+ it "provides the artist's subdirectory name" do
42
+ artist_name_to_subdir_name('dixieland').should == '/JAZZ/Dixieland'
43
+ artist_name_to_subdir_name('miles_davis').should == '/JAZZ/Miles_Davis'
44
+ artist_name_to_subdir_name('beethoven').should == '/CLASSICAL/Beethoven'
45
+ end
46
+ end
47
+
48
+ describe "#artist_key_to_subdir_name" do
49
+ it "provides the artist's subdirectory name" do
50
+ artist_key_to_subdir_name(:dx).should == '/JAZZ/Dixieland'
51
+ artist_key_to_subdir_name(:md).should == '/JAZZ/Miles_Davis'
52
+ artist_key_to_subdir_name(:lvb).should == '/CLASSICAL/Beethoven'
53
+ end
54
+ end
55
+
56
+ describe "#artist_key_to_yaml_file" do
57
+ it "provides the artist's subdirectory name" do
58
+ artist_key_to_yaml_file(:dx).should == 'Dixieland.yml'
59
+ artist_key_to_yaml_file(:md).should == 'MilesDavis.yml'
60
+ artist_key_to_yaml_file(:lvb).should == 'Beethoven.yml'
61
+ end
62
+ end
63
+
64
+ describe "#artist_name_to_yaml_file" do
65
+ it "provides the artist's subdirectory name" do
66
+ artist_name_to_yaml_file('dixieland').should == 'Dixieland.yml'
67
+ artist_name_to_yaml_file('miles_davis').should == 'MilesDavis.yml'
68
+ artist_name_to_yaml_file('beethoven').should == 'Beethoven.yml'
69
+ end
70
+ end
71
+ end
@@ -2,6 +2,15 @@ require 'spec_helper'
2
2
  require_relative '../lib/jimmy_jukebox/jukebox'
3
3
  include JimmyJukebox
4
4
 
5
+ # don't actually play music
6
+ module JimmyJukebox
7
+ class Song
8
+ def spawn_method(command, arg)
9
+ lambda { |command, arg| sleep(5) }
10
+ end
11
+ end
12
+ end
13
+
5
14
  describe Jukebox do
6
15
 
7
16
  include FakeFS::SpecHelpers
@@ -13,54 +22,51 @@ describe Jukebox do
13
22
  let(:jb) { Jukebox.new }
14
23
 
15
24
  let(:uc) { double('user_config').as_null_object }
16
-
17
25
 
18
26
  context "with no command line parameter" do
19
27
 
20
- it "exists" do
21
- jb.should_not be_nil
22
- jb.quit
23
- end
24
-
25
- it "calls play_random_song" do
26
- jb.stub(:play_random_song).and_return(nil)
27
- jb.should_receive(:play_once)
28
- jb.play_once
29
- jb.quit
30
- end
31
-
32
- it "raises exception when no songs available" do
33
- expect { jb.play_once }.to raise_error(Jukebox::NoSongException)
34
- end
35
-
36
- it "has a user_config method" do
37
- jb.user_config.is_a?(UserConfig)
38
- end
39
-
40
- it "generates an empty song list" do
41
- jb.user_config.songs.should be_empty
42
- jb.user_config.songs.length.should == 0
28
+ context "when no songs available" do
29
+ it "raises exception when no songs available" do
30
+ expect { jb }.to raise_error(Jukebox::NoSongsException)
31
+ end
43
32
  end
44
33
 
45
34
  context "when songs exist" do
46
35
 
47
- let(:song1) { '/home/xavier/Music/Rock/Beatles/Abbey_Road.mp3' }
48
- let(:song2) { '/home/xavier/Music/Rock/Beatles/Sgt_Pepper.mp3' }
49
- let(:song3) { '/home/xavier/Music/Rock/Eagles/Hotel_California.ogg' }
36
+ let(:song1) { File.expand_path('~/Music/Rock/Beatles/Abbey_Road.mp3') }
37
+ let(:song2) { File.expand_path('~/Music/Rock/Beatles/Sgt_Pepper.mp3') }
38
+ let(:song3) { File.expand_path('~/Music/Rock/Eagles/Hotel_California.ogg') }
50
39
 
51
40
  before do
52
41
  [song1, song2, song3].each do |song|
53
42
  FileUtils.mkdir_p(File.dirname(song))
54
43
  FileUtils.touch(song)
55
- Dir.chdir('/home/xavier')
44
+ Dir.chdir(File.expand_path('~'))
56
45
  end
46
+ File.exists?(song1).should be_true
57
47
  end
58
48
 
59
49
  it "generates a non-empty song list" do
60
- jb.user_config.songs.should_not be_nil
61
- jb.user_config.songs.should_not be_empty
62
- jb.user_config.songs.length.should == 3
63
- jb.user_config.songs.should include(/Abbey_Road.mp3/)
50
+ jb.songs.should_not be_nil
51
+ jb.songs.should_not be_empty
52
+ jb.songs.length.should == 3
53
+ jb.songs.should include(/Abbey_Road.mp3/)
54
+ end
55
+
56
+ it "can quit" do
57
+ jb.should_not be_nil
58
+ jb.quit
59
+ end
60
+
61
+ it "calls play_random_song" do
62
+ jb.stub(:play_random_song).and_return(nil)
63
+ jb.should_receive(:play_once)
64
+ jb.play_once
65
+ jb.quit
66
+ end
67
+
68
+ it "has a user_config method" do
69
+ jb.user_config.is_a?(UserConfig)
64
70
  end
65
71
 
66
72
  =begin
@@ -2,6 +2,7 @@ require 'spec_helper'
2
2
  require 'rspec/mocks'
3
3
  require 'fakeweb' # apparently must be required before fakefs
4
4
  FakeWeb.allow_net_connect = false
5
+ gem 'fakefs', require: 'fakefs/safe'
5
6
  require 'fakefs/safe'
6
7
  require 'jimmy_jukebox/song_loader'
7
8
 
@@ -13,69 +14,58 @@ describe JimmyJukebox::SongLoader do
13
14
  # File.directory?("/home").should be_false
14
15
  #end
15
16
 
16
- before(:all) do
17
- #ARGV.delete_if { |val| true }
18
- ARGV.clear
19
- #ARGV.pop
20
- end
21
-
22
17
  before(:each) do
18
+ ARGV.clear
23
19
  @sl = JimmyJukebox::SongLoader
24
20
  end
25
21
 
26
22
  describe "#create_save_dir" do
23
+ include FakeFS::SpecHelpers
27
24
 
28
25
  it "should create a directory" do
29
- FakeFS do
30
- topdir = File.join("/home","user_name4","Music")
31
- subdir = File.join(topdir, "rock", "Beatles")
32
- File.directory?(subdir).should be_false
33
- @sl.create_save_dir(subdir)
34
- File.directory?(subdir).should be_true
35
- end
26
+ topdir = File.join("/home","user_name4","Music")
27
+ subdir = File.join(topdir, "rock", "Beatles")
28
+ File.directory?(subdir).should be_false
29
+ @sl.create_save_dir(subdir)
30
+ File.directory?(subdir).should be_true
36
31
  end
37
32
 
38
33
  end
39
34
 
40
35
  describe "#version_of_song_in_any_dir?" do
36
+ include FakeFS::SpecHelpers
41
37
 
42
38
  it "should return true if song in top of directory tree" do
43
- FakeFS do
44
- topdir = "/home/user_name1/Music"
45
- songname = "Paperback_Writer.mp3"
46
- File.directory?(topdir).should be_false
47
- FileUtils.mkdir_p(topdir)
48
- File.directory?(topdir).should be_true
49
- Dir.chdir(topdir)
50
- File.exists?(songname).should be_false
51
- FileUtils.touch(songname)
52
- File.exists?(songname).should be_true
53
- @sl.version_of_song_in_any_dir?(songname,topdir).should be_true
54
- end
39
+ topdir = "/home/user_name1/Music"
40
+ songname = "Paperback_Writer.mp3"
41
+ File.directory?(topdir).should be_false
42
+ FileUtils.mkdir_p(topdir)
43
+ File.directory?(topdir).should be_true
44
+ Dir.chdir(topdir)
45
+ File.exists?(songname).should be_false
46
+ FileUtils.touch(songname)
47
+ File.exists?(songname).should be_true
48
+ @sl.version_of_song_in_any_dir?(songname,topdir).should be_true
55
49
  end
56
50
 
57
51
  it "should return true if song in subdirectory" do
58
- FakeFS do
59
- topdir = "/home/user_name2/Music"
60
- subdir = File.join(topdir, "rock", "Beatles")
61
- songname = "Paperback_Writer.mp3"
62
- File.directory?(subdir).should be_false
63
- FileUtils.mkdir_p(subdir)
64
- FileUtils.touch(File.join(subdir, songname))
65
- File.exists?(File.join(subdir, songname)).should be_true
66
- @sl.version_of_song_in_any_dir?(songname,subdir).should be_true
67
- end
52
+ topdir = "/home/user_name2/Music"
53
+ subdir = File.join(topdir, "rock", "Beatles")
54
+ songname = "Paperback_Writer.mp3"
55
+ File.directory?(subdir).should be_false
56
+ FileUtils.mkdir_p(subdir)
57
+ FileUtils.touch(File.join(subdir, songname))
58
+ File.exists?(File.join(subdir, songname)).should be_true
59
+ @sl.version_of_song_in_any_dir?(songname,subdir).should be_true
68
60
  end
69
61
 
70
62
  it "should return false if song not in directory tree" do
71
- FakeFS do
72
- topdir = "/home/user_name3/Music"
73
- subdir = File.join(topdir, "rock", "Beatles")
74
- songname = "Paperback_Writer.mp3"
75
- FileUtils.mkdir_p(subdir)
76
- File.exists?(File.join(subdir, songname)).should be_false
77
- @sl.version_of_song_in_any_dir?(songname,subdir).should be_false
78
- end
63
+ topdir = "/home/user_name3/Music"
64
+ subdir = File.join(topdir, "rock", "Beatles")
65
+ songname = "Paperback_Writer.mp3"
66
+ FileUtils.mkdir_p(subdir)
67
+ File.exists?(File.join(subdir, songname)).should be_false
68
+ @sl.version_of_song_in_any_dir?(songname,subdir).should be_false
79
69
  end
80
70
 
81
71
  end
@@ -121,7 +111,7 @@ describe JimmyJukebox::SongLoader do
121
111
  it "should try to download many songs" do
122
112
  dirname = File.expand_path(@sl.instance_variable_get(:@user_config).default_music_dir + '/JAZZ/Charlie_Christian')
123
113
  @sl.stub!(:version_of_song_in_any_dir?).and_return(false)
124
- @sl.should_receive(:open).exactly(8).times
114
+ @sl.should_receive(:open).exactly(9).times
125
115
  @sl.charlie_christian
126
116
  File.exists?(dirname).should be_true
127
117
  end
@@ -156,6 +146,7 @@ describe JimmyJukebox::SongLoader do
156
146
  describe "#dizzy_gillespie with dirname" do
157
147
 
158
148
  it "should try to download three songs" do
149
+ pending "have not yet implemented way to specify artist-specific directory"
159
150
  dirname = File.expand_path(@sl.instance_variable_get(:@user_config).default_music_dir + '/JAZZ/Dizzy_Gillespie')
160
151
  @sl.stub!(:version_of_song_in_any_dir?).and_return(false)
161
152
  @sl.should_receive(:open).exactly(3).times
@@ -163,16 +154,16 @@ describe JimmyJukebox::SongLoader do
163
154
  end
164
155
 
165
156
  it "should successfully download three songs" do
166
- pending("use FakeWeb")
157
+ pending "use FakeWeb"
167
158
  FakeWeb.register_uri(:any, "http://www.archive.org/download/DizzyGillespie-GroovinHigh/02.GroovinHigh.mp3", :response => "/home/james/Music/JAZZ/Dizzy_Gillespie/Groovin' High 1945.mp3")
168
159
  FakeWeb.register_uri(:any, "http://www.archive.org/download/DizzyGillespie-Manteca/01Manteca.ogg", :response => "/home/james/Music/JAZZ/Dizzy_Gillespie/01Manteca.ogg")
169
160
  FakeWeb.register_uri(:any, "http://www.archive.org/download/DizzyGillespieLouisArmstrong-UmbrellaMan/DizzyGillespieLouisArmstrong-UmbrellaMan.mp3", :response => "/home/james/Music/JAZZ/Dizzy_Gillespie/DizzyGillespieLouisArmstrong-UmbrellaMan.mp3")
170
161
  dirname = File.expand_path("/home/user_name6/non-existent-dir")
171
162
  File.exists?(dirname).should be_false
172
163
  @sl.dizzy_gillespie(dirname)
173
- #File.exists?(dirname + "/02.GroovinHigh.mp3").should be_true
174
- #File.exists?(dirname + "/01Manteca.ogg").should be_true
175
- #File.exists?(dirname + "/DizzyGillespieLouisArmstrong-UmbrellaMan.mp3").should be_true
164
+ File.exists?(dirname + "/02.GroovinHigh.mp3").should be_true
165
+ File.exists?(dirname + "/01Manteca.ogg").should be_true
166
+ File.exists?(dirname + "/DizzyGillespieLouisArmstrong-UmbrellaMan.mp3").should be_true
176
167
  FakeWeb.clean_registry
177
168
  end
178
169
 
data/spec/spec_helper.rb CHANGED
@@ -6,36 +6,3 @@ end
6
6
 
7
7
  require 'fakefs/spec_helpers'
8
8
 
9
- # Overriding FakeFS' File.expand_path
10
- # because it delegates to the same class
11
- # method in the REAL file system
12
- module FakeFS
13
- class File
14
- def self.expand_path(*args)
15
- args[0].gsub(/~/,'/home/xavier')
16
- end
17
- end
18
- # Started overriding FileUtils.ln because FakeFS doesn't know about it
19
- # Instead switched to using File.link, which FakeFS knows about
20
- end
21
-
22
- # Overriding File.expand_path
23
- # so it will provide the fake user's
24
- # home directory
25
- class File
26
- def self.expand_path(*args)
27
- args[0].gsub(/~/,'/home/xavier')
28
- end
29
- end
30
-
31
- # Override exec() to prevent songs from actually playing
32
- # Instead, start a brief sleep process
33
- #module Kernel
34
- # alias :real_exec :exec
35
- #
36
- # def exec(*cmd)
37
- # real_exec("sleep 0.2")
38
- # end
39
- #end
40
-
41
-
@@ -27,7 +27,7 @@ describe UserConfig do
27
27
  describe "#top_music_dir" do
28
28
 
29
29
  it "should parse '~/Music'" do
30
- UserConfig.top_music_dir("~/Music").should == "/home/xavier/Music"
30
+ UserConfig.top_music_dir("~/Music").should == File.expand_path("~/Music")
31
31
  end
32
32
 
33
33
  it "should parse '/home/xavier/Music'" do
@@ -35,15 +35,15 @@ describe UserConfig do
35
35
  end
36
36
 
37
37
  it "should parse '~/Music/Rock/The_Eagles/hotel_california.mp3'" do
38
- UserConfig.top_music_dir("~/Music/Rock/The_Eagles/hotel_california.mp3").should == "/home/xavier/Music"
38
+ UserConfig.top_music_dir("~/Music/Rock/The_Eagles/hotel_california.mp3").should == File.expand_path("~/Music")
39
39
  end
40
40
 
41
41
  it "should parse '~/Music/Rock/The Eagles/Hotel California.mp3'" do
42
- UserConfig.top_music_dir("~/Music/Rock/The Eagles/Hotel California.mp3").should == "/home/xavier/Music"
42
+ UserConfig.top_music_dir("~/Music/Rock/The Eagles/Hotel California.mp3").should == File.expand_path("~/Music")
43
43
  end
44
44
 
45
45
  it "should parse '~/My Music'" do
46
- UserConfig.top_music_dir("~/My Music").should == "/home/xavier/My Music"
46
+ UserConfig.top_music_dir("~/My Music").should == File.expand_path("~/My Music")
47
47
  end
48
48
 
49
49
  end
@@ -64,14 +64,30 @@ describe UserConfig do
64
64
 
65
65
  end
66
66
 
67
- context "with songs" do
67
+ context "with songs in ~/Music" do
68
+
69
+ before(:each) do
70
+ FileUtils.mkdir_p File.expand_path("~/Music")
71
+ FileUtils.touch File.expand_path("~/Music/Yellow_Submarine.mp3")
72
+ end
73
+
74
+ it "finds songs" do
75
+ uc.songs.should_not be_empty
76
+ uc.songs.length.should == 1
77
+ end
78
+
79
+ end
80
+
81
+ context "with songs in ~/Music subdirectory" do
68
82
 
69
83
  before do
70
- FileUtils.mkdir_p "/home/xavier/Music"
71
- FileUtils.touch "/home/xavier/Music/Yellow_Submarine.mp3"
84
+ FileUtils.mkdir_p File.expand_path("~/Music/ROCK/Beatles")
85
+ FileUtils.touch File.expand_path("~/Music/ROCK/Beatles/Yellow_Submarine.mp3")
72
86
  end
73
87
 
74
88
  it "finds songs" do
89
+ File.directory?(File.expand_path("~/Music/ROCK/Beatles")).should be_true
90
+ p uc.songs.to_s
75
91
  uc.songs.should_not be_empty
76
92
  uc.songs.length.should == 1
77
93
  end
metadata CHANGED
@@ -1,125 +1,114 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jimmy_jukebox
3
3
  version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.4.2
4
+ version: 0.4.3
5
+ prerelease:
6
6
  platform: ruby
7
7
  authors:
8
8
  - James Lavin
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-02-22 00:00:00.000000000 Z
12
+ date: 2013-02-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
16
- version_requirements: !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
17
18
  requirements:
18
- - - ">="
19
+ - - ! '>='
19
20
  - !ruby/object:Gem::Version
20
- version: !binary |-
21
- MA==
21
+ version: '0'
22
+ type: :development
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
22
25
  none: false
23
- requirement: !ruby/object:Gem::Requirement
24
26
  requirements:
25
- - - ">="
27
+ - - ! '>='
26
28
  - !ruby/object:Gem::Version
27
- version: !binary |-
28
- MA==
29
- none: false
30
- prerelease: false
31
- type: :development
29
+ version: '0'
32
30
  - !ruby/object:Gem::Dependency
33
31
  name: rspec-core
34
- version_requirements: !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
35
34
  requirements:
36
- - - ">="
35
+ - - ! '>='
37
36
  - !ruby/object:Gem::Version
38
- version: !binary |-
39
- MA==
37
+ version: '0'
38
+ type: :development
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
40
41
  none: false
41
- requirement: !ruby/object:Gem::Requirement
42
42
  requirements:
43
- - - ">="
43
+ - - ! '>='
44
44
  - !ruby/object:Gem::Version
45
- version: !binary |-
46
- MA==
47
- none: false
48
- prerelease: false
49
- type: :development
45
+ version: '0'
50
46
  - !ruby/object:Gem::Dependency
51
47
  name: rspec-mocks
52
- version_requirements: !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
53
50
  requirements:
54
- - - ">="
51
+ - - ! '>='
55
52
  - !ruby/object:Gem::Version
56
- version: !binary |-
57
- MA==
53
+ version: '0'
54
+ type: :development
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
58
57
  none: false
59
- requirement: !ruby/object:Gem::Requirement
60
58
  requirements:
61
- - - ">="
59
+ - - ! '>='
62
60
  - !ruby/object:Gem::Version
63
- version: !binary |-
64
- MA==
65
- none: false
66
- prerelease: false
67
- type: :development
61
+ version: '0'
68
62
  - !ruby/object:Gem::Dependency
69
63
  name: rspec-expectations
70
- version_requirements: !ruby/object:Gem::Requirement
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
71
66
  requirements:
72
- - - ">="
67
+ - - ! '>='
73
68
  - !ruby/object:Gem::Version
74
- version: !binary |-
75
- MA==
69
+ version: '0'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
76
73
  none: false
77
- requirement: !ruby/object:Gem::Requirement
78
74
  requirements:
79
- - - ">="
75
+ - - ! '>='
80
76
  - !ruby/object:Gem::Version
81
- version: !binary |-
82
- MA==
83
- none: false
84
- prerelease: false
85
- type: :development
77
+ version: '0'
86
78
  - !ruby/object:Gem::Dependency
87
79
  name: fakefs
88
- version_requirements: !ruby/object:Gem::Requirement
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
89
82
  requirements:
90
- - - ">="
83
+ - - ! '>='
91
84
  - !ruby/object:Gem::Version
92
- version: !binary |-
93
- MA==
85
+ version: '0'
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
94
89
  none: false
95
- requirement: !ruby/object:Gem::Requirement
96
90
  requirements:
97
- - - ">="
91
+ - - ! '>='
98
92
  - !ruby/object:Gem::Version
99
- version: !binary |-
100
- MA==
101
- none: false
102
- prerelease: false
103
- type: :development
93
+ version: '0'
104
94
  - !ruby/object:Gem::Dependency
105
95
  name: fakeweb
106
- version_requirements: !ruby/object:Gem::Requirement
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
107
98
  requirements:
108
- - - ">="
99
+ - - ! '>='
109
100
  - !ruby/object:Gem::Version
110
- version: !binary |-
111
- MA==
101
+ version: '0'
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
112
105
  none: false
113
- requirement: !ruby/object:Gem::Requirement
114
106
  requirements:
115
- - - ">="
107
+ - - ! '>='
116
108
  - !ruby/object:Gem::Version
117
- version: !binary |-
118
- MA==
119
- none: false
120
- prerelease: false
121
- type: :development
122
- description: jimmy_jukebox plays random MP3 & OGG songs under a directory (or set of directories) and can download music
109
+ version: '0'
110
+ description: jimmy_jukebox plays random MP3 & OGG songs under a directory (or set
111
+ of directories) and can download music
123
112
  email: james@jameslavin.com
124
113
  executables:
125
114
  - play_jukebox
@@ -162,6 +151,7 @@ files:
162
151
  - lib/jimmy_jukebox/songs/CountBasie.yml
163
152
  - lib/jimmy_jukebox/songs/ArchibaldCampBanjo.yml
164
153
  - lib/jimmy_jukebox/songs/SidneyBechet.yml
154
+ - lib/jimmy_jukebox/songs/Beethoven.yml
165
155
  - lib/jimmy_jukebox/songs/JamesPJohnson.yml
166
156
  - lib/jimmy_jukebox/songs/JellyRollMorton.yml
167
157
  - lib/jimmy_jukebox/songs/Ragtime.yml
@@ -169,39 +159,41 @@ files:
169
159
  - spec/jimmy_jukebox_spec.rb
170
160
  - spec/song_loader_spec.rb
171
161
  - spec/user_config_spec.rb
162
+ - spec/artists_spec.rb
172
163
  - spec/song_spec.rb
173
164
  - spec/spec_helper.rb
174
165
  - bin/play_jukebox
175
166
  - bin/load_jukebox
176
167
  homepage: https://github.com/JamesLavin/jimmy_jukebox
177
168
  licenses: []
178
- post_install_message: I really hope you enjoy the great jazz downloadable using this gem!
169
+ post_install_message: I really hope you enjoy the great jazz downloadable using this
170
+ gem!
179
171
  rdoc_options: []
180
172
  require_paths:
181
173
  - lib
182
174
  required_ruby_version: !ruby/object:Gem::Requirement
175
+ none: false
183
176
  requirements:
184
- - - ">="
177
+ - - ! '>='
185
178
  - !ruby/object:Gem::Version
186
- version: !binary |-
187
- MA==
188
- none: false
179
+ version: '0'
189
180
  required_rubygems_version: !ruby/object:Gem::Requirement
181
+ none: false
190
182
  requirements:
191
- - - ">="
183
+ - - ! '>='
192
184
  - !ruby/object:Gem::Version
193
- version: !binary |-
194
- MA==
195
- none: false
185
+ version: '0'
196
186
  requirements: []
197
187
  rubyforge_project: jimmy_jukebox
198
- rubygems_version: 1.8.24
199
- signing_key:
188
+ rubygems_version: 1.8.23
189
+ signing_key:
200
190
  specification_version: 3
201
191
  summary: plays your MP3 & OGG files and lets you easily download music
202
192
  test_files:
203
193
  - spec/jimmy_jukebox_spec.rb
204
194
  - spec/song_loader_spec.rb
205
195
  - spec/user_config_spec.rb
196
+ - spec/artists_spec.rb
206
197
  - spec/song_spec.rb
207
198
  - spec/spec_helper.rb
199
+ has_rdoc: