hallon 0.18.1 → 0.18.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +1 -0
- data/.travis.yml +7 -1
- data/CHANGELOG.md +8 -0
- data/Gemfile +3 -2
- data/README.markdown +34 -9
- data/Rakefile +3 -3
- data/examples/example_support.rb +9 -6
- data/hallon.gemspec +4 -6
- data/lib/hallon.rb +1 -0
- data/lib/hallon/observable.rb +15 -52
- data/lib/hallon/observable/session.rb +6 -8
- data/lib/hallon/playlist.rb +2 -14
- data/lib/hallon/session.rb +3 -3
- data/lib/hallon/version.rb +1 -1
- data/spec/hallon/observable/session_spec.rb +8 -7
- data/spec/hallon/observable_spec.rb +1 -27
- data/spec/mockspotify.rb +23 -13
- metadata +22 -70
- data/LICENSE.txt +0 -21
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: f25eaa19120499087ea81ef9f17c7102e3a62177
|
4
|
+
data.tar.gz: 1b03b1966751bd123ceb89b3d32364da27b569cc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed2e9f12f2549234d6cfc6b9a501774b3aac8179bd0f079f6a7da48a5dbcfd353f7d92eb0e760f6ab7e9ca434d77a1e01fec4800ab86f0b629b1d0385446b6a4
|
7
|
+
data.tar.gz: 68dfe742b746431e11165cb3e31f977bd5e3efccd80cbbb46aaa0a48180cb900aceb753403b7151342a55d6f65793d038f3ca0bd774e5d01feffeecdbf44c5d1
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,14 @@ Hallon’s Changelog
|
|
4
4
|
[HEAD][]
|
5
5
|
------------------
|
6
6
|
|
7
|
+
[v0.18.2][]
|
8
|
+
------------------
|
9
|
+
No changes to public API. Mostly some cleanup, and support for the new
|
10
|
+
Spotify gem.
|
11
|
+
|
12
|
+
- [470bc9786] Use weak_observable gem for weak reference callbacks.
|
13
|
+
- [b2feb8095] Require newest FFI and Spotify versions.
|
14
|
+
|
7
15
|
[v0.18.1][]
|
8
16
|
------------------
|
9
17
|
Hallon now supports spotify ~> 12.3.0. As a result, you no longer need to manually install
|
data/Gemfile
CHANGED
@@ -3,10 +3,11 @@ gemspec
|
|
3
3
|
|
4
4
|
# Useful for testing out audio.
|
5
5
|
unless ENV["TRAVIS"] # does not build on travis
|
6
|
-
gem 'hallon-openal'
|
6
|
+
gem 'hallon-openal', '~> 1.0.1'
|
7
7
|
end
|
8
8
|
|
9
9
|
gem 'ruby_parser', '>= 3.0.0.a1', '< 4.0'
|
10
10
|
gem 'pry'
|
11
11
|
gem 'simplecov'
|
12
|
-
gem '
|
12
|
+
gem 'yard'
|
13
|
+
gem 'maruku'
|
data/README.markdown
CHANGED
@@ -5,6 +5,14 @@ Hallon (Swedish for “[Raspberry][]”) is _the_ ruby gem for interacting with
|
|
5
5
|
|
6
6
|
Code samples can be found under the `examples/` directory. An explanation on how to run them can be found on the [Hallon wiki on GitHub](https://github.com/Burgestrand/Hallon/wiki).
|
7
7
|
|
8
|
+
### Contact details
|
9
|
+
|
10
|
+
- __Got questions?__ Ask on the mailing list: <mailto:ruby-hallon@googlegroups.com> (<https://groups.google.com/d/forum/ruby-hallon>)
|
11
|
+
- __Found a bug?__ Report an issue: <https://github.com/Burgestrand/Hallon/issues/new>
|
12
|
+
- __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
|
13
|
+
|
14
|
+
If you for some reason cannot use the mailing list or GitHub issue tracker you may contact me directly. My email is found on [my GitHub profile](https://github.com/Burgestrand).
|
15
|
+
|
8
16
|
Prerequisites
|
9
17
|
-------------
|
10
18
|
|
@@ -60,14 +68,6 @@ gem install hallon-openal
|
|
60
68
|
|
61
69
|
For more information about audio support in Hallon, see the section "Audio support" below.
|
62
70
|
|
63
|
-
### Contact details
|
64
|
-
|
65
|
-
- __Got questions?__ Ask on the mailing list: <mailto:ruby-hallon@googlegroups.com> (<https://groups.google.com/d/forum/ruby-hallon>)
|
66
|
-
- __Found a bug?__ Report an issue: <https://github.com/Burgestrand/Hallon/issues/new>
|
67
|
-
- __Have feedback?__ I ❤ feedback! Please send it to the mailing list.
|
68
|
-
|
69
|
-
If you for some reason cannot use the mailing list or GitHub issue tracker you may contact me directly. My email is found on [my GitHub profile](https://github.com/Burgestrand), and I’m also available as [@burgestrand on twitter](https://twitter.com/Burgestrand).
|
70
|
-
|
71
71
|
Hallon and Spotify objects
|
72
72
|
--------------------------
|
73
73
|
All objects from libspotify have a counterpart in Hallon, and just like in libspotify the objects are populated with information as it becomes available. All objects that behave in this way respond to `#loaded?`, which’ll return true if the object has been populated with data.
|
@@ -170,6 +170,9 @@ You can only keep one session with Spotify alive at a time within the same proce
|
|
170
170
|
### When forking, you need to be extra careful
|
171
171
|
If you fork, you need to instantiate the session within the process you plan to use Hallon in. You want to use Hallon in the parent? Create the session in the parent. You want to use it in the child? Create the session in the child! This is a limitation of libspotify itself.
|
172
172
|
|
173
|
+
### You must not share cache directory between processes
|
174
|
+
Hallon uses `tmp/hallon` as both cache and settings directory by default. If you launch Hallon in multiple processes, you must make sure that `cache_location` is not shared between them, by changing it in the call to [Session.initialize][], or libspotify will lock up.
|
175
|
+
|
173
176
|
### Hallon and platforms
|
174
177
|
Hallon aims to support the available platforms of the Spotify gem, which in turn depends somewhat on the platforms that libspotify support. As of current, Hallon officially supports Mac OS and Linux distributions that libspotify supports. Windows support is possible, but is yet to have been needed.
|
175
178
|
|
@@ -185,7 +188,29 @@ Credits
|
|
185
188
|
|
186
189
|
License
|
187
190
|
-------
|
188
|
-
Hallon is licensed under a 2-clause (Simplified) BSD license.
|
191
|
+
Hallon is licensed under a 2-clause (Simplified) BSD license.
|
192
|
+
|
193
|
+
Copyright 2012 Kim Burgestrand. All rights reserved.
|
194
|
+
|
195
|
+
Redistribution and use in source and binary forms, with or without modification, are
|
196
|
+
permitted provided that the following conditions are met:
|
197
|
+
|
198
|
+
1. Redistributions of source code must retain the above copyright notice, this list of
|
199
|
+
conditions and the following disclaimer.
|
200
|
+
|
201
|
+
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
202
|
+
of conditions and the following disclaimer in the documentation and/or other materials
|
203
|
+
provided with the distribution.
|
204
|
+
|
205
|
+
THIS SOFTWARE IS PROVIDED BY KIM BURGESTRAND ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
206
|
+
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
207
|
+
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KIM BURGESTRAND OR
|
208
|
+
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
209
|
+
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
210
|
+
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
211
|
+
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
212
|
+
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
213
|
+
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
189
214
|
|
190
215
|
[Raspberry]: http://images.google.com/search?q=raspberry&tbm=isch
|
191
216
|
[Spotify for Ruby]: https://github.com/Burgestrand/spotify
|
data/Rakefile
CHANGED
@@ -4,13 +4,13 @@ require 'rake'
|
|
4
4
|
begin
|
5
5
|
require 'bundler'
|
6
6
|
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
require 'yard'
|
9
|
+
YARD::Rake::YardocTask.new
|
7
10
|
rescue LoadError
|
8
11
|
# not everybody needs these
|
9
12
|
end
|
10
13
|
|
11
|
-
require 'yard'
|
12
|
-
YARD::Rake::YardocTask.new
|
13
|
-
|
14
14
|
require 'rspec/core/rake_task'
|
15
15
|
RSpec::Core::RakeTask.new('spec') do |task|
|
16
16
|
task.ruby_opts = '-W2'
|
data/examples/example_support.rb
CHANGED
@@ -42,9 +42,15 @@ end
|
|
42
42
|
|
43
43
|
# Making sure you receive the latest of the latest. Hallon does not wish to
|
44
44
|
# be replaced by older versions when showing you the shiny.
|
45
|
-
|
45
|
+
require 'bundler'
|
46
|
+
Bundler.setup
|
46
47
|
require 'hallon'
|
47
48
|
|
49
|
+
begin
|
50
|
+
require_relative 'common'
|
51
|
+
rescue LoadError
|
52
|
+
end
|
53
|
+
|
48
54
|
# This is a quick sanity check, to make sure we have all the necessities in order.
|
49
55
|
appkey_path = File.expand_path('./spotify_appkey.key')
|
50
56
|
unless File.exists?(appkey_path)
|
@@ -52,9 +58,6 @@ unless File.exists?(appkey_path)
|
|
52
58
|
Your Spotify application key could not be found at the path:
|
53
59
|
#{appkey_path}
|
54
60
|
|
55
|
-
Please adjust the path in examples/common.rb or put your application key in:
|
56
|
-
#{appkey_path}
|
57
|
-
|
58
61
|
You may download your application key from:
|
59
62
|
https://developer.spotify.com/en/libspotify/application-key/
|
60
63
|
ERROR
|
@@ -68,8 +71,8 @@ they require actual login credentials before they may run."
|
|
68
71
|
|
69
72
|
# Spotify requires a rite of passage. It’s own variant of “open sesame”, so we will
|
70
73
|
# ask you to provide them with your information.
|
71
|
-
hallon_username = prompt("Please enter your spotify username")
|
72
|
-
hallon_password = prompt("Please enter your spotify password", hide: true)
|
74
|
+
hallon_username = ENV.fetch("SPOTIFY_USERNAME") { prompt("Please enter your spotify username") }
|
75
|
+
hallon_password = ENV.fetch("SPOTIFY_PASSWORD") { prompt("Please enter your spotify password", hide: true) }
|
73
76
|
hallon_appkey = IO.read(appkey_path)
|
74
77
|
|
75
78
|
# Make sure the credentials are there. We don’t want to go without them.
|
data/hallon.gemspec
CHANGED
@@ -21,11 +21,9 @@ Gem::Specification.new do |gem|
|
|
21
21
|
gem.platform = Gem::Platform::RUBY
|
22
22
|
gem.required_ruby_version = '>= 1.9'
|
23
23
|
|
24
|
-
gem.add_dependency '
|
25
|
-
gem.add_dependency 'spotify', '~> 12.
|
26
|
-
gem.
|
24
|
+
gem.add_dependency 'weak_observable', '~> 1.0'
|
25
|
+
gem.add_dependency 'spotify', '~> 12.5.1'
|
26
|
+
gem.add_dependency 'ffi', '~> 1.8'
|
27
|
+
gem.add_development_dependency 'rake'
|
27
28
|
gem.add_development_dependency 'rspec', '~> 2'
|
28
|
-
gem.add_development_dependency 'yard'
|
29
|
-
gem.add_development_dependency 'bundler'
|
30
|
-
gem.add_development_dependency 'rdiscount'
|
31
29
|
end
|
data/lib/hallon.rb
CHANGED
data/lib/hallon/observable.rb
CHANGED
@@ -22,31 +22,7 @@ module Hallon
|
|
22
22
|
# @param [Object] object
|
23
23
|
# @param [FFI::Pointer] pointer
|
24
24
|
def subscribe(object, pointer)
|
25
|
-
|
26
|
-
ref = Ref::WeakReference.new(object)
|
27
|
-
|
28
|
-
@lock.synchronize do
|
29
|
-
if @subscribers_rev[ref.referenced_object_id]
|
30
|
-
raise ArgumentError, "already subscribed to callbacks"
|
31
|
-
end
|
32
|
-
|
33
|
-
@subscribers[key] ||= {} # use a hash for fast reverse lookups
|
34
|
-
@subscribers[key][ref.referenced_object_id] = ref
|
35
|
-
@subscribers_rev[ref.referenced_object_id] = key
|
36
|
-
end
|
37
|
-
|
38
|
-
ObjectSpace.define_finalizer(object, @unsubscriber)
|
39
|
-
end
|
40
|
-
|
41
|
-
# Retrieve all subscribers for a given pointer.
|
42
|
-
#
|
43
|
-
# @param [FFI::Pointer] pointer
|
44
|
-
def subscribers_for(pointer)
|
45
|
-
key = pointer.address
|
46
|
-
|
47
|
-
@lock.synchronize do
|
48
|
-
@subscribers.fetch(key, {}).values.map(&:object).compact
|
49
|
-
end
|
25
|
+
@observers.add(pointer.address, object, :trigger)
|
50
26
|
end
|
51
27
|
|
52
28
|
protected
|
@@ -57,18 +33,7 @@ module Hallon
|
|
57
33
|
# track of all subscribers properly.
|
58
34
|
def initialize_observable
|
59
35
|
@callbacks = initialize_callbacks
|
60
|
-
|
61
|
-
@lock = Ref::SafeMonitor.new
|
62
|
-
@subscribers = {}
|
63
|
-
@subscribers_rev = {}
|
64
|
-
@unsubscriber = proc do |object_id|
|
65
|
-
@lock.synchronize do
|
66
|
-
if key = @subscribers_rev.delete(object_id)
|
67
|
-
@subscribers[key].delete(object_id)
|
68
|
-
@subscribers.delete(key) if @subscribers[key].empty?
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
36
|
+
@observers = WeakObservable::Hub.new
|
72
37
|
end
|
73
38
|
|
74
39
|
# @param [#to_s] name
|
@@ -86,9 +51,8 @@ module Hallon
|
|
86
51
|
# @param […] arguments
|
87
52
|
# @return whatever the (last) handler returned
|
88
53
|
def trigger(pointer, event, *arguments)
|
89
|
-
|
90
|
-
|
91
|
-
subscriber.send(:trigger, event, *arguments)
|
54
|
+
if results = @observers.notify(pointer.address, event, *arguments)
|
55
|
+
results[-1]
|
92
56
|
end
|
93
57
|
end
|
94
58
|
end
|
@@ -104,11 +68,10 @@ module Hallon
|
|
104
68
|
# @return [Proc] the previous handler
|
105
69
|
# @yield (*args) event handler block
|
106
70
|
def on(event, &block)
|
71
|
+
event &&= event.to_s
|
107
72
|
raise ArgumentError, "no block given" unless block
|
108
73
|
raise NameError, "no such callback: #{event}" unless has_callback?(event)
|
109
|
-
handlers[event
|
110
|
-
handlers[event.to_s] = block
|
111
|
-
end
|
74
|
+
handlers[event].tap { handlers[event] = block }
|
112
75
|
end
|
113
76
|
|
114
77
|
# Wait for the given callbacks to fire until the block returns true
|
@@ -178,6 +141,15 @@ module Hallon
|
|
178
141
|
handlers.replace(old_handlers)
|
179
142
|
end
|
180
143
|
|
144
|
+
# @param [#to_s] name
|
145
|
+
# @param [...] arguments
|
146
|
+
# @return whatever the handler returns
|
147
|
+
def trigger(name, *arguments, &block)
|
148
|
+
if handler = handlers[name.to_s]
|
149
|
+
handler.call(*arguments, &block)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
181
153
|
protected
|
182
154
|
|
183
155
|
# Register this object as interested in callbacks.
|
@@ -191,15 +163,6 @@ module Hallon
|
|
191
163
|
end
|
192
164
|
end
|
193
165
|
|
194
|
-
# @param [#to_s] name
|
195
|
-
# @param [...] arguments
|
196
|
-
# @return whatever the handler returns
|
197
|
-
def trigger(name, *arguments, &block)
|
198
|
-
if handler = handlers[name.to_s]
|
199
|
-
handler.call(*arguments, &block)
|
200
|
-
end
|
201
|
-
end
|
202
|
-
|
203
166
|
# @return [Hash<String, Proc>]
|
204
167
|
def handlers
|
205
168
|
@__handlers ||= Hash.new(proc {})
|
@@ -91,13 +91,12 @@ module Hallon::Observable
|
|
91
91
|
# @yield [format, frames]
|
92
92
|
# @yieldparam [Hash] format (contains :type, :rate, :channels)
|
93
93
|
# @yieldparam [Enumerator<[Integer...]>] frames (each frame is an array containing format[:channels] integers of format[:type])
|
94
|
-
def music_delivery_callback(pointer,
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
format[:type] = struct[:sample_type]
|
94
|
+
def music_delivery_callback(pointer, format_struct, frames, num_frames)
|
95
|
+
format = {
|
96
|
+
rate: format_struct[:sample_rate],
|
97
|
+
channels: format_struct[:channels],
|
98
|
+
type: format_struct[:sample_type]
|
99
|
+
}
|
101
100
|
|
102
101
|
# read the frames of the given type
|
103
102
|
frames = unless num_frames.zero?
|
@@ -161,7 +160,6 @@ module Hallon::Observable
|
|
161
160
|
# @yield []
|
162
161
|
# @yieldreturn an integer pair, [samples, dropouts]
|
163
162
|
def get_audio_buffer_stats_callback(pointer, stats)
|
164
|
-
stats = Spotify::AudioBufferStats.new(stats)
|
165
163
|
samples, dropouts = trigger(pointer, :get_audio_buffer_stats)
|
166
164
|
stats[:samples] = samples.to_i
|
167
165
|
stats[:stutter] = dropouts.to_i
|
data/lib/hallon/playlist.rb
CHANGED
@@ -250,20 +250,8 @@ module Hallon
|
|
250
250
|
# libspotify does not store more than 500 subscriber names
|
251
251
|
# @return [Array<String>] list of canonical usernames
|
252
252
|
def subscribers
|
253
|
-
|
254
|
-
|
255
|
-
if ptr.null?
|
256
|
-
[]
|
257
|
-
else
|
258
|
-
struct = Spotify::Subscribers.new(ptr)
|
259
|
-
if struct[:count].zero?
|
260
|
-
[]
|
261
|
-
else
|
262
|
-
struct[:subscribers].map(&:read_string)
|
263
|
-
end
|
264
|
-
end
|
265
|
-
ensure
|
266
|
-
Spotify.playlist_subscribers_free(ptr) unless ptr.null?
|
253
|
+
subscribers = Spotify.playlist_subscribers(pointer)
|
254
|
+
subscribers.to_a
|
267
255
|
end
|
268
256
|
|
269
257
|
# @return [Integer] total number of subscribers.
|
data/lib/hallon/session.rb
CHANGED
@@ -46,7 +46,7 @@ module Hallon
|
|
46
46
|
# @see (see Session#initialize)
|
47
47
|
# @return [Session]
|
48
48
|
def Session.initialize(appkey, options = {}, &block)
|
49
|
-
raise "Session has already been initialized" if @__instance__
|
49
|
+
raise "Session has already been initialized" if defined?(@__instance__)
|
50
50
|
@__instance__ = new(appkey, options, &block)
|
51
51
|
end
|
52
52
|
|
@@ -375,8 +375,8 @@ module Hallon
|
|
375
375
|
# @see http://developer.spotify.com/en/libspotify/docs/structsp__offline__sync__status.html
|
376
376
|
def offline_sync_status
|
377
377
|
struct = Spotify::OfflineSyncStatus.new
|
378
|
-
if Spotify.offline_sync_get_status(pointer, struct
|
379
|
-
|
378
|
+
if Spotify.offline_sync_get_status(pointer, struct)
|
379
|
+
struct.to_h
|
380
380
|
else
|
381
381
|
{}
|
382
382
|
end
|
data/lib/hallon/version.rb
CHANGED
@@ -49,15 +49,15 @@ describe Hallon::Observable::Session do
|
|
49
49
|
frames
|
50
50
|
end
|
51
51
|
|
52
|
-
let(:
|
52
|
+
let(:format_struct) do
|
53
53
|
struct = Spotify::AudioFormat.new
|
54
54
|
struct[:sample_type] = :int16
|
55
55
|
struct[:sample_rate] = 44100 # 44.1khz
|
56
56
|
struct[:channels] = 2
|
57
|
-
struct
|
57
|
+
struct
|
58
58
|
end
|
59
59
|
|
60
|
-
let(:input) { [a_pointer,
|
60
|
+
let(:input) { [a_pointer, format_struct, frames, num_frames] }
|
61
61
|
let(:output) { [{rate: 44100, type: :int16, channels: 2}, data.each_slice(2)] }
|
62
62
|
|
63
63
|
it "should return the resulting value" do
|
@@ -70,7 +70,7 @@ describe Hallon::Observable::Session do
|
|
70
70
|
end
|
71
71
|
|
72
72
|
it "should not go ballistic when there is no audio data" do
|
73
|
-
subject_callback.call(a_pointer,
|
73
|
+
subject_callback.call(a_pointer, format_struct, FFI::Pointer::NULL, 0)
|
74
74
|
end
|
75
75
|
end
|
76
76
|
|
@@ -95,7 +95,8 @@ describe Hallon::Observable::Session do
|
|
95
95
|
end
|
96
96
|
|
97
97
|
specification_for_callback "get_audio_buffer_stats" do
|
98
|
-
let(:
|
98
|
+
let(:struct) { Spotify::AudioBufferStats.new }
|
99
|
+
let(:input) { [a_pointer, struct] }
|
99
100
|
let(:output) { [] }
|
100
101
|
|
101
102
|
it "should return the resulting audio buffer stats" do
|
@@ -104,7 +105,7 @@ describe Hallon::Observable::Session do
|
|
104
105
|
|
105
106
|
stats[:samples].should eq 0
|
106
107
|
stats[:stutter].should eq 0
|
107
|
-
subject_callback.call(a_pointer, stats
|
108
|
+
subject_callback.call(a_pointer, stats)
|
108
109
|
stats[:samples].should eq 5
|
109
110
|
stats[:stutter].should eq 7
|
110
111
|
end
|
@@ -114,7 +115,7 @@ describe Hallon::Observable::Session do
|
|
114
115
|
|
115
116
|
stats[:samples].should eq 0
|
116
117
|
stats[:stutter].should eq 0
|
117
|
-
subject_callback.call(a_pointer, stats
|
118
|
+
subject_callback.call(a_pointer, stats)
|
118
119
|
stats[:samples].should eq 0
|
119
120
|
stats[:stutter].should eq 0
|
120
121
|
end
|
@@ -54,27 +54,6 @@ describe Hallon::Observable do
|
|
54
54
|
|
55
55
|
describe "ClassMethods" do
|
56
56
|
subject { klass }
|
57
|
-
|
58
|
-
describe ".subscribers_for" do
|
59
|
-
around { |test| Ref::Mock.use(&test) }
|
60
|
-
|
61
|
-
it "should contain a list of weak references to subscribers" do
|
62
|
-
ptr = FFI::Pointer.new(0xDEADBEEF)
|
63
|
-
|
64
|
-
objA = klass.new
|
65
|
-
subject.subscribers_for(ptr).should eq [objA]
|
66
|
-
|
67
|
-
objB = klass.new
|
68
|
-
subject.subscribers_for(ptr).should eq [objA, objB]
|
69
|
-
|
70
|
-
Ref::Mock.gc(objA)
|
71
|
-
subject.subscribers_for(ptr).should eq [objB]
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should return an empty array if there are no subscribers" do
|
75
|
-
subject.subscribers_for(null_pointer).should be_empty
|
76
|
-
end
|
77
|
-
end
|
78
57
|
end
|
79
58
|
|
80
59
|
subject { klass.new }
|
@@ -124,8 +103,8 @@ describe Hallon::Observable do
|
|
124
103
|
it "should return the previous callback" do
|
125
104
|
previous = proc { puts "hey!" }
|
126
105
|
new_one = proc { puts "ho!" }
|
127
|
-
initial = subject.on(:testing, &previous)
|
128
106
|
|
107
|
+
subject.on(:testing, &previous)
|
129
108
|
subject.on(:testing, &new_one).should eq previous
|
130
109
|
subject.on(:testing, &previous).should eq new_one
|
131
110
|
end
|
@@ -144,11 +123,6 @@ describe Hallon::Observable do
|
|
144
123
|
expect { subject.send(:subscribe_for_callbacks) }.to raise_error(LocalJumpError)
|
145
124
|
end
|
146
125
|
|
147
|
-
it "should raise an error if the same object tries to subscribe twice" do
|
148
|
-
# we already subscribed for callbacks in initialize
|
149
|
-
expect { subject.send(:subscribe_for_callbacks) {} }.to raise_error(ArgumentError)
|
150
|
-
end
|
151
|
-
|
152
126
|
it "should do nothing if the result is a null pointer" do
|
153
127
|
klass.should_not_receive(:subscribe)
|
154
128
|
klass.any_instance.stub(:pointer).and_return(FFI::Pointer::NULL)
|
data/spec/mockspotify.rb
CHANGED
@@ -34,17 +34,17 @@ module Spotify
|
|
34
34
|
|
35
35
|
module Mock
|
36
36
|
class PlaylistTrack < Spotify::Struct
|
37
|
-
layout :track,
|
37
|
+
layout :track, :pointer,
|
38
38
|
:create_time, :int,
|
39
|
-
:creator,
|
40
|
-
:message, Spotify::
|
39
|
+
:creator, :pointer,
|
40
|
+
:message, Spotify::UTF8StringPointer,
|
41
41
|
:seen, :bool
|
42
42
|
end
|
43
43
|
|
44
44
|
class PlaylistContainerItem < Spotify::Struct
|
45
|
-
layout :playlist,
|
45
|
+
layout :playlist, :pointer,
|
46
46
|
:type, :playlist_type,
|
47
|
-
:folder_name, Spotify::
|
47
|
+
:folder_name, Spotify::UTF8StringPointer,
|
48
48
|
:folder_id, :uint64,
|
49
49
|
:num_seen_tracks, :int,
|
50
50
|
:seen_tracks, :array
|
@@ -54,25 +54,35 @@ module Spotify
|
|
54
54
|
class API
|
55
55
|
old_verbose, $VERBOSE = $VERBOSE, true
|
56
56
|
|
57
|
+
# Some of these can accept null pointers, but our type protection ensures
|
58
|
+
# that we never pass null values in place of spotify objects, so we work
|
59
|
+
# around it by not using the real types. We still want to document the kind
|
60
|
+
# used, however.
|
61
|
+
typedef :pointer, :track
|
62
|
+
typedef :pointer, :album
|
63
|
+
typedef :pointer, :artist
|
64
|
+
typedef :pointer, :playlist
|
65
|
+
typedef :pointer, :user
|
66
|
+
|
57
67
|
attach_function :mock_registry_find, [:string], :pointer
|
58
68
|
attach_function :mock_registry_add, [:string, :pointer], :void
|
59
69
|
attach_function :mock_registry_clean, [], :void
|
60
70
|
|
61
|
-
attach_function :mock_session_create, [:pointer, :connectionstate, :int, OfflineSyncStatus, :int, :int,
|
71
|
+
attach_function :mock_session_create, [:pointer, :connectionstate, :int, OfflineSyncStatus, :int, :int, :playlist], Session
|
62
72
|
attach_function :mock_user_create, [:string, :string, :bool], User
|
63
|
-
attach_function :mock_track_create, [:string, :int, :array,
|
73
|
+
attach_function :mock_track_create, [:string, :int, :array, :album, :int, :int, :int, :int, :error, :bool, :availability, :track_offline_status, :bool, :bool, :track, :bool, :bool], Track
|
64
74
|
attach_function :mock_image_create, [ImageID, :imageformat, :size_t, :buffer_in, :error], Image
|
65
75
|
attach_function :mock_artist_create, [:string, ImageID, :bool], Artist
|
66
|
-
attach_function :mock_album_create, [:string,
|
76
|
+
attach_function :mock_album_create, [:string, :artist, :int, ImageID, :albumtype, :bool, :bool], Album
|
67
77
|
|
68
|
-
attach_function :mock_albumbrowse_create, [:error, :int,
|
69
|
-
attach_function :mock_artistbrowse_create, [:error, :int,
|
78
|
+
attach_function :mock_albumbrowse_create, [:error, :int, :album, :artist, :int, :array, :int, :array, :string, :albumbrowse_complete_cb, :userdata], AlbumBrowse
|
79
|
+
attach_function :mock_artistbrowse_create, [:error, :int, :artist, :int, :array, :int, :array, :int, :array, :int, :array, :int, :array, :string, :artistbrowse_type, :artistbrowse_complete_cb, :userdata], ArtistBrowse
|
70
80
|
attach_function :mock_toplistbrowse_create, [:error, :int, :int, :array, :int, :array, :int, :array], ToplistBrowse
|
71
81
|
|
72
|
-
attach_function :mock_playlist_create, [:string, :bool,
|
73
|
-
attach_function :mock_playlistcontainer_create, [
|
82
|
+
attach_function :mock_playlist_create, [:string, :bool, :user, :bool, :string, ImageID, :bool, :uint, Subscribers, :bool, :playlist_offline_status, :int, :int, :array], Playlist
|
83
|
+
attach_function :mock_playlistcontainer_create, [:user, :bool, :int, :array, PlaylistContainerCallbacks, :userdata], PlaylistContainer
|
74
84
|
attach_function :mock_search_create, [:error, :string, :string, :int, :int, :array, :int, :int, :array, :int, :int, :array, :int, :int, :array, :search_complete_cb, :userdata], Search
|
75
|
-
attach_function :mock_subscribers, [:int, :array], Subscribers
|
85
|
+
attach_function :mock_subscribers, [:int, :array], Subscribers.by_ref
|
76
86
|
|
77
87
|
# mocked accessors
|
78
88
|
attach_function :mock_playlist_get_autolink_tracks, [Playlist], :bool
|
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hallon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.18.
|
5
|
-
prerelease:
|
4
|
+
version: 0.18.2
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Kim Burgestrand
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date:
|
11
|
+
date: 2013-04-25 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
name:
|
14
|
+
name: weak_observable
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ~>
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ~>
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,99 +27,59 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: spotify
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ~>
|
36
32
|
- !ruby/object:Gem::Version
|
37
|
-
version: 12.
|
33
|
+
version: 12.5.1
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ~>
|
44
39
|
- !ruby/object:Gem::Version
|
45
|
-
version: 12.
|
40
|
+
version: 12.5.1
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
|
-
name:
|
48
|
-
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
|
-
requirements:
|
51
|
-
- - ~>
|
52
|
-
- !ruby/object:Gem::Version
|
53
|
-
version: '0.8'
|
54
|
-
type: :development
|
55
|
-
prerelease: false
|
56
|
-
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
|
-
requirements:
|
59
|
-
- - ~>
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: '0.8'
|
62
|
-
- !ruby/object:Gem::Dependency
|
63
|
-
name: rspec
|
42
|
+
name: ffi
|
64
43
|
requirement: !ruby/object:Gem::Requirement
|
65
|
-
none: false
|
66
44
|
requirements:
|
67
45
|
- - ~>
|
68
46
|
- !ruby/object:Gem::Version
|
69
|
-
version: '
|
70
|
-
type: :
|
47
|
+
version: '1.8'
|
48
|
+
type: :runtime
|
71
49
|
prerelease: false
|
72
50
|
version_requirements: !ruby/object:Gem::Requirement
|
73
|
-
none: false
|
74
51
|
requirements:
|
75
52
|
- - ~>
|
76
53
|
- !ruby/object:Gem::Version
|
77
|
-
version: '
|
78
|
-
- !ruby/object:Gem::Dependency
|
79
|
-
name: yard
|
80
|
-
requirement: !ruby/object:Gem::Requirement
|
81
|
-
none: false
|
82
|
-
requirements:
|
83
|
-
- - ! '>='
|
84
|
-
- !ruby/object:Gem::Version
|
85
|
-
version: '0'
|
86
|
-
type: :development
|
87
|
-
prerelease: false
|
88
|
-
version_requirements: !ruby/object:Gem::Requirement
|
89
|
-
none: false
|
90
|
-
requirements:
|
91
|
-
- - ! '>='
|
92
|
-
- !ruby/object:Gem::Version
|
93
|
-
version: '0'
|
54
|
+
version: '1.8'
|
94
55
|
- !ruby/object:Gem::Dependency
|
95
|
-
name:
|
56
|
+
name: rake
|
96
57
|
requirement: !ruby/object:Gem::Requirement
|
97
|
-
none: false
|
98
58
|
requirements:
|
99
|
-
- -
|
59
|
+
- - '>='
|
100
60
|
- !ruby/object:Gem::Version
|
101
61
|
version: '0'
|
102
62
|
type: :development
|
103
63
|
prerelease: false
|
104
64
|
version_requirements: !ruby/object:Gem::Requirement
|
105
|
-
none: false
|
106
65
|
requirements:
|
107
|
-
- -
|
66
|
+
- - '>='
|
108
67
|
- !ruby/object:Gem::Version
|
109
68
|
version: '0'
|
110
69
|
- !ruby/object:Gem::Dependency
|
111
|
-
name:
|
70
|
+
name: rspec
|
112
71
|
requirement: !ruby/object:Gem::Requirement
|
113
|
-
none: false
|
114
72
|
requirements:
|
115
|
-
- -
|
73
|
+
- - ~>
|
116
74
|
- !ruby/object:Gem::Version
|
117
|
-
version: '
|
75
|
+
version: '2'
|
118
76
|
type: :development
|
119
77
|
prerelease: false
|
120
78
|
version_requirements: !ruby/object:Gem::Requirement
|
121
|
-
none: false
|
122
79
|
requirements:
|
123
|
-
- -
|
80
|
+
- - ~>
|
124
81
|
- !ruby/object:Gem::Version
|
125
|
-
version: '
|
82
|
+
version: '2'
|
126
83
|
description:
|
127
84
|
email: kim@burgestrand.se
|
128
85
|
executables: []
|
@@ -137,7 +94,6 @@ files:
|
|
137
94
|
- .yardopts
|
138
95
|
- CHANGELOG.md
|
139
96
|
- Gemfile
|
140
|
-
- LICENSE.txt
|
141
97
|
- QUIRKS
|
142
98
|
- README.markdown
|
143
99
|
- Rakefile
|
@@ -275,30 +231,26 @@ files:
|
|
275
231
|
homepage: http://github.com/Burgestrand/Hallon
|
276
232
|
licenses:
|
277
233
|
- X11 License
|
234
|
+
metadata: {}
|
278
235
|
post_install_message:
|
279
236
|
rdoc_options: []
|
280
237
|
require_paths:
|
281
238
|
- lib
|
282
239
|
required_ruby_version: !ruby/object:Gem::Requirement
|
283
|
-
none: false
|
284
240
|
requirements:
|
285
|
-
- -
|
241
|
+
- - '>='
|
286
242
|
- !ruby/object:Gem::Version
|
287
243
|
version: '1.9'
|
288
244
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
289
|
-
none: false
|
290
245
|
requirements:
|
291
|
-
- -
|
246
|
+
- - '>='
|
292
247
|
- !ruby/object:Gem::Version
|
293
248
|
version: '0'
|
294
|
-
segments:
|
295
|
-
- 0
|
296
|
-
hash: 1548945263546800899
|
297
249
|
requirements: []
|
298
250
|
rubyforge_project:
|
299
|
-
rubygems_version:
|
251
|
+
rubygems_version: 2.0.3
|
300
252
|
signing_key:
|
301
|
-
specification_version:
|
253
|
+
specification_version: 4
|
302
254
|
summary: Hallon allows you to write Ruby applications utilizing the official Spotify
|
303
255
|
C API.
|
304
256
|
test_files:
|
data/LICENSE.txt
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
Copyright 2012 Kim Burgestrand. All rights reserved.
|
2
|
-
|
3
|
-
Redistribution and use in source and binary forms, with or without modification, are
|
4
|
-
permitted provided that the following conditions are met:
|
5
|
-
|
6
|
-
1. Redistributions of source code must retain the above copyright notice, this list of
|
7
|
-
conditions and the following disclaimer.
|
8
|
-
|
9
|
-
2. Redistributions in binary form must reproduce the above copyright notice, this list
|
10
|
-
of conditions and the following disclaimer in the documentation and/or other materials
|
11
|
-
provided with the distribution.
|
12
|
-
|
13
|
-
THIS SOFTWARE IS PROVIDED BY KIM BURGESTRAND ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
14
|
-
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
|
15
|
-
FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KIM BURGESTRAND OR
|
16
|
-
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
17
|
-
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
|
18
|
-
SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
19
|
-
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
20
|
-
NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
21
|
-
ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|