shortwave 0.0.1

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.
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