hallon 0.8.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.travis.yml +2 -0
- data/CHANGELOG +43 -0
- data/Gemfile +2 -0
- data/README.markdown +21 -13
- data/Rakefile +84 -23
- data/dev/login.rb +16 -0
- data/examples/adding_tracks_to_playlist.rb +49 -0
- data/examples/logging_in.rb +1 -6
- data/examples/show_published_playlists_of_user.rb +9 -19
- data/hallon.gemspec +1 -1
- data/lib/hallon.rb +3 -2
- data/lib/hallon/album.rb +55 -41
- data/lib/hallon/album_browse.rb +41 -37
- data/lib/hallon/artist.rb +30 -21
- data/lib/hallon/artist_browse.rb +59 -41
- data/lib/hallon/base.rb +68 -5
- data/lib/hallon/enumerator.rb +1 -0
- data/lib/hallon/error.rb +3 -0
- data/lib/hallon/ext/spotify.rb +169 -36
- data/lib/hallon/image.rb +30 -44
- data/lib/hallon/link.rb +29 -43
- data/lib/hallon/linkable.rb +68 -20
- data/lib/hallon/observable.rb +0 -1
- data/lib/hallon/player.rb +21 -7
- data/lib/hallon/playlist.rb +291 -0
- data/lib/hallon/playlist_container.rb +27 -0
- data/lib/hallon/search.rb +52 -45
- data/lib/hallon/session.rb +129 -81
- data/lib/hallon/toplist.rb +37 -19
- data/lib/hallon/track.rb +68 -45
- data/lib/hallon/user.rb +69 -33
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +15 -9
- data/spec/hallon/album_spec.rb +15 -15
- data/spec/hallon/artist_browse_spec.rb +28 -9
- data/spec/hallon/artist_spec.rb +30 -14
- data/spec/hallon/enumerator_spec.rb +0 -1
- data/spec/hallon/hallon_spec.rb +20 -1
- data/spec/hallon/image_spec.rb +18 -41
- data/spec/hallon/link_spec.rb +10 -12
- data/spec/hallon/linkable_spec.rb +37 -18
- data/spec/hallon/player_spec.rb +8 -0
- data/spec/hallon/playlist_container_spec.rb +75 -0
- data/spec/hallon/playlist_spec.rb +204 -0
- data/spec/hallon/search_spec.rb +19 -16
- data/spec/hallon/session_spec.rb +61 -29
- data/spec/hallon/spotify_spec.rb +30 -0
- data/spec/hallon/toplist_spec.rb +22 -14
- data/spec/hallon/track_spec.rb +62 -21
- data/spec/hallon/user_spec.rb +47 -36
- data/spec/mockspotify.rb +35 -10
- data/spec/mockspotify/mockspotify_spec.rb +22 -0
- data/spec/spec_helper.rb +7 -3
- data/spec/support/common_objects.rb +91 -16
- data/spec/support/shared_for_linkable_objects.rb +39 -0
- metadata +30 -20
- data/Termfile +0 -7
- data/lib/hallon/synchronizable.rb +0 -32
- data/spec/hallon/synchronizable_spec.rb +0 -19
data/lib/hallon/toplist.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# coding: utf-8
|
1
2
|
module Hallon
|
2
3
|
# Toplists are what they sound like. They’re collections of
|
3
4
|
# artists, albums or tracks popular in a certain area either
|
@@ -13,6 +14,15 @@ module Hallon
|
|
13
14
|
# @overload initialize(type, country)
|
14
15
|
# @overload initialize(type)
|
15
16
|
#
|
17
|
+
# @example with a given username
|
18
|
+
# toplist = Hallon::Toplist.new(:artists, "burgestrand")
|
19
|
+
#
|
20
|
+
# @example with a given country
|
21
|
+
# toplist = Hallon::Toplist.new(:tracks, :se)
|
22
|
+
#
|
23
|
+
# @example everywhere
|
24
|
+
# toplist = Hallon::Toplist.new(:albums)
|
25
|
+
#
|
16
26
|
# @param [Symbol] type one of :artists, :albums or :tracks
|
17
27
|
# @param [String, Symbol, nil] region username, 2-letter country code or nil
|
18
28
|
def initialize(type, region = nil)
|
@@ -21,53 +31,61 @@ module Hallon
|
|
21
31
|
user = region
|
22
32
|
region = :user
|
23
33
|
when NilClass
|
24
|
-
region = :
|
34
|
+
region = :everywhere
|
25
35
|
when Symbol
|
26
36
|
region = to_country(region)
|
27
37
|
end
|
28
38
|
|
29
39
|
@callback = proc { trigger(:load) }
|
30
|
-
pointer
|
31
|
-
@pointer = Spotify::Pointer.new(pointer, :toplistbrowse, false)
|
40
|
+
@pointer = Spotify.toplistbrowse_create!(session.pointer, type, region, user, @callback, nil)
|
32
41
|
end
|
33
42
|
|
34
|
-
# @return [Boolean] true if the toplist is loaded
|
43
|
+
# @return [Boolean] true if the toplist is loaded.
|
35
44
|
def loaded?
|
36
|
-
Spotify.toplistbrowse_is_loaded(
|
45
|
+
Spotify.toplistbrowse_is_loaded(pointer)
|
37
46
|
end
|
38
47
|
|
39
|
-
# @
|
40
|
-
|
41
|
-
|
48
|
+
# @see Error.explain
|
49
|
+
# @return [Symbol] toplist error status.
|
50
|
+
def status
|
51
|
+
Spotify.toplistbrowse_error(pointer)
|
42
52
|
end
|
43
53
|
|
44
|
-
# @return [Enumerator<Artist>]
|
54
|
+
# @return [Enumerator<Artist>] a list of artists.
|
45
55
|
def artists
|
46
|
-
size = Spotify.toplistbrowse_num_artists(
|
56
|
+
size = Spotify.toplistbrowse_num_artists(pointer)
|
47
57
|
Enumerator.new(size) do |i|
|
48
|
-
artist = Spotify.toplistbrowse_artist(
|
58
|
+
artist = Spotify.toplistbrowse_artist!(pointer, i)
|
49
59
|
Artist.new(artist)
|
50
60
|
end
|
51
61
|
end
|
52
62
|
|
53
|
-
# @return [Enumerator<Album>]
|
63
|
+
# @return [Enumerator<Album>] a list of albums.
|
54
64
|
def albums
|
55
|
-
size = Spotify.toplistbrowse_num_albums(
|
65
|
+
size = Spotify.toplistbrowse_num_albums(pointer)
|
56
66
|
Enumerator.new(size) do |i|
|
57
|
-
album = Spotify.toplistbrowse_album(
|
58
|
-
|
67
|
+
album = Spotify.toplistbrowse_album!(pointer, i)
|
68
|
+
Album.new(album)
|
59
69
|
end
|
60
70
|
end
|
61
71
|
|
62
|
-
# @return [Enumerator<Track>]
|
72
|
+
# @return [Enumerator<Track>] a list of tracks.
|
63
73
|
def tracks
|
64
|
-
size = Spotify.toplistbrowse_num_tracks(
|
74
|
+
size = Spotify.toplistbrowse_num_tracks(pointer)
|
65
75
|
Enumerator.new(size) do |i|
|
66
|
-
track = Spotify.toplistbrowse_track(
|
67
|
-
|
76
|
+
track = Spotify.toplistbrowse_track!(pointer, i)
|
77
|
+
Track.new(track)
|
68
78
|
end
|
69
79
|
end
|
70
80
|
|
81
|
+
# @note If the object is not loaded, the result is undefined.
|
82
|
+
# @note Returns nil if the request was served from the local libspotify cache.
|
83
|
+
# @return [Rational, nil] time it took for the toplistbrowse request to complete (in seconds).
|
84
|
+
def request_duration
|
85
|
+
duration = Spotify.toplistbrowse_backend_request_duration(pointer)
|
86
|
+
Rational(duration, 1000) if duration > 0
|
87
|
+
end
|
88
|
+
|
71
89
|
private
|
72
90
|
# Convert a given two-character region to a Spotify
|
73
91
|
# compliant region (encoded in a 16bit integer).
|
data/lib/hallon/track.rb
CHANGED
@@ -13,12 +13,13 @@ module Hallon
|
|
13
13
|
# Overriden to use default parameter.
|
14
14
|
# @see #to_link
|
15
15
|
alias_method :_to_link, :to_link
|
16
|
+
|
16
17
|
# Create a Link to the current track and offset in seconds.
|
17
18
|
#
|
18
19
|
# @param [Float] offset offset into track in seconds
|
19
20
|
# @return [Hallon::Link]
|
20
21
|
def to_link(offset = offset)
|
21
|
-
_to_link
|
22
|
+
_to_link((offset * 1000).to_i)
|
22
23
|
end
|
23
24
|
|
24
25
|
# Offset into track in seconds this track was created with.
|
@@ -31,7 +32,7 @@ module Hallon
|
|
31
32
|
# @param [String, Link, FFI::Pointer] link
|
32
33
|
def initialize(link)
|
33
34
|
FFI::MemoryPointer.new(:int) do |ptr|
|
34
|
-
@pointer =
|
35
|
+
@pointer = to_pointer(link, :track, ptr)
|
35
36
|
@offset = Rational(ptr.read_int, 1000)
|
36
37
|
end
|
37
38
|
end
|
@@ -44,14 +45,14 @@ module Hallon
|
|
44
45
|
# @param [Integer] length
|
45
46
|
# @return [Track]
|
46
47
|
def self.local(title, artist, album = nil, length = nil)
|
47
|
-
track = Spotify.localtrack_create(artist, title, album || "", length || -1)
|
48
|
+
track = Spotify.localtrack_create!(artist, title, album || "", length || -1)
|
48
49
|
new(track)
|
49
50
|
end
|
50
51
|
|
51
52
|
# @note This’ll be an empty string unless the track is loaded.
|
52
53
|
# @return [String]
|
53
54
|
def name
|
54
|
-
Spotify.track_name(
|
55
|
+
Spotify.track_name(pointer)
|
55
56
|
end
|
56
57
|
|
57
58
|
# Duration of the track in seconds.
|
@@ -59,7 +60,7 @@ module Hallon
|
|
59
60
|
# @note This’ll be `0` unless the track is loaded.
|
60
61
|
# @return [Rational]
|
61
62
|
def duration
|
62
|
-
Rational(Spotify.track_duration(
|
63
|
+
Rational(Spotify.track_duration(pointer), 1000)
|
63
64
|
end
|
64
65
|
|
65
66
|
# Track popularity, between 0 and 1.
|
@@ -67,97 +68,119 @@ module Hallon
|
|
67
68
|
# @note This’ll be `0` unless the track is loaded.
|
68
69
|
# @return [Rational]
|
69
70
|
def popularity
|
70
|
-
Rational(Spotify.track_popularity(
|
71
|
+
Rational(Spotify.track_popularity(pointer), 100)
|
71
72
|
end
|
72
73
|
|
73
74
|
# Disc number this track appears in.
|
74
75
|
#
|
75
76
|
# @note This function is a bit special. See libspotify docs for details.
|
76
77
|
def disc
|
77
|
-
Spotify.track_disc(
|
78
|
+
Spotify.track_disc(pointer)
|
78
79
|
end
|
79
80
|
|
80
|
-
# Position of track on its’ disc.
|
81
|
-
#
|
82
81
|
# @note This function is a bit special. See libspotify docs for details.
|
82
|
+
# @return [Integer] position of track on its’ disc.
|
83
83
|
def index
|
84
|
-
Spotify.track_index(
|
84
|
+
Spotify.track_index(pointer)
|
85
85
|
end
|
86
86
|
|
87
|
-
#
|
88
|
-
#
|
89
|
-
# @return [Symbol]
|
87
|
+
# @see Error.explain
|
88
|
+
# @return [Symbol] track error status.
|
90
89
|
def status
|
91
|
-
Spotify.track_error(
|
90
|
+
Spotify.track_error(pointer)
|
92
91
|
end
|
93
92
|
|
94
|
-
#
|
95
|
-
#
|
96
|
-
# @return [Boolean]
|
93
|
+
# @return [Boolean] true if track is loaded.
|
97
94
|
def loaded?
|
98
|
-
Spotify.track_is_loaded(
|
95
|
+
Spotify.track_is_loaded(pointer)
|
99
96
|
end
|
100
97
|
|
101
|
-
#
|
98
|
+
# @note Track does not have to be loaded for this to return a useful value.
|
99
|
+
#
|
100
|
+
# @note Placeholder tracks are not really tracks, but merely containers
|
101
|
+
# for other objects to allow storing them in playlists such as the inbox.
|
102
102
|
#
|
103
|
+
# @return [Boolean] true if the track is a placeholder.
|
104
|
+
# @see unwrap
|
105
|
+
def placeholder?
|
106
|
+
Spotify.track_is_placeholder(pointer)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Unwraps a {#placeholder?} Track into its’ real object.
|
110
|
+
#
|
111
|
+
# @see placeholder?
|
112
|
+
# @return [Track, Artist, Album, Playlist]
|
113
|
+
def unwrap
|
114
|
+
return self unless placeholder?
|
115
|
+
|
116
|
+
case (link = to_link).type
|
117
|
+
when :playlist
|
118
|
+
Playlist.new(link)
|
119
|
+
when :album
|
120
|
+
Album.new(link)
|
121
|
+
when :artist
|
122
|
+
Artist.new(link)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
# @return [Symbol] track offline status.
|
127
|
+
def offline_status
|
128
|
+
Spotify.track_offline_get_status(pointer)
|
129
|
+
end
|
130
|
+
|
103
131
|
# @note This’ll be `nil` unless the track is loaded.
|
104
|
-
# @return [Hallon::Album]
|
132
|
+
# @return [Hallon::Album] album this track belongs to.
|
105
133
|
def album
|
106
|
-
album = Spotify.track_album(
|
134
|
+
album = Spotify.track_album!(pointer)
|
107
135
|
Album.new(album) unless album.null?
|
108
136
|
end
|
109
137
|
|
110
|
-
# Artist who performed this Track.
|
111
|
-
#
|
112
138
|
# @note There may be more than one artist, see {#artists} for retrieving them all!
|
113
139
|
# @see #artists
|
114
|
-
# @return [Hallon::Artist, nil]
|
140
|
+
# @return [Hallon::Artist, nil] artist who performed this track.
|
115
141
|
def artist
|
116
142
|
artists.first
|
117
143
|
end
|
118
144
|
|
119
|
-
# All {Artist}s who performed this Track.
|
120
|
-
#
|
121
145
|
# @note Track must be loaded, or you’ll get zero artists.
|
122
|
-
# @return [Hallon::Enumerator<Artist>]
|
146
|
+
# @return [Hallon::Enumerator<Artist>] all {Artist}s who performed this Track.
|
123
147
|
def artists
|
124
|
-
size = Spotify.track_num_artists(
|
148
|
+
size = Spotify.track_num_artists(pointer)
|
125
149
|
Enumerator.new(size) do |i|
|
126
|
-
artist = Spotify.track_artist(
|
127
|
-
Artist.new(artist)
|
150
|
+
artist = Spotify.track_artist!(pointer, i)
|
151
|
+
Artist.new(artist)
|
128
152
|
end
|
129
153
|
end
|
130
154
|
|
131
|
-
# True if the Track is available.
|
132
|
-
#
|
133
155
|
# @note This’ll always return false unless the track is loaded.
|
134
|
-
# @return [Boolean]
|
156
|
+
# @return [Boolean] true if {#availability} is available.
|
135
157
|
def available?
|
136
|
-
|
158
|
+
availability == :available
|
137
159
|
end
|
138
160
|
|
139
|
-
#
|
161
|
+
# Track availability.
|
140
162
|
#
|
163
|
+
# @return [Symbol] :unavailable, :available, :not_streamable, :banned_by_artist
|
164
|
+
def availability
|
165
|
+
Spotify.track_get_availability(session.pointer, pointer)
|
166
|
+
end
|
167
|
+
|
141
168
|
# @note This’ll always return false unless the track is loaded.
|
142
|
-
# @return [Boolean]
|
169
|
+
# @return [Boolean] true if the track is a local track.
|
143
170
|
def local?
|
144
|
-
Spotify.track_is_local(session.pointer,
|
171
|
+
Spotify.track_is_local(session.pointer, pointer)
|
145
172
|
end
|
146
173
|
|
147
|
-
# True if the Track is autolinked.
|
148
|
-
#
|
149
174
|
# @note This’ll always return false unless the track is loaded.
|
150
|
-
# @return [Boolean]
|
175
|
+
# @return [Boolean] true if the track is autolinked.
|
151
176
|
def autolinked?
|
152
|
-
Spotify.track_is_autolinked(session.pointer,
|
177
|
+
Spotify.track_is_autolinked(session.pointer, pointer)
|
153
178
|
end
|
154
179
|
|
155
|
-
# True if the track is starred.
|
156
|
-
#
|
157
180
|
# @note This’ll always return false unless the track is loaded.
|
158
|
-
# @return [Boolean]
|
181
|
+
# @return [Boolean] true if the track is starred.
|
159
182
|
def starred?
|
160
|
-
Spotify.track_is_starred(session.pointer,
|
183
|
+
Spotify.track_is_starred(session.pointer, pointer)
|
161
184
|
end
|
162
185
|
|
163
186
|
# Set {#starred?} status of current track.
|
data/lib/hallon/user.rb
CHANGED
@@ -9,60 +9,96 @@ module Hallon
|
|
9
9
|
class User < Base
|
10
10
|
extend Linkable
|
11
11
|
|
12
|
-
#
|
13
|
-
# Given a Link, get its’ underlying pointer.
|
12
|
+
# A Post is created upon sending tracks (with an optional message) to a user.
|
14
13
|
#
|
15
|
-
#
|
16
|
-
|
17
|
-
|
18
|
-
|
14
|
+
# @see http://developer.spotify.com/en/libspotify/docs/group__inbox.html
|
15
|
+
class Post < Base
|
16
|
+
include Observable
|
17
|
+
|
18
|
+
# @param [Spotify::Pointer<inbox>]
|
19
|
+
def initialize(username, message, tracks, &block)
|
20
|
+
@callback = proc { trigger(:load) }
|
21
|
+
|
22
|
+
FFI::MemoryPointer.new(:pointer, tracks.length) do |ary|
|
23
|
+
ary.write_array_of_pointer tracks.map(&:pointer)
|
24
|
+
@pointer = Spotify.inbox_post_tracks!(session.pointer, username, ary, tracks.length, message, @callback, nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# @see Error.explain
|
29
|
+
# @return [Symbol] error status of inbox post
|
30
|
+
def status
|
31
|
+
Spotify.inbox_error(pointer)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
19
35
|
from_link :profile do |link|
|
20
|
-
Spotify.link_as_user(link)
|
36
|
+
Spotify.link_as_user!(link)
|
21
37
|
end
|
22
38
|
|
23
|
-
# @macro [attach] to_link
|
24
|
-
# Create a Link to the current object.
|
25
|
-
#
|
26
|
-
# @method to_link
|
27
|
-
# @scope instance
|
28
|
-
# @return [Hallon::Link]
|
29
39
|
to_link :from_user
|
30
40
|
|
31
41
|
# Construct a new instance of User.
|
32
42
|
#
|
33
|
-
# @
|
43
|
+
# @example from a canonical username
|
44
|
+
# Hallon::User.new("burgestrand")
|
45
|
+
#
|
46
|
+
# @example from a spotify URI
|
47
|
+
# Hallon::User.new("spotify:user:burgestrand")
|
48
|
+
#
|
49
|
+
# @note You can also instantiate User with a canonical username
|
50
|
+
# @param [String, Link, Spotify::Pointer] link
|
34
51
|
def initialize(link)
|
35
|
-
@pointer =
|
52
|
+
@pointer = to_pointer(link, :user) do
|
53
|
+
if link.is_a?(String) and link !~ /\Aspotify:user:/
|
54
|
+
to_pointer("spotify:user:#{link}", :user)
|
55
|
+
end
|
56
|
+
end
|
36
57
|
end
|
37
58
|
|
38
59
|
# @return [Boolean] true if the user is loaded
|
39
60
|
def loaded?
|
40
|
-
Spotify.user_is_loaded(
|
61
|
+
Spotify.user_is_loaded(pointer)
|
41
62
|
end
|
42
63
|
|
43
|
-
# Retrieve the name of the
|
64
|
+
# Retrieve the canonical name of the User.
|
44
65
|
#
|
45
|
-
# @note Unless the user is {User#loaded?} only the canonical name is accessible
|
46
|
-
# @param [Symbol] type one of :canonical, :display, :full
|
47
66
|
# @return [String]
|
48
|
-
def name
|
49
|
-
|
50
|
-
when :display
|
51
|
-
Spotify.user_display_name(@pointer)
|
52
|
-
when :full
|
53
|
-
Spotify.user_full_name(@pointer)
|
54
|
-
when :canonical
|
55
|
-
Spotify.user_canonical_name(@pointer)
|
56
|
-
else
|
57
|
-
raise ArgumentError, "expected type to be :display, :full or :canonical, but was #{type}"
|
58
|
-
end.to_s
|
67
|
+
def name
|
68
|
+
Spotify.user_canonical_name(pointer)
|
59
69
|
end
|
60
70
|
|
61
|
-
# Retrieve the
|
71
|
+
# Retrieve the dispaly name of the User.
|
62
72
|
#
|
73
|
+
# @note Unless {#loaded?} is true, this will return the same thing as {#name}.
|
63
74
|
# @return [String]
|
64
|
-
def
|
65
|
-
Spotify.
|
75
|
+
def display_name
|
76
|
+
Spotify.user_display_name(pointer)
|
77
|
+
end
|
78
|
+
|
79
|
+
# Retrieve the users’ starred playlist.
|
80
|
+
#
|
81
|
+
# @note Returns nil unless {User#loaded?}
|
82
|
+
# @return [Playlist, nil]
|
83
|
+
def starred
|
84
|
+
playlist = Spotify.session_starred_for_user_create!(session.pointer, name)
|
85
|
+
Playlist.new(playlist) unless playlist.null?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Send tracks to this users’ inbox, with an optional message.
|
89
|
+
#
|
90
|
+
# @overload post(message, tracks)
|
91
|
+
# @param [#to_s] message
|
92
|
+
# @param [Array<Track>] tracks
|
93
|
+
#
|
94
|
+
# @overload post(tracks)
|
95
|
+
# @param [Array<Track>] tracks
|
96
|
+
#
|
97
|
+
# @return [Post, nil]
|
98
|
+
def post(message = nil, tracks)
|
99
|
+
message &&= message.encode('UTF-8')
|
100
|
+
post = Post.new(name, message, tracks)
|
101
|
+
post unless post.pointer.null?
|
66
102
|
end
|
67
103
|
end
|
68
104
|
end
|
data/lib/hallon/version.rb
CHANGED
@@ -1,20 +1,26 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::AlbumBrowse do
|
3
|
-
|
4
|
-
|
5
|
-
album = Hallon::Album.new(mock_album)
|
6
|
-
Spotify.should_receive(:albumbrowse_create).and_return(mock_albumbrowse)
|
7
|
-
Hallon::AlbumBrowse.new(album)
|
8
|
-
end
|
9
|
-
end
|
3
|
+
let(:browse) { mock_session { Hallon::AlbumBrowse.new(mock_album) } }
|
4
|
+
subject { browse }
|
10
5
|
|
11
6
|
it { should be_loaded }
|
12
|
-
its(:
|
7
|
+
its(:status) { should eq :ok }
|
13
8
|
its(:album) { should eq Hallon::Album.new(mock_album) }
|
14
9
|
its(:artist) { should eq Hallon::Artist.new(mock_artist) }
|
15
10
|
its('copyrights.size') { should eq 2 }
|
16
11
|
its('copyrights.to_a') { should eq %w[Kim Elin] }
|
17
12
|
its('tracks.size') { should eq 2 }
|
18
|
-
its('tracks.to_a') { should eq
|
13
|
+
its('tracks.to_a') { should eq instantiate(Hallon::Track, mock_track, mock_track_two) }
|
19
14
|
its(:review) { should eq "This album is AWESOME" }
|
15
|
+
|
16
|
+
describe "#request_duration" do
|
17
|
+
it "should return the request duration in seconds" do
|
18
|
+
browse.request_duration.should eq 2.751
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should be nil if the request was fetched from local cache" do
|
22
|
+
Spotify.should_receive(:albumbrowse_backend_request_duration).and_return(-1)
|
23
|
+
browse.request_duration.should be_nil
|
24
|
+
end
|
25
|
+
end
|
20
26
|
end
|