songfile 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 7df1397b9db1fa3f47f171ffb299e5bf1adb4cf13c79a46d530d38ca8bf3c827
4
+ data.tar.gz: a7fc63446d0eb7e1d0dd62e3e2e07acada88837d7c79df54fc6a0ed19eefdf82
5
+ SHA512:
6
+ metadata.gz: e6d6bbef6b0464361f0c01d50f33d1e2a552ca911c9a427f1cd34d763ab953d760af6640ccb717b642870ea040677e08851acb4976f1504cff7c2b134be4459b
7
+ data.tar.gz: 46c141fa5607114913b52f9dbf8e31080ecf31e19ff09ae5a21aed71b06e278025f3c32e3d649e26234f451cf1bd072779757e3e566843baf5b40428100120c0
data/LICENSE.txt ADDED
@@ -0,0 +1,19 @@
1
+ Copyright (c) 2022 Jamie Clark / The Pragmatic Studio
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ of this software and associated documentation files (the "Software"), to deal
5
+ in the Software without restriction, including without limitation the rights
6
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ copies of the Software, and to permit persons to whom the Software is
8
+ furnished to do so, subject to the following conditions:
9
+
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
12
+
13
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19
+ SOFTWARE.
data/README.txt ADDED
@@ -0,0 +1,9 @@
1
+ ************************************** BASIC INSTRUCTIONS **************************************
2
+ TO RUN DEFAULT CSV SHEET (THE WALL)):
3
+ ruby bin/songfile
4
+
5
+ TO RUN DARK SIDE OF THE MOON ALBUM SONGS
6
+ ruby bin/songfile bin/DSOTM.csv
7
+
8
+ TO RUN SPECS:
9
+ rspec (not "rspec .")
data/bin/DSOTM.csv ADDED
@@ -0,0 +1,10 @@
1
+ Speak to Me,1000
2
+ Breathe,500
3
+ On the Run,900
4
+ Time,300
5
+ The Great Gig in the Sky,100
6
+ Money,200
7
+ Us and Them,400
8
+ Any Colour You Like,800
9
+ Brain Damage,700
10
+ Eclipse,600
data/bin/THE_WALL.csv ADDED
@@ -0,0 +1,13 @@
1
+ In the Flesh?,100
2
+ Vera,200
3
+ Hey You,300
4
+ Run Like Hell,400
5
+ Comfortably Numb,500
6
+ Pigs on the Wing,600
7
+ Another Brick in the Wall Part 1,700
8
+ Is There Anybody Out There?,800
9
+ The Trial,900
10
+ Stop,1000
11
+ Goodbye Blue Sky, 1100
12
+ Young Lust,
13
+ Nobody Home,
data/bin/songfile ADDED
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env ruby
2
+ #(File created 9:47pm on 5/8/22)
3
+ #end of day one is 8:24pm-10:47pm 5/8/22
4
+ #day two is 5:45pm - .... 9pm 5/24/22
5
+ #day three is 9:55pm - .... 11:15pm 6/8/22 (oof)
6
+ #day four is 7:30pm - 8:30pm, resumed at 9:40pm - 1am 6/14/22
7
+ #day five is 12:45pm - 1:30pm before work 6/15/22
8
+ #day six is 12am - 7:05pm 7 hours straight 6/18/22
9
+ #day seven is 4:30pm - 8:15pm and 10pm - 12:30am 6/19/22
10
+ #day eight is 8:55pm - 11:45pm 6/20/22
11
+ #day nine is 11:47pm - 5:34am!! 6/22/22 (night)
12
+ #day ten is 8:08pm - 12:24am and 12:50am - 3:30am 6/22/22 (day)
13
+
14
+ require_relative '../lib/songfile/playlist' # calls the playlist class file
15
+ require_relative '../lib/songfile/song' # calls the song class file
16
+ require_relative '../lib/songfile/die'
17
+ require_relative '../lib/songfile/council'
18
+ require_relative '../lib/songfile/classic_song'
19
+
20
+ # (technically require_relative 'song' isnt needed here as well since it is referenced within the playlist file already)
21
+
22
+ my_list = Songfile::Playlist.new("Jamie's Pink Floyd Playlist")
23
+ default_player_file = File.join(File.dirname(__FILE__), "THE_WALL.csv") #plays an entered file OR the default (WALL.csv)
24
+ my_list.load_songs(ARGV.shift || default_player_file)
25
+
26
+ #Lines 28 and 29 can be uncommented to add a "classic song" from within the driving program file!
27
+ #classic_song = Songfile::ClassicSong.new("Time") #default rank of 10000 assigned bc not specified, then halved bc it is a ClassicSong
28
+ #my_list.add_song(classic_song)
29
+
30
+ loop do
31
+ puts "\nHow many rounds? ('quit' to exit)"
32
+ ans = gets.chomp.downcase
33
+
34
+ case ans
35
+ when /^\d+$/
36
+ if ans.to_i > 20
37
+ puts "ERROR: Maximum number of rounds allowed: 20." # I will set a limit to 20 rounds
38
+ else
39
+ my_list.play(ans.to_i) # converts to integer
40
+ end
41
+ when 'quit', 'exit', 'q', 'e', 'ex'
42
+ my_list.print_stats # currently, this must be called SEPARATELY, not from within the "play" method to get the tests to pass
43
+ break
44
+ else
45
+ puts "Please enter a number or 'quit'"
46
+ end
47
+ end
48
+
49
+ my_list.save_output #this goes after the loop
50
+
51
+ # my_list.show_titles
52
+ # ^ shows titles in the "array" format using "p"
53
+
54
+
55
+
@@ -0,0 +1,18 @@
1
+ require_relative 'song'
2
+ module Songfile
3
+ class ClassicSong < Song
4
+ attr_reader :initial_rank
5
+ def initialize(title, rank=10000)
6
+ @initial_rank = rank
7
+ @title = titleize(title)
8
+ @rank = (rank.abs()) / 2
9
+ puts "New song '#{@title}' (classic) with rank of #{@rank} was created."
10
+ # puts "The classic song '#{@title}' jumps the chart with a halved rank !"
11
+ end
12
+ end
13
+
14
+ if __FILE__ == $0
15
+ classic_song = ClassicSong.new("Time", 10000)
16
+ # puts "The classic song '#{classic_song.title}' jumps the chart with a halved rank (#{classic_song.initial_rank}/2) of #{classic_song.rank}!"
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ module Songfile #< this line nested on TOP of Reviewer = Struct.new
2
+ Reviewer = Struct.new(:name, :influence) #bigger number means more influence (I use them as multiplier values)
3
+ module Council
4
+ REVIEWERS = [
5
+ Reviewer.new(:Roger_Waters, 100),
6
+ Reviewer.new(:Nick_Mason, 50),
7
+ Reviewer.new(:David_Gilmour, 100),
8
+ Reviewer.new(:Richard_Wright, 50),
9
+ Reviewer.new(:Syd_Barrett, 25)
10
+ ]
11
+
12
+ def self.random
13
+ REVIEWERS.sample
14
+ end
15
+ end
16
+
17
+ if __FILE__ == $0
18
+ p Council::REVIEWERS.map(&:name)
19
+ person = Council.random
20
+ puts "#{person.name} is reviewing your playlist."
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ module Songfile
2
+ class Die
3
+ attr_reader :number
4
+
5
+ def roll
6
+ @number = rand(1..6)
7
+ end
8
+
9
+ def initialize
10
+ roll #the new die object now initializes as soon as "roll" is called anywhere.
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,159 @@
1
+ require_relative 'song'
2
+ require_relative 'die'
3
+ require_relative 'playlist_turn'
4
+ require_relative 'council'
5
+ require 'csv'
6
+ module Songfile
7
+ class Playlist
8
+ attr_reader :name, :list #you can read the title (name) of the playlist
9
+ def initialize(name) #this method converts a Playlist.new specified title to the correct format when created
10
+ @name = name.upcase #upcased all playlist titles for now
11
+ @list = []
12
+ puts "Playlist '#{@name}' was created."
13
+ end
14
+
15
+ def show_titles
16
+ p self.list.map(&:title) # p is used within the method to print the array properly, and it is only an array of titles
17
+ end
18
+
19
+ def show_reviewers
20
+ reviewers = Council::REVIEWERS
21
+ puts "\nThere are #{reviewers.size} playlist reviewers:"
22
+ reviewers.each do |r|
23
+ puts "#{r.name}, #{r.influence}"
24
+ end
25
+ end
26
+
27
+ def add_song(song) #when you add a song, the list re-sorts itself
28
+ @list << song
29
+ @list = @list.sort { |a, b| a.rank <=> b.rank } #this line is critical to have so that original song order by rank is displayed by the text output!
30
+ @original_list = @list # whenever a song is added, the list is stored
31
+ # NOTE: ^^ I disabled the list sorting itself whenever a new song is added. All the responsibility is
32
+ # now handed over to the sort songs method which 1) sorts all songs in array by rank then
33
+ # normalizes the rank values based on the amount of songs in the playlist!
34
+ end
35
+
36
+ def sort_songs #created this method... it looks very similar to the print_stats method
37
+ @list.each do |song| #sort by rank step 1
38
+ @list = @list.sort { |a, b| a.rank <=> b.rank }
39
+ end
40
+ end
41
+ def normalize_ranks
42
+ @list.each do |song| #step 2 (after ALL songs are sorted by rank)
43
+ song.rank = @list.index(song) + 1 # NOW you normalize rank once all songs are sorted
44
+ #song.rank = @list.index(song) + 1 # NOW you normalize rank once all songs are sorted
45
+ # puts "#{song.rank}) #{song.title}"
46
+ end
47
+ end
48
+ def multiply_ranks
49
+ @list.each do |song| #step 2 (after ALL songs are sorted by rank)
50
+ song.rank *= 10 # multiplies each song's rank by 10. This method is used after "normalize ranks" in the play method
51
+ end
52
+ end
53
+
54
+
55
+ def play(rounds=1) #play one round by default
56
+ puts "\nThere are #{@list.size} songs in this playlist:"
57
+ sort_songs # use of SELF to call sort_songs on the applicable Playlist object from inside the play method
58
+ normalize_ranks # is now separate from sorting songs
59
+ @list.each do |song|
60
+ puts "#{song.rank}) #{song.title}"
61
+ end
62
+
63
+ multiply_ranks
64
+
65
+ show_reviewers # this method is standalone, no reference to self is needed
66
+
67
+ 1.upto(rounds) do |round|
68
+ puts "\nRound #{round}:"
69
+ # puts "number rolled is #{number_rolled}"
70
+ @list.each do |song|
71
+ puts song
72
+ PlaylistTurn.take_turn(song)
73
+ puts song
74
+ end
75
+ end
76
+
77
+ #self.print_stats #activating this code will make two tests fail because sort/normalization is
78
+ #performed within the print stats method which, when enabled INSIDE the "play" method
79
+ #makes the math check test fail! (activating this code sorts/normalizes the new ranks
80
+ #before the math checker is run, aka after the "play" method is completed)
81
+ end
82
+
83
+ def print_stats
84
+ sort_songs # FIRST SORT FOR PREVIEW/DISPLAY
85
+ puts "\n#{@name} Final Rankings:"
86
+ @list.each do |song|
87
+ puts "#{song.title} (#{song.rank})"
88
+ end
89
+
90
+ puts "\nOriginal list order:"
91
+ @original_list.each do |song|
92
+ puts "#{@original_list.index(song) + 1}) #{song.title}"
93
+ end
94
+
95
+ normalize_ranks # NOW NORMALIZE RANKINGS
96
+
97
+ top_ten_songs, average_songs = @list.partition { |song| song.top_ten? }
98
+ puts "\nNew list order:"
99
+ if @list.size > 10
100
+ puts "Top 10 Songs:"
101
+ top_ten_songs.each do |song|
102
+ puts "#{song.rank}) #{song.title}"
103
+ end
104
+ puts "\nOther Songs:"
105
+ average_songs.each do |song|
106
+ puts "#{song.rank}) #{song.title}"
107
+ end
108
+ else
109
+ puts "\nTop #{@list.size} Songs:"
110
+ @list.each do |song|
111
+ puts "#{song.rank}) #{song.title}"
112
+ end
113
+ end
114
+ end
115
+
116
+ def load_songs(from_file)
117
+ CSV.foreach(from_file, 'r:bom|utf-8') do |row|
118
+ if row[1].to_i == 0
119
+ song = Song.new(row[0], 10000) # THIS is the code that sets nil to 10000 by default so that sorted song is ranked last in playlist
120
+ else
121
+ song = Song.new(row[0], row[1].to_i)# << this "index" stuff syntax allows for nil ranks to "pass/fly" (and get reassigned to default of 0) THIS is where default gets assigned.
122
+
123
+ end
124
+ add_song(song)
125
+ end
126
+ end
127
+ def save_output(to_file="songfile_output.txt")
128
+ File.open(to_file, "w") do |file|
129
+ file.puts Time.new.strftime("File updated on %m/%d/%Y at %I:%M %p")
130
+ file.puts "\nOriginal list order:"
131
+ @original_list.each do |song|
132
+ file.puts "#{@original_list.index(song) + 1}) #{song.title}"
133
+ end
134
+ file.puts "\nNew list order:"
135
+
136
+ top_ten_songs, average_songs = @list.partition { |song| song.top_ten? }
137
+
138
+ if @list.size > 10
139
+ file.puts "Top 10 Songs:" # literally copied from print stats but with "file.puts" not "puts"
140
+ top_ten_songs.each do |song|
141
+ file.puts "#{song.rank}) #{song.title}"
142
+ end
143
+ file.puts "\nOther Songs:"
144
+ average_songs.each do |song|
145
+ file.puts "#{song.rank}) #{song.title}"
146
+ end
147
+ else
148
+ file.puts "\nTop #{@list.size} Songs:"
149
+ @list.each do |song|
150
+ file.puts "#{song.rank}) #{song.title}"
151
+ end
152
+ end
153
+
154
+ end
155
+
156
+ end
157
+
158
+ end
159
+ end
@@ -0,0 +1,26 @@
1
+ require_relative 'song'
2
+ require_relative 'die'
3
+ require_relative 'council'
4
+ module Songfile
5
+ module PlaylistTurn
6
+
7
+ def self.take_turn(song)
8
+
9
+ reviewer = Council.random
10
+ #puts reviewer
11
+ puts "'#{song.title}' was reviewed by #{reviewer.name} (#{reviewer.influence} influence)"
12
+
13
+ die = Die.new
14
+ number_rolled = die.roll
15
+ case number_rolled
16
+ when 5..6
17
+ song.thumbs_up(reviewer.influence)
18
+ when 3..4
19
+ puts "'#{song.title}' was skipped."
20
+ when 1..2
21
+ song.thumbs_down(reviewer.influence)
22
+ else # (nothing is added if die roll is 3 or 4... or 0 etc.)
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,78 @@
1
+ require_relative 'playlist'
2
+ # set Lowercase_words to be a global variable bc the warning was annoying!
3
+ # the warning in question: "warning: already initialized constant Lowercase_words"
4
+
5
+ $Lowercase_words = %w{and as at but by for from
6
+ if in into like near nor of off on once
7
+ onto or over past so than that the till
8
+ to up upon v. vs vs. with when yet}
9
+ module Songfile
10
+ class Song
11
+ #attr_reader :rank # allows you to print the "rank" attribute outside the Song class (GETTER method)
12
+ # attr_writer :title, :rank # allows you to write to the "title" and "rank" attributes outside the Song class (SETTER method)
13
+ attr_accessor :title, :rank # allows you to read and write to "title" and "rank" attribute outside the Song class
14
+
15
+ def titleize(title) #the actual titleize method (only hangup is "Like" (as a verb) vs "like" (as a preposition))
16
+ title.downcase.split.each_with_index.map{ |x, index| $Lowercase_words.include?(x) && index > 0 ? x : x.capitalize }.join(" ")
17
+ end
18
+
19
+ def initialize(title, rank=10000) #this method converts a Song.new specified title to the correct format when created
20
+ @title = titleize(title)
21
+ @rank = rank.abs() # the absolute value prevents anyone from typing in a NEGATIVE rank
22
+ puts "New song '#{@title}' with rank of #{@rank} was created."
23
+ end
24
+
25
+ def title=(new_title) #this method converts a Song.new specified title to the correct format when overwritten
26
+ @title = new_title
27
+ @title = titleize(@title)
28
+ end
29
+
30
+ def thumbs_up(value=1)
31
+ @rank -= value
32
+ puts "'#{@title}' received a thumbs up!"
33
+ end
34
+
35
+ def thumbs_down(value=1)
36
+ @rank += value
37
+ puts "'#{@title}' received a thumbs down!"
38
+ end
39
+
40
+ def describe
41
+ puts "'#{@title}' has a rank of #{@rank}."
42
+ end
43
+
44
+ def top_ten?
45
+ result = case @rank
46
+ when 1..10 then true
47
+ end
48
+ end
49
+
50
+ def status
51
+ top_ten? ? "*Top 10*" : "*Not Top 10*"
52
+ end
53
+
54
+ def to_s #defines what happens when you use puts on an object of class "Song"
55
+ "#{@title} (#{@rank})"
56
+ #"#{@title} (#{@rank}) #{status}"
57
+ #^^REMOVING "top 10" classification while the score is still computing!
58
+ end
59
+ end
60
+
61
+ #code that only runs inside THIS file (songfile.rb relies only on the class code and ignores this if statement code)
62
+ if __FILE__ == $0
63
+ song1 = Song.new("Run like Hell", 4)
64
+ song2 = Song.new("The Trial", 1)
65
+ song3 = Song.new("Outside the Wall", 11)
66
+ array = [song1, song2, song3]
67
+ array.each do |song|
68
+ puts song
69
+ song.describe
70
+ song.thumbs_up
71
+ song.thumbs_up
72
+ song.thumbs_down
73
+ song.thumbs_up
74
+ puts song
75
+ end
76
+
77
+ end
78
+ end
@@ -0,0 +1,52 @@
1
+ # require_relative "council"
2
+ require 'songfile/council'
3
+ module Songfile
4
+ describe Reviewer do
5
+
6
+ before do
7
+ @reviewer = Reviewer.new(:Tre_Cool, 49)
8
+ end
9
+
10
+ it "has a name attribute" do
11
+ @reviewer.name.should == :Tre_Cool
12
+ end
13
+
14
+ it "has a correct influence (age in this case) attribute" do
15
+ @reviewer.influence.should == 49
16
+ end
17
+
18
+ end
19
+
20
+ describe Council do
21
+
22
+ it "returns a random reviewer from the council" do
23
+ reviewer = Council.random
24
+ Council::REVIEWERS.should include(reviewer)
25
+ end
26
+
27
+ it "has five reviewers" do
28
+ Council::REVIEWERS.size.should == 5
29
+ end
30
+
31
+ it "has Roger Waters (100)" do
32
+ Council::REVIEWERS[0].should == Reviewer.new(:Roger_Waters, 100)
33
+ end
34
+
35
+ it "has Nick Mason (50)" do
36
+ Council::REVIEWERS[1].should == Reviewer.new(:Nick_Mason, 50)
37
+ end
38
+
39
+ it "has David_Gilmour (100)" do
40
+ Council::REVIEWERS[2].should == Reviewer.new(:David_Gilmour, 100)
41
+ end
42
+
43
+ it "has Richard_Wright (50)" do
44
+ Council::REVIEWERS[3].should == Reviewer.new(:Richard_Wright, 50)
45
+ end
46
+
47
+ it "Syd_Barrett (25)" do
48
+ Council::REVIEWERS[4].should == Reviewer.new(:Syd_Barrett, 25)
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,108 @@
1
+ # require_relative "playlist"
2
+ require 'songfile/playlist'
3
+ # require_relative "die"
4
+ require 'songfile/die'
5
+ # require_relative "council"
6
+ require 'songfile/council'
7
+ module Songfile
8
+ describe Playlist do
9
+
10
+ before do
11
+ @playlist = Playlist.new("test playlist")
12
+ end
13
+
14
+ context "single song playlist" do
15
+
16
+ before do
17
+ @initial_rank = -10
18
+ @song = Song.new("the happiest days of our lives", @initial_rank)
19
+ @initial_rank = @song.rank #this line had to be added to update the @inital rank
20
+ #variable in the test file so that it is updated to reflect the initialization of the "rank" attribute
21
+ #of the project (which changes negative values to their absolute value versions!)
22
+ @playlist.add_song(@song)
23
+ @round_amount = 2 # you only need to change the test in one place (this line)
24
+ # to run different number of rounds in the spec file!
25
+ end
26
+
27
+ it "initial rank gets converted to a positive value" do # kind of a "duplicate" test from the one in song_spec.rb
28
+ # expect(@song.rank).to eq(@initial_rank.abs())
29
+ expect(@song.rank).to eq(10)
30
+ end
31
+
32
+ it "initial rank gets normalized correctly" do # not a duplicate test, this tests the normalize and multiplier methods
33
+ # expect(@song.rank).to eq(@initial_rank.abs())
34
+ @playlist.sort_songs
35
+ @playlist.normalize_ranks
36
+ expect(@song.rank).to eq(1)
37
+ end
38
+
39
+ it "initial rank gets normalized and multiplied correctly" do # not a duplicate test, this tests the normalize and multiplier methods
40
+ # expect(@song.rank).to eq(@initial_rank.abs())
41
+ @playlist.sort_songs
42
+ @playlist.normalize_ranks
43
+ @playlist.multiply_ranks
44
+ expect(@song.rank).to eq(10)
45
+ end
46
+
47
+ it "thumbs up on high number (5-6)" do
48
+ Die.any_instance.stub(:roll).and_return(5)
49
+ allow(Council).to receive(:random).and_return(Council::REVIEWERS[0]) # FINALLY got the right code to retrieve roger each roll!
50
+ @playlist.play(@round_amount)
51
+ expect(@song.rank).to eq((10) - (100 * @round_amount)) # the (100) represents the new ranking (normalized and multiplied) of the only song in the list
52
+ end # thumbs down makes rank number smaller therefore higher on list!
53
+
54
+ it "no change on medium number (3-4)" do
55
+ Die.any_instance.stub(:roll).and_return(3)
56
+ @playlist.play(@round_amount)
57
+ expect(@song.rank).to eq((10)) # 10: The one song in the playlist gets a normalized rank of 1 which gets multiplied to 10.
58
+ end
59
+
60
+ it "thumbs down on low number (1-2)" do
61
+ Die.any_instance.stub(:roll).and_return(1)
62
+ allow(Council).to receive(:random).and_return(Council::REVIEWERS[0])
63
+ @playlist.play(@round_amount)
64
+ expect(@song.rank).to eq((10) + (100 * @round_amount)) # the (10) represents the new ranking (normalized and multiplied) of the only song in the list
65
+ end # thumbs down makes rank bigger therefore lower on list!
66
+ end
67
+
68
+ context "multiple song playlist" do
69
+ before do
70
+ @song1 = Song.new("In the Flesh?", 500) # middle song, should come out to rank = 2
71
+ @song2 = Song.new("Vera", 1000) # last song, should come out to rank = 3
72
+ @song3 = Song.new("Comfortably Numb", 25) # top song, should come out to rank = 1
73
+
74
+ @playlist.add_song(@song1)
75
+ @playlist.add_song(@song2)
76
+ @playlist.add_song(@song3)
77
+
78
+ @playlist.sort_songs #this method sorts before running the game!
79
+ @playlist.normalize_ranks #this normalizes the ranks to the array size
80
+ end
81
+
82
+ it "all three songs are correctly sorted in the playlist" do
83
+ expect(@playlist.show_titles).to eq(["Comfortably Numb", "In the Flesh?", "Vera"])
84
+ end
85
+
86
+ it "all three songs are correctly ranked" do
87
+ expect(@song1.rank).to eq(2)
88
+ expect(@song2.rank).to eq(3)
89
+ expect(@song3.rank).to eq(1)
90
+ end
91
+
92
+ end
93
+
94
+ context "default values replacing nils (multiple song playlist)" do
95
+ before do
96
+ @my_list = Playlist.new("Jamie's Pink Floyd Playlist")
97
+
98
+ default_player_file = File.join(File.dirname(__FILE__), "../../bin/THE_WALL.csv") #plays an entered file OR the default (WALL.csv)
99
+ @my_list.load_songs(ARGV.shift || default_player_file)
100
+ end
101
+
102
+ it "replaces nil rank values with default value of 10000" do
103
+ expect(@my_list.list[11].rank).to eq(10000) # "young lust" correctly gets assigned default rank of 10000
104
+ end
105
+ end
106
+
107
+ end
108
+ end
@@ -0,0 +1,80 @@
1
+ # ***** SONG TEST FILE *******
2
+ # require_relative 'song' # calls the song class file
3
+ require 'songfile/song'
4
+
5
+ module Songfile
6
+ describe Song do
7
+
8
+ context "song with a NEGATIVE ranking" do
9
+ before do
10
+ @song = Song.new("the happiest days of our lives", -10) # a user types in a negative rank (not ok)
11
+ end
12
+
13
+ it "automatically gets a negative rank # assigned to a positive rank #" do
14
+ expect(@song.rank).to eq(10) #rather than -10
15
+ end
16
+ end
17
+
18
+ context "default ranking song" do
19
+ before do
20
+ @initial_rank = 0
21
+ @song = Song.new("the happiest days of our lives")
22
+ end
23
+
24
+ it "has a default rank of 10000" do
25
+ #song.rank.should == 10000
26
+ @song = Song.new("the happiest days of our lives")
27
+ expect(@song.rank).to eq(10000) #Changed default to 10000 so UNRANKED songs are listed lowest in the playlist (assuming other RANKED songs are < 10000)
28
+ end
29
+
30
+ it "IS NOT a top 10 song" do
31
+ expect(@song.status).to eq("*Not Top 10*")
32
+ end
33
+ end
34
+
35
+ before do
36
+ @initial_rank = 10
37
+ @song = Song.new("the happiest days of our lives", @initial_rank)
38
+ end
39
+
40
+ it "has a capitalized title" do
41
+ #song.title.should == "The Happiest Days of Our Lives"
42
+ expect(@song.title).to eq("The Happiest Days of Our Lives") #better, new syntax
43
+ end
44
+
45
+ it "has an initial rank" do
46
+ #song.title.should == "The Happiest Days of Our Lives"
47
+ expect(@song.rank).to eq(10) #better, new syntax
48
+ expect(@initial_rank).to eq(10) #better, new syntax
49
+ end
50
+
51
+ it "has correct description" do
52
+ expect do
53
+ @song.describe
54
+ end.to output("'#{@song.title}' has a rank of #{@song.rank}.\n").to_stdout
55
+ end
56
+
57
+ it "has correct display with 'to_s' (Song)" do
58
+ expect(@song.to_s).to eq("The Happiest Days of Our Lives (10)") #removed *top 10* display from to_s method
59
+ end
60
+
61
+ it "has correct status" do
62
+ expect(@song.status).to eq("*Top 10*")
63
+ end
64
+
65
+ it "has correct rank after thumbs up" do
66
+ @song.thumbs_up
67
+ expect(@song.rank).to eq(9)
68
+ end
69
+
70
+ it "has correct rank after thumbs down" do
71
+ @song.thumbs_down
72
+ expect(@song.rank).to eq(11)
73
+ end
74
+
75
+ it "IS a top 10 song" do
76
+ expect(@song.status).to eq("*Top 10*")
77
+ end
78
+
79
+ end
80
+ end
metadata ADDED
@@ -0,0 +1,89 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: songfile
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - Jamie Clark
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2022-06-23 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '2.8'
20
+ - - ">="
21
+ - !ruby/object:Gem::Version
22
+ version: 2.8.0
23
+ type: :development
24
+ prerelease: false
25
+ version_requirements: !ruby/object:Gem::Requirement
26
+ requirements:
27
+ - - "~>"
28
+ - !ruby/object:Gem::Version
29
+ version: '2.8'
30
+ - - ">="
31
+ - !ruby/object:Gem::Version
32
+ version: 2.8.0
33
+ description: |
34
+ ************************************** BASIC INSTRUCTIONS **************************************
35
+ TO RUN DEFAULT CSV SHEET (THE WALL)):
36
+ ruby bin/songfile
37
+
38
+ TO RUN DARK SIDE OF THE MOON ALBUM SONGS
39
+ ruby bin/songfile bin/DSOTM.csv
40
+
41
+ TO RUN SPECS:
42
+ rspec (not "rspec .")
43
+ email: clarkcjamie@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - LICENSE.txt
49
+ - README.txt
50
+ - bin/DSOTM.csv
51
+ - bin/THE_WALL.csv
52
+ - bin/songfile
53
+ - lib/songfile/classic_song.rb
54
+ - lib/songfile/council.rb
55
+ - lib/songfile/die.rb
56
+ - lib/songfile/playlist.rb
57
+ - lib/songfile/playlist_turn.rb
58
+ - lib/songfile/song.rb
59
+ - spec/songfile/council_spec.rb
60
+ - spec/songfile/playlist_spec.rb
61
+ - spec/songfile/song_spec.rb
62
+ homepage: http://pragmaticstudio.com
63
+ licenses:
64
+ - MIT
65
+ metadata: {}
66
+ post_install_message:
67
+ rdoc_options: []
68
+ require_paths:
69
+ - lib
70
+ required_ruby_version: !ruby/object:Gem::Requirement
71
+ requirements:
72
+ - - ">="
73
+ - !ruby/object:Gem::Version
74
+ version: '1.9'
75
+ required_rubygems_version: !ruby/object:Gem::Requirement
76
+ requirements:
77
+ - - ">="
78
+ - !ruby/object:Gem::Version
79
+ version: '0'
80
+ requirements: []
81
+ rubygems_version: 3.3.7
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Text based game for ranking music playlists featuring multiple rounds, a
85
+ panel of reviewers from Pink Floyd, and output of the newly ranked playlist.
86
+ test_files:
87
+ - spec/songfile/council_spec.rb
88
+ - spec/songfile/playlist_spec.rb
89
+ - spec/songfile/song_spec.rb