shortwave 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/.document +5 -0
  2. data/.gitignore +10 -0
  3. data/.gitmodules +3 -0
  4. data/LICENSE +20 -0
  5. data/README.rdoc +74 -0
  6. data/Rakefile +133 -0
  7. data/VERSION +1 -0
  8. data/lib/shortwave.rb +12 -0
  9. data/lib/shortwave/authentication.rb +107 -0
  10. data/lib/shortwave/facade.rb +3 -0
  11. data/lib/shortwave/facade/build/facade_builder.rb +199 -0
  12. data/lib/shortwave/facade/build/facade_template.erb +17 -0
  13. data/lib/shortwave/facade/lastfm.rb +878 -0
  14. data/lib/shortwave/facade/remote.rb +86 -0
  15. data/lib/shortwave/model/album.rb +33 -0
  16. data/lib/shortwave/model/artist.rb +62 -0
  17. data/lib/shortwave/model/base_model.rb +112 -0
  18. data/lib/shortwave/model/chart_dates.rb +15 -0
  19. data/lib/shortwave/model/comparison.rb +15 -0
  20. data/lib/shortwave/model/event.rb +55 -0
  21. data/lib/shortwave/model/group.rb +26 -0
  22. data/lib/shortwave/model/location.rb +45 -0
  23. data/lib/shortwave/model/playlist.rb +36 -0
  24. data/lib/shortwave/model/shout.rb +21 -0
  25. data/lib/shortwave/model/tag.rb +47 -0
  26. data/lib/shortwave/model/track.rb +71 -0
  27. data/lib/shortwave/model/user.rb +70 -0
  28. data/lib/shortwave/model/venue.rb +37 -0
  29. data/lib/shortwave/model/weekly_charts.rb +31 -0
  30. data/lib/shortwave/providers.rb +161 -0
  31. data/shortwave.gemspec +178 -0
  32. data/test/authentication_test.rb +64 -0
  33. data/test/build/build_test.rb +25 -0
  34. data/test/build/data/intro.yml +2 -0
  35. data/test/build/data/screens/album_addTags.html +1238 -0
  36. data/test/build/data/screens/intro_truncated.html +426 -0
  37. data/test/build/data/screens/tasteometer_compare.html +1274 -0
  38. data/test/build/data/screens/user_getLovedTracks.html +1278 -0
  39. data/test/build/data/screens/venue_search.html +1261 -0
  40. data/test/build/facade_builder_test.rb +23 -0
  41. data/test/build/parameter_test.rb +43 -0
  42. data/test/build/remote_method_test.rb +47 -0
  43. data/test/build/ruby_class_test.rb +12 -0
  44. data/test/build/ruby_method_test.rb +137 -0
  45. data/test/helper.rb +35 -0
  46. data/test/model/album_test.rb +62 -0
  47. data/test/model/artist_test.rb +103 -0
  48. data/test/model/chart_dates_test.rb +11 -0
  49. data/test/model/comparison_test.rb +18 -0
  50. data/test/model/data/album_info.xml +38 -0
  51. data/test/model/data/album_search.xml +210 -0
  52. data/test/model/data/artist_info.xml +58 -0
  53. data/test/model/data/artist_search.xml +109 -0
  54. data/test/model/data/artist_shouts.xml +546 -0
  55. data/test/model/data/artist_top_fans.xml +405 -0
  56. data/test/model/data/event_info.xml +47 -0
  57. data/test/model/data/group_members.xml +242 -0
  58. data/test/model/data/group_weekly_album_chart.xml +1754 -0
  59. data/test/model/data/group_weekly_artist_chart.xml +604 -0
  60. data/test/model/data/group_weekly_track_chart.xml +1005 -0
  61. data/test/model/data/location_events.xml +383 -0
  62. data/test/model/data/ok.xml +2 -0
  63. data/test/model/data/playlist_fetch.xml +227 -0
  64. data/test/model/data/tag_search.xml +110 -0
  65. data/test/model/data/tag_similar.xml +254 -0
  66. data/test/model/data/tag_top_albums.xml +805 -0
  67. data/test/model/data/tag_top_artists.xml +605 -0
  68. data/test/model/data/tag_top_tags.xml +1254 -0
  69. data/test/model/data/tag_top_tracks.xml +843 -0
  70. data/test/model/data/tag_weekly_chart_list.xml +57 -0
  71. data/test/model/data/tasteometer_compare.xml +54 -0
  72. data/test/model/data/track_info.xml +53 -0
  73. data/test/model/data/track_search.xml +195 -0
  74. data/test/model/data/user_chartlist.xml +90 -0
  75. data/test/model/data/user_info.xml +16 -0
  76. data/test/model/data/user_neighbours.xml +484 -0
  77. data/test/model/data/user_playlists.xml +17 -0
  78. data/test/model/data/user_recent_tracks.xml +124 -0
  79. data/test/model/data/user_recommended_artists.xml +454 -0
  80. data/test/model/data/user_shouts.xml +9 -0
  81. data/test/model/data/user_weekly_artist_chart.xml +478 -0
  82. data/test/model/data/venue_events.xml +556 -0
  83. data/test/model/data/venue_past_events.xml +1778 -0
  84. data/test/model/data/venue_search.xml +355 -0
  85. data/test/model/event_test.rb +63 -0
  86. data/test/model/group_test.rb +45 -0
  87. data/test/model/location_test.rb +25 -0
  88. data/test/model/playlist_test.rb +51 -0
  89. data/test/model/shout_test.rb +23 -0
  90. data/test/model/tag_test.rb +39 -0
  91. data/test/model/track_test.rb +67 -0
  92. data/test/model/user_test.rb +125 -0
  93. data/test/model/venue_test.rb +60 -0
  94. data/test/provider/album_provider_test.rb +26 -0
  95. data/test/provider/artist_provider_test.rb +25 -0
  96. data/test/provider/group_provider_test.rb +9 -0
  97. data/test/provider/location_provider_test.rb +9 -0
  98. data/test/provider/playlist_provider_test.rb +12 -0
  99. data/test/provider/tag_provider_test.rb +24 -0
  100. data/test/provider/track_provider_test.rb +26 -0
  101. data/test/provider/user_provider_test.rb +11 -0
  102. data/test/provider/venue_provider_test.rb +15 -0
  103. data/test/provider_test_helper.rb +27 -0
  104. data/test/remote_test.rb +26 -0
  105. metadata +209 -0
@@ -0,0 +1,23 @@
1
+ require 'helper'
2
+ require 'facade/build/facade_builder'
3
+
4
+ class FacadeBuilderTest < TestCase
5
+
6
+ test "remote method definitions can be loaded from file" do
7
+ expected = {"User" => {"foo.bar" => "/baz"}}
8
+ assert_equal( expected, FacadeBuilder.new.remote_method_definitions(File.dirname(__FILE__) + "/data/intro.yml") )
9
+ end
10
+
11
+ test "remote method defintions can be added to file" do
12
+ expected = {"A" => {"B" => "C"}}
13
+
14
+ File.expects(:exists?).returns(false)
15
+ DocumentationRemote.expects(:scrape_remote_method_index).returns(expected)
16
+ fh = mock()
17
+ fh.expects(:write).with("--- \nA: \n B: C\n")
18
+ File.expects(:open).yields(fh)
19
+
20
+ assert_equal( expected, FacadeBuilder.new.remote_method_definitions("non-existent") )
21
+ end
22
+
23
+ end
@@ -0,0 +1,43 @@
1
+ require 'helper'
2
+ require 'facade/build/facade_builder'
3
+
4
+ class ParameterTest < TestCase
5
+
6
+ test "can be parsed from an html screen" do
7
+ assert_equal 2, make_parameters("user_getLovedTracks").size
8
+ end
9
+
10
+ test "have a name" do
11
+ assert_equal :user, make_parameters("user_getLovedTracks").first.name
12
+ end
13
+
14
+ test "can be required or optional" do
15
+ assert make_parameters("venue_search").first.required?
16
+ assert ! make_parameters("venue_search")[1].required?
17
+ end
18
+
19
+ test "can have a description" do
20
+ assert_equal "The venue name you would like to search for.",
21
+ make_parameters("venue_search").first.description
22
+ end
23
+
24
+ test "copes with defaults in the optional section" do
25
+ assert ! make_parameters("tasteometer_compare")[4].required?
26
+ end
27
+
28
+ test "copes with multiple parameters defined as type[1|2]" do
29
+ assert_equal :type1, make_parameters("tasteometer_compare").first.name
30
+ assert_equal :type2, make_parameters("tasteometer_compare")[1].name
31
+ end
32
+
33
+ test "copes with extra information in the required string" do
34
+ assert make_parameters("tasteometer_compare").first.required?
35
+ end
36
+
37
+ private
38
+
39
+ def make_parameters(screen)
40
+ raw = File.read(File.dirname(__FILE__) + "/data/screens/#{screen}.html")
41
+ Shortwave::Facade::Build::Parameter.parse(raw)
42
+ end
43
+ end
@@ -0,0 +1,47 @@
1
+ require 'helper'
2
+ require 'facade/build/facade_builder'
3
+
4
+ class RemoteMethodTest < TestCase
5
+
6
+ test "parsed method has a description" do
7
+ make_builder "user_getLovedTracks"
8
+ assert_equal "Get the last 50 tracks loved by a user.", @method.description
9
+ end
10
+
11
+ test "parsed method has a remote name" do
12
+ make_builder "user_getLovedTracks"
13
+ assert_equal "user.getLovedTracks", @method.remote_name
14
+ end
15
+
16
+ test "parsed method has a name" do
17
+ make_builder "user_getLovedTracks"
18
+ assert_equal :loved_tracks, @method.name
19
+ end
20
+
21
+ test "parsed method has parameters" do
22
+ make_builder "user_getLovedTracks"
23
+ assert_equal [:user, :api_key], @method.parameters.map {|p| p.name }
24
+ end
25
+
26
+ test "read methods should use http GET" do
27
+ make_builder "user_getLovedTracks"
28
+ assert_equal :get, @method.http_method
29
+ end
30
+
31
+ test "write methods should use http POST" do
32
+ make_builder "album_addTags"
33
+ assert_equal :post, @method.http_method
34
+ end
35
+
36
+ test "parsed methods have sample response code" do
37
+ make_builder "album_addTags"
38
+ assert_equal "<lfm status=\"ok\">\n</lfm>", @method.sample_response
39
+ end
40
+
41
+ private
42
+
43
+ def make_builder(screen)
44
+ raw = File.read(File.dirname(__FILE__) + "/data/screens/#{screen}.html")
45
+ @method = Shortwave::Facade::Build::RemoteMethod.new(raw)
46
+ end
47
+ end
@@ -0,0 +1,12 @@
1
+ require 'helper'
2
+ require 'facade/build/facade_builder'
3
+
4
+ include Shortwave::Facade::Build
5
+
6
+ class RubyClassTest < TestCase
7
+
8
+ test "has a name" do
9
+ assert_equal "User", RubyClass.new("User").name
10
+ end
11
+
12
+ end
@@ -0,0 +1,137 @@
1
+ require 'helper'
2
+ require 'facade/build/facade_builder'
3
+
4
+ include Shortwave::Facade::Build
5
+
6
+ RemoteMethodStub = Struct.new(:remote_name, :name, :description, :sample_response, :parameters, :http_method)
7
+ ParameterStub = Struct.new(:name, :description, :required)
8
+
9
+ class ParameterStub
10
+ def required?
11
+ required
12
+ end
13
+ end
14
+
15
+ class RubyMethodTest < TestCase
16
+
17
+ test "outputs a simple method signature with no arguments" do
18
+ method = RemoteMethodStub.new("user.getLovedTracks", :loved_tracks)
19
+ assert_equal "loved_tracks", RubyMethod.new(method).signature
20
+ end
21
+
22
+ test "outputs the description as first line of comment" do
23
+ method = RemoteMethodStub.new("user.getLovedTracks", :loved_tracks, "A user's loved tracks")
24
+ assert_equal "# A user's loved tracks", RubyMethod.new(method).comment.first
25
+ end
26
+
27
+ test "outputs parameter descriptions as a comment" do
28
+ method = RemoteMethodStub.new("user.getLovedTracks",
29
+ :loved_tracks,
30
+ "Description",
31
+ nil,
32
+ [ParameterStub.new(:user, "A username", true),
33
+ ParameterStub.new(:optional, "Optional", false),
34
+ ParameterStub.new(:api_key, "api key", true)])
35
+
36
+ expected = ["# Description",
37
+ "#",
38
+ "# +user+:: A username",
39
+ "#",
40
+ "# <b>Options</b>",
41
+ "# +optional+:: Optional"]
42
+ assert_equal expected, RubyMethod.new(method).comment
43
+ end
44
+
45
+ test "adds required parameters to the method signature" do
46
+ method = RemoteMethodStub.new("user.getLovedTracks",
47
+ :loved_tracks,
48
+ nil,
49
+ nil,
50
+ [ParameterStub.new(:user, "A username", true)])
51
+
52
+ assert_equal "loved_tracks(user)", RubyMethod.new(method).signature
53
+ end
54
+
55
+ [:api_key, :api_sig, :sk].each do |param|
56
+ test "#{param} parameter should not be part of the signature" do
57
+ method = RemoteMethodStub.new("user.getLovedTracks",
58
+ :loved_tracks,
59
+ nil,
60
+ nil,
61
+ [ParameterStub.new(:user, "A username", true),
62
+ ParameterStub.new(param, "API key", true)])
63
+
64
+ assert_equal "loved_tracks(user)", RubyMethod.new(method).signature
65
+ end
66
+ end
67
+
68
+ test "optional parameters should be collapsed to an options hash" do
69
+ method = RemoteMethodStub.new("user.getLovedTracks",
70
+ :loved_tracks,
71
+ nil,
72
+ nil,
73
+ [ParameterStub.new(:user, "A username", true),
74
+ ParameterStub.new(:number, "optional", false)])
75
+
76
+ assert_equal "loved_tracks(user, options={})", RubyMethod.new(method).signature
77
+ end
78
+
79
+ test "method body generates a GET request to the remote method" do
80
+ method = RemoteMethodStub.new("user.getLovedTracks",
81
+ :loved_tracks,
82
+ nil,
83
+ nil,
84
+ [ParameterStub.new(:user, "A username", true)],
85
+ :get)
86
+
87
+ expected = ["get(:standard, {:method => \"user.getLovedTracks\", :user => user})"]
88
+ assert_equal expected, RubyMethod.new(method).body
89
+ end
90
+
91
+ test "optional parameters are merged into the sent data" do
92
+ method = RemoteMethodStub.new("user.getLovedTracks",
93
+ :loved_tracks,
94
+ nil,
95
+ nil,
96
+ [ParameterStub.new(:user, "A username", true),
97
+ ParameterStub.new(:number, "optional", false)],
98
+ :get)
99
+
100
+ expected = ["get(:standard, {:method => \"user.getLovedTracks\", :user => user}.merge(options))"]
101
+ assert_equal expected, RubyMethod.new(method).body
102
+ end
103
+
104
+ test "write methods are sent via POST" do
105
+ method = RemoteMethodStub.new("user.getLovedTracks",
106
+ :loved_tracks,
107
+ nil,
108
+ nil,
109
+ [ParameterStub.new(:user, "A username", true),
110
+ ParameterStub.new(:number, "optional", false)],
111
+ :post)
112
+
113
+ assert_equal "post", RubyMethod.new(method).body.first[0..3]
114
+ end
115
+
116
+ test "method with an sk parameter should be a session method" do
117
+ method = RemoteMethodStub.new("user.getLovedTracks",
118
+ :loved_tracks,
119
+ nil,
120
+ nil,
121
+ [ParameterStub.new(:sk, "sk", true)],
122
+ :get)
123
+ expected = ["get(:session, {:method => \"user.getLovedTracks\"})"]
124
+ assert_equal expected, RubyMethod.new(method).body
125
+ end
126
+
127
+ test "method with an api_sig but no sk parameter should be a signed method" do
128
+ method = RemoteMethodStub.new("user.getLovedTracks",
129
+ :loved_tracks,
130
+ nil,
131
+ nil,
132
+ [ParameterStub.new(:api_sig, "api_sig", true)],
133
+ :get)
134
+ expected = ["get(:signed, {:method => \"user.getLovedTracks\"})"]
135
+ assert_equal expected, RubyMethod.new(method).body
136
+ end
137
+ end
data/test/helper.rb ADDED
@@ -0,0 +1,35 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'mocha'
4
+ require 'fakeweb'
5
+
6
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
7
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
8
+ require 'shortwave'
9
+
10
+ FakeWeb.allow_net_connect = false
11
+ TestCase = Test::Unit::TestCase
12
+
13
+ class TestCase
14
+ def setup
15
+ FakeWeb.clean_registry
16
+ end
17
+
18
+ def self.test(name, &block)
19
+ test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
20
+ defined = instance_method(test_name) rescue false
21
+ raise "#{test_name} is already defined in #{self}" if defined
22
+
23
+ if block_given?
24
+ define_method(test_name, &block)
25
+ else
26
+ define_method(test_name) do
27
+ flunk "No implementation for #{test_name}"
28
+ end
29
+ end
30
+ end
31
+ end
32
+
33
+ include Shortwave
34
+ require 'provider_test_helper'
35
+
@@ -0,0 +1,62 @@
1
+ require 'helper'
2
+
3
+ class AlbumTest < TestCase
4
+ include ProviderTestHelper
5
+
6
+ def setup
7
+ super
8
+ @facade.stubs(:session).returns(stub(:album_facade => @facade, :merge! => nil, :signed_in? => true))
9
+ @album = Model::Album.parse(xml("album_info"), :single => true)
10
+ @album.session = @facade.session
11
+ end
12
+
13
+ test "has a name" do
14
+ assert_equal "Only Life", @album.name
15
+ end
16
+
17
+ test "has an id" do
18
+ assert_equal 2045356, @album.id
19
+ end
20
+
21
+ test "has a url" do
22
+ assert_equal "http://www.last.fm/music/The+Feelies/Only+Life", @album.url
23
+ end
24
+
25
+ test "has a release date" do
26
+ assert_equal Time.local(1987, 11, 30, 0, 0, 0), @album.release_date
27
+ end
28
+
29
+ test "has images" do
30
+ assert_equal 4, @album.images.size
31
+ end
32
+
33
+ test "has a musicbrainz id" do
34
+ assert_equal "464efacc-a133-4ae6-a9ff-7573c448eb32", @album.mbid
35
+ end
36
+
37
+ test "has listeners" do
38
+ assert_equal 10068, @album.listeners
39
+ end
40
+
41
+ test "has a play count" do
42
+ assert_equal 67545, @album.play_count
43
+ end
44
+
45
+ test "has tags" do
46
+ assert_equal 5, @album.tags.size
47
+ end
48
+
49
+ test "has an artist name" do
50
+ assert_equal "The Feelies", @album.artist_name
51
+ end
52
+
53
+ test "can be tagged by a user" do
54
+ @facade.expects(:add_tags).with("The Feelies", "Only Life", "tag1,tag2,tag3")
55
+ @album.add_tags("tag1", "tag2", "tag3")
56
+ end
57
+
58
+ test "can remove a user tag" do
59
+ @facade.expects(:remove_tag).with("The Feelies", "Only Life", "tag1")
60
+ @album.remove_tag("tag1")
61
+ end
62
+ end
@@ -0,0 +1,103 @@
1
+ require 'helper'
2
+
3
+ class ArtistTest < TestCase
4
+ include ProviderTestHelper
5
+
6
+ def setup
7
+ super
8
+ @artist = Model::Artist.parse(xml("artist_info"), :single => true)
9
+ end
10
+
11
+ test "has a name" do
12
+ assert_equal "The Feelies", @artist.name
13
+ end
14
+
15
+ test "has a url" do
16
+ assert_equal "http://www.last.fm/music/The+Feelies", @artist.url
17
+ end
18
+
19
+ test "has a musicbrainz id" do
20
+ assert_equal "28c07254-aeae-42ad-beea-67f59c3c8baf", @artist.mbid
21
+ end
22
+
23
+ test "has listeners" do
24
+ assert_equal 43593, @artist.listeners
25
+ end
26
+
27
+ test "has a play count" do
28
+ assert_equal 498218, @artist.play_count
29
+ end
30
+
31
+ test "has a biography and summary" do
32
+ assert @artist.biography
33
+ assert @artist.biography_summary
34
+ end
35
+
36
+ test "has images" do
37
+ assert_equal 3, @artist.images.size
38
+ end
39
+
40
+ test "has user tags" do
41
+ @artist.session = StubSession.new
42
+ expect_get "method=artist.getTags&artist=The%20Feelies", :tag_search
43
+ @artist.my_tags
44
+ end
45
+
46
+ test "has shouts" do
47
+ @artist.session = StubSession.new
48
+ expect_get "method=artist.getShouts&artist=The%20Feelies", :artist_shouts
49
+ assert_equal 104, @artist.shouts.size
50
+ end
51
+
52
+ test "can be shouted at" do
53
+ @facade.stubs(:session).returns(stub(:artist_facade => @facade))
54
+ @artist.session = @facade.session
55
+ @facade.expects(:shout).with("The Feelies", "Hi there").returns(xml("ok"))
56
+ @artist.shout("Hi there")
57
+ end
58
+
59
+ test "can be shared with other users or email addresses" do
60
+ @facade.stubs(:session).returns(stub(:artist_facade => @facade))
61
+ @artist.session = @facade.session
62
+ args = ["The Feelies", "roland@example.com,kate", {:message => "This is awesome!"}]
63
+ @facade.expects(:share).with(*args).returns(xml("ok"))
64
+ # TODO should be a user object, not just a username
65
+ @artist.share(["roland@example.com", "kate"], "This is awesome!")
66
+ end
67
+
68
+ test "has events" do
69
+ @artist.session = StubSession.new
70
+ expect_get "method=artist.getEvents&artist=The%20Feelies", :venue_events
71
+ assert @artist.events.first.kind_of? Model::Event
72
+ end
73
+
74
+ test "has similar artists" do
75
+ @artist.session = StubSession.new
76
+ expect_get "method=artist.getSimilar&artist=The%20Feelies", :artist_search
77
+ assert @artist.similar.first.kind_of? Model::Artist
78
+ end
79
+
80
+ test "has albums" do
81
+ @artist.session = StubSession.new
82
+ expect_get "method=artist.getTopAlbums&artist=The%20Feelies", :album_search
83
+ assert @artist.albums.first.kind_of? Model::Album
84
+ end
85
+
86
+ test "has fans" do
87
+ @artist.session = StubSession.new
88
+ expect_get "method=artist.getTopFans&artist=The%20Feelies", :artist_top_fans
89
+ assert @artist.fans.first.kind_of? Model::User
90
+ end
91
+
92
+ test "has tags" do
93
+ @artist.session = StubSession.new
94
+ expect_get "method=artist.getTopTags&artist=The%20Feelies", :tag_search
95
+ assert @artist.tags.first.kind_of? Model::Tag
96
+ end
97
+
98
+ test "has tracks" do
99
+ @artist.session = StubSession.new
100
+ expect_get "method=artist.getTopTracks&artist=The%20Feelies", :track_search
101
+ assert @artist.tracks.first.kind_of? Model::Track
102
+ end
103
+ end