gingerhendrix-scrobbler2 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. data/README +5 -0
  2. data/Rakefile +8 -0
  3. data/VERSION.yml +4 -0
  4. data/generators/acceptance_test/USAGE +9 -0
  5. data/generators/acceptance_test/acceptance_test_generator.rb +57 -0
  6. data/generators/acceptance_test/templates/acceptance_test.rb.erb +14 -0
  7. data/generators/resource/USAGE +8 -0
  8. data/generators/resource/resource_generator.rb +47 -0
  9. data/generators/resource/templates/resource.rb.erb +11 -0
  10. data/generators/resource/templates/spec.rb.erb +22 -0
  11. data/lib/scrobbler2.rb +23 -0
  12. data/lib/scrobbler2/album.rb +11 -0
  13. data/lib/scrobbler2/artist.rb +29 -0
  14. data/lib/scrobbler2/auth.rb +19 -0
  15. data/lib/scrobbler2/base.rb +73 -0
  16. data/lib/scrobbler2/event.rb +12 -0
  17. data/lib/scrobbler2/geo.rb +15 -0
  18. data/lib/scrobbler2/group.rb +14 -0
  19. data/lib/scrobbler2/library.rb +12 -0
  20. data/lib/scrobbler2/playlist.rb +10 -0
  21. data/lib/scrobbler2/tag.rb +17 -0
  22. data/lib/scrobbler2/track.rb +13 -0
  23. data/lib/scrobbler2/user.rb +29 -0
  24. data/lib/scrobbler2/venue.rb +12 -0
  25. data/test/acceptance/album/info_test.rb +56 -0
  26. data/test/acceptance/artist/add_tags_test.rb +14 -0
  27. data/test/acceptance/artist/events_test.rb +47 -0
  28. data/test/acceptance/artist/info_test.rb +53 -0
  29. data/test/acceptance/artist/shouts_test.rb +48 -0
  30. data/test/acceptance/artist/similar_artists_test.rb +20 -0
  31. data/test/acceptance/artist/tags_test.rb +24 -0
  32. data/test/acceptance/artist/top_albums_test.rb +34 -0
  33. data/test/acceptance/artist/top_fans.rb +19 -0
  34. data/test/acceptance/artist/top_tags.rb +18 -0
  35. data/test/acceptance/artist/top_tracks.rb +47 -0
  36. data/test/acceptance/auth/auth_test.rb +21 -0
  37. data/test/acceptance/event/info_test.rb +66 -0
  38. data/test/acceptance/event/shouts_test.rb +49 -0
  39. data/test/acceptance/geo/events_test.rb +14 -0
  40. data/test/acceptance/geo/top_artists_test.rb +16 -0
  41. data/test/acceptance/geo/top_tracks_test.rb +16 -0
  42. data/test/acceptance/group/members_test.rb +60 -0
  43. data/test/acceptance/group/weekly_album_chart_test.rb +61 -0
  44. data/test/acceptance/group/weekly_artist_chart_test.rb +54 -0
  45. data/test/acceptance/group/weekly_chart_list_test.rb +39 -0
  46. data/test/acceptance/group/weekly_track_chart_test.rb +61 -0
  47. data/test/acceptance/library/albums_test.rb +34 -0
  48. data/test/acceptance/library/artists_test.rb +33 -0
  49. data/test/acceptance/library/tracks_test.rb +33 -0
  50. data/test/acceptance/playlist/fetch_test.rb +68 -0
  51. data/test/acceptance/shared/album.rb +41 -0
  52. data/test/acceptance/shared/artist.rb +16 -0
  53. data/test/acceptance/shared/paged_result.rb +16 -0
  54. data/test/acceptance/shared/top_fans.rb +29 -0
  55. data/test/acceptance/shared/top_tags.rb +23 -0
  56. data/test/acceptance/shared/track.rb +23 -0
  57. data/test/acceptance/tag/similar_test.rb +15 -0
  58. data/test/acceptance/tag/top_albums_test.rb +37 -0
  59. data/test/acceptance/tag/top_artists_test.rb +31 -0
  60. data/test/acceptance/tag/top_tags_test.rb +33 -0
  61. data/test/acceptance/tag/top_tracks_test.rb +33 -0
  62. data/test/acceptance/tag/weekly_artist_chart.rb +54 -0
  63. data/test/acceptance/tag/weekly_chart_list.rb +39 -0
  64. data/test/acceptance/test_helper.rb +12 -0
  65. data/test/acceptance/track/info_test.rb +47 -0
  66. data/test/acceptance/track/similar_test.rb +22 -0
  67. data/test/acceptance/track/top_fans_test.rb +23 -0
  68. data/test/acceptance/track/top_tags_test.rb +24 -0
  69. data/test/acceptance/user/events_test.rb +27 -0
  70. data/test/acceptance/user/friends_test.rb +14 -0
  71. data/test/acceptance/user/info_test.rb +24 -0
  72. data/test/acceptance/user/loved_tracks_test.rb +14 -0
  73. data/test/acceptance/user/neighbours_test.rb +14 -0
  74. data/test/acceptance/user/past_events_test.rb +14 -0
  75. data/test/acceptance/user/playlists_test.rb +14 -0
  76. data/test/acceptance/user/recent_tracks_test.rb +14 -0
  77. data/test/acceptance/user/recommended_artists_test.rb +16 -0
  78. data/test/acceptance/user/recommended_events_test.rb +16 -0
  79. data/test/acceptance/user/shouts_test.rb +14 -0
  80. data/test/acceptance/user/top_albums_test.rb +14 -0
  81. data/test/acceptance/user/top_artists_test.rb +14 -0
  82. data/test/acceptance/user/top_tags_test.rb +14 -0
  83. data/test/acceptance/user/top_tracks_test.rb +14 -0
  84. data/test/acceptance/user/weekly_album_chart_test.rb +14 -0
  85. data/test/acceptance/user/weekly_artist_chart_test.rb +14 -0
  86. data/test/acceptance/user/weekly_chart_list_test.rb +14 -0
  87. data/test/acceptance/user/weekly_track_chart_test.rb +14 -0
  88. data/test/acceptance/venue/events_test.rb +14 -0
  89. data/test/acceptance/venue/past_events_test.rb +14 -0
  90. data/test/generators/test_acceptance_test_generator.rb +46 -0
  91. data/test/generators/test_generator_helper.rb +29 -0
  92. data/test/generators/test_resource_generator.rb +71 -0
  93. data/test/unit/album_spec.rb +17 -0
  94. data/test/unit/artist_spec.rb +62 -0
  95. data/test/unit/auth_spec.rb +22 -0
  96. data/test/unit/base_spec.rb +193 -0
  97. data/test/unit/event_spec.rb +23 -0
  98. data/test/unit/geo_spec.rb +36 -0
  99. data/test/unit/group_spec.rb +38 -0
  100. data/test/unit/library_spec.rb +27 -0
  101. data/test/unit/playlist_spec.rb +18 -0
  102. data/test/unit/spec_helper.rb +7 -0
  103. data/test/unit/tag_spec.rb +50 -0
  104. data/test/unit/track_spec.rb +33 -0
  105. data/test/unit/user_spec.rb +148 -0
  106. data/test/unit/venue_spec.rb +29 -0
  107. metadata +259 -0
data/README ADDED
@@ -0,0 +1,5 @@
1
+ Scrobbler2
2
+ ==========
3
+
4
+
5
+ A ruby library for accessing the last.fm api v2.0. Based on John Nunemaker's httParty gem and inspired by his scrobbler gem.
data/Rakefile ADDED
@@ -0,0 +1,8 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+ require 'rake/rdoctask'
4
+ require 'spec/rake/spectask'
5
+
6
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
7
+
8
+ task :default => 'test:unit'
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :patch: 4
3
+ :major: 0
4
+ :minor: 0
@@ -0,0 +1,9 @@
1
+ Description:
2
+ Generate a scrobbler2 acceptance test
3
+
4
+ Usage:
5
+ ./script/generate acceptance_test resource func
6
+
7
+ * resource is a last.fm api resource (eg. user, track etc)
8
+ * func is a last.fm api method (eg. info, similar, top_tags etc)
9
+
@@ -0,0 +1,57 @@
1
+ class AcceptanceTestGenerator < RubiGen::Base
2
+
3
+ # default_options :author => nil
4
+
5
+ attr_reader :resource
6
+ attr_reader :func
7
+
8
+ def initialize(runtime_args, runtime_options = {})
9
+ super
10
+ usage if args.empty? || args.length < 2
11
+ @resource = args.shift
12
+ @func = args.shift
13
+ extract_options
14
+ end
15
+
16
+ def manifest
17
+ record do |m|
18
+ # Ensure appropriate folder(s) exists
19
+ m.directory "test/acceptance/#{@resource}"
20
+
21
+ # Create stubs
22
+ m.template "acceptance_test.rb.erb", "test/acceptance/#{@resource}/#{@func}_test.rb"
23
+ # m.template_copy_each ["template.rb", "template2.rb"]
24
+ # m.template_copy_each ["template.rb", "template2.rb"], "some/path"
25
+ # m.file "file", "some_file_copied"
26
+ # m.file_copy_each ["path/to/file", "path/to/file2"]
27
+ # m.file_copy_each ["path/to/file", "path/to/file2"], "some/path"
28
+ end
29
+ end
30
+
31
+ protected
32
+ def banner
33
+ <<-EOS
34
+ Creates a scrobbler2 acceptance test
35
+
36
+ USAGE: #{$0} #{spec.name} resource func
37
+ EOS
38
+ end
39
+
40
+ def add_options!(opts)
41
+ # opts.separator ''
42
+ # opts.separator 'Options:'
43
+ # For each option below, place the default
44
+ # at the top of the file next to "default_options"
45
+ # opts.on("-a", "--author=\"Your Name\"", String,
46
+ # "Some comment about this option",
47
+ # "Default: none") { |options[:author]| }
48
+ # opts.on("-v", "--version", "Show the #{File.basename($0)} version number and quit.")
49
+ end
50
+
51
+ def extract_options
52
+ # for each option, extract it into a local variable (and create an "attr_reader :author" at the top)
53
+ # Templates can access these value via the attr_reader-generated methods, but not the
54
+ # raw instance variable value.
55
+ # @author = options[:author]
56
+ end
57
+ end
@@ -0,0 +1,14 @@
1
+ require File.dirname(__FILE__) + '/../test_helper.rb'
2
+
3
+ describe "<%=func%> for <%=resource%> ..." do
4
+
5
+ before(:all) do #We only want to hit the webservice once.
6
+ @<%=resource%> = Scrobbler2::<%=resource.classify%>.new "..."
7
+ @<%=func%> = @<%=resource%>.<%=func%>
8
+ end
9
+
10
+ it "should be hash" do
11
+ @<%=func%>.should be_kind_of Hash
12
+ end
13
+
14
+ end
@@ -0,0 +1,8 @@
1
+ Description:
2
+ Generate a scrobbler2 resource
3
+
4
+ Usage:
5
+ ./script/generate resource resource [funcs]
6
+
7
+ * resource is a last.fm api resource (eg. user, track etc)
8
+ * funcs are a list of last.fm get api method (eg. info, similar, top_tags etc)
@@ -0,0 +1,47 @@
1
+ class ResourceGenerator < RubiGen::Base
2
+
3
+ default_options :author => nil
4
+
5
+ attr_reader :name
6
+ attr_reader :funcs
7
+
8
+ def initialize(runtime_args, runtime_options = {})
9
+ super
10
+ usage if args.empty?
11
+ @name = args.shift
12
+ @funcs = args
13
+ extract_options
14
+ end
15
+
16
+ def manifest
17
+ record do |m|
18
+ # Ensure appropriate folder(s) exists
19
+ m.directory 'lib/scrobbler2'
20
+ m.directory 'test/unit'
21
+
22
+ # Create stubs
23
+ m.template "resource.rb.erb", "lib/scrobbler2/#{name}.rb"
24
+ m.template "spec.rb.erb", "test/unit/#{name}_spec.rb"
25
+
26
+ # Create acceptance tests
27
+ funcs.each do |func|
28
+ m.dependency "acceptance_test", [name, func]
29
+ end
30
+ end
31
+ end
32
+
33
+ protected
34
+ def banner
35
+ <<-EOS
36
+ Creates a scrobbler2 resource
37
+
38
+ USAGE: #{$0} #{spec.name} name funcs
39
+ EOS
40
+ end
41
+
42
+ def add_options!(opts)
43
+ end
44
+
45
+ def extract_options
46
+ end
47
+ end
@@ -0,0 +1,11 @@
1
+ module Scrobbler2
2
+ class <%= name.classify %> < Base
3
+
4
+ def initialize()
5
+ @query = {}#TODO eg. {:artist => artist, :track => track}
6
+ end
7
+ <% funcs.each do |func| %>
8
+ get_resource :<%=func%>, :root => "<%=func.camelize.downcase%>"
9
+ <% end %>
10
+ end
11
+ end
@@ -0,0 +1,22 @@
1
+ require File.dirname(__FILE__) + "/spec_helper.rb"
2
+
3
+ describe "<%=name.classify%>" do
4
+ before(:each) do
5
+ @<%=name%> = Scrobbler2::<%=name.classify%>.new "..."
6
+ @<%=name%>.class.stub!(:get).and_return Hash.new
7
+ end
8
+
9
+ it "should have a default query {TODO}" do
10
+ @<%=name%>.instance_variable_get(:@query).should == {}
11
+ end
12
+
13
+ <% funcs.each do |func| %>
14
+
15
+ it "<%=func%> should call get with '<%=name%>.get<%=func%>'" do
16
+ @<%=name%>.class.should_receive(:get).with('<%=name%>.get<%=func%>', anything(), anything()).and_return Hash.new
17
+ @<%=name%>.<%=func%>
18
+ end
19
+
20
+ <% end %>
21
+
22
+ end
data/lib/scrobbler2.rb ADDED
@@ -0,0 +1,23 @@
1
+ require 'rubygems'
2
+ require 'httparty'
3
+ require 'active_support'
4
+ $: << File.dirname(__FILE__)
5
+
6
+ module Scrobbler2
7
+
8
+ end
9
+
10
+ require 'scrobbler2/base.rb'
11
+ require 'scrobbler2/auth.rb'
12
+ require 'scrobbler2/album.rb'
13
+ require 'scrobbler2/artist.rb'
14
+ require 'scrobbler2/event.rb'
15
+ require 'scrobbler2/geo.rb'
16
+ require 'scrobbler2/group.rb'
17
+ require 'scrobbler2/library.rb'
18
+ require 'scrobbler2/playlist.rb'
19
+ require 'scrobbler2/tag.rb'
20
+ require 'scrobbler2/track.rb'
21
+ require 'scrobbler2/user.rb'
22
+ require 'scrobbler2/venue.rb'
23
+
@@ -0,0 +1,11 @@
1
+ module Scrobbler2
2
+ class Album < Base
3
+
4
+ def initialize(artist, album)
5
+ @query = {:artist => artist, :album => album}
6
+ end
7
+
8
+ get_resource :info, :root => 'album'
9
+
10
+ end
11
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module Scrobbler2
3
+ class Artist < Base
4
+
5
+ def initialize(artist)
6
+ @query = {:artist => artist}
7
+ end
8
+
9
+ get_resource :events, :root => 'events'
10
+ get_resource :info, :root => 'artist'
11
+ get_resource :shouts, :root => 'shouts'
12
+ get_resource :similar, :root => 'similarartists'
13
+ get_resource :top_albums, :root => 'topalbums'
14
+ get_resource :top_fans, :root => 'topfans'
15
+ get_resource :top_tags, :root => 'toptags'
16
+ get_resource :top_tracks, :root => 'toptracks'
17
+
18
+ def tags
19
+ return @tags if @tags
20
+ @tags = self.class.get_with_auth("artist.gettags", @query)["lfm"]["tags"]
21
+ end
22
+
23
+ def add_tags(tags)
24
+ query = @query.merge :tags => tags.join(",")
25
+ self.class.post_with_auth("artist.addtags", query)
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,19 @@
1
+ module Scrobbler2
2
+ class Auth < Base
3
+
4
+ def token
5
+ return @token if @token
6
+ @token = self.class.get_with_auth("auth.gettoken")["lfm"]["token"]
7
+ end
8
+
9
+ def url
10
+ "http://www.last.fm/api/auth/?api_key=#{api_key}&token=#{token}"
11
+ end
12
+
13
+ def session
14
+ return @session if @session
15
+ @session = self.class.get_with_auth("auth.getsession", {:token => token})["lfm"]["session"]
16
+ end
17
+
18
+ end
19
+ end
@@ -0,0 +1,73 @@
1
+
2
+
3
+ module Scrobbler2
4
+ class Base
5
+ cattr_accessor :api_key
6
+ cattr_accessor :api_secret
7
+ cattr_accessor :session_key
8
+
9
+ def self.get(method, query={}, options={})
10
+ query = query.merge({:api_key => api_key, :method => method, :format => 'json'})
11
+ options = options.merge({:query => query})
12
+
13
+ response = HTTParty.get('http://ws.audioscrobbler.com/2.0/', options)
14
+ end
15
+
16
+ def self.get_resource(name, options = {})
17
+ define_method name do |*args|
18
+ query = args[1] || {}
19
+ local_options = args[0] || {}
20
+ local_value = instance_variable_get("@#{name.to_s}")
21
+ return local_value if local_value && !options[:force]
22
+
23
+ query = query.merge options[:query] if options[:query]
24
+ query = query.merge(@query) if @query && !options[:query]
25
+
26
+ method_name = options[:resource_name] || self.class.name.split("::").last.downcase + ".get#{name.to_s.tr('_', '').downcase}"
27
+ if options[:auth]
28
+ value = self.class.get_with_auth(method_name, query, local_options)
29
+ else
30
+ value = self.class.get(method_name, query, local_options)
31
+ end
32
+ value = value[options[:root]] if options[:root]
33
+
34
+ instance_variable_set("@#{name}", value)
35
+ end
36
+ end
37
+
38
+ #implements signed requests
39
+ def self.get_with_auth(method, query={}, options={})
40
+ http_with_auth(:get, method, query, options)
41
+ end
42
+
43
+ def self.http_with_auth(http_method, method, query={}, options={})
44
+ query = query.merge({:api_key => api_key, :method => method})
45
+ query = query.merge({:sk => session_key}) if session_key
46
+
47
+ signature = sign(query)
48
+ query = query.merge({:api_sig => signature})
49
+
50
+ if(http_method == :get)
51
+ options = options.merge({:query => query})
52
+ else
53
+ options = options.merge({:body => query})
54
+ end
55
+ response = HTTParty.send(http_method, 'http://ws.audioscrobbler.com/2.0/', options)
56
+ end
57
+
58
+ def self.post_with_auth(method, query={}, options={})
59
+ http_with_auth(:post, method, query, options)
60
+ end
61
+
62
+ def self.sign(query)
63
+ signature = query_signature(query)
64
+ md5 = Digest::MD5.hexdigest(signature)
65
+ end
66
+
67
+ def self.query_signature(query)
68
+ signature = query.sort {|a,b| a[0].to_s <=> b[0].to_s }.map { |param| param.join('') }.join('')
69
+ signature = "#{signature}#{api_secret}"
70
+ signature
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,12 @@
1
+ module Scrobbler2
2
+ class Event < Base
3
+
4
+ def initialize(event_id)
5
+ @query = {:event => event_id}
6
+ end
7
+
8
+ get_resource :info, :root => 'event'
9
+ get_resource :shouts, :root => 'shouts'
10
+
11
+ end
12
+ end
@@ -0,0 +1,15 @@
1
+ module Scrobbler2
2
+ class Geo < Base
3
+
4
+ def initialize()
5
+ @query = {}#TODO eg. {:artist => artist, :track => track}
6
+ end
7
+
8
+ get_resource :events, :root => "events"
9
+
10
+ get_resource :top_artists, :root => "topartists"
11
+
12
+ get_resource :top_tracks, :root => "toptracks"
13
+
14
+ end
15
+ end
@@ -0,0 +1,14 @@
1
+ module Scrobbler2
2
+ class Group < Base
3
+
4
+ def initialize(group_name)
5
+ @query = {:group => group_name}
6
+ end
7
+
8
+ get_resource :members, :root => 'members'
9
+ get_resource :weekly_album_chart, :root => 'weeklyalbumchart'
10
+ get_resource :weekly_artist_chart, :root => 'weeklyartistchart'
11
+ get_resource :weekly_track_chart, :root => 'weeklytrackchart'
12
+ get_resource :weekly_chart_list, :root => 'weeklychartlist'
13
+ end
14
+ end
@@ -0,0 +1,12 @@
1
+ module Scrobbler2
2
+ class Library < Base
3
+
4
+ def initialize(user)
5
+ @query = {:user => user}
6
+ end
7
+
8
+ get_resource :artists, :root => 'artists'
9
+ get_resource :albums, :root => 'albums'
10
+ get_resource :tracks, :root => 'tracks'
11
+ end
12
+ end
@@ -0,0 +1,10 @@
1
+ module Scrobbler2
2
+ class Playlist < Base
3
+
4
+ def initialize(playlist_url)
5
+ @query = {:playlistURL => playlist_url}
6
+ end
7
+
8
+ get_resource :fetch, :root => 'playlist', :resource_name => 'playlist.fetch'
9
+ end
10
+ end
@@ -0,0 +1,17 @@
1
+
2
+ module Scrobbler2
3
+ class Tag < Base
4
+
5
+ def initialize(tag)
6
+ @query = {:tag => tag}
7
+ end
8
+
9
+ get_resource :similar, :root => 'similar'
10
+ get_resource :top_artists, :root => 'topartists'
11
+ get_resource :top_albums, :root => 'topalbums'
12
+ get_resource :top_tracks, :root => 'toptracks'
13
+ get_resource :top_tags, :root => 'toptags'
14
+ get_resource :weekly_artist_chart, :root => 'weeklyartistchart'
15
+ get_resource :weekly_chart_list, :root => 'weeklychartlist'
16
+ end
17
+ end