hallon 0.3.0 → 0.4.0

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