spinna 0.0.1
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 +14 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +67 -0
- data/Rakefile +16 -0
- data/bin/spinna +7 -0
- data/lib/spinna.rb +12 -0
- data/lib/spinna/cli.rb +23 -0
- data/lib/spinna/client.rb +44 -0
- data/lib/spinna/config.rb +86 -0
- data/lib/spinna/history.rb +76 -0
- data/lib/spinna/music_library.rb +36 -0
- data/lib/spinna/picker.rb +52 -0
- data/lib/spinna/version.rb +3 -0
- data/spec/fixtures/data_dir/config.yml +3 -0
- data/spec/fixtures/data_dir/config1.yml +2 -0
- data/spec/fixtures/data_dir/config2.yml +3 -0
- data/spec/fixtures/data_dir/config3.yml +4 -0
- data/spec/fixtures/data_dir/config4.yml +4 -0
- data/spec/fixtures/data_dir/history.log +3 -0
- data/spec/fixtures/source_dir/album1/.gitkeep +0 -0
- data/spec/fixtures/source_dir/album2/.gitkeep +0 -0
- data/spec/fixtures/source_dir/album3/.gitkeep +0 -0
- data/spec/functional/get_spec.rb +99 -0
- data/spec/spec_helper.rb +41 -0
- data/spec/unit/client_spec.rb +115 -0
- data/spec/unit/config_spec.rb +125 -0
- data/spec/unit/history_spec.rb +82 -0
- data/spec/unit/music_library_spec.rb +59 -0
- data/spec/unit/picker_spec.rb +250 -0
- data/spinna.gemspec +30 -0
- metadata +206 -0
File without changes
|
File without changes
|
File without changes
|
@@ -0,0 +1,99 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'open3'
|
3
|
+
|
4
|
+
describe 'spinna get' do
|
5
|
+
before do
|
6
|
+
create_fake_source_dir
|
7
|
+
create_fake_data_dir
|
8
|
+
@download_dir = create_tmp_download_dir
|
9
|
+
ENV['SPINNA_DATA_DIR'] = File.join(Dir.tmpdir, 'spinna')
|
10
|
+
@wd = Dir.getwd
|
11
|
+
Dir.chdir(@download_dir)
|
12
|
+
end
|
13
|
+
|
14
|
+
after do
|
15
|
+
ENV.delete('SPINNA_DATA_DIR')
|
16
|
+
Dir.chdir(@wd)
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when used without any options' do
|
20
|
+
before do
|
21
|
+
Open3.popen3("#{@wd}/bin/spinna get") do |stdin, stdout, stderr, wait_thr|
|
22
|
+
@stdout = stdout.read
|
23
|
+
@stderr = stderr.read
|
24
|
+
@exit_status = wait_thr.value
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'gets the number of albums set in the config from source_dir' do
|
29
|
+
# It must not have output any errors.
|
30
|
+
@stderr.must_be_empty
|
31
|
+
|
32
|
+
# Gets the correct number of picks
|
33
|
+
picks = @stdout.split("\n")
|
34
|
+
picks.size.must_equal 2
|
35
|
+
|
36
|
+
# Exits with a successful exit code
|
37
|
+
@exit_status.success?.must_equal true
|
38
|
+
|
39
|
+
# It added the picks to the history log
|
40
|
+
history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
|
41
|
+
history.split("\n").size.must_equal 2
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when given a -n (--number_of_picks) option' do
|
46
|
+
before do
|
47
|
+
Open3.popen3("#{@wd}/bin/spinna get -n 3") do |stdin, stdout, stderr, wait_thr|
|
48
|
+
@stdout = stdout.read
|
49
|
+
@stderr = stderr.read
|
50
|
+
@exit_status = wait_thr.value
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
it 'gets that number of albums from source_dir' do
|
55
|
+
# It must not output any errors
|
56
|
+
@stderr.must_be_empty
|
57
|
+
|
58
|
+
# Gets the correct number of picks
|
59
|
+
# picks = @stdout.split("\n")
|
60
|
+
# picks.size.must_equal 3
|
61
|
+
|
62
|
+
# Exits with a successful exit code
|
63
|
+
@exit_status.success?.must_equal true
|
64
|
+
|
65
|
+
# It updates the history log
|
66
|
+
history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
|
67
|
+
history.split("\n").size.must_equal 3
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when given a -p (--pattern) option' do
|
72
|
+
before do
|
73
|
+
Open3.popen3("#{@wd}/bin/spinna get -p \"album 1\" -n 1") do |stdin, stdout, stderr, wait_thr|
|
74
|
+
@stdout = stdout.read
|
75
|
+
@stderr = stderr.read
|
76
|
+
@exit_status = wait_thr.value
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
it 'picks only albums that match the given pattern' do
|
81
|
+
# It must not output any errors
|
82
|
+
@stderr.must_be_empty
|
83
|
+
|
84
|
+
# Gets the correct number of picks
|
85
|
+
picks = @stdout.split("\n")
|
86
|
+
picks.size.must_equal 1
|
87
|
+
|
88
|
+
# The pick should match the given pattern
|
89
|
+
picks.first.must_equal "Copying album 1..."
|
90
|
+
|
91
|
+
# Exits with a successful exit code
|
92
|
+
@exit_status.success?.must_equal true
|
93
|
+
|
94
|
+
# It updates the history log
|
95
|
+
history = File.read("#{ENV['SPINNA_DATA_DIR']}/history.log")
|
96
|
+
history.split("\n").size.must_equal 1
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'minitest/autorun'
|
2
|
+
require 'minitest/spec'
|
3
|
+
require 'minitest/pride'
|
4
|
+
require 'minitest-spec-context'
|
5
|
+
require 'mocha/mini_test'
|
6
|
+
require 'minitest/reporters'
|
7
|
+
require 'tmpdir'
|
8
|
+
require 'fileutils'
|
9
|
+
|
10
|
+
Minitest::Reporters.use! Minitest::Reporters::DefaultReporter.new(:color => true)
|
11
|
+
|
12
|
+
def create_fake_source_dir
|
13
|
+
path = File.join(Dir.tmpdir, 'spinna_source_dir')
|
14
|
+
FileUtils.rm_rf(path)
|
15
|
+
FileUtils.mkdir(path)
|
16
|
+
5.times do |i|
|
17
|
+
FileUtils.mkdir(File.join(path, "album #{i+1}"))
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def create_fake_data_dir
|
22
|
+
path = File.join(Dir.tmpdir, 'spinna')
|
23
|
+
FileUtils.rm_rf(path)
|
24
|
+
FileUtils.mkdir(path)
|
25
|
+
config = {
|
26
|
+
'source_dir' => File.join(Dir.tmpdir, 'spinna_source_dir'),
|
27
|
+
'history_size' => 4,
|
28
|
+
'number_of_picks' => 2
|
29
|
+
}
|
30
|
+
config_path = File.join(path, 'config.yml')
|
31
|
+
File.open(config_path, 'w+') do |f|
|
32
|
+
f.write config.to_yaml
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def create_tmp_download_dir
|
37
|
+
path = File.join(Dir.tmpdir, 'spinna_download_dir')
|
38
|
+
FileUtils.rm_rf(path)
|
39
|
+
FileUtils.mkdir(path)
|
40
|
+
path
|
41
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spinna/client'
|
3
|
+
|
4
|
+
describe Spinna::Client do
|
5
|
+
describe '.new' do
|
6
|
+
let(:config) { stub() }
|
7
|
+
let(:history) { stub() }
|
8
|
+
let(:picker) { stub() }
|
9
|
+
let(:music_library) { stub() }
|
10
|
+
|
11
|
+
before do
|
12
|
+
Spinna::Config.expects(:new).returns(config)
|
13
|
+
Spinna::History.expects(:new).returns(history)
|
14
|
+
Spinna::MusicLibrary.expects(:new).returns(music_library)
|
15
|
+
end
|
16
|
+
|
17
|
+
subject { Spinna::Client.new }
|
18
|
+
|
19
|
+
it 'assigns a config object to an instance variable' do
|
20
|
+
subject.config.must_equal config
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'assigns a history object to an instance variable' do
|
24
|
+
subject.history.must_equal history
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'assigns a music_library object to an instance variable' do
|
28
|
+
subject.library.must_equal music_library
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe '#get' do
|
33
|
+
let(:default_number_of_picks) { 2 }
|
34
|
+
let(:picker) { stub }
|
35
|
+
let(:music_library) { stub }
|
36
|
+
let(:picks) { ['album 1', 'album 2'] }
|
37
|
+
|
38
|
+
before do
|
39
|
+
Spinna::Config.stubs(:new).returns(config)
|
40
|
+
Spinna::History.stubs(:new).returns(history)
|
41
|
+
Spinna::Picker.stubs(:new).returns(picker)
|
42
|
+
Spinna::MusicLibrary.stubs(:new).returns(music_library)
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'when called without arguments' do
|
46
|
+
let(:config) do
|
47
|
+
stub(
|
48
|
+
:number_of_picks => default_number_of_picks,
|
49
|
+
:source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
|
50
|
+
)
|
51
|
+
end
|
52
|
+
let(:history) { stub }
|
53
|
+
let(:picker) do
|
54
|
+
picker = stub
|
55
|
+
picker.stubs(:pick).returns(picks)
|
56
|
+
picker
|
57
|
+
end
|
58
|
+
|
59
|
+
subject { Spinna::Client.new }
|
60
|
+
|
61
|
+
it 'requests the default number of picks from the picker' do
|
62
|
+
picker.expects(:pick).with(default_number_of_picks, nil)
|
63
|
+
subject.get
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'returns the picks from the picker' do
|
67
|
+
subject.get.must_equal picks
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'when given a number_of_picks option' do
|
72
|
+
let(:config) do
|
73
|
+
stub(
|
74
|
+
:number_of_picks => default_number_of_picks,
|
75
|
+
:source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
|
76
|
+
)
|
77
|
+
end
|
78
|
+
let(:history) { stub }
|
79
|
+
let(:picker) { stub(:pick => [picks.first]) }
|
80
|
+
|
81
|
+
subject { Spinna::Client.new }
|
82
|
+
|
83
|
+
it 'requests the given number of picks from the picker' do
|
84
|
+
picker.expects(:pick).with(1, nil).returns([picks.first])
|
85
|
+
subject.get(:number_of_picks => 1)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'returns the picks from the picker' do
|
89
|
+
subject.get(:number_of_picks => 1).must_equal [picks.first]
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context 'when given a pattern' do
|
94
|
+
let(:config) do
|
95
|
+
stub(
|
96
|
+
:number_of_picks => default_number_of_picks,
|
97
|
+
:source_dir => File.expand_path("../../fixtures/source_dir", __FILE__)
|
98
|
+
)
|
99
|
+
end
|
100
|
+
let(:history) { stub }
|
101
|
+
let(:picker) { stub(:pick => [picks.first]) }
|
102
|
+
|
103
|
+
subject { Spinna::Client.new }
|
104
|
+
|
105
|
+
it 'requests the picks from the picker with the correct options' do
|
106
|
+
picker.expects(:pick).with(1, 'foo').returns([picks.first])
|
107
|
+
subject.get(:number_of_picks => 1, :pattern => 'foo')
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'returns the picks from the picker' do
|
111
|
+
subject.get(:number_of_picks => 1, :pattern => 'foo').must_equal [picks.first]
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spinna/config'
|
3
|
+
|
4
|
+
describe Spinna::Config do
|
5
|
+
describe 'DEFAULT_HISTORY_SIZE' do
|
6
|
+
it 'is set to 50' do
|
7
|
+
Spinna::Config::DEFAULT_HISTORY_SIZE.must_equal 50
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'DEFAULT_NUMBER_OF_PICKS' do
|
12
|
+
it 'is set to 10' do
|
13
|
+
Spinna::Config::DEFAULT_NUMBER_OF_PICKS.must_equal 10
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#new' do
|
18
|
+
let(:data_dir) { File.expand_path("../../fixtures/data_dir", __FILE__) }
|
19
|
+
let(:non_existing_data_dir) { File.join(Dir.home, '.nonexisting') }
|
20
|
+
|
21
|
+
context 'when the data_dir does not exist' do
|
22
|
+
let(:opts) { {:data_dir => non_existing_data_dir} }
|
23
|
+
|
24
|
+
subject {
|
25
|
+
Hash.new(:foo => 'bar')
|
26
|
+
}
|
27
|
+
|
28
|
+
it 'creates it and raises error because the configuration file is missing' do
|
29
|
+
Dir.expects(:mkdir).with(opts[:data_dir], 0700)
|
30
|
+
proc { Spinna::Config.new(opts) }.must_raise Spinna::ConfigFileNotFoundError
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
context 'when the configuration file does not exist' do
|
35
|
+
let(:opts) { {:data_dir => non_existing_data_dir} }
|
36
|
+
|
37
|
+
subject do
|
38
|
+
Spinna::Config.new(opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
before do
|
42
|
+
Dir.stubs(:mkdir)
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'throws an exception' do
|
46
|
+
opts = {:data_dir => non_existing_data_dir}
|
47
|
+
err = proc { subject }.must_raise Spinna::ConfigFileNotFoundError
|
48
|
+
err.message.must_match %r{Could not find the configuration file.}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'when the configuration file is not valid json' do
|
53
|
+
it 'throws an exception' do
|
54
|
+
opts = {
|
55
|
+
:data_dir => data_dir,
|
56
|
+
:config_file => 'config1.yml'
|
57
|
+
}
|
58
|
+
err = proc { Spinna::Config.new(opts) }.must_raise Spinna::InvalidConfigFileError
|
59
|
+
err.message.must_match %r{Could not parse the configuration file.}
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when the source_dir config parameter is missing' do
|
64
|
+
it 'throws an exception' do
|
65
|
+
opts = {
|
66
|
+
:data_dir => data_dir,
|
67
|
+
:config_file => 'config2.yml'
|
68
|
+
}
|
69
|
+
err = proc { Spinna::Config.new(opts) }.must_raise Spinna::InvalidConfigFileError
|
70
|
+
err.message.must_match %r{You must set a source_dir in your configuration file.}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
context 'when the configuration is valid and all parameters were provided' do
|
75
|
+
it 'sets the source_dir' do
|
76
|
+
opts = {
|
77
|
+
:data_dir => data_dir,
|
78
|
+
:config_file => 'config.yml'
|
79
|
+
}
|
80
|
+
config = Spinna::Config.new(opts)
|
81
|
+
config.source_dir.must_equal '/foo'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'sets the history_size' do
|
85
|
+
opts = {
|
86
|
+
:data_dir => data_dir,
|
87
|
+
:config_file => 'config.yml'
|
88
|
+
}
|
89
|
+
config = Spinna::Config.new(opts)
|
90
|
+
config.history_size.must_equal 10
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'sets the number_of_picks' do
|
94
|
+
opts = {
|
95
|
+
:data_dir => data_dir,
|
96
|
+
:config_file => 'config.yml'
|
97
|
+
}
|
98
|
+
config = Spinna::Config.new(opts)
|
99
|
+
config.number_of_picks.must_equal 5
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'when the configuration is valid but the history_size was not provided' do
|
104
|
+
it 'uses the default value' do
|
105
|
+
opts = {
|
106
|
+
:data_dir => data_dir,
|
107
|
+
:config_file => 'config3.yml'
|
108
|
+
}
|
109
|
+
config = Spinna::Config.new(opts)
|
110
|
+
config.history_size.must_equal Spinna::Config::DEFAULT_HISTORY_SIZE
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'when the configuration is valid but the number_of_picks was not provided' do
|
115
|
+
it 'uses the default value' do
|
116
|
+
opts = {
|
117
|
+
:data_dir => data_dir,
|
118
|
+
:config_file => 'config4.yml'
|
119
|
+
}
|
120
|
+
config = Spinna::Config.new(opts)
|
121
|
+
config.number_of_picks.must_equal Spinna::Config::DEFAULT_NUMBER_OF_PICKS
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'spinna/history'
|
3
|
+
require 'spinna/config'
|
4
|
+
|
5
|
+
describe Spinna::History do
|
6
|
+
let(:data_dir) { File.expand_path("../../fixtures/data_dir", __FILE__) }
|
7
|
+
let(:opts) { {:data_dir => data_dir} }
|
8
|
+
let(:config) { Spinna::Config.new(opts) }
|
9
|
+
let(:history_size) { 3 }
|
10
|
+
|
11
|
+
describe '#new' do
|
12
|
+
subject { Spinna::History.new(config) }
|
13
|
+
|
14
|
+
it 'saves the passed in config in an instance variable' do
|
15
|
+
subject.config.must_equal config
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'reads the history log from the filesystem' do
|
19
|
+
subject.log.size.must_equal history_size
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#append' do
|
24
|
+
subject { Spinna::History.new(config) }
|
25
|
+
|
26
|
+
context 'when the album is not in the history' do
|
27
|
+
it 'appends the album at the end of the history log' do
|
28
|
+
size_before_append = subject.log.size
|
29
|
+
subject.append('album 11')
|
30
|
+
subject.log.size.must_equal size_before_append + 1
|
31
|
+
subject.log.last.must_equal 'album 11'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'when the album is already in the history' do
|
36
|
+
it 'does nothing' do
|
37
|
+
size_before_append = subject.log.size
|
38
|
+
subject.append('album 1')
|
39
|
+
subject.log.size.must_equal size_before_append
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
context 'when the history log is full' do
|
44
|
+
it 'removes the old albums from the log to make room for the new albums' do
|
45
|
+
subject.config.history_size = 3
|
46
|
+
subject.append('album 4')
|
47
|
+
subject.log.size.must_equal 3
|
48
|
+
subject.log.first.must_equal 'album 2'
|
49
|
+
subject.log.last.must_equal 'album 4'
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe '#include?' do
|
55
|
+
subject { Spinna::History.new(config) }
|
56
|
+
|
57
|
+
context 'when the album is in the log' do
|
58
|
+
it 'returns true' do
|
59
|
+
subject.include?('album 1').must_equal true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
context 'when the album is not in the log' do
|
64
|
+
it 'returns false' do
|
65
|
+
subject.include?('album 99').must_equal false
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
describe '#save' do
|
71
|
+
# This is used to fake writing the history.log file.
|
72
|
+
let(:fake_history_log) { StringIO.new('', 'w+') }
|
73
|
+
|
74
|
+
it 'saves the log to the filesystem' do
|
75
|
+
subject = Spinna::History.new(config)
|
76
|
+
# Use of mocking here so that we don’t actually write to the filesystem.
|
77
|
+
File.expects(:open).with(subject.history_path, 'w+').yields(fake_history_log)
|
78
|
+
subject.save
|
79
|
+
fake_history_log.string.must_equal "album 1\nalbum 2\nalbum 3\n"
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|