songfile 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE.txt +19 -0
- data/README.txt +9 -0
- data/bin/DSOTM.csv +10 -0
- data/bin/THE_WALL.csv +13 -0
- data/bin/songfile +55 -0
- data/lib/songfile/classic_song.rb +18 -0
- data/lib/songfile/council.rb +22 -0
- data/lib/songfile/die.rb +13 -0
- data/lib/songfile/playlist.rb +159 -0
- data/lib/songfile/playlist_turn.rb +26 -0
- data/lib/songfile/song.rb +78 -0
- data/spec/songfile/council_spec.rb +52 -0
- data/spec/songfile/playlist_spec.rb +108 -0
- data/spec/songfile/song_spec.rb +80 -0
- metadata +89 -0
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
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
|
data/lib/songfile/die.rb
ADDED
@@ -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
|