hallon 0.13.0 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.md +43 -1
- data/Gemfile +0 -2
- data/LICENSE.txt +1 -1
- data/README.markdown +94 -44
- data/examples/playing_audio.rb +4 -5
- data/lib/hallon.rb +20 -0
- data/lib/hallon/album.rb +13 -12
- data/lib/hallon/album_browse.rb +1 -0
- data/lib/hallon/artist.rb +13 -12
- data/lib/hallon/artist_browse.rb +1 -0
- data/lib/hallon/base.rb +2 -0
- data/lib/hallon/image.rb +18 -10
- data/lib/hallon/loadable.rb +24 -0
- data/lib/hallon/observable.rb +1 -1
- data/lib/hallon/observable/playlist.rb +10 -16
- data/lib/hallon/observable/playlist_container.rb +12 -6
- data/lib/hallon/player.rb +3 -3
- data/lib/hallon/playlist.rb +34 -11
- data/lib/hallon/playlist_container.rb +10 -4
- data/lib/hallon/search.rb +1 -0
- data/lib/hallon/session.rb +2 -2
- data/lib/hallon/toplist.rb +17 -12
- data/lib/hallon/track.rb +1 -0
- data/lib/hallon/user.rb +48 -11
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +2 -0
- data/spec/hallon/album_spec.rb +14 -7
- data/spec/hallon/artist_browse_spec.rb +2 -0
- data/spec/hallon/artist_spec.rb +14 -8
- data/spec/hallon/hallon_spec.rb +12 -0
- data/spec/hallon/image_spec.rb +18 -9
- data/spec/hallon/loadable_spec.rb +46 -0
- data/spec/hallon/observable/playlist_spec.rb +11 -5
- data/spec/hallon/observable_spec.rb +6 -0
- data/spec/hallon/playlist_container_spec.rb +6 -0
- data/spec/hallon/playlist_spec.rb +21 -4
- data/spec/hallon/search_spec.rb +2 -0
- data/spec/hallon/toplist_spec.rb +40 -23
- data/spec/hallon/track_spec.rb +2 -0
- data/spec/hallon/user_post_spec.rb +75 -0
- data/spec/hallon/user_spec.rb +7 -11
- data/spec/spec_helper.rb +2 -2
- metadata +20 -16
- data/examples/audio_driver.rb +0 -55
data/lib/hallon/version.rb
CHANGED
data/spec/hallon/album_spec.rb
CHANGED
@@ -1,5 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
|
+
#
|
2
3
|
describe Hallon::Album do
|
4
|
+
it { should be_a Hallon::Loadable }
|
5
|
+
|
3
6
|
it_should_behave_like "a Linkable object" do
|
4
7
|
let(:spotify_uri) { "spotify:album:1xvnWMz2PNFf7mXOSRuLws" }
|
5
8
|
end
|
@@ -28,21 +31,25 @@ describe Hallon::Album do
|
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
|
-
describe "cover" do
|
34
|
+
describe "#cover" do
|
32
35
|
it "should be nil if there is no image" do
|
33
36
|
Spotify.should_receive(:album_cover).and_return(null_pointer)
|
34
37
|
album.cover.should be_nil
|
35
|
-
|
36
|
-
Spotify.should_receive(:link_create_from_album_cover).and_return(null_pointer)
|
37
|
-
album.cover(false).should be_nil
|
38
38
|
end
|
39
39
|
|
40
40
|
it "should be an image if it exists" do
|
41
|
-
|
41
|
+
stub_session { album.cover.should eq Hallon::Image.new(mock_image_id) }
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe "#cover_link" do
|
46
|
+
it "should be nil if there is no image" do
|
47
|
+
Spotify.should_receive(:link_create_from_album_cover).and_return(null_pointer)
|
48
|
+
album.cover_link.should be_nil
|
42
49
|
end
|
43
50
|
|
44
|
-
it "should be a link if
|
45
|
-
album.
|
51
|
+
it "should be a link if it exists" do
|
52
|
+
album.cover_link.should eq Hallon::Link.new("spotify:image:3ad93423add99766e02d563605c6e76ed2b0e450")
|
46
53
|
end
|
47
54
|
end
|
48
55
|
|
data/spec/hallon/artist_spec.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::Artist do
|
3
|
+
it { should be_a Hallon::Loadable }
|
4
|
+
|
3
5
|
it_should_behave_like "a Linkable object" do
|
4
6
|
let(:spotify_uri) { "spotify:artist:3bftcFwl4vqRNNORRsqm1G" }
|
5
7
|
end
|
@@ -29,20 +31,24 @@ describe Hallon::Artist do
|
|
29
31
|
describe "#portrait" do
|
30
32
|
let(:link) { Hallon::Link.new(mock_image_uri) }
|
31
33
|
|
32
|
-
|
33
|
-
|
34
|
+
it "should be nil if an image is not available" do
|
35
|
+
Spotify.should_receive(:artist_portrait).and_return(null_pointer)
|
36
|
+
artist.portrait.should be_nil
|
34
37
|
end
|
35
38
|
|
36
|
-
|
37
|
-
artist.portrait
|
39
|
+
it "should be an image if it exists" do
|
40
|
+
stub_session { artist.portrait.should eq Hallon::Image.new(mock_image_id) }
|
38
41
|
end
|
42
|
+
end
|
39
43
|
|
44
|
+
describe "#portrait_link" do
|
40
45
|
it "should be nil if an image is not available" do
|
41
|
-
Spotify.should_receive(:artist_portrait).and_return(null_pointer)
|
42
|
-
artist.portrait.should be_nil
|
43
|
-
|
44
46
|
Spotify.should_receive(:link_create_from_artist_portrait).and_return(null_pointer)
|
45
|
-
artist.
|
47
|
+
artist.portrait_link.should be_nil
|
48
|
+
end
|
49
|
+
|
50
|
+
it "should be a link if it exists" do
|
51
|
+
artist.portrait_link.should eq Hallon::Link.new(mock_image_uri)
|
46
52
|
end
|
47
53
|
end
|
48
54
|
end
|
data/spec/hallon/hallon_spec.rb
CHANGED
@@ -18,4 +18,16 @@ describe Hallon do
|
|
18
18
|
it { should match uri }
|
19
19
|
end
|
20
20
|
end
|
21
|
+
|
22
|
+
describe "#load_timeout" do
|
23
|
+
it "should raise an error given a negative timeout" do
|
24
|
+
expect { Hallon.load_timeout = -1 }.to raise_error(ArgumentError)
|
25
|
+
end
|
26
|
+
|
27
|
+
it "should allow setting and retrieving the value" do
|
28
|
+
Hallon.load_timeout.should eq 5
|
29
|
+
Hallon.load_timeout = 0.2
|
30
|
+
Hallon.load_timeout.should eq 0.2
|
31
|
+
end
|
32
|
+
end
|
21
33
|
end
|
data/spec/hallon/image_spec.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
require 'ostruct'
|
3
3
|
|
4
4
|
describe Hallon::Image do
|
5
|
+
it { described_class.should include Hallon::Loadable }
|
6
|
+
|
5
7
|
it_should_behave_like "a Linkable object" do
|
6
8
|
let(:spotify_uri) { "spotify:image:#{mock_image_hex}" }
|
7
9
|
let(:custom_object) { mock_image_hex }
|
@@ -24,9 +26,16 @@ describe Hallon::Image do
|
|
24
26
|
its(:status) { should be :ok }
|
25
27
|
its(:format) { should be :jpeg }
|
26
28
|
|
27
|
-
describe "id" do
|
28
|
-
|
29
|
-
|
29
|
+
describe "#id" do
|
30
|
+
it "should return the image id as a hexadecimal string" do
|
31
|
+
image.id.should eq mock_image_hex
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "#raw_id" do
|
36
|
+
it "should return the image id as a binary string" do
|
37
|
+
image.raw_id.should eq mock_image_id
|
38
|
+
end
|
30
39
|
end
|
31
40
|
|
32
41
|
describe "#data" do
|
@@ -51,17 +60,17 @@ describe Hallon::Image do
|
|
51
60
|
it "should compare ids (but only if other is an Image)" do
|
52
61
|
other = double
|
53
62
|
other.should_receive(:is_a?).with(Hallon::Image).and_return(true)
|
54
|
-
other.should_receive(:
|
63
|
+
other.should_receive(:raw_id).and_return(image.raw_id)
|
55
64
|
|
56
|
-
image.should
|
57
|
-
image.should_not
|
65
|
+
image.should eq other
|
66
|
+
image.should_not eq double
|
58
67
|
end
|
59
68
|
|
60
69
|
it "should not call #id if other is not an image" do
|
61
|
-
|
62
|
-
|
70
|
+
other = double
|
71
|
+
other.should_not_receive(:raw_id)
|
63
72
|
|
64
|
-
image.should_not eq
|
73
|
+
image.should_not eq other
|
65
74
|
end
|
66
75
|
end
|
67
76
|
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
|
3
|
+
describe Hallon::Loadable do
|
4
|
+
let(:session) { double(:session, :process_events => 5) }
|
5
|
+
let(:loadable) do
|
6
|
+
_session = session
|
7
|
+
Class.new do
|
8
|
+
include Hallon::Loadable
|
9
|
+
|
10
|
+
define_method(:session) { _session }
|
11
|
+
end.new
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#load" do
|
15
|
+
it "should timeout if the object does not load in time" do
|
16
|
+
Hallon.stub(:load_timeout).and_return(0.001)
|
17
|
+
loadable.stub(:loaded?).and_return(false)
|
18
|
+
expect { loadable.load }.to raise_error(Hallon::TimeoutError)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should use the Hallon.load_timeout by default" do
|
22
|
+
Hallon.should_receive(:load_timeout).and_return(0.075)
|
23
|
+
Timeout.should_receive(:timeout).with(0.075, Hallon::TimeoutError).and_yield
|
24
|
+
loadable.stub(:loaded?).and_return(true)
|
25
|
+
loadable.load
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return the object in question on success" do
|
29
|
+
loadable.stub(:loaded?).and_return(true)
|
30
|
+
loadable.load.should eq loadable
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should raise an error when status is an error" do
|
34
|
+
session.should_receive(:process_events).once
|
35
|
+
loadable.stub(:loaded?).and_return(false)
|
36
|
+
loadable.stub(:status).and_return(:other_permanent)
|
37
|
+
expect { loadable.load }.to raise_error(Hallon::Error)
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should not raise an error when status is_loading" do
|
41
|
+
loadable.stub(:loaded?).and_return(false, true)
|
42
|
+
loadable.stub(:status).and_return(:is_loading)
|
43
|
+
loadable.load.should eq loadable
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -1,7 +1,13 @@
|
|
1
1
|
describe Hallon::Observable::Playlist do
|
2
2
|
let(:trackpointers_size) { 2 }
|
3
|
+
let(:track_index_pointers) do
|
4
|
+
tracks = FFI::MemoryPointer.new(:pointer, trackpointers_size)
|
5
|
+
tracks.write_array_of_int([0, 1])
|
6
|
+
tracks
|
7
|
+
end
|
8
|
+
|
3
9
|
let(:trackpointers) do
|
4
|
-
tracks = FFI::MemoryPointer.new(:pointer,
|
10
|
+
tracks = FFI::MemoryPointer.new(:pointer, trackpointers_size)
|
5
11
|
tracks.write_array_of_pointer([mock_track, mock_track_two])
|
6
12
|
tracks
|
7
13
|
end
|
@@ -16,13 +22,13 @@ describe Hallon::Observable::Playlist do
|
|
16
22
|
end
|
17
23
|
|
18
24
|
specification_for_callback "tracks_removed" do
|
19
|
-
let(:input) { [a_pointer,
|
20
|
-
let(:output) { [
|
25
|
+
let(:input) { [a_pointer, track_index_pointers, trackpointers_size, :userdata] }
|
26
|
+
let(:output) { [[0, 1], subject] }
|
21
27
|
end
|
22
28
|
|
23
29
|
specification_for_callback "tracks_moved" do
|
24
|
-
let(:input) { [a_pointer,
|
25
|
-
let(:output) { [
|
30
|
+
let(:input) { [a_pointer, track_index_pointers, trackpointers_size, 7, :userdata] }
|
31
|
+
let(:output) { [[0, 1], 7, subject] }
|
26
32
|
end
|
27
33
|
|
28
34
|
specification_for_callback "playlist_renamed" do
|
@@ -136,6 +136,12 @@ describe Hallon::Observable do
|
|
136
136
|
expect { subject.send(:subscribe_for_callbacks) {} }.to raise_error(ArgumentError)
|
137
137
|
end
|
138
138
|
|
139
|
+
it "should do nothing if the result is a null pointer" do
|
140
|
+
klass.should_not_receive(:subscribe)
|
141
|
+
klass.any_instance.stub(:pointer).and_return(FFI::Pointer::NULL)
|
142
|
+
subject.send(:subscribe_for_callbacks) {}
|
143
|
+
end
|
144
|
+
|
139
145
|
it "should always yield the *same* object" do
|
140
146
|
a = klass.new
|
141
147
|
b = klass.new
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::PlaylistContainer do
|
3
|
+
it { should be_a Hallon::Loadable }
|
4
|
+
|
3
5
|
let(:container) { Hallon::PlaylistContainer.new(mock_container) }
|
4
6
|
|
5
7
|
subject { container }
|
@@ -18,6 +20,10 @@ describe Hallon::PlaylistContainer do
|
|
18
20
|
container.contents[-1].should eq playlist
|
19
21
|
end.to change{ container.size }.by(1)
|
20
22
|
end
|
23
|
+
|
24
|
+
it "should raise an error if the name is invalid" do
|
25
|
+
expect { container.add(" ") }.to raise_error(ArgumentError)
|
26
|
+
end
|
21
27
|
end
|
22
28
|
|
23
29
|
context "given a string that’s a valid spotify playlist uri" do
|
@@ -2,9 +2,11 @@
|
|
2
2
|
require 'time'
|
3
3
|
|
4
4
|
describe Hallon::Playlist do
|
5
|
+
it { should be_a Hallon::Loadable }
|
6
|
+
|
5
7
|
it_should_behave_like "a Linkable object" do
|
6
8
|
let(:spotify_uri) { "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi" }
|
7
|
-
let(:described_class) { Hallon::Playlist
|
9
|
+
let(:described_class) { stub_session(Hallon::Playlist) }
|
8
10
|
end
|
9
11
|
|
10
12
|
subject { playlist }
|
@@ -12,6 +14,20 @@ describe Hallon::Playlist do
|
|
12
14
|
Hallon::Playlist.new(mock_playlist)
|
13
15
|
end
|
14
16
|
|
17
|
+
describe ".invalid_name?" do
|
18
|
+
it "should return false if the name is valid" do
|
19
|
+
Hallon::Playlist.invalid_name?("Moo").should be_false
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return an error message when the name is blank" do
|
23
|
+
Hallon::Playlist.invalid_name?(" ").should match "blank"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should return an error message when the name is too long" do
|
27
|
+
Hallon::Playlist.invalid_name?("Moo" * 256).should match "bytes"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
15
31
|
it { should be_loaded }
|
16
32
|
it { should be_collaborative }
|
17
33
|
it { should_not be_pending }
|
@@ -108,8 +124,9 @@ describe Hallon::Playlist do
|
|
108
124
|
playlist.tracks.to_a.should eq new_tracks
|
109
125
|
end
|
110
126
|
|
111
|
-
it "should raise an error if
|
112
|
-
expect { playlist.remove(-1) }.to raise_error(
|
127
|
+
it "should raise an error if given invalid parameters" do
|
128
|
+
expect { playlist.remove(-1) }.to raise_error(ArgumentError)
|
129
|
+
expect { playlist.remove(playlist.size) }.to raise_error(ArgumentError)
|
113
130
|
end
|
114
131
|
end
|
115
132
|
|
@@ -135,7 +152,7 @@ describe Hallon::Playlist do
|
|
135
152
|
end
|
136
153
|
|
137
154
|
it "should fail given an empty name" do
|
138
|
-
expect { playlist.name = "" }.to raise_error(
|
155
|
+
expect { playlist.name = "" }.to raise_error(ArgumentError)
|
139
156
|
end
|
140
157
|
|
141
158
|
it "should fail given a name of only spaces" do
|
data/spec/hallon/search_spec.rb
CHANGED
data/spec/hallon/toplist_spec.rb
CHANGED
@@ -1,23 +1,56 @@
|
|
1
1
|
describe Hallon::Toplist do
|
2
|
+
it { should be_a Hallon::Loadable }
|
3
|
+
|
2
4
|
let(:toplist) do
|
3
5
|
Spotify.registry_add 'spotify:toplist:artists:everywhere', mock_toplistbrowse
|
4
6
|
mock_session { Hallon::Toplist.new(:artists) }
|
5
7
|
end
|
6
|
-
|
7
8
|
subject { toplist }
|
8
9
|
|
9
10
|
it { should be_a Hallon::Observable }
|
11
|
+
|
12
|
+
describe ".new" do
|
13
|
+
it "should fail given an invalid type" do
|
14
|
+
expect { stub_session { Hallon::Toplist.new(:invalid_type) } }.to raise_error(ArgumentError, /invalid enum value/)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "should pass the username given a string to libspotify" do
|
18
|
+
Spotify.registry_add 'spotify:toplist:user:Kim:tracks', mock_toplistbrowse
|
19
|
+
stub_session { Hallon::Toplist.new(:tracks, "Kim").should be_loaded }
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should pass the correct region to libspotify" do
|
23
|
+
Spotify.registry_add 'spotify:toplist:tracks:SE', mock_toplistbrowse
|
24
|
+
mock_session { Hallon::Toplist.new(:tracks, :se).should be_loaded }
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
10
28
|
it { should be_loaded }
|
11
29
|
its(:status) { should eq :ok }
|
12
30
|
|
13
|
-
|
14
|
-
|
31
|
+
describe "#type" do
|
32
|
+
it "should be the same as the type given to .new" do
|
33
|
+
toplist = mock_session { Hallon::Toplist.new(:tracks, :se) }
|
34
|
+
toplist.type.should eq :tracks
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#results" do
|
39
|
+
it "should return an enumerator of the correct type" do
|
40
|
+
toplist.should_receive(:type).and_return(:artists)
|
41
|
+
toplist.results.to_a.should eq instantiate(Hallon::Artist, mock_artist, mock_artist_two)
|
42
|
+
end
|
15
43
|
|
16
|
-
|
17
|
-
|
44
|
+
it "should return an enumerator of the correct type" do
|
45
|
+
toplist.should_receive(:type).and_return(:albums)
|
46
|
+
toplist.results.to_a.should eq instantiate(Hallon::Album, mock_album)
|
47
|
+
end
|
18
48
|
|
19
|
-
|
20
|
-
|
49
|
+
it "should return an enumerator of the correct type" do
|
50
|
+
toplist.should_receive(:type).and_return(:tracks)
|
51
|
+
toplist.results.to_a.should eq instantiate(Hallon::Track, mock_track, mock_track_two)
|
52
|
+
end
|
53
|
+
end
|
21
54
|
|
22
55
|
describe "#request_duration" do
|
23
56
|
it "should return the request duration in seconds" do
|
@@ -29,20 +62,4 @@ describe Hallon::Toplist do
|
|
29
62
|
toplist.request_duration.should be_nil
|
30
63
|
end
|
31
64
|
end
|
32
|
-
|
33
|
-
describe ".new" do
|
34
|
-
it "should fail given an invalid type" do
|
35
|
-
expect { mock_session { Hallon::Toplist.new(:invalid_type) } }.to raise_error(ArgumentError, /invalid enum value/)
|
36
|
-
end
|
37
|
-
|
38
|
-
it "should pass the username given a string to libspotify" do
|
39
|
-
Spotify.registry_add 'spotify:toplist:user:Kim', mock_toplistbrowse
|
40
|
-
mock_session { Hallon::Toplist.new(:tracks, "Kim").should be_loaded }
|
41
|
-
end
|
42
|
-
|
43
|
-
it "should pass the correct region to libspotify" do
|
44
|
-
Spotify.registry_add 'spotify:toplist:tracks:SE', mock_toplistbrowse
|
45
|
-
mock_session { Hallon::Toplist.new(:tracks, :se).should be_loaded }
|
46
|
-
end
|
47
|
-
end
|
48
65
|
end
|