hallon 0.11.0 → 0.12.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.
- data/.yardopts +1 -0
- data/{CHANGELOG → CHANGELOG.md} +82 -27
- data/Gemfile +1 -0
- data/README.markdown +1 -1
- data/Rakefile +8 -6
- data/examples/adding_tracks_to_playlist.rb +3 -0
- data/examples/logging_in.rb +3 -0
- data/examples/playing_audio.rb +130 -0
- data/examples/printing_link_information.rb +3 -0
- data/examples/show_published_playlists_of_user.rb +5 -13
- data/hallon.gemspec +2 -2
- data/lib/hallon.rb +15 -0
- data/lib/hallon/album.rb +1 -1
- data/lib/hallon/album_browse.rb +4 -3
- data/lib/hallon/artist.rb +1 -1
- data/lib/hallon/artist_browse.rb +5 -4
- data/lib/hallon/base.rb +7 -2
- data/lib/hallon/error.rb +1 -1
- data/lib/hallon/ext/spotify.rb +26 -42
- data/lib/hallon/image.rb +7 -8
- data/lib/hallon/observable.rb +134 -62
- data/lib/hallon/observable/album_browse.rb +30 -0
- data/lib/hallon/observable/artist_browse.rb +31 -0
- data/lib/hallon/observable/image.rb +31 -0
- data/lib/hallon/observable/player.rb +13 -0
- data/lib/hallon/observable/playlist.rb +194 -0
- data/lib/hallon/observable/playlist_container.rb +74 -0
- data/lib/hallon/observable/post.rb +30 -0
- data/lib/hallon/observable/search.rb +29 -0
- data/lib/hallon/observable/session.rb +236 -0
- data/lib/hallon/observable/toplist.rb +30 -0
- data/lib/hallon/player.rb +8 -17
- data/lib/hallon/playlist.rb +11 -7
- data/lib/hallon/playlist_container.rb +11 -4
- data/lib/hallon/queue.rb +71 -0
- data/lib/hallon/search.rb +10 -7
- data/lib/hallon/session.rb +18 -21
- data/lib/hallon/toplist.rb +4 -3
- data/lib/hallon/user.rb +5 -5
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/album_browse_spec.rb +4 -0
- data/spec/hallon/artist_browse_spec.rb +4 -0
- data/spec/hallon/base_spec.rb +26 -9
- data/spec/hallon/hallon_spec.rb +0 -18
- data/spec/hallon/image_spec.rb +0 -1
- data/spec/hallon/link_spec.rb +14 -0
- data/spec/hallon/observable/album_browse_spec.rb +7 -0
- data/spec/hallon/observable/artist_browse_spec.rb +7 -0
- data/spec/hallon/observable/image_spec.rb +8 -0
- data/spec/hallon/observable/playlist_container_spec.rb +21 -0
- data/spec/hallon/observable/playlist_spec.rb +85 -0
- data/spec/hallon/observable/post_spec.rb +8 -0
- data/spec/hallon/observable/search_spec.rb +7 -0
- data/spec/hallon/observable/session_spec.rb +143 -0
- data/spec/hallon/observable/toplist_spec.rb +7 -0
- data/spec/hallon/observable_spec.rb +134 -65
- data/spec/hallon/playlist_container_spec.rb +24 -18
- data/spec/hallon/playlist_spec.rb +2 -0
- data/spec/hallon/queue_spec.rb +35 -0
- data/spec/hallon/session_spec.rb +4 -4
- data/spec/hallon/spotify_spec.rb +35 -9
- data/spec/mockspotify.rb +2 -3
- data/spec/spec_helper.rb +0 -1
- data/spec/support/common_objects.rb +27 -15
- data/spec/support/enumerable_comparison.rb +9 -0
- data/spec/support/shared_for_callbacks.rb +60 -0
- data/spec/support/shared_for_linkable_objects.rb +1 -1
- metadata +56 -20
@@ -0,0 +1,30 @@
|
|
1
|
+
module Hallon::Observable
|
2
|
+
# Callbacks related to the {Hallon::Toplist} object.
|
3
|
+
module Toplist
|
4
|
+
# Includes {Hallon::Observable} for you.
|
5
|
+
def self.extended(other)
|
6
|
+
other.send(:include, Hallon::Observable)
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
|
11
|
+
# @return [Method] load callback
|
12
|
+
def initialize_callbacks
|
13
|
+
callback_for(:load)
|
14
|
+
end
|
15
|
+
|
16
|
+
# This callback is fired when the Image object is fully loaded.
|
17
|
+
#
|
18
|
+
# @example listening to this callback
|
19
|
+
# toplist.on(:load) do
|
20
|
+
# puts "the toplist has loaded!"
|
21
|
+
# end
|
22
|
+
#
|
23
|
+
# @yield [self]
|
24
|
+
# @yieldparam [Toplist] self
|
25
|
+
def load_callback(pointer, userdata)
|
26
|
+
trigger(pointer, :load)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
data/lib/hallon/player.rb
CHANGED
@@ -3,12 +3,11 @@ module Hallon
|
|
3
3
|
# A wrapper around Session for playing, stopping and otherwise
|
4
4
|
# controlling the playback features of libspotify.
|
5
5
|
#
|
6
|
-
# @note This is very much a work in progress.
|
7
|
-
# takes care of all callbacks, and the callbacks themselves
|
8
|
-
# must still be handled by means of Ruby FFI.
|
6
|
+
# @note This is very much a work in progress.
|
9
7
|
# @see Session
|
10
8
|
class Player
|
11
|
-
|
9
|
+
# meep?
|
10
|
+
extend Observable::Player
|
12
11
|
|
13
12
|
# @return [Spotify::Pointer<Session>] session pointer
|
14
13
|
attr_reader :pointer
|
@@ -25,7 +24,7 @@ module Hallon
|
|
25
24
|
#
|
26
25
|
# @example
|
27
26
|
# Hallon::Player.new(session) do
|
28
|
-
# on(:music_delivery) do
|
27
|
+
# on(:music_delivery) do |format, frames|
|
29
28
|
# end
|
30
29
|
#
|
31
30
|
# on(:start_playback) do
|
@@ -56,20 +55,12 @@ module Hallon
|
|
56
55
|
@session = session
|
57
56
|
@pointer = @session.pointer
|
58
57
|
|
59
|
-
%w[
|
58
|
+
%w[
|
59
|
+
start_playback stop_playback play_token_lost end_of_track
|
60
|
+
streaming_error get_audio_buffer_stats music_delivery
|
61
|
+
].each do |cb|
|
60
62
|
@session.on(cb) { |*args| trigger(cb, *args) }
|
61
63
|
end
|
62
|
-
|
63
|
-
@session.on(:audio_buffer_stats) do |stats_ptr|
|
64
|
-
stats = Spotify::AudioBufferStats.new(stats_ptr)
|
65
|
-
samples, dropouts = trigger(:buffer_size?)
|
66
|
-
stats[:samples] = samples || 0
|
67
|
-
stats[:dropouts] = dropouts || 0
|
68
|
-
end
|
69
|
-
|
70
|
-
@session.on(:music_delivery) do |format, frames, num_frames|
|
71
|
-
trigger(:music_delivery, format, frames, num_frames)
|
72
|
-
end
|
73
64
|
end
|
74
65
|
|
75
66
|
# Set preferred playback bitrate.
|
data/lib/hallon/playlist.rb
CHANGED
@@ -6,9 +6,6 @@ module Hallon
|
|
6
6
|
#
|
7
7
|
# @see http://developer.spotify.com/en/libspotify/docs/group__playlist.html
|
8
8
|
class Playlist < Base
|
9
|
-
include Observable
|
10
|
-
extend Linkable
|
11
|
-
|
12
9
|
# Playlist::Track is a {Track} with additional information attached to it,
|
13
10
|
# that is specific to the playlist it was created from. The returned track
|
14
11
|
# is a snapshot of the information, so even if the underlying track moves,
|
@@ -80,6 +77,11 @@ module Hallon
|
|
80
77
|
end
|
81
78
|
end
|
82
79
|
|
80
|
+
extend Linkable
|
81
|
+
|
82
|
+
# CAN HAZ CALLBAKZ
|
83
|
+
extend Observable::Playlist
|
84
|
+
|
83
85
|
from_link :playlist do |pointer|
|
84
86
|
Spotify.playlist_create!(session.pointer, pointer)
|
85
87
|
end
|
@@ -92,8 +94,10 @@ module Hallon
|
|
92
94
|
def initialize(link)
|
93
95
|
@pointer = to_pointer(link, :playlist)
|
94
96
|
|
95
|
-
|
96
|
-
|
97
|
+
subscribe_for_callbacks do |callbacks|
|
98
|
+
Spotify.playlist_remove_callbacks(pointer, callbacks, nil)
|
99
|
+
Spotify.playlist_add_callbacks(pointer, callbacks, nil)
|
100
|
+
end
|
97
101
|
end
|
98
102
|
|
99
103
|
# @return [Boolean] true if the playlist is loaded
|
@@ -167,8 +171,8 @@ module Hallon
|
|
167
171
|
def name=(name)
|
168
172
|
name = name.to_s.encode('UTF-8')
|
169
173
|
|
170
|
-
unless name.
|
171
|
-
raise ArgumentError, "name must be shorter than 256
|
174
|
+
unless name.bytesize < 256
|
175
|
+
raise ArgumentError, "name must be shorter than 256 bytes"
|
172
176
|
end
|
173
177
|
|
174
178
|
unless name =~ /[^ ]/u
|
@@ -64,6 +64,11 @@ module Hallon
|
|
64
64
|
end if other.is_a?(Folder)
|
65
65
|
end
|
66
66
|
|
67
|
+
# @return [Enumerator<Playlist, Folder>] contents of this folder
|
68
|
+
def contents
|
69
|
+
container.contents[(@begin + 1)..(@end - 1)]
|
70
|
+
end
|
71
|
+
|
67
72
|
# @return [Boolean] true if the folder has moved.
|
68
73
|
def moved?
|
69
74
|
Spotify.playlistcontainer_playlist_folder_id(container.pointer, @begin) != id or
|
@@ -71,7 +76,7 @@ module Hallon
|
|
71
76
|
end
|
72
77
|
end
|
73
78
|
|
74
|
-
|
79
|
+
extend Observable::PlaylistContainer
|
75
80
|
|
76
81
|
# Wrap an existing PlaylistContainer pointer in an object.
|
77
82
|
#
|
@@ -79,8 +84,10 @@ module Hallon
|
|
79
84
|
def initialize(pointer)
|
80
85
|
@pointer = to_pointer(pointer, :playlistcontainer)
|
81
86
|
|
82
|
-
|
83
|
-
|
87
|
+
subscribe_for_callbacks do |callbacks|
|
88
|
+
Spotify.playlistcontainer_remove_callbacks(pointer, callbacks, nil)
|
89
|
+
Spotify.playlistcontainer_add_callbacks(pointer, callbacks, nil)
|
90
|
+
end
|
84
91
|
end
|
85
92
|
|
86
93
|
# @return [Boolean] true if the container is loaded.
|
@@ -224,7 +231,7 @@ module Hallon
|
|
224
231
|
# @return [Boolean] true if the operation can be performed
|
225
232
|
def can_move?(from, to)
|
226
233
|
error = move_playlist(from, to, true)
|
227
|
-
|
234
|
+
_, symbol = Error.disambiguate(error)
|
228
235
|
symbol == :ok
|
229
236
|
end
|
230
237
|
|
data/lib/hallon/queue.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'thread'
|
3
|
+
|
4
|
+
module Hallon
|
5
|
+
# Hallon::Queue is a non-blocking (well, not entirely) sized FIFO queue.
|
6
|
+
#
|
7
|
+
# You initialize the queue with a `max_size`, and then push data to it.
|
8
|
+
# For every push operation, the Queue will tell you how much of your data
|
9
|
+
# it could consume. If the queue becomes full, it won’t accept any more
|
10
|
+
# data (and will return 0 on the #push operation) until you pull some data
|
11
|
+
# out of it with #pop.
|
12
|
+
#
|
13
|
+
# Hallon::Queue is useful for handling {Hallon::Observable::Session#music_delivery_callback}.
|
14
|
+
#
|
15
|
+
# @example
|
16
|
+
# queue = Hallon::Queue.new(4)
|
17
|
+
# queue.push([1, 2]) # => 2
|
18
|
+
# queue.push([3]) # => 1
|
19
|
+
# queue.push([4, 5, 6]) # => 1
|
20
|
+
# queue.push([5, 6]) # => 0
|
21
|
+
# queue.pop(1) # => [1]
|
22
|
+
# queue.push([5, 6]) # => 1
|
23
|
+
# queue.pop # => [2, 3, 4, 5]
|
24
|
+
class Queue
|
25
|
+
attr_reader :max_size
|
26
|
+
|
27
|
+
# @param [Integer] max_size
|
28
|
+
def initialize(max_size)
|
29
|
+
@mutex = Mutex.new
|
30
|
+
@condv = ConditionVariable.new
|
31
|
+
|
32
|
+
@max_size = max_size
|
33
|
+
@samples = []
|
34
|
+
end
|
35
|
+
|
36
|
+
# @param [#take] data
|
37
|
+
# @return [Integer] how much of the data that was added to the queue
|
38
|
+
def push(samples)
|
39
|
+
synchronize do
|
40
|
+
can_accept = max_size - size
|
41
|
+
new_samples = samples.take(can_accept)
|
42
|
+
|
43
|
+
@samples.concat(new_samples)
|
44
|
+
@condv.signal
|
45
|
+
|
46
|
+
new_samples.size
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
# @note If the queue is empty, this operation will block until data is available.
|
51
|
+
# @param [Integer] num_samples max number of samples to pop off the queue
|
52
|
+
# @return [Array] data, where data.size might be less than num_samples but never more
|
53
|
+
def pop(num_samples = max_size)
|
54
|
+
synchronize do
|
55
|
+
@condv.wait(@mutex) while @samples.empty?
|
56
|
+
@samples.shift(num_samples)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# @return [Integer] number of samples in buffer
|
61
|
+
def size
|
62
|
+
@samples.size
|
63
|
+
end
|
64
|
+
|
65
|
+
private
|
66
|
+
# @yield (merely a wrapper over @mutex.synchronize)
|
67
|
+
def synchronize
|
68
|
+
@mutex.synchronize { return yield }
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
data/lib/hallon/search.rb
CHANGED
@@ -5,7 +5,7 @@ module Hallon
|
|
5
5
|
#
|
6
6
|
# @see http://developer.spotify.com/en/libspotify/docs/group__search.html
|
7
7
|
class Search < Base
|
8
|
-
|
8
|
+
extend Observable::Search
|
9
9
|
|
10
10
|
# @return [Array<Symbol>] a list of radio genres available for search
|
11
11
|
def self.genres
|
@@ -35,10 +35,11 @@ module Hallon
|
|
35
35
|
|
36
36
|
search = allocate
|
37
37
|
search.instance_eval do
|
38
|
-
|
39
|
-
|
38
|
+
subscribe_for_callbacks do |callback|
|
39
|
+
@pointer = Spotify.radio_search_create!(session.pointer, from_year, to_year, genres, callback, nil)
|
40
|
+
end
|
40
41
|
|
41
|
-
raise FFI::NullPointerError, "radio search failed" if
|
42
|
+
raise FFI::NullPointerError, "radio search failed" if pointer.null?
|
42
43
|
end
|
43
44
|
|
44
45
|
search
|
@@ -57,10 +58,12 @@ module Hallon
|
|
57
58
|
# @see http://developer.spotify.com/en/libspotify/docs/group__search.html#gacf0b5e902e27d46ef8b1f40e332766df
|
58
59
|
def initialize(query, options = {})
|
59
60
|
o = Search.defaults.merge(options)
|
60
|
-
@callback = proc { trigger(:load) }
|
61
|
-
@pointer = Spotify.search_create!(session.pointer, query, o[:tracks_offset].to_i, o[:tracks].to_i, o[:albums_offset].to_i, o[:albums].to_i, o[:artists_offset].to_i, o[:artists].to_i, @callback, nil)
|
62
61
|
|
63
|
-
|
62
|
+
subscribe_for_callbacks do |callback|
|
63
|
+
@pointer = Spotify.search_create!(session.pointer, query, o[:tracks_offset].to_i, o[:tracks].to_i, o[:albums_offset].to_i, o[:albums].to_i, o[:artists_offset].to_i, o[:artists].to_i, callback, nil)
|
64
|
+
end
|
65
|
+
|
66
|
+
raise FFI::NullPointerError, "search for “#{query}” failed" if pointer.null?
|
64
67
|
end
|
65
68
|
|
66
69
|
# @return [Boolean] true if the search has been fully loaded.
|
data/lib/hallon/session.rb
CHANGED
@@ -30,8 +30,8 @@ module Hallon
|
|
30
30
|
undef :instance
|
31
31
|
end
|
32
32
|
|
33
|
-
# Session
|
34
|
-
|
33
|
+
# We have Session callbacks that you can listen to!
|
34
|
+
extend Observable::Session
|
35
35
|
|
36
36
|
# Initializes the Spotify session. If you need to access the
|
37
37
|
# instance at a later time, you can use {instance}.
|
@@ -105,22 +105,23 @@ module Hallon
|
|
105
105
|
raise ArgumentError, "User-agent must be less than 256 bytes long"
|
106
106
|
end
|
107
107
|
|
108
|
-
# Set configuration, as well as callbacks
|
109
|
-
config = Spotify::SessionConfig.new
|
110
|
-
config[:api_version] = Hallon::API_VERSION
|
111
|
-
config.application_key = appkey
|
112
|
-
@options.each { |(key, value)| config.send(:"#{key}=", value) }
|
113
|
-
config[:callbacks] = Spotify::SessionCallbacks.create(self, @sp_callbacks = {})
|
114
|
-
|
115
108
|
# Default cache size is 0 (automatic)
|
116
109
|
@cache_size = 0
|
117
110
|
|
118
|
-
|
111
|
+
subscribe_for_callbacks do |callbacks|
|
112
|
+
config = Spotify::SessionConfig.new
|
113
|
+
config[:api_version] = Hallon::API_VERSION
|
114
|
+
config.application_key = appkey
|
115
|
+
@options.each { |(key, value)| config.send(:"#{key}=", value) }
|
116
|
+
config[:callbacks] = callbacks
|
117
|
+
|
118
|
+
instance_eval(&block) if block_given?
|
119
119
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
120
|
+
# You pass a pointer to the session pointer to libspotify >:)
|
121
|
+
FFI::MemoryPointer.new(:pointer) do |p|
|
122
|
+
Error::maybe_raise Spotify.session_create(config, p)
|
123
|
+
@pointer = p.read_pointer
|
124
|
+
end
|
124
125
|
end
|
125
126
|
end
|
126
127
|
|
@@ -154,7 +155,8 @@ module Hallon
|
|
154
155
|
def process_events_on(*events)
|
155
156
|
yield or protecting_handlers do
|
156
157
|
channel = SizedQueue.new(1)
|
157
|
-
|
158
|
+
block = proc { |*args| channel << args }
|
159
|
+
events.each { |event| on(event, &block) }
|
158
160
|
on(:notify_main_thread) { channel << :notify }
|
159
161
|
|
160
162
|
loop do
|
@@ -399,11 +401,6 @@ module Hallon
|
|
399
401
|
status == :offline
|
400
402
|
end
|
401
403
|
|
402
|
-
# @return [String] string representation of the Session.
|
403
|
-
def to_s
|
404
|
-
"<#{self.class.name}:0x#{object_id.to_s(16)} status=#{status} @options=#{options.inspect}>"
|
405
|
-
end
|
406
|
-
|
407
404
|
private
|
408
405
|
# Set starred status of given tracks.
|
409
406
|
#
|
@@ -426,7 +423,7 @@ module Hallon
|
|
426
423
|
# if the user does not have premium, libspotify will still fire logged_in as :ok,
|
427
424
|
# but a few moments later it fires connection_error; waiting for both and checking
|
428
425
|
# for errors on both hopefully circumvents this!
|
429
|
-
wait_for(:logged_in, :connection_error) do |
|
426
|
+
wait_for(:logged_in, :connection_error) do |error|
|
430
427
|
Error.maybe_raise(error)
|
431
428
|
session.logged_in?
|
432
429
|
end
|
data/lib/hallon/toplist.rb
CHANGED
@@ -6,7 +6,7 @@ module Hallon
|
|
6
6
|
#
|
7
7
|
# @see http://developer.spotify.com/en/libspotify/docs/group__toplist.html
|
8
8
|
class Toplist < Base
|
9
|
-
|
9
|
+
extend Observable::Toplist
|
10
10
|
|
11
11
|
# Create a Toplist browsing object.
|
12
12
|
#
|
@@ -36,8 +36,9 @@ module Hallon
|
|
36
36
|
region = to_country(region)
|
37
37
|
end
|
38
38
|
|
39
|
-
|
40
|
-
|
39
|
+
subscribe_for_callbacks do |callback|
|
40
|
+
@pointer = Spotify.toplistbrowse_create!(session.pointer, type, region, user, callback, nil)
|
41
|
+
end
|
41
42
|
end
|
42
43
|
|
43
44
|
# @return [Boolean] true if the toplist is loaded.
|
data/lib/hallon/user.rb
CHANGED
@@ -13,15 +13,15 @@ module Hallon
|
|
13
13
|
#
|
14
14
|
# @see http://developer.spotify.com/en/libspotify/docs/group__inbox.html
|
15
15
|
class Post < Base
|
16
|
-
|
16
|
+
extend Observable::Post
|
17
17
|
|
18
18
|
# @param [Spotify::Pointer<inbox>]
|
19
19
|
def initialize(username, message, tracks, &block)
|
20
|
-
|
20
|
+
ary = FFI::MemoryPointer.new(:pointer, tracks.length)
|
21
|
+
ary.write_array_of_pointer tracks.map(&:pointer)
|
21
22
|
|
22
|
-
|
23
|
-
|
24
|
-
@pointer = Spotify.inbox_post_tracks!(session.pointer, username, ary, tracks.length, message, @callback, nil)
|
23
|
+
subscribe_for_callbacks do |callback|
|
24
|
+
@pointer = Spotify.inbox_post_tracks!(session.pointer, username, ary, tracks.length, message, callback, nil)
|
25
25
|
end
|
26
26
|
end
|
27
27
|
|
data/lib/hallon/version.rb
CHANGED
@@ -5,6 +5,10 @@ describe Hallon::AlbumBrowse do
|
|
5
5
|
Spotify.should_receive(:albumbrowse_create).and_return(null_pointer)
|
6
6
|
expect { mock_session { Hallon::AlbumBrowse.new(mock_album) } }.to raise_error(FFI::NullPointerError)
|
7
7
|
end
|
8
|
+
|
9
|
+
it "should raise an error given a non-album spotify pointer" do
|
10
|
+
expect { Hallon::AlbumBrowse.new(mock_artist) }.to raise_error(TypeError)
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
14
|
let(:browse) do
|
@@ -5,6 +5,10 @@ describe Hallon::ArtistBrowse do
|
|
5
5
|
Spotify.should_receive(:artistbrowse_create).and_return(null_pointer)
|
6
6
|
expect { mock_session { Hallon::ArtistBrowse.new(mock_artist) } }.to raise_error(FFI::NullPointerError)
|
7
7
|
end
|
8
|
+
|
9
|
+
it "should raise an error given a non-album spotify pointer" do
|
10
|
+
expect { Hallon::ArtistBrowse.new(mock_album) }.to raise_error(TypeError)
|
11
|
+
end
|
8
12
|
end
|
9
13
|
|
10
14
|
let(:browse) do
|
data/spec/hallon/base_spec.rb
CHANGED
@@ -2,34 +2,51 @@ describe Hallon::Base do
|
|
2
2
|
let(:klass) do
|
3
3
|
Class.new(Hallon::Base) do
|
4
4
|
def initialize(pointer)
|
5
|
-
@pointer = pointer
|
5
|
+
@pointer = to_pointer(pointer, :base) { |x| x }
|
6
6
|
end
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
10
|
+
let(:base_pointer) do
|
11
|
+
Spotify.stub!(:base_add_ref, :base_release)
|
12
|
+
Spotify::Pointer.new(a_pointer, :base, true)
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#to_pointer" do
|
16
|
+
it "should not accept raw FFI pointers" do
|
17
|
+
expect { klass.new(a_pointer) }.to raise_error(TypeError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should raise an error if given an invalid pointer type" do
|
21
|
+
expect { klass.new(mock_album) }.to raise_error(TypeError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
10
25
|
describe ".from" do
|
11
26
|
it "should return a new object if given pointer is not null" do
|
12
|
-
|
13
|
-
klass.from(a_pointer).should_not be_nil
|
27
|
+
klass.from(base_pointer).should_not be_nil
|
14
28
|
end
|
15
29
|
|
16
30
|
it "should return nil if given pointer is null" do
|
17
|
-
|
18
|
-
|
31
|
+
klass.from(null_pointer).should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should return nil if given object is nil" do
|
35
|
+
klass.from(nil).should be_nil
|
19
36
|
end
|
20
37
|
end
|
21
38
|
|
22
39
|
describe "#==" do
|
23
40
|
it "should compare the pointers if applicable" do
|
24
|
-
one = klass.new(
|
25
|
-
two = klass.new(
|
41
|
+
one = klass.new(base_pointer)
|
42
|
+
two = klass.new(base_pointer)
|
26
43
|
|
27
44
|
one.should eq two
|
28
45
|
end
|
29
46
|
|
30
47
|
it "should fall back to default object comparison" do
|
31
|
-
one = klass.new(
|
32
|
-
two = klass.new(
|
48
|
+
one = klass.new(base_pointer)
|
49
|
+
two = klass.new(base_pointer)
|
33
50
|
two.stub(:respond_to?).and_return(false)
|
34
51
|
|
35
52
|
one.should_not eq two
|