spotify 12.4.0 → 12.5.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.
- checksums.yaml +7 -0
- data/.travis.yml +3 -0
- data/CHANGELOG.md +24 -1
- data/Gemfile +2 -2
- data/README.markdown +2 -0
- data/examples/audio-stream.rb +5 -8
- data/examples/logging-in.rb +6 -12
- data/lib/spotify/api/link.rb +1 -1
- data/lib/spotify/api/playlist.rb +4 -4
- data/lib/spotify/api/playlist_container.rb +2 -2
- data/lib/spotify/api/session.rb +5 -5
- data/lib/spotify/managed_pointer.rb +12 -13
- data/lib/spotify/objects.rb +1 -0
- data/lib/spotify/structs.rb +2 -0
- data/lib/spotify/structs/session_config.rb +12 -18
- data/lib/spotify/structs/subscribers.rb +46 -3
- data/lib/spotify/type_safety.rb +25 -0
- data/lib/spotify/types.rb +2 -1
- data/lib/spotify/types/byte_string.rb +28 -0
- data/lib/spotify/types/{nul_string.rb → utf8_string_pointer.rb} +3 -3
- data/lib/spotify/version.rb +1 -1
- data/spec/spec_helper.rb +15 -5
- data/spec/spotify/managed_pointer_spec.rb +12 -1
- data/spec/spotify/structs/session_config_spec.rb +2 -2
- data/spec/spotify/structs/struct_spec.rb +2 -2
- data/spec/spotify/structs/subscribers_spec.rb +108 -24
- data/spec/spotify/type_safety_spec.rb +36 -0
- data/spec/spotify/types/byte_string_spec.rb +26 -0
- data/spec/spotify/types/utf8_string_pointer_spec.rb +49 -0
- data/spec/support/spotify_util.rb +2 -0
- metadata +41 -50
- data/spec/spotify/types/nul_string_spec.rb +0 -31
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: bf64e70f3fd55a846fc2a016a2948cf547e92f54
|
4
|
+
data.tar.gz: 1012f48eb4fcb112b5866d63defe433a0974e2bb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: c6b782905e37db551e1291e1769508d5f0fa0d6f1c6932700b9c0bace51433228e558ea607d99937a6e2f5b26c2a0066e93e069c74a7b2878cd5f315f6c5d376
|
7
|
+
data.tar.gz: b402e97d8772d953ae453b7b1d61a3cd73ad9346f970b739adb23d97cc3740a0677c4c1c14845af482ace77434adef085333bb9b491ba70ee53e3dcb5a29d9f3
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,26 @@
|
|
1
1
|
[HEAD][]
|
2
2
|
-----------
|
3
|
+
|
4
|
+
[v12.5.0][]
|
5
|
+
-----------
|
6
|
+
This release *also* breaks backwards-compatibilty, now all functions
|
7
|
+
accepting structs also have type-safety protection, similar to what
|
8
|
+
happens for pointers in v12.4.0.
|
9
|
+
|
10
|
+
Additionally, gem now supports JRuby and Rubinius explicitly!
|
11
|
+
|
12
|
+
- [a450bf27b9] implement type safety for all struct arguments
|
13
|
+
- [44b35d6432] automatic release for Subscribers struct
|
14
|
+
- [1c88809139] force application_key to be assigned as a string in SessionConfig
|
15
|
+
- [c9bc974d44] Subscribers now always have a :subscribers member
|
16
|
+
- [05e691c2aa] allow instantiating Subscribers from NULL
|
17
|
+
- [c83c9feb1c] Enable rbx-19mode on travis-ci.org
|
18
|
+
- [3e153a48f4] Enable jruby-19mode on travis-ci.org
|
19
|
+
- [72aadf4906] Use UTF8 everywhere, even in struct fields
|
20
|
+
- [e05b286118] Make Subscribers enumerable
|
21
|
+
|
22
|
+
[v12.4.0][]
|
23
|
+
-----------
|
3
24
|
This release breaks backwards-compatibility, as functions will no
|
4
25
|
longer accept pointers of any other type of what they expect. This
|
5
26
|
means that you must wrap any pointers in a Spotify::ManagedPointer
|
@@ -164,8 +185,10 @@ v0.0.0
|
|
164
185
|
------
|
165
186
|
- release to register rubygems.org name
|
166
187
|
|
167
|
-
[HEAD]: https://github.com/Burgestrand/spotify/compare/v12.
|
188
|
+
[HEAD]: https://github.com/Burgestrand/spotify/compare/v12.5.0...HEAD
|
168
189
|
|
190
|
+
[v12.5.0]: https://github.com/Burgestrand/spotify/compare/v12.4.0...v12.5.0
|
191
|
+
[v12.4.0]: https://github.com/Burgestrand/spotify/compare/v12.3.0...v12.4.0
|
169
192
|
[v12.3.0]: https://github.com/Burgestrand/spotify/compare/v12.2.0...v12.3.0
|
170
193
|
[v12.2.0]: https://github.com/Burgestrand/spotify/compare/v12.0.3...v12.2.0
|
171
194
|
[v12.0.3]: https://github.com/Burgestrand/spotify/compare/v12.0.2...v12.0.3
|
data/Gemfile
CHANGED
data/README.markdown
CHANGED
@@ -18,11 +18,13 @@ The Spotify gem has:
|
|
18
18
|
- [Automatic garbage collection][]. Piggybacking on Ruby’s GC to manage pointer lifecycle.
|
19
19
|
- [Parallell function call protection][]. libspotify is not thread-safe, but Spotify protects you.
|
20
20
|
- [Type conversion and type safety][]. Special pointers for every Spotify type, protecting you from accidental mix-ups.
|
21
|
+
- [Support for JRuby and Rubinius][]. Thanks to FFI, the gem runs fine on the main three Ruby implementations!
|
21
22
|
|
22
23
|
[100% API coverage]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/API
|
23
24
|
[Automatic garbage collection]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/ManagedPointer
|
24
25
|
[Parallell function call protection]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify#method_missing-class_method
|
25
26
|
[Type conversion and type safety]: http://rdoc.info/github/Burgestrand/spotify/master/Spotify/ManagedPointer
|
27
|
+
[Support for JRuby and Rubinius]: https://github.com/Burgestrand/spotify/blob/master/.travis.yml
|
26
28
|
|
27
29
|
The Spotify gem is aimed at experienced developers
|
28
30
|
--------------------------------------------------
|
data/examples/audio-stream.rb
CHANGED
@@ -50,8 +50,7 @@ class FrameReader
|
|
50
50
|
@channels = channels
|
51
51
|
@sample_type = sample_type
|
52
52
|
@size = frames_count * @channels
|
53
|
-
|
54
|
-
@pointer = FFI::Pointer.new(frames_ptr)
|
53
|
+
@pointer = FFI::Pointer.new(@sample_type, frames_ptr)
|
55
54
|
end
|
56
55
|
|
57
56
|
attr_reader :size
|
@@ -59,11 +58,10 @@ class FrameReader
|
|
59
58
|
def each
|
60
59
|
return enum_for(__method__) unless block_given?
|
61
60
|
|
62
|
-
ffi_read = :"
|
63
|
-
ffi_size = FFI.type_size(@sample_type)
|
61
|
+
ffi_read = :"read_#{@sample_type}"
|
64
62
|
|
65
63
|
(0...size).each do |index|
|
66
|
-
yield @pointer.public_send(ffi_read
|
64
|
+
yield @pointer[index].public_send(ffi_read)
|
67
65
|
end
|
68
66
|
end
|
69
67
|
end
|
@@ -118,8 +116,7 @@ $session_callbacks = {
|
|
118
116
|
$logger.debug("session (player)") { "music delivery audio discontuity" }
|
119
117
|
else
|
120
118
|
frames = FrameReader.new(format[:channels], format[:sample_type], num_frames, frames)
|
121
|
-
|
122
|
-
consumed_frames = consumed_samples / format[:channels]
|
119
|
+
consumed_frames = plaything.stream(frames, format.to_h)
|
123
120
|
$logger.debug("session (player)") { "music delivery #{consumed_frames} of #{num_frames}" }
|
124
121
|
consumed_frames
|
125
122
|
end
|
@@ -141,7 +138,7 @@ $session_callbacks = {
|
|
141
138
|
# https://developer.spotify.com/technologies/libspotify/docs/12.1.45/structsp__session__config.html
|
142
139
|
config = Spotify::SessionConfig.new({
|
143
140
|
api_version: Spotify::API_VERSION.to_i,
|
144
|
-
application_key: IO.read("./spotify_appkey.key"),
|
141
|
+
application_key: IO.read("./spotify_appkey.key", encoding: "BINARY"),
|
145
142
|
cache_location: ".spotify/",
|
146
143
|
settings_location: ".spotify/",
|
147
144
|
tracefile: "spotify_tracefile.txt",
|
data/examples/logging-in.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
2
|
# encoding: utf-8
|
3
3
|
|
4
|
-
require
|
5
|
-
require
|
4
|
+
require "bundler/setup"
|
5
|
+
require "spotify"
|
6
|
+
require "logger"
|
6
7
|
|
7
8
|
# We use a logger to print some information on when things are happening.
|
8
9
|
$logger = Logger.new($stderr)
|
@@ -11,21 +12,14 @@ $logger = Logger.new($stderr)
|
|
11
12
|
# Some utility.
|
12
13
|
#
|
13
14
|
|
14
|
-
# This method is just for convenience. Calling the process_events function
|
15
|
-
# is slightly cumbersome.
|
16
|
-
def process_events(session)
|
17
|
-
FFI::MemoryPointer.new(:int) do |ptr|
|
18
|
-
Spotify.session_process_events(session, ptr)
|
19
|
-
return Rational(ptr.read_int, 1000)
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
15
|
# libspotify supports callbacks, but they are not useful for waiting on
|
24
16
|
# operations (how they fire can be strange at times, and sometimes they
|
25
17
|
# might not fire at all). As a result, polling is the way to go.
|
26
18
|
def poll(session)
|
27
19
|
until yield
|
28
|
-
|
20
|
+
FFI::MemoryPointer.new(:int) do |ptr|
|
21
|
+
Spotify.session_process_events(session, ptr)
|
22
|
+
end
|
29
23
|
sleep(0.01)
|
30
24
|
end
|
31
25
|
end
|
data/lib/spotify/api/link.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Spotify
|
2
2
|
class API
|
3
3
|
# @!group Link
|
4
|
-
attach_function :link_create_from_string, [
|
4
|
+
attach_function :link_create_from_string, [ UTF8String ], Link
|
5
5
|
attach_function :link_create_from_track, [ Track, :int ], Link
|
6
6
|
attach_function :link_create_from_album, [ Album ], Link
|
7
7
|
attach_function :link_create_from_artist, [ Artist ], Link
|
data/lib/spotify/api/playlist.rb
CHANGED
@@ -2,8 +2,8 @@ module Spotify
|
|
2
2
|
class API
|
3
3
|
# @!group Playlist
|
4
4
|
attach_function :playlist_is_loaded, [ Playlist ], :bool
|
5
|
-
attach_function :playlist_add_callbacks, [ Playlist, PlaylistCallbacks, :userdata ], :error
|
6
|
-
attach_function :playlist_remove_callbacks, [ Playlist, PlaylistCallbacks, :userdata ], :error
|
5
|
+
attach_function :playlist_add_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], :error
|
6
|
+
attach_function :playlist_remove_callbacks, [ Playlist, PlaylistCallbacks.by_ref, :userdata ], :error
|
7
7
|
attach_function :playlist_num_tracks, [ Playlist ], :int
|
8
8
|
attach_function :playlist_track, [ Playlist, :int ], Track
|
9
9
|
attach_function :playlist_track_create_time, [ Playlist, :int ], :int
|
@@ -24,8 +24,8 @@ module Spotify
|
|
24
24
|
attach_function :playlist_remove_tracks, [ Playlist, :array, :int ], :error
|
25
25
|
attach_function :playlist_reorder_tracks, [ Playlist, :array, :int, :int ], :error
|
26
26
|
attach_function :playlist_num_subscribers, [ Playlist ], :uint
|
27
|
-
attach_function :playlist_subscribers, [ Playlist ], Subscribers
|
28
|
-
attach_function :playlist_subscribers_free, [ Subscribers ], :error
|
27
|
+
attach_function :playlist_subscribers, [ Playlist ], Subscribers.auto_ptr
|
28
|
+
attach_function :playlist_subscribers_free, [ Subscribers.by_ref ], :error
|
29
29
|
attach_function :playlist_update_subscribers, [ Session, Playlist ], :error
|
30
30
|
attach_function :playlist_is_in_ram, [ Session, Playlist ], :bool
|
31
31
|
attach_function :playlist_set_in_ram, [ Session, Playlist, :bool ], :error
|
@@ -1,8 +1,8 @@
|
|
1
1
|
module Spotify
|
2
2
|
class API
|
3
3
|
# @!group PlaylistContainer
|
4
|
-
attach_function :playlistcontainer_add_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks, :userdata ], :error
|
5
|
-
attach_function :playlistcontainer_remove_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks, :userdata ], :error
|
4
|
+
attach_function :playlistcontainer_add_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], :error
|
5
|
+
attach_function :playlistcontainer_remove_callbacks, [ PlaylistContainer, PlaylistContainerCallbacks.by_ref, :userdata ], :error
|
6
6
|
attach_function :playlistcontainer_num_playlists, [ PlaylistContainer ], :int
|
7
7
|
attach_function :playlistcontainer_playlist, [ PlaylistContainer, :int ], Playlist
|
8
8
|
attach_function :playlistcontainer_playlist_type, [ PlaylistContainer, :int ], :playlist_type
|
data/lib/spotify/api/session.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
module Spotify
|
2
2
|
class API
|
3
3
|
# @!group Session
|
4
|
-
attach_function :session_create, [ SessionConfig, :buffer_out ], :error
|
4
|
+
attach_function :session_create, [ SessionConfig.by_ref, :buffer_out ], :error
|
5
5
|
attach_function :session_release, [ Session ], :error
|
6
6
|
attach_function :session_process_events, [ Session, :buffer_out ], :error
|
7
|
-
attach_function :session_login, [ Session, UTF8String,
|
7
|
+
attach_function :session_login, [ Session, UTF8String, UTF8String, :bool, UTF8String ], :error
|
8
8
|
attach_function :session_relogin, [ Session ], :error
|
9
9
|
attach_function :session_forget_me, [ Session ], :error
|
10
10
|
attach_function :session_remembered_user, [ Session, :buffer_out, :size_t ], :int
|
@@ -28,19 +28,19 @@ module Spotify
|
|
28
28
|
attach_function :session_set_connection_rules, [ Session, :connection_rules ], :error
|
29
29
|
attach_function :offline_tracks_to_sync, [ Session ], :int
|
30
30
|
attach_function :offline_num_playlists, [ Session ], :int
|
31
|
-
attach_function :offline_sync_get_status, [ Session, OfflineSyncStatus ], :bool
|
31
|
+
attach_function :offline_sync_get_status, [ Session, OfflineSyncStatus.by_ref ], :bool
|
32
32
|
attach_function :offline_time_left, [ Session ], :int
|
33
33
|
attach_function :session_user_country, [ Session ], :int
|
34
34
|
attach_function :session_preferred_offline_bitrate, [ Session, :bitrate, :bool ], :error
|
35
35
|
attach_function :session_set_volume_normalization, [ Session, :bool ], :error
|
36
36
|
attach_function :session_get_volume_normalization, [ Session ], :bool
|
37
37
|
attach_function :session_flush_caches, [ Session ], :error
|
38
|
-
attach_function :session_user_name, [ Session ],
|
38
|
+
attach_function :session_user_name, [ Session ], UTF8String
|
39
39
|
attach_function :session_set_private_session, [ Session, :bool ], :error
|
40
40
|
attach_function :session_is_private_session, [ Session ], :bool
|
41
41
|
attach_function :session_set_scrobbling, [ Session, :social_provider, :scrobbling_state ], :error
|
42
42
|
attach_function :session_is_scrobbling, [ Session, :social_provider, :buffer_out ], :error
|
43
43
|
attach_function :session_is_scrobbling_possible, [ Session, :social_provider, :buffer_out ], :error
|
44
|
-
attach_function :session_set_social_credentials, [ Session, :social_provider, UTF8String,
|
44
|
+
attach_function :session_set_social_credentials, [ Session, :social_provider, UTF8String, UTF8String ], :error
|
45
45
|
end
|
46
46
|
end
|
@@ -15,6 +15,8 @@ module Spotify
|
|
15
15
|
#
|
16
16
|
# @api private
|
17
17
|
class ManagedPointer < FFI::AutoPointer
|
18
|
+
extend Spotify::TypeSafety
|
19
|
+
|
18
20
|
class << self
|
19
21
|
# Releases the given pointer if it is not null.
|
20
22
|
#
|
@@ -24,7 +26,7 @@ module Spotify
|
|
24
26
|
def release(pointer)
|
25
27
|
unless pointer.null?
|
26
28
|
# this is to circumvent the type protection
|
27
|
-
pointer =
|
29
|
+
pointer = type_class.new(pointer)
|
28
30
|
pointer.autorelease = false
|
29
31
|
|
30
32
|
$stderr.puts "Spotify.#{type}_release(#{pointer.inspect})" if $DEBUG
|
@@ -36,7 +38,7 @@ module Spotify
|
|
36
38
|
#
|
37
39
|
# This method derives the retain method from the class name.
|
38
40
|
#
|
39
|
-
# @param [self] pointer must be an instance of {#
|
41
|
+
# @param [self] pointer must be an instance of {#type_class}
|
40
42
|
def retain(pointer)
|
41
43
|
unless pointer.null?
|
42
44
|
$stderr.puts "Spotify.#{type}_add_ref(#{pointer.inspect})" if $DEBUG
|
@@ -49,13 +51,17 @@ module Spotify
|
|
49
51
|
def to_native(value, ctx)
|
50
52
|
if value.nil? or value.null?
|
51
53
|
raise TypeError, "#{name} pointers cannot be null, was #{value.inspect}"
|
52
|
-
elsif value.kind_of?(base_class)
|
53
|
-
super
|
54
54
|
else
|
55
|
-
|
55
|
+
super
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
|
+
# @see https://github.com/jruby/jruby/issues/607
|
60
|
+
# @return [Integer] size of the native type, defined for JRuby.
|
61
|
+
def size
|
62
|
+
FFI.type_size(:pointer)
|
63
|
+
end
|
64
|
+
|
59
65
|
# Retaining class is needed for the functions that return a pointer that
|
60
66
|
# does not have its reference count increased. This class is a subclass
|
61
67
|
# of the ManagedPointer, and should behave the same in all circumstances
|
@@ -79,7 +85,7 @@ module Spotify
|
|
79
85
|
|
80
86
|
protected
|
81
87
|
|
82
|
-
def
|
88
|
+
def type_class
|
83
89
|
superclass
|
84
90
|
end
|
85
91
|
end
|
@@ -101,13 +107,6 @@ module Spotify
|
|
101
107
|
def type
|
102
108
|
name.split('::')[-1].downcase
|
103
109
|
end
|
104
|
-
|
105
|
-
# Retrieves the base class for this pointer. This is overridden
|
106
|
-
# by the {.retaining_class}. It is used for type-checking inside
|
107
|
-
# {.to_native}.
|
108
|
-
def base_class
|
109
|
-
self
|
110
|
-
end
|
111
110
|
end
|
112
111
|
|
113
112
|
# @return [String] string representation of self.
|
data/lib/spotify/objects.rb
CHANGED
data/lib/spotify/structs.rb
CHANGED
@@ -3,6 +3,8 @@ module Spotify
|
|
3
3
|
# checking that happens in the Spotify::API namespace, and
|
4
4
|
# it also allows you to initialize structs with a hash.
|
5
5
|
class Struct < FFI::Struct
|
6
|
+
extend Spotify::TypeSafety
|
7
|
+
|
6
8
|
# This is used by FFI to do type lookups when creating the
|
7
9
|
# struct layout. By overriding this we can trick FFI into
|
8
10
|
# looking up types in the right location.
|
@@ -20,22 +20,22 @@ module Spotify
|
|
20
20
|
class SessionConfig < Spotify::Struct
|
21
21
|
it = {}
|
22
22
|
it[:api_version] = :int
|
23
|
-
it[:cache_location] =
|
24
|
-
it[:settings_location] =
|
25
|
-
it[:application_key] =
|
23
|
+
it[:cache_location] = UTF8StringPointer
|
24
|
+
it[:settings_location] = UTF8StringPointer
|
25
|
+
it[:application_key] = ByteString
|
26
26
|
it[:application_key_size] = :size_t
|
27
|
-
it[:user_agent] =
|
27
|
+
it[:user_agent] = UTF8StringPointer
|
28
28
|
it[:callbacks] = SessionCallbacks.by_ref
|
29
29
|
it[:userdata] = :userdata
|
30
30
|
it[:compress_playlists] = :bool
|
31
31
|
it[:dont_save_metadata_for_playlists] = :bool
|
32
32
|
it[:initially_unload_playlists] = :bool
|
33
|
-
it[:device_id] =
|
34
|
-
it[:proxy] =
|
35
|
-
it[:proxy_username] =
|
36
|
-
it[:proxy_password] =
|
37
|
-
it[:ca_certs_filename] =
|
38
|
-
it[:tracefile] =
|
33
|
+
it[:device_id] = UTF8StringPointer
|
34
|
+
it[:proxy] = UTF8StringPointer
|
35
|
+
it[:proxy_username] = UTF8StringPointer
|
36
|
+
it[:proxy_password] = UTF8StringPointer
|
37
|
+
it[:ca_certs_filename] = UTF8StringPointer if Spotify::API.linux?
|
38
|
+
it[:tracefile] = UTF8StringPointer
|
39
39
|
layout(it)
|
40
40
|
|
41
41
|
# Overridden for some keys for convenience.
|
@@ -49,14 +49,8 @@ module Spotify
|
|
49
49
|
def []=(key, value)
|
50
50
|
case key
|
51
51
|
when :application_key
|
52
|
-
|
53
|
-
|
54
|
-
pointer.write_string(value)
|
55
|
-
super(key, pointer)
|
56
|
-
self[:application_key_size] = pointer.size
|
57
|
-
else
|
58
|
-
super
|
59
|
-
end
|
52
|
+
super(key, value)
|
53
|
+
self[:application_key_size] = value.bytesize if value
|
60
54
|
else super
|
61
55
|
end
|
62
56
|
end
|
@@ -1,11 +1,29 @@
|
|
1
1
|
module Spotify
|
2
2
|
# Spotify::Struct for Subscribers of a Playlist.
|
3
3
|
#
|
4
|
+
# Memory looks like this:
|
5
|
+
# 00 00 00 00 <- count of subscribers
|
6
|
+
# 00 00 00 00 <- pointer to subscriber 1
|
7
|
+
# …… …… …… ……
|
8
|
+
# 00 00 00 00 <- pointer to subscriber n
|
9
|
+
#
|
4
10
|
# @attr [Fixnum] count
|
5
11
|
# @attr [Array<Pointer<String>>] subscribers
|
6
12
|
class Subscribers < Spotify::Struct
|
13
|
+
include Enumerable
|
14
|
+
|
15
|
+
class << self
|
16
|
+
def release(pointer)
|
17
|
+
unless pointer.null?
|
18
|
+
pointer = type_class.new(pointer)
|
19
|
+
$stderr.puts "Spotify.playlist_subscribers_free(#{pointer.inspect})" if $DEBUG
|
20
|
+
Spotify.playlist_subscribers_free(pointer)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
7
25
|
layout :count => :uint,
|
8
|
-
:subscribers => [
|
26
|
+
:subscribers => [UTF8StringPointer, 0] # array of pointers to strings
|
9
27
|
|
10
28
|
# Redefined, as the layout of the Struct can only be determined
|
11
29
|
# at run-time.
|
@@ -13,18 +31,43 @@ module Spotify
|
|
13
31
|
# @param [FFI::Pointer, Integer] pointer_or_count
|
14
32
|
def initialize(pointer_or_count)
|
15
33
|
count = if pointer_or_count.is_a?(FFI::Pointer)
|
16
|
-
pointer_or_count.
|
34
|
+
if pointer_or_count.null?
|
35
|
+
0
|
36
|
+
else
|
37
|
+
pointer_or_count.read_uint
|
38
|
+
end
|
17
39
|
else
|
18
40
|
pointer_or_count
|
19
41
|
end
|
20
42
|
|
21
43
|
layout = [:count, :uint]
|
22
|
-
layout += [:subscribers, [
|
44
|
+
layout += [:subscribers, [UTF8StringPointer, count]]
|
23
45
|
|
24
46
|
if pointer_or_count.is_a?(FFI::Pointer)
|
25
47
|
super(pointer_or_count, *layout)
|
26
48
|
else
|
27
49
|
super(nil, *layout)
|
50
|
+
self[:count] = count
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Yields every subscriber as a UTF8-encoded string.
|
55
|
+
#
|
56
|
+
# @yield [subscriber]
|
57
|
+
# @yieldparam [String] subscriber
|
58
|
+
def each
|
59
|
+
return enum_for(__method__) { count } unless block_given?
|
60
|
+
count.times { |index| yield self[:subscribers][index] }
|
61
|
+
end
|
62
|
+
|
63
|
+
private
|
64
|
+
|
65
|
+
# @return [Integer] number of subscribers in the struct.
|
66
|
+
def count
|
67
|
+
if null?
|
68
|
+
0
|
69
|
+
else
|
70
|
+
self[:count]
|
28
71
|
end
|
29
72
|
end
|
30
73
|
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Spotify
|
2
|
+
module TypeSafety
|
3
|
+
# Convert given value to native value, with type checking.
|
4
|
+
#
|
5
|
+
# @note Calls super-implementation if type is safe.
|
6
|
+
#
|
7
|
+
# @param value
|
8
|
+
# @param ctx
|
9
|
+
# @raise [TypeError] if value is not of the same kind as {#type_class}.
|
10
|
+
def to_native(value, ctx)
|
11
|
+
if value.kind_of?(type_class)
|
12
|
+
super
|
13
|
+
else
|
14
|
+
raise TypeError, "expected a kind of #{name}, was #{value.class}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Retrieve the type that all objects going into to_native must be of.
|
19
|
+
#
|
20
|
+
# @return self by default
|
21
|
+
def type_class
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/spotify/types.rb
CHANGED
@@ -0,0 +1,28 @@
|
|
1
|
+
module Spotify
|
2
|
+
module ByteString
|
3
|
+
extend FFI::DataConverter
|
4
|
+
native_type FFI::Type::POINTER
|
5
|
+
|
6
|
+
class << self
|
7
|
+
# Given either a String or nil, make an actual FFI::Pointer
|
8
|
+
# of that value, without an ending NULL-byte.
|
9
|
+
#
|
10
|
+
# @param [#to_str, nil] value
|
11
|
+
# @param ctx
|
12
|
+
# @return [FFI::Pointer]
|
13
|
+
def to_native(value, ctx)
|
14
|
+
value && begin
|
15
|
+
value = value.to_str
|
16
|
+
|
17
|
+
pointer = FFI::MemoryPointer.new(:char, value.bytesize)
|
18
|
+
pointer.write_string(value)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# @see NulString.reference_required?
|
23
|
+
def reference_required?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -4,7 +4,7 @@ module Spotify
|
|
4
4
|
#
|
5
5
|
# Keep in mind this implementation is unsafe to use on Rubinius
|
6
6
|
# as long as it ignores the .reference_required? indication.
|
7
|
-
module
|
7
|
+
module UTF8StringPointer
|
8
8
|
extend FFI::DataConverter
|
9
9
|
native_type FFI::Type::POINTER
|
10
10
|
|
@@ -16,7 +16,7 @@ module Spotify
|
|
16
16
|
# @param ctx
|
17
17
|
# @return [FFI::Pointer]
|
18
18
|
def to_native(value, ctx)
|
19
|
-
value && FFI::MemoryPointer.from_string(value.to_str)
|
19
|
+
value && FFI::MemoryPointer.from_string(value.to_str.encode("UTF-8"))
|
20
20
|
end
|
21
21
|
|
22
22
|
# Given a pointer, read out it’s string.
|
@@ -25,7 +25,7 @@ module Spotify
|
|
25
25
|
# @param ctx
|
26
26
|
# @return [String, nil]
|
27
27
|
def from_native(value, ctx)
|
28
|
-
value.read_string unless value.null?
|
28
|
+
value.read_string.force_encoding("UTF-8") unless value.null?
|
29
29
|
end
|
30
30
|
|
31
31
|
# Used by FFI::StructLayoutField to know if this field
|
data/lib/spotify/version.rb
CHANGED
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
# encoding: utf-8
|
2
|
-
require
|
3
|
-
require
|
4
|
-
require
|
2
|
+
require "rbgccxml"
|
3
|
+
require "rspec"
|
4
|
+
require "pry"
|
5
5
|
|
6
|
-
require
|
7
|
-
require
|
6
|
+
require "spec/support/hook_spotify"
|
7
|
+
require "spec/support/spotify_util"
|
8
8
|
|
9
9
|
# You can pregenerate new XML files through:
|
10
10
|
# gccxml spec/api-mac.h -fxml=spec/api-mac.xml
|
@@ -17,4 +17,14 @@ RSpec.configure do |config|
|
|
17
17
|
def api
|
18
18
|
Spotify::API
|
19
19
|
end
|
20
|
+
|
21
|
+
config.filter_run_excluding(engine: ->(engine) do
|
22
|
+
! Array(engine).include?(RUBY_ENGINE)
|
23
|
+
end)
|
24
|
+
|
25
|
+
config.filter_run_excluding(ruby_version: ->(requirement) do
|
26
|
+
ruby_version = Gem::Version.new(RUBY_VERSION)
|
27
|
+
required_version = Gem::Requirement.new(requirement)
|
28
|
+
! required_version.satisfied_by?(ruby_version)
|
29
|
+
end)
|
20
30
|
end
|
@@ -68,7 +68,18 @@ describe Spotify::ManagedPointer do
|
|
68
68
|
end
|
69
69
|
end
|
70
70
|
|
71
|
-
describe "
|
71
|
+
describe ".size" do
|
72
|
+
it "returns the size of a pointer" do
|
73
|
+
Spotify::ManagedPointer.size.should eq FFI.type_size(:pointer)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
# We only test this on MRI, since it does not work in quite
|
78
|
+
# the same way on JRuby nor Rubinius with regards to the GC.
|
79
|
+
#
|
80
|
+
# Luckily, if it works on MRI, we should be able to assume
|
81
|
+
# that it works on JRuby and Rubinius too.
|
82
|
+
describe "garbage collection", :engine => "ruby" do
|
72
83
|
module Spotify
|
73
84
|
class << API
|
74
85
|
def bogus_add_ref(pointer)
|
@@ -13,8 +13,8 @@ describe Spotify::SessionConfig do
|
|
13
13
|
config[:application_key].read_string(5).should eq "h\x00e\x00y"
|
14
14
|
end
|
15
15
|
|
16
|
-
it "does not
|
16
|
+
it "does not support setting application key with a pointer" do
|
17
17
|
expect { config[:application_key] = FFI::MemoryPointer.from_string("yay") }
|
18
|
-
.
|
18
|
+
.to raise_error(NoMethodError, /to_str/)
|
19
19
|
end
|
20
20
|
end
|
@@ -2,8 +2,8 @@ describe Spotify::Struct do
|
|
2
2
|
let(:klass) do
|
3
3
|
Class.new(Spotify::Struct) do
|
4
4
|
layout :api_version => :int,
|
5
|
-
:cache_location => Spotify::
|
6
|
-
:user_agent => Spotify::
|
5
|
+
:cache_location => Spotify::UTF8StringPointer,
|
6
|
+
:user_agent => Spotify::UTF8StringPointer,
|
7
7
|
:compress_playlists => :bool
|
8
8
|
end
|
9
9
|
end
|
@@ -1,31 +1,115 @@
|
|
1
1
|
describe Spotify::Subscribers do
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
2
|
+
describe "#initialize" do
|
3
|
+
context "given a null pointer" do
|
4
|
+
subject(:subscribers) do
|
5
|
+
Spotify::Subscribers.new(FFI::Pointer::NULL)
|
6
|
+
end
|
7
|
+
|
8
|
+
it "is null" do
|
9
|
+
should be_null
|
10
|
+
end
|
11
|
+
|
12
|
+
it "protects against referencing non-allocated memory" do
|
13
|
+
expect { subscribers[:count] }.to raise_error(FFI::NullPointerError)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "is empty" do
|
17
|
+
subscribers.to_a.should be_empty
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context "given an empty struct pointer" do
|
22
|
+
let(:memory) do
|
23
|
+
pointer = FFI::MemoryPointer.new(:uint)
|
24
|
+
pointer.write_uint(0)
|
25
|
+
pointer
|
26
|
+
end
|
27
|
+
|
28
|
+
subject(:subscribers) do
|
29
|
+
pointer = FFI::Pointer.new(memory.address)
|
30
|
+
Spotify::Subscribers.new(pointer)
|
31
|
+
end
|
32
|
+
|
33
|
+
specify do
|
34
|
+
subscribers[:count].should be_zero
|
35
|
+
end
|
36
|
+
|
37
|
+
it "is empty" do
|
38
|
+
subscribers.to_a.should be_empty
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
context "given a filled struct pointer" do
|
43
|
+
let(:memory) do
|
44
|
+
klass = Class.new(Spotify::Struct) do
|
45
|
+
layout count: :uint,
|
46
|
+
a: Spotify::UTF8StringPointer,
|
47
|
+
b: Spotify::UTF8StringPointer
|
48
|
+
end
|
49
|
+
|
50
|
+
klass.new.tap do |struct|
|
51
|
+
struct[:count] = 2
|
52
|
+
struct[:a] = "Alpha"
|
53
|
+
struct[:b] = "Beta"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
subject(:subscribers) do
|
58
|
+
Spotify::Subscribers.new(memory.pointer)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "has the correct count" do
|
62
|
+
subscribers[:count].should eq 2
|
63
|
+
end
|
64
|
+
|
65
|
+
it "contains the subscribers" do
|
66
|
+
subscribers[:subscribers][0].should eq "Alpha"
|
67
|
+
subscribers[:subscribers][1].should eq "Beta"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "given an integer count" do
|
72
|
+
subject(:subscribers) do
|
73
|
+
Spotify::Subscribers.new(2)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "allocates memory for a `count` sized subscribers" do
|
77
|
+
subscribers[:subscribers].size.should eq 2
|
78
|
+
end
|
79
|
+
|
80
|
+
it "assigns count to the correct count" do
|
81
|
+
subscribers[:count].should eq 2
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#[:subscribers]" do
|
87
|
+
it "raises an error when referencing a value out of bounds" do
|
88
|
+
subscribers = Spotify::Subscribers.new(2)
|
89
|
+
expect { subscribers[:subscribers][2] }.to raise_error(IndexError)
|
90
|
+
end
|
20
91
|
end
|
21
92
|
|
93
|
+
describe "#each" do
|
94
|
+
subject(:subscribers) do
|
95
|
+
Spotify::Subscribers.new(3).tap do |struct|
|
96
|
+
struct[:count] = 3
|
97
|
+
struct[:subscribers][0] = "Alpha"
|
98
|
+
struct[:subscribers][1] = "Beta"
|
99
|
+
struct[:subscribers][2] = "Gamma"
|
100
|
+
end
|
101
|
+
end
|
22
102
|
|
23
|
-
|
24
|
-
|
25
|
-
|
103
|
+
it "returns an enumerator with a defined size when not given a block", :ruby_version => ">= 2.0.0" do
|
104
|
+
enumerator = subscribers.each
|
105
|
+
enumerator.should be_a Enumerator
|
106
|
+
enumerator.size.should eq 3
|
107
|
+
end
|
26
108
|
|
27
|
-
|
28
|
-
|
29
|
-
|
109
|
+
it "yields every subscriber as an UTF-8 encoded string" do
|
110
|
+
strings = subscribers.to_a
|
111
|
+
strings.should eq %w[Alpha Beta Gamma]
|
112
|
+
strings.map(&:encoding).uniq.should eq [Encoding::UTF_8]
|
113
|
+
end
|
30
114
|
end
|
31
115
|
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
describe Spotify::TypeSafety do
|
2
|
+
let(:superklass) do
|
3
|
+
Class.new do
|
4
|
+
def self.to_native(value, ctx)
|
5
|
+
value
|
6
|
+
end
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:klass) do
|
11
|
+
Class.new(superklass) do
|
12
|
+
extend Spotify::TypeSafety
|
13
|
+
|
14
|
+
def self.type_class
|
15
|
+
self
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#to_native" do
|
21
|
+
it "calls to the superclass if value is accepted" do
|
22
|
+
value = klass.new
|
23
|
+
klass.to_native(value, nil).should eq value
|
24
|
+
end
|
25
|
+
|
26
|
+
it "raises a type error if the value is of the wrong type" do
|
27
|
+
expect { klass.to_native(Object.new, nil) }.to raise_error(TypeError, /expected a kind of/)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#type_class" do
|
32
|
+
it "defaults to the class itself" do
|
33
|
+
klass.type_class.should eq klass
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
describe Spotify::ByteString do
|
2
|
+
describe ".to_native" do
|
3
|
+
it "returns a memory pointer containing the given string, without ending NULL byte" do
|
4
|
+
pointer = Spotify::ByteString.to_native("coolio", nil)
|
5
|
+
pointer.size.should eq 6
|
6
|
+
end
|
7
|
+
|
8
|
+
it "returns nil when given nil" do
|
9
|
+
pointer = Spotify::ByteString.to_native(nil, nil)
|
10
|
+
pointer.should be_nil
|
11
|
+
end
|
12
|
+
|
13
|
+
it "raises an error when given a non-string" do
|
14
|
+
expect { Spotify::ByteString.to_native({}, nil) }
|
15
|
+
.to raise_error(NoMethodError, /to_str/)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe ".from_native" do
|
20
|
+
it "returns the value, there is no size information" do
|
21
|
+
pointer = FFI::MemoryPointer.from_string("hey")
|
22
|
+
value = Spotify::ByteString.from_native(pointer, nil)
|
23
|
+
value.should eql pointer
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
describe Spotify::UTF8StringPointer do
|
3
|
+
describe ".to_native" do
|
4
|
+
it "returns a memory pointer containing the given string" do
|
5
|
+
pointer = Spotify::UTF8StringPointer.to_native("coolio", nil)
|
6
|
+
pointer.read_string.should eq "coolio"
|
7
|
+
end
|
8
|
+
|
9
|
+
it "returns nil when given nil" do
|
10
|
+
pointer = Spotify::UTF8StringPointer.to_native(nil, nil)
|
11
|
+
pointer.should be_nil
|
12
|
+
end
|
13
|
+
|
14
|
+
it "converts strings to UTF-8" do
|
15
|
+
string = "åäö".encode("ISO-8859-1")
|
16
|
+
pointer = Spotify::UTF8StringPointer.to_native(string, nil)
|
17
|
+
|
18
|
+
string.bytesize.should eq 3
|
19
|
+
pointer.read_string.bytesize.should eq 6
|
20
|
+
end
|
21
|
+
|
22
|
+
it "raises an error when given a non-string" do
|
23
|
+
expect { Spotify::UTF8StringPointer.to_native({}, nil) }
|
24
|
+
.to raise_error(NoMethodError, /to_str/)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
describe ".from_native" do
|
29
|
+
it "returns an empty string if given a null pointer" do
|
30
|
+
value = Spotify::UTF8StringPointer.from_native(FFI::Pointer::NULL, nil)
|
31
|
+
value.should be_nil
|
32
|
+
end
|
33
|
+
|
34
|
+
it "returns the string value of the string pointer" do
|
35
|
+
pointer = FFI::MemoryPointer.from_string("hey")
|
36
|
+
value = Spotify::UTF8StringPointer.from_native(pointer, nil)
|
37
|
+
value.should eq "hey"
|
38
|
+
end
|
39
|
+
|
40
|
+
it "forces the encoding to UTF-8" do
|
41
|
+
string = FFI::MemoryPointer.from_string("åäö".encode("ISO-8859-1"))
|
42
|
+
|
43
|
+
value = Spotify::UTF8StringPointer.from_native(string, nil)
|
44
|
+
value.bytesize.should eq 3
|
45
|
+
value.encoding.should eq Encoding::UTF_8
|
46
|
+
value.should_not be_valid_encoding
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
metadata
CHANGED
@@ -1,102 +1,91 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spotify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
version: 12.4.0
|
4
|
+
version: 12.5.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Kim Burgestrand
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-04-24 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
|
-
|
14
|
+
name: ffi
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.0'
|
20
|
-
- -
|
20
|
+
- - '>='
|
21
21
|
- !ruby/object:Gem::Version
|
22
22
|
version: 1.0.11
|
23
|
-
|
23
|
+
type: :runtime
|
24
24
|
prerelease: false
|
25
|
-
|
26
|
-
requirement: !ruby/object:Gem::Requirement
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
27
26
|
requirements:
|
28
27
|
- - ~>
|
29
28
|
- !ruby/object:Gem::Version
|
30
29
|
version: '1.0'
|
31
|
-
- -
|
30
|
+
- - '>='
|
32
31
|
- !ruby/object:Gem::Version
|
33
32
|
version: 1.0.11
|
34
|
-
none: false
|
35
|
-
type: :runtime
|
36
33
|
- !ruby/object:Gem::Dependency
|
37
|
-
version_requirements: !ruby/object:Gem::Requirement
|
38
|
-
requirements:
|
39
|
-
- - ~>
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
version: 12.1.51
|
42
|
-
none: false
|
43
|
-
prerelease: false
|
44
34
|
name: libspotify
|
45
35
|
requirement: !ruby/object:Gem::Requirement
|
46
36
|
requirements:
|
47
37
|
- - ~>
|
48
38
|
- !ruby/object:Gem::Version
|
49
39
|
version: 12.1.51
|
50
|
-
none: false
|
51
40
|
type: :runtime
|
52
|
-
|
41
|
+
prerelease: false
|
53
42
|
version_requirements: !ruby/object:Gem::Requirement
|
54
43
|
requirements:
|
55
|
-
- -
|
44
|
+
- - ~>
|
56
45
|
- !ruby/object:Gem::Version
|
57
|
-
version:
|
58
|
-
|
59
|
-
prerelease: false
|
46
|
+
version: 12.1.51
|
47
|
+
- !ruby/object:Gem::Dependency
|
60
48
|
name: rake
|
61
49
|
requirement: !ruby/object:Gem::Requirement
|
62
50
|
requirements:
|
63
|
-
- -
|
51
|
+
- - '>='
|
64
52
|
- !ruby/object:Gem::Version
|
65
53
|
version: '0'
|
66
|
-
none: false
|
67
54
|
type: :development
|
68
|
-
|
55
|
+
prerelease: false
|
69
56
|
version_requirements: !ruby/object:Gem::Requirement
|
70
57
|
requirements:
|
71
|
-
- -
|
58
|
+
- - '>='
|
72
59
|
- !ruby/object:Gem::Version
|
73
60
|
version: '0'
|
74
|
-
|
75
|
-
prerelease: false
|
61
|
+
- !ruby/object:Gem::Dependency
|
76
62
|
name: rbgccxml
|
77
63
|
requirement: !ruby/object:Gem::Requirement
|
78
64
|
requirements:
|
79
|
-
- -
|
65
|
+
- - '>='
|
80
66
|
- !ruby/object:Gem::Version
|
81
67
|
version: '0'
|
82
|
-
none: false
|
83
68
|
type: :development
|
84
|
-
|
69
|
+
prerelease: false
|
85
70
|
version_requirements: !ruby/object:Gem::Requirement
|
86
71
|
requirements:
|
87
|
-
- -
|
72
|
+
- - '>='
|
88
73
|
- !ruby/object:Gem::Version
|
89
74
|
version: '0'
|
90
|
-
|
91
|
-
prerelease: false
|
75
|
+
- !ruby/object:Gem::Dependency
|
92
76
|
name: rspec
|
93
77
|
requirement: !ruby/object:Gem::Requirement
|
94
78
|
requirements:
|
95
|
-
- -
|
79
|
+
- - '>='
|
96
80
|
- !ruby/object:Gem::Version
|
97
81
|
version: '0'
|
98
|
-
none: false
|
99
82
|
type: :development
|
83
|
+
prerelease: false
|
84
|
+
version_requirements: !ruby/object:Gem::Requirement
|
85
|
+
requirements:
|
86
|
+
- - '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
100
89
|
description:
|
101
90
|
email:
|
102
91
|
- kim@burgestrand.se
|
@@ -161,10 +150,12 @@ files:
|
|
161
150
|
- lib/spotify/structs/session_callbacks.rb
|
162
151
|
- lib/spotify/structs/session_config.rb
|
163
152
|
- lib/spotify/structs/subscribers.rb
|
153
|
+
- lib/spotify/type_safety.rb
|
164
154
|
- lib/spotify/types.rb
|
155
|
+
- lib/spotify/types/byte_string.rb
|
165
156
|
- lib/spotify/types/image_id.rb
|
166
|
-
- lib/spotify/types/nul_string.rb
|
167
157
|
- lib/spotify/types/utf8_string.rb
|
158
|
+
- lib/spotify/types/utf8_string_pointer.rb
|
168
159
|
- lib/spotify/util.rb
|
169
160
|
- lib/spotify/version.rb
|
170
161
|
- spec/bench_helper.rb
|
@@ -181,8 +172,10 @@ files:
|
|
181
172
|
- spec/spotify/structs/struct_spec.rb
|
182
173
|
- spec/spotify/structs/subscribers_spec.rb
|
183
174
|
- spec/spotify/structs_spec.rb
|
175
|
+
- spec/spotify/type_safety_spec.rb
|
176
|
+
- spec/spotify/types/byte_string_spec.rb
|
184
177
|
- spec/spotify/types/image_id_spec.rb
|
185
|
-
- spec/spotify/types/
|
178
|
+
- spec/spotify/types/utf8_string_pointer_spec.rb
|
186
179
|
- spec/spotify/types/utf8_string_spec.rb
|
187
180
|
- spec/support/api-linux.h
|
188
181
|
- spec/support/api-linux.xml
|
@@ -196,30 +189,26 @@ files:
|
|
196
189
|
homepage: https://github.com/Burgestrand/spotify
|
197
190
|
licenses:
|
198
191
|
- X11 License
|
192
|
+
metadata: {}
|
199
193
|
post_install_message:
|
200
194
|
rdoc_options: []
|
201
195
|
require_paths:
|
202
196
|
- lib
|
203
197
|
required_ruby_version: !ruby/object:Gem::Requirement
|
204
198
|
requirements:
|
205
|
-
- -
|
199
|
+
- - '>='
|
206
200
|
- !ruby/object:Gem::Version
|
207
201
|
version: '1.9'
|
208
|
-
none: false
|
209
202
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
210
203
|
requirements:
|
211
|
-
- -
|
204
|
+
- - '>='
|
212
205
|
- !ruby/object:Gem::Version
|
213
206
|
version: '0'
|
214
|
-
segments:
|
215
|
-
- 0
|
216
|
-
hash: -321866255872055088
|
217
|
-
none: false
|
218
207
|
requirements: []
|
219
208
|
rubyforge_project:
|
220
|
-
rubygems_version:
|
209
|
+
rubygems_version: 2.0.3
|
221
210
|
signing_key:
|
222
|
-
specification_version:
|
211
|
+
specification_version: 4
|
223
212
|
summary: Low-level Ruby bindings for libspotify
|
224
213
|
test_files:
|
225
214
|
- spec/bench_helper.rb
|
@@ -236,8 +225,10 @@ test_files:
|
|
236
225
|
- spec/spotify/structs/struct_spec.rb
|
237
226
|
- spec/spotify/structs/subscribers_spec.rb
|
238
227
|
- spec/spotify/structs_spec.rb
|
228
|
+
- spec/spotify/type_safety_spec.rb
|
229
|
+
- spec/spotify/types/byte_string_spec.rb
|
239
230
|
- spec/spotify/types/image_id_spec.rb
|
240
|
-
- spec/spotify/types/
|
231
|
+
- spec/spotify/types/utf8_string_pointer_spec.rb
|
241
232
|
- spec/spotify/types/utf8_string_spec.rb
|
242
233
|
- spec/support/api-linux.h
|
243
234
|
- spec/support/api-linux.xml
|
@@ -1,31 +0,0 @@
|
|
1
|
-
describe Spotify::NULString do
|
2
|
-
describe ".to_native" do
|
3
|
-
it "returns a memory pointer containing the given string" do
|
4
|
-
pointer = Spotify::NULString.to_native("coolio", nil)
|
5
|
-
pointer.read_string.should eq "coolio"
|
6
|
-
end
|
7
|
-
|
8
|
-
it "returns nil when given nil" do
|
9
|
-
pointer = Spotify::NULString.to_native(nil, nil)
|
10
|
-
pointer.should be_nil
|
11
|
-
end
|
12
|
-
|
13
|
-
it "raises an error when given a non-string" do
|
14
|
-
expect { Spotify::NULString.to_native({}, nil) }
|
15
|
-
.to raise_error(NoMethodError, /to_str/)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
|
19
|
-
describe ".from_native" do
|
20
|
-
it "returns an empty string if given a null pointer" do
|
21
|
-
value = Spotify::NULString.from_native(FFI::Pointer::NULL, nil)
|
22
|
-
value.should be_nil
|
23
|
-
end
|
24
|
-
|
25
|
-
it "returns the string value of the string pointer" do
|
26
|
-
pointer = FFI::MemoryPointer.from_string("hey")
|
27
|
-
value = Spotify::NULString.from_native(pointer, nil)
|
28
|
-
value.should eq "hey"
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|