hallon 0.8.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/.travis.yml +2 -0
  2. data/CHANGELOG +43 -0
  3. data/Gemfile +2 -0
  4. data/README.markdown +21 -13
  5. data/Rakefile +84 -23
  6. data/dev/login.rb +16 -0
  7. data/examples/adding_tracks_to_playlist.rb +49 -0
  8. data/examples/logging_in.rb +1 -6
  9. data/examples/show_published_playlists_of_user.rb +9 -19
  10. data/hallon.gemspec +1 -1
  11. data/lib/hallon.rb +3 -2
  12. data/lib/hallon/album.rb +55 -41
  13. data/lib/hallon/album_browse.rb +41 -37
  14. data/lib/hallon/artist.rb +30 -21
  15. data/lib/hallon/artist_browse.rb +59 -41
  16. data/lib/hallon/base.rb +68 -5
  17. data/lib/hallon/enumerator.rb +1 -0
  18. data/lib/hallon/error.rb +3 -0
  19. data/lib/hallon/ext/spotify.rb +169 -36
  20. data/lib/hallon/image.rb +30 -44
  21. data/lib/hallon/link.rb +29 -43
  22. data/lib/hallon/linkable.rb +68 -20
  23. data/lib/hallon/observable.rb +0 -1
  24. data/lib/hallon/player.rb +21 -7
  25. data/lib/hallon/playlist.rb +291 -0
  26. data/lib/hallon/playlist_container.rb +27 -0
  27. data/lib/hallon/search.rb +52 -45
  28. data/lib/hallon/session.rb +129 -81
  29. data/lib/hallon/toplist.rb +37 -19
  30. data/lib/hallon/track.rb +68 -45
  31. data/lib/hallon/user.rb +69 -33
  32. data/lib/hallon/version.rb +1 -1
  33. data/spec/hallon/album_browse_spec.rb +15 -9
  34. data/spec/hallon/album_spec.rb +15 -15
  35. data/spec/hallon/artist_browse_spec.rb +28 -9
  36. data/spec/hallon/artist_spec.rb +30 -14
  37. data/spec/hallon/enumerator_spec.rb +0 -1
  38. data/spec/hallon/hallon_spec.rb +20 -1
  39. data/spec/hallon/image_spec.rb +18 -41
  40. data/spec/hallon/link_spec.rb +10 -12
  41. data/spec/hallon/linkable_spec.rb +37 -18
  42. data/spec/hallon/player_spec.rb +8 -0
  43. data/spec/hallon/playlist_container_spec.rb +75 -0
  44. data/spec/hallon/playlist_spec.rb +204 -0
  45. data/spec/hallon/search_spec.rb +19 -16
  46. data/spec/hallon/session_spec.rb +61 -29
  47. data/spec/hallon/spotify_spec.rb +30 -0
  48. data/spec/hallon/toplist_spec.rb +22 -14
  49. data/spec/hallon/track_spec.rb +62 -21
  50. data/spec/hallon/user_spec.rb +47 -36
  51. data/spec/mockspotify.rb +35 -10
  52. data/spec/mockspotify/mockspotify_spec.rb +22 -0
  53. data/spec/spec_helper.rb +7 -3
  54. data/spec/support/common_objects.rb +91 -16
  55. data/spec/support/shared_for_linkable_objects.rb +39 -0
  56. metadata +30 -20
  57. data/Termfile +0 -7
  58. data/lib/hallon/synchronizable.rb +0 -32
  59. data/spec/hallon/synchronizable_spec.rb +0 -19
data/.travis.yml CHANGED
@@ -1,2 +1,4 @@
1
1
  rvm:
2
2
  - 1.9.2
3
+ - 1.9.3
4
+
data/CHANGELOG CHANGED
@@ -1,6 +1,49 @@
1
1
  Hallon’s Changelog
2
2
  ==================
3
3
 
4
+ v0.9.0
5
+ ------------------
6
+ - Upgraded to libspotify *v10*
7
+ - Improve documentation consistency
8
+ - Link.new now raises an error if there’s no session
9
+ - Minimal PlaylistContainer support (more to come next version)
10
+
11
+ [ Added ]
12
+ - Playlist subsystem support
13
+ - Toplist#request_duration
14
+ - AlbumBrowse#request_duration
15
+ - ArtistBrowse#request_duration
16
+ - ArtistBrowse.types
17
+ - Player#volume_normalization(?|=)
18
+ - Session.new accepting device_id/tracefile options
19
+ - Session#login!/relogin!/logout! convenience methods
20
+ - Session#starred: starred playlist for currently logged in user
21
+ - Session#inbox: inbox for currently logged in user
22
+ - Session.instance?
23
+ - Image.new(image_id_in_hex) support
24
+ - Link#to_uri
25
+ - User.new(canonical_username)
26
+ - User#post: posting tracks to other users’ inboxes
27
+ - User#starred: starred playlist of a given user
28
+ - Track#placeholder?
29
+ - Track#offline_status
30
+ - Track#unwrap
31
+ - type parameter to Artist#browse
32
+
33
+ [ Fixed ]
34
+ - Moved from using FFI::Pointers to Spotify::Pointers
35
+ - Spotify::Pointer garbage collection
36
+ - Link#valid? using exceptions for flow control
37
+ - Session#connection_rules= now raises an error when given invalid rule
38
+ - Search.radio now raises an error when given invalid genres
39
+
40
+ [ Changed ]
41
+ - Playlist::Track#seen= removed in favor of Playlist#seen(index, yesno)
42
+ - Object#error -> Object#status (AlbumBrowse, ArtistBrowse, Search, Toplist, User)
43
+ - Album#year renamed to Album#release_year
44
+ - Linkable.from_link/to_link and resulting #from_link are now private
45
+
46
+
4
47
  v0.8.0
5
48
  ------------------
6
49
  [ Added ]
data/Gemfile CHANGED
@@ -1,4 +1,6 @@
1
1
  source :rubygems
2
2
  gemspec
3
3
 
4
+ gem 'ruby_parser'
5
+ gem 'pry'
4
6
  gem 'cover_me', :platform => :ruby_19
data/README.markdown CHANGED
@@ -1,4 +1,4 @@
1
- [What is Hallon?][] [![Build Status][]](http://travis-ci.org/Burgestrand/Hallon) ([but that’s okay](https://github.com/Burgestrand/Hallon/issues/33))
1
+ [What is Hallon?][] [![Build Status][]](http://travis-ci.org/Burgestrand/Hallon)
2
2
  ===============
3
3
 
4
4
  We rubyists have this awesome [spotify gem][] allowing us to use [libspotify][] from within Ruby, but it has a significant drawback: the `libspotify` API is very hard to use. Now, we can’t have that, so what do we do? We make Hallon!
@@ -8,12 +8,22 @@ Hallon is Swedish for “Raspberry”, and has been written to satisfy my needs
8
8
  Hallon would not have been possible if not for these people:
9
9
 
10
10
  - Per Reimers, cracking synchronization bugs with me in the deep night (4 AM) and correcting me when I didn’t know better
11
- - [Spotify](http://www.spotify.com/), providing a service worth attention (and my money!)
12
- - [Linus Oleander](https://github.com/oleander), involving me with the [radiofy.se](http://radiofy.se) project, ultimately spawning the necessity of Hallon
13
- - [Jesper Särnesjö][], creator of [Greenstripes][], making me think of Hallon as an achievable goal
11
+ - [Spotify][], providing a service worth attention (and my money!)
12
+ - [Linus Oleander][], spawning the need for Hallon by having me in the [radiofy.se](http://radiofy.se) project
13
+
14
+ Also, these people are worthy of mention simply for their contribution:
15
+
16
+ - [Jesper Särnesjö][], unknowingly providing me a starting point with [Greenstripes][]
17
+ - Emil “@mrevilme” Palm, for his patience in helping me debug Hallon deadlock issues
14
18
 
15
19
  Code samples can be found under `examples/` directory.
16
20
 
21
+ You have any questions?
22
+ -----------------------
23
+ If you need to discuss issues or feature requests you can use [Hallons issue tracker](http://github.com/Burgestrand/Hallon/issues). For *anything* else you have to say or ask I can also be reached via [email (found on GitHub profile)](http://github.com/Burgestrand) or [@burgestrand on twitter](http://twitter.com/Burgestrand).
24
+
25
+ In fact, you can contact me via email or twitter even if it’s about features or issues. I’ll probably put them in the issue tracker myself after the discussion ;)
26
+
17
27
  This is awesome! I want to help!
18
28
  --------------------------------
19
29
  Sweet! You contribute in more than one way!
@@ -24,15 +34,8 @@ Sweet! You contribute in more than one way!
24
34
  ### [Send me feedback and requests](http://github.com/Burgestrand/Hallon/issues)
25
35
  Really, I ❤ feedback! Suggestions on how to improve the API, tell me what is delicious about Hallon, tell me what is yucky about Hallon… anything! All feedback is useful in one way or another.
26
36
 
27
- You have any questions?
28
- -----------------------
29
- If you need to discuss issues or feature requests you can use [Hallons issue tracker](http://github.com/Burgestrand/Hallon/issues). For *anything* else you have to say or ask I can also be reached via [email (found on GitHub profile)](http://github.com/Burgestrand) or [@burgestrand on twitter](http://twitter.com/Burgestrand).
30
-
31
- In fact, you can contact me via email or twitter even if it’s about features or issues. I’ll probably put them in the issue tracker myself after the discussion ;)
32
-
33
- What’s the catch?
34
- -----------------
35
- There are several!
37
+ Finally, here’s some important notes
38
+ ------------------------------------
36
39
 
37
40
  ### Hallon is unstable
38
41
  The API is unstable, my code is likely unstable. Everything should be considered unstable!
@@ -43,6 +46,9 @@ You can only keep one session with Spotify alive at a time in the same process,
43
46
  ### You still have to worry about threads
44
47
  I have been doing my best at hiding the complexity in `libspotify`, but it’s still a work in progress. Despite my efforts, you’ll need to be familiar with concurrent programming to use Hallon properly.
45
48
 
49
+ ### When forking, you need to be extra careful
50
+ If you fork, you need to instantiate the session in the process you plan to use Hallon in. You want to use Hallon in the parent? Create the session in the parent. You want to use it in the child? Create the session in the child! This is a limitation of libspotify itself.
51
+
46
52
  Versioning policy
47
53
  -----------------
48
54
  Hallon uses [semantic versioning](http://semver.org) as of v0.0.0. As long
@@ -57,5 +63,7 @@ Hallon is licensed under a 2-clause (Simplified) BSD license. More information c
57
63
  [libspotify]: http://developer.spotify.com/en/libspotify/overview/
58
64
  [Greenstripes]: http://github.com/sarnesjo/greenstripes
59
65
  [Jesper Särnesjö]: http://jesper.sarnesjo.org/
66
+ [Linus Oleander]: https://github.com/oleander
67
+ [Spotify]: http://spotify.com/
60
68
  [What is Hallon?]: http://burgestrand.se/articles/hallon-delicious-ruby-bindings-to-libspotify.html
61
69
  [Build Status]: https://secure.travis-ci.org/Burgestrand/Hallon.png
data/Rakefile CHANGED
@@ -9,12 +9,12 @@ YARD::Rake::YardocTask.new
9
9
 
10
10
  require 'rspec/core/rake_task'
11
11
  RSpec::Core::RakeTask.new('spec') do |task|
12
- task.skip_bundler = true
13
12
  task.ruby_opts = '-W2'
14
13
  end
15
14
 
16
15
  desc "Run the full test suite and generate a coverage report"
17
16
  task 'spec:cov' => ['clean', 'spec'] do
17
+ require 'bundler/setup'
18
18
  require 'cover_me'
19
19
  require './spec/support/cover_me'
20
20
 
@@ -24,6 +24,8 @@ end
24
24
 
25
25
  desc "Process the Hallon codebase, finding out which Spotify methods are being used"
26
26
  task 'spotify:coverage' do
27
+ require 'bundler/setup'
28
+
27
29
  require 'set'
28
30
  require 'spotify'
29
31
 
@@ -34,18 +36,39 @@ task 'spotify:coverage' do
34
36
  abort
35
37
  end
36
38
 
39
+ # Wrapped functions return pointers that are auto-GC’d by Ruby,
40
+ # so we ignore add_ref and release for these methods; but since
41
+ # we don’t know their type by mere name, we must resort to this
42
+ # hack to do it automatically (because we can).
43
+ class << Spotify
44
+ def lookup_return_value(name)
45
+ @function_to_return_type[name.to_s]
46
+ end
47
+
48
+ def define_singleton_method(name, &block)
49
+ return_type = block.binding.eval("return_type")
50
+ @function_to_return_type ||= {}
51
+ @function_to_return_type[name.to_s] = return_type
52
+
53
+ super
54
+ end
55
+ end
56
+ require 'hallon/ext/spotify'
57
+
37
58
  methods = Spotify.methods(false).map(&:to_s)
59
+ auto_gc = Set.new(methods.grep(/!\z/))
38
60
  covered = Set.new(methods)
61
+ warning = []
39
62
  ignored = [
40
63
  'session_release', # segfaults on libspotify <= 9
41
64
  'session_userdata', # wont support this
42
65
  'link_as_track', # using link_as_track_and_offset instead
43
- 'toplistbrowse_add_ref', # toplistbrowse creates its’ own pointer
44
- 'artistbrowse_add_ref', # artistbrowse creates its’ own pointer
45
- 'albumbrowse_add_ref', # albumbrowse creates its’ own pointer
46
- 'link_add_ref', # all creation of links has +1 ref
47
- 'image_add_ref', # all creation of image has +1 ref
48
- 'search_add_ref', # search creates its’ own pointer
66
+ 'link_as_track!', # using link_as_track_and_offset! instead
67
+ 'wrap_function', # not a spotify function
68
+ 'lookup_return_value', # custom method
69
+ 'define_singleton_method', # overloaded by us
70
+ 'image_remove_load_callback', # cleared when Image is GCd
71
+ 'playlist_remove_callbacks', # cleared when Playlist is GCd
49
72
  ]
50
73
 
51
74
  covered -= ignored
@@ -56,28 +79,43 @@ task 'spotify:coverage' do
56
79
  handlers = Hash.new(Hash.new(silencer))
57
80
 
58
81
  # Direct calls
59
- handlers[Sexp.new(:const, :Spotify)] = Hash.new(proc { |_, meth, _| meth })
60
-
61
- # Spotify Pointer
62
- pointer = handlers[Sexp.new(:colon2, [:const, :Spotify], :Pointer)] = Hash.new(printer)
63
- pointer[:new] = proc do |recv, meth, (_, ptr, name, release)|
64
- name = name.value
65
- release &&= release.value != :false
66
- ["#{name}_release", "#{name if release}_add_ref"]
67
- end
82
+ handlers[Sexp.new(:const, :Spotify)] = Hash.new(proc do |_, meth, _|
83
+ if auto_gc.include?("#{meth}!")
84
+ warning << meth
85
+ end
86
+
87
+ result = [meth]
88
+
89
+ # if it’s auto-GC’d, we can also account for _release and _add_ref
90
+ if meth =~ /(.+)!\z/
91
+ return_type = Spotify.lookup_return_value(meth)
92
+
93
+ result << $1
94
+ result << "#{return_type}_release"
95
+ result << "#{return_type}_add_ref"
96
+ end
97
+
98
+ result
99
+ end)
68
100
 
69
101
  # DSL Methods
70
102
  no_receiver = handlers[nil] = Hash.new(silencer)
71
103
  no_receiver[:from_link] = no_receiver[:to_link] = proc do |recv, meth, (_, name)|
72
104
  prefix = meth == :to_link ? "link_create" : "link"
73
- "%s_%s" % [prefix, name.value]
105
+ method = "%s_%s" % [prefix, name.value]
106
+ [method, "#{method}!"]
74
107
  end
75
108
 
109
+ fails = {}
76
110
  FileList['lib/**/*.rb'].each do |file|
77
- ast = RubyParser.new.parse File.read(file)
78
- ast.each_of_type(:call) do |_, recv, meth, args, *rest|
79
- name = handlers[recv][meth].call(recv, meth, args)
80
- covered.subtract Array(name).map(&:to_s)
111
+ begin
112
+ ast = RubyParser.new.parse File.read(file)
113
+ ast.each_of_type(:call) do |_, recv, meth, args, *rest|
114
+ name = handlers[recv][meth].call(recv, meth, args)
115
+ covered.subtract Array(name).map(&:to_s)
116
+ end
117
+ rescue => e
118
+ fails[file] = e.message.strip + " (#{e.class.name})"
81
119
  end
82
120
  end
83
121
 
@@ -91,15 +129,38 @@ task 'spotify:coverage' do
91
129
 
92
130
  puts "Ignored:"
93
131
  ignored.each_slice(3) do |slice|
94
- puts "\t#{slice.join(', ')}"
132
+ puts " #{slice.join(', ')}"
95
133
  end
96
134
  puts
97
135
 
136
+ unless fails.empty?
137
+ puts "Failures:"
138
+ fails.each_pair do |file, fail|
139
+ puts " #{file}: #{fail}"
140
+ end
141
+ puts
142
+ end
143
+
144
+ unless warning.empty?
145
+ puts "Warnings (use auto-gc methods instead!):"
146
+ warning.each do |method|
147
+ puts " #{method}"
148
+ end
149
+ puts
150
+ end
151
+
98
152
  puts "Coverage: %.02f%%" % (100 * (1 - covered.size.fdiv(methods.size)))
99
153
  end
100
154
 
155
+ desc "Download mockspotify submodule"
156
+ task 'mock:fetch' do
157
+ unless File.exists?('./spec/mockspotify/libmockspotify/src/libmockspotify.h')
158
+ sh 'git submodule update --init'
159
+ end
160
+ end
161
+
101
162
  desc "Compile mockspotify"
102
- task 'mock:compile' do
163
+ task 'mock:compile' => 'mock:fetch' do
103
164
  Dir.chdir 'spec/mockspotify' do
104
165
  sh 'ruby extconf.rb'
105
166
  sh 'make'
data/dev/login.rb ADDED
@@ -0,0 +1,16 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require File.expand_path('../../spec/support/config', __FILE__)
3
+
4
+ require 'bundler/setup'
5
+ require 'hallon'
6
+ require 'pry'
7
+
8
+ session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
9
+ on(:log_message) do |message|
10
+ puts "[LOG] #{message}"
11
+ end
12
+ end
13
+
14
+ session.login! ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
15
+
16
+ binding.pry
@@ -0,0 +1,49 @@
1
+ # coding: utf-8
2
+ require 'hallon'
3
+ require './spec/support/config'
4
+
5
+ ##
6
+ # Configuration
7
+ #
8
+ # uri to the playlist you wish to add tracks to
9
+ playlist_uri = "spotify:user:burgestrand:playlist:07AX9IY9Hqmj1RqltcG0fi"
10
+
11
+ # array of track uris you wish to add to the playlist
12
+ track_uris = %w[spotify:track:6GHrP1i3vQo1e8VkEHRnvz spotify:track:2t7u74OJXHf0qQxXHpnb2R spotify:track:24q7a0Bo5MFLJUslg1lsS5]
13
+
14
+ # index to add the tracks to in the playlist
15
+ position = 0
16
+
17
+ session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
18
+ on(:log_message) do |message|
19
+ puts "[LOG] #{message}"
20
+ end
21
+ end
22
+
23
+ session.login!(ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD'])
24
+ puts "Successfully logged in!"
25
+
26
+ # First, we load the playlist. This is necessary for libspotify
27
+ # to know if we have write access to it or not. Not doing it might
28
+ # end us up getting permission denied errors later.
29
+ puts "Loading playlist #{playlist_uri}"
30
+ playlist = Hallon::Playlist.new(playlist_uri)
31
+ session.wait_for { playlist.loaded? }
32
+
33
+ # Convert all track URIs to actual Tracks.
34
+ puts "Loading #{track_uris.length} tracks"
35
+ tracks = track_uris.map { |x| Hallon::Track.new(x) }
36
+
37
+ # … insert the tracks at the desired position into the playlist.
38
+ playlist.insert(position, tracks)
39
+
40
+ # finally, wait for the updates to the playlist to be acknowledged by the
41
+ # Spotify back-end. Once they have, we’ll see the tracks in our desktop
42
+ # client as well.
43
+ puts "Uploading playlist changes to Spotify back-end!"
44
+
45
+ state_changed = false
46
+ playlist.on(:playlist_state_changed) { state_changed = true }
47
+ session.wait_for { state_changed && ! playlist.pending? }
48
+
49
+ puts "We’re done!"
@@ -8,11 +8,6 @@ session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
8
8
  end
9
9
  end
10
10
 
11
- session.login ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
12
-
13
- session.wait_for(:logged_in) { |error| Hallon::Error.maybe_raise(error) }
14
- session.wait_for(:connection_error) do |error|
15
- session.logged_in? or Hallon::Error.maybe_raise(error)
16
- end
11
+ session.login!(ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD'])
17
12
 
18
13
  puts "Successfully logged in!"
@@ -39,12 +39,7 @@ session = Hallon::Session.initialize IO.read(ENV['HALLON_APPKEY']) do
39
39
  end
40
40
  end
41
41
 
42
- session.login ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD']
43
-
44
- session.wait_for(:logged_in) { |error| Hallon::Error.maybe_raise(error) }
45
- session.wait_for(:connection_error) do |error|
46
- session.logged_in? or Hallon::Error.maybe_raise(error)
47
- end
42
+ session.login!(ENV['HALLON_USERNAME'], ENV['HALLON_PASSWORD'])
48
43
 
49
44
  puts "Successfully logged in!"
50
45
 
@@ -55,7 +50,7 @@ while username = prompt("Enter a Spotify username: ")
55
50
  username = nil if username.empty?
56
51
 
57
52
  puts "Fetching container for #{username || "current user"}..."
58
- container = Spotify::session_publishedcontainer_for_user_create(session.pointer, username)
53
+ container = Spotify::session_publishedcontainer_for_user_create!(session.pointer, username)
59
54
  if container.null?
60
55
  puts "Failed (unknown reason)."
61
56
  next
@@ -67,26 +62,21 @@ while username = prompt("Enter a Spotify username: ")
67
62
  puts "Listing #{num_playlists} playlists."
68
63
 
69
64
  num_playlists.times do |i|
70
- playlist = Spotify::playlistcontainer_playlist(container, i)
71
- session.wait_for { Spotify::playlist_is_loaded(playlist) }
65
+ playlist = Spotify::playlistcontainer_playlist!(container, i)
66
+ playlist = Hallon::Playlist.new(playlist)
67
+ session.wait_for { playlist.loaded? }
72
68
 
73
69
  puts
74
- puts Spotify::playlist_name(playlist) << ": "
70
+ puts playlist.name << ": "
75
71
 
76
- num_tracks = Spotify::playlist_num_tracks(playlist)
77
- num_tracks.times do |j|
78
- # Here we go back into Hallon API, passing the raw pointer
79
- # to Hallon::Track.new; this means all of Hallon::Track API
80
- # is supported on “track” here!
81
- track = Hallon::Track.new(Spotify::playlist_track(playlist, j))
72
+ num_tracks = playlist.tracks.size
73
+ playlist.tracks.each_with_index do |track, i|
82
74
  session.wait_for { track.loaded? }
83
75
 
84
- puts "\t (#{j+1}/#{num_tracks}) #{track.name}"
76
+ puts "\t (#{i+1}/#{num_tracks}) #{track.name}"
85
77
  end
86
78
  end
87
79
  rescue Interrupt
88
80
  # do nothing, continue with loop
89
- ensure
90
- Spotify::playlistcontainer_release(container) unless container.nil?
91
81
  end
92
82
  end
data/hallon.gemspec CHANGED
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.platform = Gem::Platform::RUBY
22
22
  gem.required_ruby_version = '~> 1.8'
23
23
 
24
- gem.add_dependency 'spotify', '~> 9.0.0'
24
+ gem.add_dependency 'spotify', '~> 10.1.0'
25
25
  gem.add_development_dependency 'bundler', '~> 1.0'
26
26
  gem.add_development_dependency 'rake', '~> 0.8'
27
27
  gem.add_development_dependency 'rspec', '~> 2'
data/lib/hallon.rb CHANGED
@@ -3,7 +3,6 @@ require 'spotify'
3
3
  require 'hallon/ext/spotify'
4
4
  require 'hallon/ext/ffi'
5
5
 
6
- require 'hallon/synchronizable'
7
6
  require 'hallon/observable'
8
7
  require 'hallon/linkable'
9
8
 
@@ -11,6 +10,7 @@ require 'hallon/version'
11
10
  require 'hallon/error'
12
11
  require 'hallon/base'
13
12
  require 'hallon/enumerator'
13
+
14
14
  require 'hallon/session'
15
15
  require 'hallon/link'
16
16
  require 'hallon/user'
@@ -19,7 +19,8 @@ require 'hallon/track'
19
19
  require 'hallon/album'
20
20
  require 'hallon/artist'
21
21
  require 'hallon/toplist'
22
-
22
+ require 'hallon/playlist'
23
+ require 'hallon/playlist_container'
23
24
  require 'hallon/album_browse'
24
25
  require 'hallon/artist_browse'
25
26
  require 'hallon/player'