spotify 12.4.0 → 12.5.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|