songfile 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|