hallon 0.3.0 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/CHANGELOG +11 -0
- data/hallon.gemspec +1 -3
- data/lib/hallon.rb +5 -2
- data/lib/hallon/album.rb +77 -0
- data/lib/hallon/base.rb +20 -0
- data/lib/hallon/image.rb +36 -9
- data/lib/hallon/link.rb +5 -16
- data/lib/hallon/linkable.rb +33 -27
- data/lib/hallon/session.rb +1 -6
- data/lib/hallon/track.rb +7 -10
- data/lib/hallon/user.rb +6 -7
- data/lib/hallon/version.rb +1 -1
- data/spec/fixtures/example_uris.rb +3 -2
- data/spec/hallon/album_spec.rb +44 -0
- data/spec/hallon/image_spec.rb +22 -17
- data/spec/hallon/link_spec.rb +14 -1
- data/spec/hallon/linkable_spec.rb +25 -27
- data/spec/hallon/track_spec.rb +13 -32
- data/spec/hallon/user_spec.rb +1 -10
- data/spec/support/common_objects.rb +18 -0
- metadata +21 -37
data/CHANGELOG
CHANGED
@@ -1,6 +1,17 @@
|
|
1
1
|
Hallon’s Changelog
|
2
2
|
==================
|
3
3
|
|
4
|
+
NEXT
|
5
|
+
------------------
|
6
|
+
- No longer uses autotest as development dependency
|
7
|
+
- Add Hallon::Base class
|
8
|
+
- Cleaned up specs to use same mocks everywhere
|
9
|
+
- Album subsystem support (except for #cover and #artist)
|
10
|
+
- Add optional parameter to have Image#id return raw id
|
11
|
+
- Make Hallon::URI match image URIs
|
12
|
+
- Allow Image.new to accept an image id
|
13
|
+
- Add Album#cover
|
14
|
+
|
4
15
|
v0.3.0
|
5
16
|
------------------
|
6
17
|
- Don’t use bundler for :spec and :test rake tasks
|
data/hallon.gemspec
CHANGED
@@ -19,11 +19,9 @@ Gem::Specification.new do |gem|
|
|
19
19
|
gem.required_ruby_version = '~> 1.8'
|
20
20
|
|
21
21
|
gem.add_dependency 'spotify', '~> 8.0.5'
|
22
|
-
gem.add_development_dependency 'mockspotify', '~> 0.1.
|
22
|
+
gem.add_development_dependency 'mockspotify', '~> 0.1.8'
|
23
23
|
gem.add_development_dependency 'rake', '~> 0.8'
|
24
24
|
gem.add_development_dependency 'rspec', '~> 2'
|
25
|
-
gem.add_development_dependency 'autotest-standalone'
|
26
|
-
gem.add_development_dependency 'autotest-growl'
|
27
25
|
gem.add_development_dependency 'yard'
|
28
26
|
gem.add_development_dependency 'rdiscount'
|
29
27
|
end
|
data/lib/hallon.rb
CHANGED
@@ -10,11 +10,13 @@ require 'hallon/linkable'
|
|
10
10
|
|
11
11
|
require 'hallon/version'
|
12
12
|
require 'hallon/error'
|
13
|
+
require 'hallon/base'
|
13
14
|
require 'hallon/session'
|
14
15
|
require 'hallon/link'
|
15
16
|
require 'hallon/user'
|
16
17
|
require 'hallon/image'
|
17
18
|
require 'hallon/track'
|
19
|
+
require 'hallon/album'
|
18
20
|
|
19
21
|
# The Hallon module wraps around all Hallon objects to avoid polluting
|
20
22
|
# the global namespace. To start using Hallon, you most likely want to
|
@@ -28,9 +30,10 @@ module Hallon
|
|
28
30
|
# @example
|
29
31
|
# Hallon::URI === "spotify:user:burgestrand" # => true
|
30
32
|
URI = /(spotify:(?:
|
31
|
-
(?:artist|album|track|user:[^:]+:playlist)
|
33
|
+
(?:artist|album|track|user:[^:]+:playlist):\h+
|
32
34
|
|user:[^:]+
|
33
|
-
|search:(?:[-\w$\.+!*'(),]
|
35
|
+
|search:(?:[-\w$\.+!*'(),]+|%\h{2})+
|
36
|
+
|image:\h{40}
|
34
37
|
))
|
35
38
|
/x
|
36
39
|
end
|
data/lib/hallon/album.rb
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
module Hallon
|
2
|
+
# Albums are non-detailed metadata about actual music albums.
|
3
|
+
#
|
4
|
+
# To retrieve copyrights, album review and tracks you need to browse
|
5
|
+
# the album, which is not currently supported by Hallon. You can retrieve
|
6
|
+
# the {#pointer} use the raw Spotify API on it, however.
|
7
|
+
#
|
8
|
+
# @note All metadata methods require the album to be {Album#loaded?}
|
9
|
+
#
|
10
|
+
# @see http://developer.spotify.com/en/libspotify/docs/group__album.html
|
11
|
+
class Album < Base
|
12
|
+
def self.types
|
13
|
+
Spotify.enum_type(:albumtype).to_hash
|
14
|
+
end
|
15
|
+
|
16
|
+
extend Linkable
|
17
|
+
|
18
|
+
from_link :as_album
|
19
|
+
to_link :from_album
|
20
|
+
|
21
|
+
# Construct an Album from a link.
|
22
|
+
#
|
23
|
+
# @param [String, Link, FFI::Pointer] link
|
24
|
+
def initialize(link)
|
25
|
+
@pointer = Spotify::Pointer.new from_link(link), :album, true
|
26
|
+
end
|
27
|
+
|
28
|
+
# Name of album.
|
29
|
+
#
|
30
|
+
# @return [String]
|
31
|
+
def name
|
32
|
+
Spotify.album_name(@pointer)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Release year of album.
|
36
|
+
#
|
37
|
+
# @return [Integer]
|
38
|
+
def year
|
39
|
+
Spotify.album_year(@pointer)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Retrieve album type.
|
43
|
+
#
|
44
|
+
# @return [Symbol] one of {Album.types}
|
45
|
+
def type
|
46
|
+
Spotify.album_type(@pointer)
|
47
|
+
end
|
48
|
+
|
49
|
+
# True if the album is available from the current session.
|
50
|
+
#
|
51
|
+
# @return [Boolean]
|
52
|
+
def available?
|
53
|
+
Spotify.album_is_available(@pointer)
|
54
|
+
end
|
55
|
+
|
56
|
+
# True if album has been loaded.
|
57
|
+
#
|
58
|
+
# @return [Boolean]
|
59
|
+
def loaded?
|
60
|
+
Spotify.album_is_loaded(@pointer)
|
61
|
+
end
|
62
|
+
|
63
|
+
# Retrieve album cover art.
|
64
|
+
#
|
65
|
+
# @return [Image]
|
66
|
+
def cover(session = Session.instance)
|
67
|
+
image_id = Spotify.album_cover(@pointer)
|
68
|
+
Hallon::Image.new(image_id.read_string(20), session) unless image_id.null?
|
69
|
+
end
|
70
|
+
|
71
|
+
# Not yet implemented.
|
72
|
+
def artist
|
73
|
+
return if (ptr = Spotify.album_artist(@pointer)).null?
|
74
|
+
raise NotImplementedError
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
data/lib/hallon/base.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
module Hallon
|
2
|
+
# All objects in Hallon are mere representations of Spotify objects.
|
3
|
+
# Hallon::Base covers basic functionality shared by all of these.
|
4
|
+
class Base
|
5
|
+
# Underlying FFI pointer.
|
6
|
+
#
|
7
|
+
# @return [FFI::Pointer]
|
8
|
+
attr_reader :pointer
|
9
|
+
|
10
|
+
# True if both objects represent the *same* object.
|
11
|
+
#
|
12
|
+
# @param [Object] other
|
13
|
+
# @return [Boolean]
|
14
|
+
def ==(other)
|
15
|
+
pointer == other.pointer
|
16
|
+
rescue NoMethodError
|
17
|
+
super
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/hallon/image.rb
CHANGED
@@ -3,25 +3,37 @@ module Hallon
|
|
3
3
|
# Images are JPEG images that can be linked to and saved.
|
4
4
|
#
|
5
5
|
# @see http://developer.spotify.com/en/libspotify/docs/group__image.html
|
6
|
-
class Image
|
6
|
+
class Image < Base
|
7
7
|
extend Linkable
|
8
8
|
|
9
|
-
from_link
|
10
|
-
Spotify::image_create_from_link(session
|
9
|
+
from_link :as_image do |link, session|
|
10
|
+
Spotify::image_create_from_link(session, link)
|
11
11
|
end
|
12
12
|
|
13
|
-
to_link
|
13
|
+
to_link :from_image
|
14
14
|
|
15
15
|
# Image triggers `:load` when loaded
|
16
16
|
include Hallon::Observable
|
17
17
|
|
18
18
|
# Create a new instance of an Image.
|
19
19
|
#
|
20
|
-
# @param [String, Link, FFI::Pointer] link
|
20
|
+
# @param [String, Link, FFI::Pointer] link link or image id
|
21
21
|
# @param [Hallon::Session] session
|
22
22
|
def initialize(link, session = Session.instance)
|
23
|
+
if link.is_a?(String)
|
24
|
+
link = to_id($1) if link =~ %r|image[:/](\h{40})|
|
25
|
+
|
26
|
+
FFI::MemoryPointer.new(:char, 20) do |ptr|
|
27
|
+
ptr.write_bytes link
|
28
|
+
link = Spotify.image_create(session.pointer, ptr)
|
29
|
+
end
|
30
|
+
else
|
31
|
+
link = from_link(link, session.pointer)
|
32
|
+
end
|
33
|
+
|
34
|
+
@pointer = Spotify::Pointer.new link, :image
|
35
|
+
|
23
36
|
@callback = proc { trigger(:load) }
|
24
|
-
@pointer = Spotify::Pointer.new from_link(link, session), :image
|
25
37
|
Spotify::image_add_load_callback(@pointer, @callback, nil)
|
26
38
|
|
27
39
|
# TODO: remove load_callback when @pointer is released
|
@@ -50,11 +62,13 @@ module Hallon
|
|
50
62
|
Spotify::image_format(@pointer)
|
51
63
|
end
|
52
64
|
|
53
|
-
# Retrieve image ID as a
|
65
|
+
# Retrieve image ID as a string.
|
54
66
|
#
|
67
|
+
# @param [Boolean] raw true if you want the image id as a hexadecimal string
|
55
68
|
# @return [String]
|
56
|
-
def id
|
57
|
-
Spotify::image_image_id(@pointer).read_string(20)
|
69
|
+
def id(raw = false)
|
70
|
+
id = Spotify::image_image_id(@pointer).read_string(20)
|
71
|
+
raw ? id : to_hex(id)
|
58
72
|
end
|
59
73
|
|
60
74
|
# Raw image data as a binary encoded string.
|
@@ -66,5 +80,18 @@ module Hallon
|
|
66
80
|
return data.read_bytes(size.read_size_t)
|
67
81
|
end
|
68
82
|
end
|
83
|
+
|
84
|
+
protected
|
85
|
+
# @param [String]
|
86
|
+
# @return [String]
|
87
|
+
def to_hex(id)
|
88
|
+
id.unpack('H40')[0]
|
89
|
+
end
|
90
|
+
|
91
|
+
# @param [String]
|
92
|
+
# @return [String]
|
93
|
+
def to_id(hex)
|
94
|
+
[hex].pack('H40')
|
95
|
+
end
|
69
96
|
end
|
70
97
|
end
|
data/lib/hallon/link.rb
CHANGED
@@ -3,9 +3,7 @@ module Hallon
|
|
3
3
|
# Wraps Spotify URIs in a class, giving access to methods performable on them.
|
4
4
|
#
|
5
5
|
# @see http://developer.spotify.com/en/libspotify/docs/group__link.html
|
6
|
-
class Link
|
7
|
-
include Comparable
|
8
|
-
|
6
|
+
class Link < Base
|
9
7
|
# True if the given Spotify URI is valid (parsable by libspotify).
|
10
8
|
#
|
11
9
|
# @param (see Hallon::Link#initialize)
|
@@ -71,22 +69,13 @@ module Hallon
|
|
71
69
|
"http://open.spotify.com/%s" % to_str[8..-1].gsub(':', '/')
|
72
70
|
end
|
73
71
|
|
74
|
-
# Compare this Link to another object
|
75
|
-
#
|
76
|
-
# @param [#to_str] other
|
77
|
-
# @return [Integer]
|
78
|
-
def <=>(other)
|
79
|
-
if other.respond_to?(:to_str)
|
80
|
-
to_str <=> other.to_str
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
72
|
# True if this link equals `other.to_str`
|
85
73
|
#
|
86
74
|
# @param [#to_str] other
|
87
75
|
# @return [Boolean]
|
88
76
|
def ==(other)
|
89
|
-
|
77
|
+
return super unless other.respond_to?(:to_str)
|
78
|
+
to_str == other.to_str
|
90
79
|
end
|
91
80
|
|
92
81
|
# String representation of the given Link.
|
@@ -96,7 +85,7 @@ module Hallon
|
|
96
85
|
"<#{self.class.name} #{to_str}>"
|
97
86
|
end
|
98
87
|
|
99
|
-
# Retrieve the underlying pointer.
|
88
|
+
# Retrieve the underlying pointer. Used by {Linkable}.
|
100
89
|
#
|
101
90
|
# @param [Symbol] expected_type if given, makes sure the link is of this type
|
102
91
|
# @return [FFI::Pointer]
|
@@ -105,7 +94,7 @@ module Hallon
|
|
105
94
|
unless type == expected_type
|
106
95
|
raise ArgumentError, "expected #{expected_type} link, but it is of type #{type}"
|
107
96
|
end if expected_type
|
108
|
-
|
97
|
+
super()
|
109
98
|
end
|
110
99
|
end
|
111
100
|
end
|
data/lib/hallon/linkable.rb
CHANGED
@@ -6,47 +6,53 @@ module Hallon
|
|
6
6
|
# @note Linkable is not part of Hallons’ public API.
|
7
7
|
# @private
|
8
8
|
module Linkable
|
9
|
-
#
|
10
|
-
include Forwardable
|
11
|
-
|
12
|
-
# Creates `from_link` class & instance method which’ll convert a link to a pointer
|
9
|
+
# Defines `#from_link`, used in converting a link to a pointer.
|
13
10
|
#
|
14
|
-
# @
|
15
|
-
#
|
16
|
-
#
|
11
|
+
# @overload from_link(type)
|
12
|
+
# Convert from a link using said method.
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# from_link :as_album # => Spotify.link_as_album(pointer, *args)
|
16
|
+
#
|
17
|
+
# @param [Symbol] as_object link conversion method, formatted `as_type`
|
18
|
+
#
|
19
|
+
# @overload from_link(type) { |*args| … }
|
20
|
+
# Use the given block to convert the link.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# from_link :profile do |pointer|
|
24
|
+
# Spotify.link_as_user(pointer)
|
25
|
+
# end
|
26
|
+
#
|
27
|
+
# @param [#to_s] type link type
|
28
|
+
# @yield [link, *args] called when conversion is needed from Link pointer
|
29
|
+
# @yieldparam [Hallon::Link] link
|
30
|
+
# @yieldparam *args any extra arguments given to `#from_link`
|
17
31
|
#
|
18
|
-
# @param [Symbol] type expected link type
|
19
|
-
# @yield [link, *args] called when conversion is needed from Link pointer
|
20
|
-
# @yieldparam [Hallon::Link] link
|
21
|
-
# @yieldparam *args any extra arguments given to `#from_link`
|
22
32
|
# @see Link#pointer
|
23
|
-
def from_link(
|
24
|
-
|
33
|
+
def from_link(as_object, &block)
|
34
|
+
block ||= Spotify.method(:"link_#{as_object}")
|
35
|
+
type = as_object.to_s[/^(as_)?([^_]+)/, 2].to_sym
|
36
|
+
|
37
|
+
define_method(:from_link) do |link, *args|
|
25
38
|
if link.is_a? FFI::Pointer then link else
|
26
|
-
|
39
|
+
block.call Link.new(link).pointer(type), *args
|
27
40
|
end
|
28
41
|
end
|
29
|
-
|
30
|
-
def_delegators 'self.class', :from_link
|
31
42
|
end
|
32
43
|
|
33
|
-
# Defines
|
44
|
+
# Defines `#to_link` method, which converts the the current object to a {Link}
|
34
45
|
#
|
35
46
|
# @example
|
36
|
-
# to_link
|
47
|
+
# to_link :from_artist # => Spotify.link_create_from_artist
|
37
48
|
#
|
38
|
-
# @
|
39
|
-
# @param [Symbol] type object kind
|
49
|
+
# @param [Symbol] cmethod object kind
|
40
50
|
# @return [Link]
|
41
|
-
def to_link(
|
42
|
-
|
43
|
-
link = Spotify.__send__(:"
|
51
|
+
def to_link(cmethod)
|
52
|
+
define_method(:to_link) do |*args|
|
53
|
+
link = Spotify.__send__(:"link_create_#{cmethod}", @pointer, *args)
|
44
54
|
Hallon::Link.new(link)
|
45
55
|
end
|
46
|
-
|
47
|
-
define_method(:to_link) do |*args, &block|
|
48
|
-
self.class.to_link(@pointer, *args, &block)
|
49
|
-
end
|
50
56
|
end
|
51
57
|
end
|
52
58
|
end
|
data/lib/hallon/session.rb
CHANGED
@@ -9,17 +9,12 @@ module Hallon
|
|
9
9
|
# with Spotify before using them.
|
10
10
|
#
|
11
11
|
# @see https://developer.spotify.com/en/libspotify/docs/group__session.html
|
12
|
-
class Session
|
12
|
+
class Session < Base
|
13
13
|
# The options Hallon used at {Session#initialize}.
|
14
14
|
#
|
15
15
|
# @return [Hash]
|
16
16
|
attr_reader :options
|
17
17
|
|
18
|
-
# Underlying Spotify pointer.
|
19
|
-
#
|
20
|
-
# @return [FFI::Pointer]
|
21
|
-
attr_reader :pointer
|
22
|
-
|
23
18
|
# libspotify only allows one session per process.
|
24
19
|
include Singleton
|
25
20
|
class << self
|
data/lib/hallon/track.rb
CHANGED
@@ -4,18 +4,21 @@ module Hallon
|
|
4
4
|
# are browsable entities that can also be played by streaming.
|
5
5
|
#
|
6
6
|
# @see http://developer.spotify.com/en/libspotify/docs/group__track.html
|
7
|
-
class Track
|
7
|
+
class Track < Base
|
8
8
|
extend Linkable
|
9
9
|
|
10
|
-
from_link
|
11
|
-
to_link
|
10
|
+
from_link :as_track_and_offset
|
11
|
+
to_link :from_track
|
12
12
|
|
13
|
+
# Overriden to use default parameter.
|
14
|
+
# @see #to_link
|
15
|
+
alias_method :_to_link, :to_link
|
13
16
|
# Create a Link to the current track and offset in seconds.
|
14
17
|
#
|
15
18
|
# @param [Float] offset offset into track in seconds
|
16
19
|
# @return [Hallon::Link]
|
17
20
|
def to_link(offset = offset)
|
18
|
-
|
21
|
+
_to_link (offset * 1000).to_i
|
19
22
|
end
|
20
23
|
|
21
24
|
# Offset into track in seconds this track was created with.
|
@@ -23,12 +26,6 @@ module Hallon
|
|
23
26
|
# @return [Rational]
|
24
27
|
attr_reader :offset
|
25
28
|
|
26
|
-
# Underlying Spotify pointer.
|
27
|
-
#
|
28
|
-
# @private
|
29
|
-
# @return [FFI::Pointer]
|
30
|
-
attr_reader :pointer
|
31
|
-
|
32
29
|
# Construct a new Track instance.
|
33
30
|
#
|
34
31
|
# @param [String, Link, FFI::Pointer] link
|
data/lib/hallon/user.rb
CHANGED
@@ -6,17 +6,19 @@ module Hallon
|
|
6
6
|
# status between users.
|
7
7
|
#
|
8
8
|
# @see http://developer.spotify.com/en/libspotify/docs/group__user.html
|
9
|
-
class User
|
9
|
+
class User < Base
|
10
10
|
extend Linkable
|
11
11
|
|
12
12
|
# @macro [attach] from_link
|
13
13
|
# Given a Link, get its’ underlying pointer.
|
14
14
|
#
|
15
15
|
# @method to_link
|
16
|
-
# @scope
|
16
|
+
# @scope instance
|
17
17
|
# @param [String, Hallon::Link, FFI::Pointer] link
|
18
18
|
# @return [FFI::Pointer]
|
19
|
-
from_link
|
19
|
+
from_link :profile do |link|
|
20
|
+
Spotify::link_as_user(link)
|
21
|
+
end
|
20
22
|
|
21
23
|
# @macro [attach] to_link
|
22
24
|
# Create a Link to the current object.
|
@@ -24,10 +26,7 @@ module Hallon
|
|
24
26
|
# @method to_link
|
25
27
|
# @scope instance
|
26
28
|
# @return [Hallon::Link]
|
27
|
-
to_link
|
28
|
-
|
29
|
-
# Used by {Session#relation_type?}
|
30
|
-
attr_reader :pointer
|
29
|
+
to_link :from_user
|
31
30
|
|
32
31
|
# Construct a new instance of User.
|
33
32
|
#
|
data/lib/hallon/version.rb
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
def example_uris
|
2
2
|
{
|
3
3
|
"spotify:search:omg%2bwtf%2b%ef%a3%bf%c3%9f%e2%88%82%2bbbq" => :search,
|
4
|
-
"spotify:track:3oN2Kq1h07LSSBSLYQp0Ns" => :track,
|
5
4
|
"spotify:album:6I58XCEkOnfUVsfpDehzlQ" => :album,
|
6
5
|
"spotify:artist:6MF9fzBmfXghAz953czmBC" => :artist,
|
7
6
|
"spotify:user:burgestrand:playlist:4nQnbGi4kALbME9csEqdW2" => :playlist,
|
8
7
|
"spotify:user:burgestrand" => :profile,
|
9
8
|
"spotify:user:burgestrand:starred" => :starred,
|
10
|
-
"spotify:
|
9
|
+
"spotify:image:c78f091482e555bd2ffacfcd9cbdc0714b221663" => :image,
|
10
|
+
"spotify:track:3oN2Kq1h07LSSBSLYQp0Ns" => :track,
|
11
|
+
"spotify:track:7N2Vc8u56VGA4KUrGbikC2#1:40" => :track,
|
11
12
|
}
|
12
13
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
describe Hallon::Album do
|
3
|
+
subject { Hallon::Album.new(mock_album) }
|
4
|
+
|
5
|
+
its(:name) { should eq "Finally Woken" }
|
6
|
+
its(:year) { should be 2004 }
|
7
|
+
its(:type) { should be :single }
|
8
|
+
|
9
|
+
it { should be_available }
|
10
|
+
it { should be_loaded }
|
11
|
+
|
12
|
+
describe "artist" do
|
13
|
+
it "should be nil if there is no artist" do
|
14
|
+
Spotify.should_receive(:album_artist).and_return(null_pointer)
|
15
|
+
subject.artist.should be_nil
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be an artist if it exists"
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "cover" do
|
22
|
+
before { Hallon::Session.should_receive(:instance).and_return(session) }
|
23
|
+
|
24
|
+
it "should be nil if there is no image" do
|
25
|
+
Spotify.should_receive(:album_cover).and_return(null_pointer)
|
26
|
+
subject.cover.should be_nil
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should be an image if it exists" do
|
30
|
+
FFI::MemoryPointer.new(:string, 20) do |ptr|
|
31
|
+
ptr.write_string(mock_image_id)
|
32
|
+
|
33
|
+
Spotify.should_receive(:album_cover).and_return(ptr)
|
34
|
+
subject.cover.id.should eq mock_image_hex
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe ".types" do
|
40
|
+
it "should not be an empty hash" do
|
41
|
+
Hallon::Album.types.should_not be_empty
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/hallon/image_spec.rb
CHANGED
@@ -1,29 +1,20 @@
|
|
1
1
|
# coding: utf-8
|
2
|
-
require 'ostruct'
|
3
|
-
|
4
2
|
describe Hallon::Image, :session => true do
|
5
|
-
let(:session) { OpenStruct.new(:pointer => nil) }
|
6
|
-
|
7
3
|
describe "an image instance" do
|
8
4
|
let(:image) do
|
9
5
|
Hallon::Session.should_receive(:instance).and_return session
|
10
|
-
|
11
|
-
image = Spotify.mock_image(
|
12
|
-
"3ad93423add99766e02d563605c6e76ed2b0e450".gsub(/../) { |x| x.to_i(16).chr },
|
13
|
-
:jpeg,
|
14
|
-
File.size(fixture_image_path),
|
15
|
-
File.read(fixture_image_path),
|
16
|
-
:ok
|
17
|
-
)
|
18
|
-
|
19
|
-
Hallon::Image.new(image)
|
6
|
+
Hallon::Image.new(mock_image)
|
20
7
|
end
|
21
8
|
|
22
9
|
subject { image }
|
23
10
|
|
24
11
|
its(:status) { should be :ok }
|
25
12
|
its(:format) { should be :jpeg }
|
26
|
-
|
13
|
+
|
14
|
+
describe "id" do
|
15
|
+
specify("in hex") { subject.id.should eq mock_image_hex }
|
16
|
+
specify("raw") { subject.id(true).should eq mock_image_id }
|
17
|
+
end
|
27
18
|
|
28
19
|
describe "#data" do
|
29
20
|
subject { image.data }
|
@@ -45,9 +36,23 @@ describe Hallon::Image, :session => true do
|
|
45
36
|
end
|
46
37
|
end
|
47
38
|
|
39
|
+
context "created from an url" do
|
40
|
+
subject { Hallon::Image.new("http://open.spotify.com/image/c78f091482e555bd2ffacfcd9cbdc0714b221663", session) }
|
41
|
+
its(:id) { should eq "c78f091482e555bd2ffacfcd9cbdc0714b221663" }
|
42
|
+
end
|
43
|
+
|
48
44
|
context "created from an uri" do
|
49
|
-
|
50
|
-
|
45
|
+
subject { Hallon::Image.new("spotify:image:c78f091482e555bd2ffacfcd9cbdc0714b221663", session) }
|
46
|
+
its(:id) { should eq "c78f091482e555bd2ffacfcd9cbdc0714b221663" }
|
47
|
+
end
|
48
|
+
|
49
|
+
context "created from an id" do
|
50
|
+
subject { Hallon::Image.new(mock_image_id, session) }
|
51
|
+
its(:id) { should eq mock_image_hex }
|
52
|
+
end
|
53
|
+
|
54
|
+
context "created from a link" do
|
55
|
+
subject { Hallon::Image.new(Hallon::Link.new("spotify:image:c78f091482e555bd2ffacfcd9cbdc0714b221663"), session) }
|
51
56
|
its(:id) { should eq "c78f091482e555bd2ffacfcd9cbdc0714b221663" }
|
52
57
|
end
|
53
58
|
|
data/spec/hallon/link_spec.rb
CHANGED
@@ -78,7 +78,20 @@ describe Hallon::Link do
|
|
78
78
|
end
|
79
79
|
|
80
80
|
it "should not fail when #to_str is unavailable" do
|
81
|
-
|
81
|
+
object = Object.new
|
82
|
+
object.should_not respond_to :to_str
|
83
|
+
subject.should_not eq object
|
84
|
+
end
|
85
|
+
|
86
|
+
it "should compare underlying pointers if #to_str is unavailable" do
|
87
|
+
object = Hallon::Link.new(FFI::Pointer.new(subject.pointer))
|
88
|
+
|
89
|
+
def object.respond_to?(o)
|
90
|
+
return false if o == :to_str
|
91
|
+
super
|
92
|
+
end
|
93
|
+
|
94
|
+
subject.should eq object
|
82
95
|
end
|
83
96
|
end
|
84
97
|
end
|
@@ -1,43 +1,41 @@
|
|
1
1
|
describe Hallon::Linkable do
|
2
|
-
|
2
|
+
let(:klass) do
|
3
3
|
klass = Class.new
|
4
|
-
klass.
|
5
|
-
|
6
|
-
klass.instance_exec do
|
4
|
+
klass.instance_eval do
|
7
5
|
extend Hallon::Linkable
|
8
|
-
from_link :foobar
|
9
6
|
end
|
7
|
+
klass
|
8
|
+
end
|
9
|
+
|
10
|
+
let(:object) { klass.new }
|
10
11
|
|
11
|
-
|
12
|
+
before(:each) { Spotify.stub(:link_as_search) }
|
13
|
+
|
14
|
+
it "should define the #from_link method" do
|
15
|
+
object.should_not respond_to :from_link
|
16
|
+
klass.from_link(:as_search)
|
17
|
+
object.should respond_to :from_link
|
12
18
|
end
|
13
19
|
|
14
20
|
describe "#from_link" do
|
15
|
-
it "should call the
|
16
|
-
|
17
|
-
klass = Class.new
|
21
|
+
it "should call the appropriate Spotify function" do
|
22
|
+
Spotify.should_receive(:link_as_search)
|
18
23
|
|
19
|
-
klass.
|
20
|
-
|
21
|
-
from_link(nil) { called = true }
|
22
|
-
end
|
23
|
-
|
24
|
-
klass.from_link("spotify:search:whatever")
|
25
|
-
called.should eq true
|
24
|
+
klass.from_link(:as_search)
|
25
|
+
object.from_link 'spotify:search:moo'
|
26
26
|
end
|
27
27
|
|
28
|
-
it "should
|
29
|
-
|
30
|
-
|
31
|
-
link = mock
|
32
|
-
link.stub(:pointer)
|
33
|
-
Hallon::Link.stub(:new => link)
|
28
|
+
it "should call the given block if necessary" do
|
29
|
+
Spotify.should_not_receive(:link_as_search)
|
34
30
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
31
|
+
called = false
|
32
|
+
klass.from_link(:as_search) { called = true }
|
33
|
+
expect { object.from_link 'spotify:search:whatever' }.to change { called }
|
34
|
+
end
|
39
35
|
|
40
|
-
|
36
|
+
it "should pass extra parameters to the defining block" do
|
37
|
+
klass.from_link(:search) { |link, *args| args }
|
38
|
+
object.from_link("spotify:search:burgestrand", :cool, 5).should eq [:cool, 5]
|
41
39
|
end
|
42
40
|
end
|
43
41
|
end
|
data/spec/hallon/track_spec.rb
CHANGED
@@ -1,28 +1,8 @@
|
|
1
1
|
# coding: utf-8
|
2
2
|
describe Hallon::Track, :session => true do
|
3
|
-
|
4
|
-
let(:album) { Spotify.mock_album("Album", artist, 2011, nil, :unknown, true, true) }
|
5
|
-
|
6
|
-
subject do
|
7
|
-
artists = FFI::MemoryPointer.new(:pointer)
|
8
|
-
artists.write_pointer artist
|
9
|
-
|
10
|
-
track = Spotify.mock_track(
|
11
|
-
"Elucteene", # name
|
12
|
-
1, artists, # num_artists, artists
|
13
|
-
album, # album
|
14
|
-
123_456, # duration
|
15
|
-
42, # popularity
|
16
|
-
2, 7, # disc, index
|
17
|
-
0, true # error, loaded
|
18
|
-
)
|
19
|
-
|
20
|
-
artists.free
|
21
|
-
|
22
|
-
Hallon::Track.new(track)
|
23
|
-
end
|
3
|
+
subject { Hallon::Track.new(mock_track) }
|
24
4
|
|
25
|
-
its(:name) { should eq "
|
5
|
+
its(:name) { should eq "They" }
|
26
6
|
its(:disc) { should be 2 }
|
27
7
|
its(:index) { should be 7 }
|
28
8
|
its(:status) { should be :ok }
|
@@ -30,34 +10,35 @@ describe Hallon::Track, :session => true do
|
|
30
10
|
its(:duration) { should eq 123.456 }
|
31
11
|
its(:popularity) { should eq 0.42 }
|
32
12
|
|
33
|
-
|
34
|
-
|
13
|
+
its("album.name") { should eq "Finally Woken" }
|
14
|
+
pending("artist.name") { should eq "Jem" }
|
35
15
|
|
36
16
|
it { should be_loaded }
|
37
17
|
|
38
18
|
describe "album" do
|
39
19
|
it "should be an album when there is one" do
|
40
|
-
|
20
|
+
subject.album.should eq Hallon::Album.new(mock_album)
|
41
21
|
end
|
42
22
|
|
43
23
|
it "should be nil when there isn’t one" do
|
44
24
|
Spotify.should_receive(:track_album).and_return(FFI::Pointer.new(0))
|
45
|
-
|
46
25
|
subject.album.should be_nil
|
47
26
|
end
|
48
27
|
end
|
49
28
|
|
50
29
|
describe "to_link" do
|
30
|
+
before(:each) { Hallon::Link.stub(:new) }
|
31
|
+
|
51
32
|
it "should pass the current offset by default" do
|
33
|
+
Spotify.should_receive(:link_create_from_track).with(subject.pointer, 10_000)
|
52
34
|
subject.should_receive(:offset).and_return(10)
|
53
|
-
described_class.should_receive(:to_link).with(subject.pointer, 10_000)
|
54
35
|
|
55
36
|
subject.to_link
|
56
37
|
end
|
57
38
|
|
58
39
|
it "should accept offset as parameter" do
|
40
|
+
Spotify.should_receive(:link_create_from_track).with(subject.pointer, 1_337_000)
|
59
41
|
subject.should_not_receive(:offset)
|
60
|
-
described_class.should_receive(:to_link).with(subject.pointer, 1_337_000)
|
61
42
|
|
62
43
|
subject.to_link(1337)
|
63
44
|
end
|
@@ -78,12 +59,12 @@ describe Hallon::Track, :session => true do
|
|
78
59
|
|
79
60
|
describe "a local track" do
|
80
61
|
subject do
|
81
|
-
Hallon::Track.local "
|
62
|
+
Hallon::Track.local "Nissy", "Emmy", "Coolio", 100
|
82
63
|
end
|
83
64
|
|
84
|
-
its(:name) { should eq "
|
85
|
-
|
86
|
-
pending("
|
65
|
+
its(:name) { should eq "Nissy" }
|
66
|
+
its("album.name") { should eq "Coolio" }
|
67
|
+
pending("artist.name") { should eq "Emmy" }
|
87
68
|
its(:duration) { should eq 0.1 }
|
88
69
|
end
|
89
70
|
end
|
data/spec/hallon/user_spec.rb
CHANGED
@@ -28,16 +28,7 @@ describe Hallon::User do
|
|
28
28
|
end
|
29
29
|
|
30
30
|
describe "an instance", :logged_in => true do
|
31
|
-
let(:user)
|
32
|
-
user = Spotify.mock_user(
|
33
|
-
"burgestrand", "Burgestrand", "Kim Burgestrand",
|
34
|
-
"https://secure.gravatar.com/avatar/b67b73b5b1fd84119ec788b1c3df02ad",
|
35
|
-
:none, true
|
36
|
-
)
|
37
|
-
Hallon::User.new(user)
|
38
|
-
end
|
39
|
-
|
40
|
-
subject { user }
|
31
|
+
let(:user) { Hallon::User.new(mock_user) }
|
41
32
|
|
42
33
|
describe "#to_link" do
|
43
34
|
it "should return a Link for this user" do
|
@@ -0,0 +1,18 @@
|
|
1
|
+
RSpec::Core::ExampleGroup.instance_eval do
|
2
|
+
let(:mock_artist) { Spotify.mock_artist("Jem", true) }
|
3
|
+
let(:mock_album) { Spotify.mock_album("Finally Woken", mock_artist, 2004, "DEADBEEFDEADBEEFDEAD", :single, true, true) }
|
4
|
+
let(:mock_user) { Spotify.mock_user("burgestrand", "Burgestrand", "Kim Burgestrand", "https://secure.gravatar.com/avatar/b67b73b5b1fd84119ec788b1c3df02ad", :none, true) }
|
5
|
+
let(:mock_image) { Spotify.mock_image(mock_image_id, :jpeg, File.size(fixture_image_path), File.read(fixture_image_path), :ok) }
|
6
|
+
let(:mock_track) do
|
7
|
+
track = nil
|
8
|
+
FFI::MemoryPointer.new(:pointer) do |ary|
|
9
|
+
ary.write_pointer mock_artist
|
10
|
+
track = Spotify.mock_track("They", 1, ary, mock_album, 123_456, 42, 2, 7, 0, true)
|
11
|
+
end
|
12
|
+
track
|
13
|
+
end
|
14
|
+
|
15
|
+
let(:mock_image_hex) { "3ad93423add99766e02d563605c6e76ed2b0e450" }
|
16
|
+
let(:mock_image_id) { ":\xD94#\xAD\xD9\x97f\xE0-V6\x05\xC6\xE7n\xD2\xB0\xE4P" }
|
17
|
+
let(:null_pointer) { FFI::Pointer.new(0) }
|
18
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hallon
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-07-
|
12
|
+
date: 2011-07-27 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: spotify
|
16
|
-
requirement: &
|
16
|
+
requirement: &2156138200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
@@ -21,21 +21,21 @@ dependencies:
|
|
21
21
|
version: 8.0.5
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2156138200
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: mockspotify
|
27
|
-
requirement: &
|
27
|
+
requirement: &2156137500 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: 0.1.
|
32
|
+
version: 0.1.8
|
33
33
|
type: :development
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2156137500
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: rake
|
38
|
-
requirement: &
|
38
|
+
requirement: &2156136740 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0.8'
|
44
44
|
type: :development
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2156136740
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: rspec
|
49
|
-
requirement: &
|
49
|
+
requirement: &2156136060 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,32 +54,10 @@ dependencies:
|
|
54
54
|
version: '2'
|
55
55
|
type: :development
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
58
|
-
- !ruby/object:Gem::Dependency
|
59
|
-
name: autotest-standalone
|
60
|
-
requirement: &2161048660 !ruby/object:Gem::Requirement
|
61
|
-
none: false
|
62
|
-
requirements:
|
63
|
-
- - ! '>='
|
64
|
-
- !ruby/object:Gem::Version
|
65
|
-
version: '0'
|
66
|
-
type: :development
|
67
|
-
prerelease: false
|
68
|
-
version_requirements: *2161048660
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: autotest-growl
|
71
|
-
requirement: &2161047680 !ruby/object:Gem::Requirement
|
72
|
-
none: false
|
73
|
-
requirements:
|
74
|
-
- - ! '>='
|
75
|
-
- !ruby/object:Gem::Version
|
76
|
-
version: '0'
|
77
|
-
type: :development
|
78
|
-
prerelease: false
|
79
|
-
version_requirements: *2161047680
|
57
|
+
version_requirements: *2156136060
|
80
58
|
- !ruby/object:Gem::Dependency
|
81
59
|
name: yard
|
82
|
-
requirement: &
|
60
|
+
requirement: &2156135380 !ruby/object:Gem::Requirement
|
83
61
|
none: false
|
84
62
|
requirements:
|
85
63
|
- - ! '>='
|
@@ -87,10 +65,10 @@ dependencies:
|
|
87
65
|
version: '0'
|
88
66
|
type: :development
|
89
67
|
prerelease: false
|
90
|
-
version_requirements: *
|
68
|
+
version_requirements: *2156135380
|
91
69
|
- !ruby/object:Gem::Dependency
|
92
70
|
name: rdiscount
|
93
|
-
requirement: &
|
71
|
+
requirement: &2156134600 !ruby/object:Gem::Requirement
|
94
72
|
none: false
|
95
73
|
requirements:
|
96
74
|
- - ! '>='
|
@@ -98,7 +76,7 @@ dependencies:
|
|
98
76
|
version: '0'
|
99
77
|
type: :development
|
100
78
|
prerelease: false
|
101
|
-
version_requirements: *
|
79
|
+
version_requirements: *2156134600
|
102
80
|
description:
|
103
81
|
email: kim@burgestrand.se
|
104
82
|
executables: []
|
@@ -121,6 +99,8 @@ files:
|
|
121
99
|
- examples/printing_link_information.rb
|
122
100
|
- hallon.gemspec
|
123
101
|
- lib/hallon.rb
|
102
|
+
- lib/hallon/album.rb
|
103
|
+
- lib/hallon/base.rb
|
124
104
|
- lib/hallon/error.rb
|
125
105
|
- lib/hallon/ext/ffi.rb
|
126
106
|
- lib/hallon/ext/object.rb
|
@@ -136,6 +116,7 @@ files:
|
|
136
116
|
- lib/hallon/version.rb
|
137
117
|
- spec/fixtures/example_uris.rb
|
138
118
|
- spec/fixtures/pink_cover.jpg
|
119
|
+
- spec/hallon/album_spec.rb
|
139
120
|
- spec/hallon/error_spec.rb
|
140
121
|
- spec/hallon/ffi_spec.rb
|
141
122
|
- spec/hallon/hallon_spec.rb
|
@@ -149,6 +130,7 @@ files:
|
|
149
130
|
- spec/hallon/user_spec.rb
|
150
131
|
- spec/spec_helper.rb
|
151
132
|
- spec/support/.gitkeep
|
133
|
+
- spec/support/common_objects.rb
|
152
134
|
- spec/support/context_logged_in.rb
|
153
135
|
- spec/support/cover_me.rb
|
154
136
|
- spec/support/shared_for_loadable_objects.rb
|
@@ -180,6 +162,7 @@ summary: Delicious Ruby bindings to the official Spotify API
|
|
180
162
|
test_files:
|
181
163
|
- spec/fixtures/example_uris.rb
|
182
164
|
- spec/fixtures/pink_cover.jpg
|
165
|
+
- spec/hallon/album_spec.rb
|
183
166
|
- spec/hallon/error_spec.rb
|
184
167
|
- spec/hallon/ffi_spec.rb
|
185
168
|
- spec/hallon/hallon_spec.rb
|
@@ -193,6 +176,7 @@ test_files:
|
|
193
176
|
- spec/hallon/user_spec.rb
|
194
177
|
- spec/spec_helper.rb
|
195
178
|
- spec/support/.gitkeep
|
179
|
+
- spec/support/common_objects.rb
|
196
180
|
- spec/support/context_logged_in.rb
|
197
181
|
- spec/support/cover_me.rb
|
198
182
|
- spec/support/shared_for_loadable_objects.rb
|