mikeplayer 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/.gitignore +51 -0
- data/Gemfile +4 -0
- data/LICENSE +674 -0
- data/README.md +2 -0
- data/Rakefile +10 -0
- data/bin/MikePlayer.rb +26 -0
- data/lib/mikeplayer/executable.rb +27 -0
- data/lib/mikeplayer/play_thread.rb +14 -0
- data/lib/mikeplayer/playlist.rb +101 -0
- data/lib/mikeplayer/settings.rb +74 -0
- data/lib/mikeplayer/song.rb +51 -0
- data/lib/mikeplayer/version.rb +3 -0
- data/lib/mikeplayer.rb +254 -0
- data/mikeplayer.gemspec +36 -0
- data/test/mikeplayer/settings_test.rb +17 -0
- data/test/mikeplayer_test.rb +9 -0
- data/test/test_helper.rb +5 -0
- metadata +142 -0
data/Rakefile
ADDED
data/bin/MikePlayer.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'mikeplayer'
|
4
|
+
|
5
|
+
options = {}
|
6
|
+
OptionParser.new do |opt|
|
7
|
+
opt.banner = <<-EOF
|
8
|
+
Usage: MikePlayer.rb [options] <search || file>
|
9
|
+
|
10
|
+
Example: `MikePlayer.rb --shuffle --directory /User/Catman/Music cats /MyMusic/GreatestBand-Song.mp3`
|
11
|
+
Finds all songs matching 'cats' in directory /User/Catman/Music ignoring case
|
12
|
+
and specific song /MyMusic/GreatestBand-Song.mp3
|
13
|
+
and randomizes the order
|
14
|
+
|
15
|
+
EOF
|
16
|
+
opt.on('-s', '--shuffle', 'Shuffle playlist.') { |o| options[:shuffle] = true }
|
17
|
+
opt.on('-r', '--random n', 'Create playlist with randomly picked n songs.') { |o| options[:random] = o.to_i }
|
18
|
+
opt.on('-o', '--overwrite', 'Overwrite playlist.') { |o| options[:overwrite] = true }
|
19
|
+
opt.on('-v', '--volume n', 'Changes default volume.') { |o| options[:volume] = o }
|
20
|
+
opt.on('-p', '--playlist name', 'Play playlist name.') { |o| options[:playlist] = o }
|
21
|
+
opt.on('-l', '--list', 'List songs in playlist.') { |o| options[:list] = true; }
|
22
|
+
opt.on('-d', '--directory name', 'Directory to find mp3s.') { |o| options[:directory] = o }
|
23
|
+
opt.on('-t', '--time minutes', 'Limit time to number of minutes.') { |o| options[:minutes] = o }
|
24
|
+
end.parse!
|
25
|
+
|
26
|
+
MikePlayer::Player.new(options, ARGV).play
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module MikePlayer
|
2
|
+
class PlayThread
|
3
|
+
def initialize(filename)
|
4
|
+
@filename = filename
|
5
|
+
@mp3info = Mp3Info.new(filename)
|
6
|
+
end
|
7
|
+
|
8
|
+
def info
|
9
|
+
artist = "#{@mp3info.tag.artist}"
|
10
|
+
title = "#{@mp3info.tag.title}"
|
11
|
+
|
12
|
+
if (true == artist.empty?) && (true == title.empty?)
|
13
|
+
return File.basename(filename, '.mp3')
|
14
|
+
elsif (true == artist.empty?)
|
15
|
+
artist = "?????"
|
16
|
+
elsif (true == title.empty?)
|
17
|
+
title = "?????"
|
18
|
+
end
|
19
|
+
|
20
|
+
return "#{artist} - #{title}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_json
|
24
|
+
return @filename
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
module MikePlayer
|
2
|
+
class Playlist
|
3
|
+
attr_reader :songs
|
4
|
+
|
5
|
+
def initialize(filename)
|
6
|
+
@filename = filename
|
7
|
+
@songs = []
|
8
|
+
@song_i = 0
|
9
|
+
@length = 0
|
10
|
+
|
11
|
+
load_songs
|
12
|
+
|
13
|
+
@loaded_song_count = @songs.size
|
14
|
+
end
|
15
|
+
|
16
|
+
def <<(song)
|
17
|
+
if ((true == File.file?(song)) && (false == @songs.any? { |s| s.filename == song }))
|
18
|
+
@songs << Song.new(song)
|
19
|
+
@length += @songs.last.length
|
20
|
+
end
|
21
|
+
|
22
|
+
return self
|
23
|
+
end
|
24
|
+
|
25
|
+
def add_random(n, directory)
|
26
|
+
files = Dir.glob(File.join(directory, "**", "*.mp3"), File::FNM_CASEFOLD) - @songs
|
27
|
+
|
28
|
+
files.sample(n).each do |file|
|
29
|
+
self << file
|
30
|
+
end
|
31
|
+
|
32
|
+
return self
|
33
|
+
end
|
34
|
+
|
35
|
+
def find_song(file, directory)
|
36
|
+
if (true == File.file?(file))
|
37
|
+
self << file
|
38
|
+
else
|
39
|
+
Dir.glob(File.join(directory, "**", "*#{file}*"), File::FNM_CASEFOLD).each do |f|
|
40
|
+
self << f
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
return self
|
45
|
+
end
|
46
|
+
|
47
|
+
def current
|
48
|
+
return @songs[@song_i]
|
49
|
+
end
|
50
|
+
|
51
|
+
def next
|
52
|
+
@song_i += 1
|
53
|
+
|
54
|
+
return self.current
|
55
|
+
end
|
56
|
+
|
57
|
+
def previous
|
58
|
+
@song_i -= 1 unless @song_i <= 0
|
59
|
+
|
60
|
+
return self.current
|
61
|
+
end
|
62
|
+
|
63
|
+
def shuffle!
|
64
|
+
@songs.shuffle!
|
65
|
+
|
66
|
+
return self
|
67
|
+
end
|
68
|
+
|
69
|
+
def save
|
70
|
+
File.open(@filename, 'w') do |f|
|
71
|
+
f.puts(JSON.pretty_generate(@songs.map {|s| s.to_json }))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def name
|
76
|
+
return File.basename(@filename, Settings::PL_FILE_ENDING)
|
77
|
+
end
|
78
|
+
|
79
|
+
def info
|
80
|
+
return "#{self.name} loaded #{@loaded_song_count} songs with length #{Song.as_duration_str(@length)}, added #{@songs.size - @loaded_song_count}"
|
81
|
+
end
|
82
|
+
|
83
|
+
def current_song_info
|
84
|
+
song_i_str = "#{@song_i + 1}".rjust(@songs.size.to_s.size)
|
85
|
+
|
86
|
+
return "Playing (#{song_i_str}/#{@songs.size}): #{current.info}".freeze
|
87
|
+
end
|
88
|
+
|
89
|
+
def finished?
|
90
|
+
return @song_i == @songs.size
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def load_songs
|
96
|
+
if File.file?(@filename)
|
97
|
+
JSON.parse(File.read(@filename)).each {|song| self << song}
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module MikePlayer
|
2
|
+
class Settings
|
3
|
+
DEFAULT_DIRECTORY = 'Music'.freeze
|
4
|
+
DEFAULT_VOLUME = '0.1'
|
5
|
+
SETTINGS_DIRECTORY = '.mikeplayer'.freeze
|
6
|
+
PL_FILE_ENDING = '.mpl'.freeze
|
7
|
+
|
8
|
+
attr_reader :random, :music_dir, :playlist, :volume
|
9
|
+
|
10
|
+
def initialize(options)
|
11
|
+
@shuffle = options[:shuffle]
|
12
|
+
@overwrite = options[:overwrite]
|
13
|
+
@list = options[:list]
|
14
|
+
@home = options[:home] || Dir.home
|
15
|
+
@volume = options[:volume] || DEFAULT_VOLUME
|
16
|
+
@music_dir = options[:directory] || File.join(@home, DEFAULT_DIRECTORY)
|
17
|
+
@settings_dir = options[:settings] || File.join(@home, SETTINGS_DIRECTORY)
|
18
|
+
@minutes = options[:minutes].to_i
|
19
|
+
@random = options[:random].to_i
|
20
|
+
|
21
|
+
if (false == Dir.exist?(@settings_dir))
|
22
|
+
Dir.mkdir(@settings_dir)
|
23
|
+
end
|
24
|
+
|
25
|
+
@playlist = find_playlist(options[:playlist])
|
26
|
+
|
27
|
+
remove_playlist_if_needed(@playlist)
|
28
|
+
end
|
29
|
+
|
30
|
+
def shuffle?
|
31
|
+
return true == @shuffle
|
32
|
+
end
|
33
|
+
|
34
|
+
def random?
|
35
|
+
return 0 < @random
|
36
|
+
end
|
37
|
+
|
38
|
+
def overwrite?
|
39
|
+
return true == @overwrite
|
40
|
+
end
|
41
|
+
|
42
|
+
def list?
|
43
|
+
return true == @list
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def find_playlist(user_option)
|
49
|
+
name = nil
|
50
|
+
|
51
|
+
if (false == user_option.nil?)
|
52
|
+
if (true == File.file?(user_option))
|
53
|
+
return user_option
|
54
|
+
else
|
55
|
+
name = File.basename(user_option, PL_FILE_ENDING)
|
56
|
+
end
|
57
|
+
elsif (true == self.random?)
|
58
|
+
name = "random_n#{@random}"
|
59
|
+
else
|
60
|
+
name = 'default'
|
61
|
+
end
|
62
|
+
|
63
|
+
return File.join(@settings_dir, "#{name}#{PL_FILE_ENDING}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def remove_playlist_if_needed(filename)
|
67
|
+
if (true == File.file?(filename))
|
68
|
+
if ((true == overwrite?) || (true == random?))
|
69
|
+
File.delete(filename)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module MikePlayer
|
2
|
+
class Song
|
3
|
+
attr_reader :filename
|
4
|
+
|
5
|
+
def initialize(filename)
|
6
|
+
@filename = filename
|
7
|
+
@mp3info = Mp3Info.new(filename)
|
8
|
+
end
|
9
|
+
|
10
|
+
def info
|
11
|
+
artist = "#{@mp3info.tag.artist}"
|
12
|
+
title = "#{@mp3info.tag.title}"
|
13
|
+
|
14
|
+
if (true == artist.empty?) && (true == title.empty?)
|
15
|
+
return File.basename(@filename, '.mp3')
|
16
|
+
elsif (true == artist.empty?)
|
17
|
+
artist = "?????"
|
18
|
+
elsif (true == title.empty?)
|
19
|
+
title = "?????"
|
20
|
+
end
|
21
|
+
|
22
|
+
return "#{artist} - #{title}"
|
23
|
+
end
|
24
|
+
|
25
|
+
def length
|
26
|
+
return @mp3info.length
|
27
|
+
end
|
28
|
+
|
29
|
+
def length_str(elapsed_time)
|
30
|
+
return Song.as_duration_str(self.length, elapsed_time)
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_json
|
34
|
+
return @filename.to_s
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.as_duration_str(l, t = nil)
|
38
|
+
l_hr = "%02d" % (l / 3600).floor
|
39
|
+
l_min = "%02d" % ((l % 3600 )/ 60).floor
|
40
|
+
l_sec = "%02d" % (l % 60)
|
41
|
+
e_min = "%02d" % (t / 60).floor unless t.nil?
|
42
|
+
e_sec = "%02d" % (t % 60) unless t.nil?
|
43
|
+
|
44
|
+
result = "#{l_min}:#{l_sec}"
|
45
|
+
result = "#{l_hr}:#{result}" if l >= 3600
|
46
|
+
result = "#{e_min}:#{e_sec} [#{result}]" unless t.nil?
|
47
|
+
|
48
|
+
return result
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
data/lib/mikeplayer.rb
ADDED
@@ -0,0 +1,254 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
require 'json'
|
3
|
+
require 'open3'
|
4
|
+
require 'io/console'
|
5
|
+
require 'mp3info'
|
6
|
+
require 'mikeplayer/version'
|
7
|
+
require 'mikeplayer/settings'
|
8
|
+
require 'mikeplayer/playlist'
|
9
|
+
require 'mikeplayer/song'
|
10
|
+
|
11
|
+
module MikePlayer
|
12
|
+
class Player
|
13
|
+
PAUSE_INDICATOR = " ||".freeze
|
14
|
+
SLEEP_SETTING = 0.5
|
15
|
+
STOPPED = :stopped
|
16
|
+
PLAYING = :playing
|
17
|
+
PAUSED = :paused
|
18
|
+
|
19
|
+
def initialize(options, *args)
|
20
|
+
@settings = Settings.new(options)
|
21
|
+
@playlist = Playlist.new(@settings.playlist)
|
22
|
+
@command = ''
|
23
|
+
@pid = nil
|
24
|
+
@timer_start = nil
|
25
|
+
@state = STOPPED
|
26
|
+
|
27
|
+
check_system
|
28
|
+
|
29
|
+
if (true == @settings.list?)
|
30
|
+
@songs.map { |song| File.basename(song) }.sort.each {|song| puts "#{File.basename(song)}"}
|
31
|
+
|
32
|
+
exit 0
|
33
|
+
end
|
34
|
+
|
35
|
+
args.flatten.each do |arg|
|
36
|
+
@playlist.find_song(arg, @settings.music_dir)
|
37
|
+
end
|
38
|
+
|
39
|
+
if (true == @settings.random?)
|
40
|
+
@playlist.add_random(@settings.random, @settings.music_dir)
|
41
|
+
end
|
42
|
+
|
43
|
+
@playlist.save
|
44
|
+
end
|
45
|
+
|
46
|
+
def play
|
47
|
+
@playlist.shuffle! if @settings.shuffle?
|
48
|
+
|
49
|
+
print "Playlist #{@playlist.info}\n"
|
50
|
+
|
51
|
+
if @playlist.finished?
|
52
|
+
puts "No songs in playlist."
|
53
|
+
|
54
|
+
exit 1
|
55
|
+
end
|
56
|
+
|
57
|
+
@thread = Thread.new do
|
58
|
+
display_width = 0
|
59
|
+
|
60
|
+
while (false == @playlist.finished?)
|
61
|
+
song = @playlist.current
|
62
|
+
@song_start = Time.now
|
63
|
+
info_prefix = "\r#{@playlist.current_song_info}".freeze
|
64
|
+
|
65
|
+
stdin, stdother, thread_info = Open3.popen2e('play', '--no-show-progress', '--volume', @settings.volume, song.filename)
|
66
|
+
|
67
|
+
@state = PLAYING
|
68
|
+
@pid = thread_info.pid
|
69
|
+
indicator = ''
|
70
|
+
|
71
|
+
while (true == pid_alive?)
|
72
|
+
pause_if_over_time_limit
|
73
|
+
|
74
|
+
if (true == playing?)
|
75
|
+
indicator = "#{'>' * (playing_time % 4)}"
|
76
|
+
info_changed = true
|
77
|
+
elsif (true == paused?) && (PAUSE_INDICATOR != indicator)
|
78
|
+
indicator = PAUSE_INDICATOR
|
79
|
+
info_changed = true
|
80
|
+
end
|
81
|
+
|
82
|
+
if (true == info_changed)
|
83
|
+
mindicator = ""
|
84
|
+
|
85
|
+
if (0 < minutes_remaining)
|
86
|
+
mindicator = "(#{minutes_remaining}↓) "
|
87
|
+
end
|
88
|
+
|
89
|
+
info = "#{info_prefix} #{song.length_str(playing_time)} #{mindicator}#{indicator}".ljust(display_width)
|
90
|
+
|
91
|
+
display_width = info.size
|
92
|
+
|
93
|
+
print(info)
|
94
|
+
|
95
|
+
$stdout.flush
|
96
|
+
end
|
97
|
+
|
98
|
+
sleep SLEEP_SETTING
|
99
|
+
end
|
100
|
+
|
101
|
+
stdin.close
|
102
|
+
stdother.close
|
103
|
+
|
104
|
+
@pid = nil
|
105
|
+
|
106
|
+
if (true == playing?)
|
107
|
+
next_song
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
@pid = nil
|
112
|
+
exit
|
113
|
+
end
|
114
|
+
|
115
|
+
wait_on_user
|
116
|
+
|
117
|
+
puts ""
|
118
|
+
end
|
119
|
+
|
120
|
+
def cmd_exist?(cmd)
|
121
|
+
if (true != system('command'))
|
122
|
+
raise "Missing 'command' command, which is used to test compatibility."
|
123
|
+
end
|
124
|
+
|
125
|
+
if (true != system("command -v #{cmd} >/dev/null 2>&1"))
|
126
|
+
return false
|
127
|
+
end
|
128
|
+
|
129
|
+
return true
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
|
134
|
+
def check_system
|
135
|
+
%w(play).each do |cmd|
|
136
|
+
if (false == cmd_exist?(cmd))
|
137
|
+
raise "#{cmd} failed, do you have sox installed?"
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
return nil
|
142
|
+
end
|
143
|
+
|
144
|
+
def wait_on_user
|
145
|
+
while ('q' != @command)
|
146
|
+
@command = STDIN.getch
|
147
|
+
|
148
|
+
if ('c' == @command)
|
149
|
+
press_pause
|
150
|
+
elsif ('v' == @command)
|
151
|
+
next_song
|
152
|
+
elsif ('z' == @command)
|
153
|
+
previous_song
|
154
|
+
elsif ('q' == @command) && (false == @pid.nil?)
|
155
|
+
stop_song
|
156
|
+
@thread.kill
|
157
|
+
elsif ('t' == @command)
|
158
|
+
@timer_start = Time.now
|
159
|
+
elsif (false == @timer_start.nil?) && ("#{@command.to_i}" == @command)
|
160
|
+
if (0 == @minutes)
|
161
|
+
@minutes = @command.to_i
|
162
|
+
else
|
163
|
+
@minutes *= 10
|
164
|
+
@minutes += @command.to_i
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def playing?
|
171
|
+
return (PLAYING == @state)
|
172
|
+
end
|
173
|
+
|
174
|
+
def paused?
|
175
|
+
return (PAUSED == @state)
|
176
|
+
end
|
177
|
+
|
178
|
+
def press_pause
|
179
|
+
if (true == playing?)
|
180
|
+
kill("STOP")
|
181
|
+
@state = PAUSED
|
182
|
+
elsif (true == paused?)
|
183
|
+
kill("CONT")
|
184
|
+
@state = PLAYING
|
185
|
+
else
|
186
|
+
print("Confused state #{@state}.")
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def stop_song
|
191
|
+
if (true == paused?)
|
192
|
+
kill("CONT")
|
193
|
+
end
|
194
|
+
|
195
|
+
kill("INT")
|
196
|
+
|
197
|
+
sleep 0.2
|
198
|
+
|
199
|
+
if (true == pid_alive?)
|
200
|
+
kill("KILL")
|
201
|
+
end
|
202
|
+
|
203
|
+
@state = STOPPED
|
204
|
+
end
|
205
|
+
|
206
|
+
def pid_alive?(pid = @pid)
|
207
|
+
if (false == pid.nil?)
|
208
|
+
return system("ps -p #{pid} > /dev/null")
|
209
|
+
end
|
210
|
+
|
211
|
+
return false
|
212
|
+
end
|
213
|
+
|
214
|
+
def next_song
|
215
|
+
stop_song
|
216
|
+
|
217
|
+
@playlist.next
|
218
|
+
end
|
219
|
+
|
220
|
+
def previous_song
|
221
|
+
stop_song
|
222
|
+
|
223
|
+
@playlist.previous
|
224
|
+
end
|
225
|
+
|
226
|
+
def kill(signal)
|
227
|
+
if (false == @pid.nil?)
|
228
|
+
Process.kill(signal, @pid)
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def pause_if_over_time_limit
|
233
|
+
if (false == @timer_start.nil?) && (0 < @minutes) && (true == playing?)
|
234
|
+
if (0 > minutes_remaining)
|
235
|
+
press_pause
|
236
|
+
@timer_start = nil
|
237
|
+
@minutes = 0
|
238
|
+
end
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
def playing_time
|
243
|
+
return (Time.now - @song_start).to_i
|
244
|
+
end
|
245
|
+
|
246
|
+
def minutes_remaining
|
247
|
+
if ((0 == @minutes) || (@timer_start.nil?))
|
248
|
+
return -1
|
249
|
+
else
|
250
|
+
return (@minutes - ((Time.now - @timer_start).to_i / 60).to_i)
|
251
|
+
end
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
data/mikeplayer.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'mikeplayer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |gem|
|
7
|
+
gem.name = 'mikeplayer'
|
8
|
+
gem.version = MikePlayer::VERSION
|
9
|
+
gem.authors = ['Mike Crockett']
|
10
|
+
gem.email = ['rubygems@mmcrockett.com']
|
11
|
+
gem.summary = 'Wraps Sox\'s `play` command, allowing playslists, find, random and time limit.'
|
12
|
+
gem.executables << 'MikePlayer.rb'
|
13
|
+
gem.description = <<-EOF.gsub(/^\s+/, '')
|
14
|
+
#{gem.summary}
|
15
|
+
|
16
|
+
Once a song is playing you can:
|
17
|
+
'x' to previous
|
18
|
+
'c' to pause/play
|
19
|
+
'v' to next
|
20
|
+
'q' to quit
|
21
|
+
't' n to set a timer that will pause the music after n minutes
|
22
|
+
EOF
|
23
|
+
gem.homepage = 'https://github.com/mmcrockett/mikeplayer'
|
24
|
+
|
25
|
+
gem.files = `git ls-files`.split($/)
|
26
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
27
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
28
|
+
gem.require_paths = ['lib']
|
29
|
+
gem.licenses = ['MIT']
|
30
|
+
|
31
|
+
gem.add_dependency 'json', '~> 1.8'
|
32
|
+
gem.add_dependency 'ruby-mp3info', '~> 0.8'
|
33
|
+
gem.add_dependency 'minitest', '~> 5'
|
34
|
+
gem.add_development_dependency 'rake', '~> 12'
|
35
|
+
gem.add_development_dependency 'byebug', '~> 11'
|
36
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class SettingsTest < Minitest::Test
|
4
|
+
describe 'settings' do
|
5
|
+
let(:home) { File.join('', 'tmp') }
|
6
|
+
let(:sdir) { File.join(home, MikePlayer::Settings::SETTINGS_DIRECTORY) }
|
7
|
+
|
8
|
+
before do
|
9
|
+
Dir.delete(sdir) if Dir.exist?(sdir)
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'creates a settings directory' do
|
13
|
+
MikePlayer::Settings.new(home: home)
|
14
|
+
assert(Dir.exist?(sdir))
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|