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 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.7'
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):[a-zA-Z0-9]+
33
+ (?:artist|album|track|user:[^:]+:playlist):\h+
32
34
  |user:[^:]+
33
- |search:(?:[-\w$\.+!*'(),]+|%[a-fA-F0-9]{2})+
35
+ |search:(?:[-\w$\.+!*'(),]+|%\h{2})+
36
+ |image:\h{40}
34
37
  ))
35
38
  /x
36
39
  end
@@ -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
@@ -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(:image) do |link, session|
10
- Spotify::image_create_from_link(session.pointer, link)
9
+ from_link :as_image do |link, session|
10
+ Spotify::image_create_from_link(session, link)
11
11
  end
12
12
 
13
- to_link(:image)
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 hexadecimal string.
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).unpack('H*')[0]
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
- (self <=> other) == 0
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
- @pointer
97
+ super()
109
98
  end
110
99
  end
111
100
  end
@@ -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
- # These are extended onto a class when {Linkable} is included.
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
- # @example
15
- # # Creates instance method `from_link(link)`
16
- # from_link(:playlist) { |link| Spotify::link_as_playlist(link) }
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(type)
24
- define_singleton_method(:from_link) do |link, *args|
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
- yield Link.new(link).pointer(type), *args
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 `to_link` class & instance method.
44
+ # Defines `#to_link` method, which converts the the current object to a {Link}
34
45
  #
35
46
  # @example
36
- # to_link(:artist)
47
+ # to_link :from_artist # => Spotify.link_create_from_artist
37
48
  #
38
- # @note Calls down to `Spotify::link_create_from_#{type}(@pointer)`
39
- # @param [Symbol] type object kind
49
+ # @param [Symbol] cmethod object kind
40
50
  # @return [Link]
41
- def to_link(type)
42
- define_singleton_method(:to_link) do |ptr, *args|
43
- link = Spotify.__send__(:"link_create_from_#{type}", ptr, *args)
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
@@ -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(:track) { |link, ptr| Spotify.link_as_track_and_offset(link, ptr) }
11
- to_link(:track)
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
- self.class.to_link(@pointer, (offset * 1000).to_i)
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 class
16
+ # @scope instance
17
17
  # @param [String, Hallon::Link, FFI::Pointer] link
18
18
  # @return [FFI::Pointer]
19
- from_link(:profile) { |link| Spotify::link_as_user(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(:user)
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
  #
@@ -3,5 +3,5 @@ module Hallon
3
3
  # Current release version of Hallon
4
4
  #
5
5
  # @see http://semver.org/
6
- VERSION = [0, 3, 0].join('.')
6
+ VERSION = [0, 4, 0].join('.')
7
7
  end
@@ -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:track:7N2Vc8u56VGA4KUrGbikC2#1:40" => :track
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
@@ -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
- its(:id) { should eq "3ad93423add99766e02d563605c6e76ed2b0e450" }
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
- let(:image) { Hallon::Image.new("spotify:image:c78f091482e555bd2ffacfcd9cbdc0714b221663", session) }
50
- subject { image }
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
 
@@ -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
- subject.should_not eq Object.new
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
- it "should define the #from_link method" do
2
+ let(:klass) do
3
3
  klass = Class.new
4
- klass.should_not respond_to :from_link
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
- klass.should respond_to :from_link
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 given block if necessary" do
16
- called = false
17
- klass = Class.new
21
+ it "should call the appropriate Spotify function" do
22
+ Spotify.should_receive(:link_as_search)
18
23
 
19
- klass.instance_exec do
20
- extend Hallon::Linkable
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 pass extra parameters to the defining block" do
29
- klass = Class.new
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
- klass.instance_exec do
36
- extend Hallon::Linkable
37
- from_link(nil) { |link, *args| args }
38
- end
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
- klass.from_link("spotify:user:burgestrand", :cool, 5).should eq [:cool, 5]
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
@@ -1,28 +1,8 @@
1
1
  # coding: utf-8
2
2
  describe Hallon::Track, :session => true do
3
- let(:artist) { Spotify.mock_artist("Artist", true) }
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 "Elucteene" }
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
- xit("artist.name") { should eq "Artist" }
34
- xit("album.name") { should eq "Album" }
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 "Title", "Artist", "Coolio", 100
62
+ Hallon::Track.local "Nissy", "Emmy", "Coolio", 100
82
63
  end
83
64
 
84
- its(:name) { should eq "Title" }
85
- pending("artist.name") { should eq "Artist" }
86
- pending("album.name") { should eq "Album" }
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
@@ -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) do
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.3.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-25 00:00:00.000000000Z
12
+ date: 2011-07-27 00:00:00.000000000Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: spotify
16
- requirement: &2161051120 !ruby/object:Gem::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: *2161051120
24
+ version_requirements: *2156138200
25
25
  - !ruby/object:Gem::Dependency
26
26
  name: mockspotify
27
- requirement: &2161050620 !ruby/object:Gem::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.7
32
+ version: 0.1.8
33
33
  type: :development
34
34
  prerelease: false
35
- version_requirements: *2161050620
35
+ version_requirements: *2156137500
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: rake
38
- requirement: &2161050020 !ruby/object:Gem::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: *2161050020
46
+ version_requirements: *2156136740
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: rspec
49
- requirement: &2161049380 !ruby/object:Gem::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: *2161049380
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: &2161046920 !ruby/object:Gem::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: *2161046920
68
+ version_requirements: *2156135380
91
69
  - !ruby/object:Gem::Dependency
92
70
  name: rdiscount
93
- requirement: &2161044780 !ruby/object:Gem::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: *2161044780
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