notu 0.1.0

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 (45) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +5 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +3 -0
  5. data/MIT-LICENSE +20 -0
  6. data/Rakefile +10 -0
  7. data/VERSION +1 -0
  8. data/lib/notu.rb +18 -0
  9. data/lib/notu/error.rb +15 -0
  10. data/lib/notu/html_document.rb +20 -0
  11. data/lib/notu/http_download.rb +39 -0
  12. data/lib/notu/library.rb +52 -0
  13. data/lib/notu/loved_tracks.rb +40 -0
  14. data/lib/notu/most_played_tracks.rb +46 -0
  15. data/lib/notu/network_error.rb +6 -0
  16. data/lib/notu/parse_error.rb +6 -0
  17. data/lib/notu/track.rb +30 -0
  18. data/notu.gemspec +27 -0
  19. data/spec/cassettes/Notu_HtmlDocument/_get/follows_redirects.yml +178 -0
  20. data/spec/cassettes/Notu_HtmlDocument/_get/raise_a_NetworkError_on_404.yml +80 -0
  21. data/spec/cassettes/Notu_HtmlDocument/_get/raise_a_ParseError_if_not_a_valid_document.yml +369 -0
  22. data/spec/cassettes/Notu_HtmlDocument/_get/returns_document_parsed.yml +134 -0
  23. data/spec/cassettes/Notu_HttpDownload/_get/accepts_HTTPS_URL.yml +134 -0
  24. data/spec/cassettes/Notu_HttpDownload/_get/follow_redirects.yml +178 -0
  25. data/spec/cassettes/Notu_HttpDownload/_get/raise_a_NetworkError_if_too_many_redirects.yml +47 -0
  26. data/spec/cassettes/Notu_HttpDownload/_get/raise_a_NetworkError_on_404.yml +80 -0
  27. data/spec/cassettes/Notu_HttpDownload/_get/retrives_document_from_given_URL.yml +134 -0
  28. data/spec/cassettes/Notu_LovedTracks/_each/returns_nil.yml +2568 -0
  29. data/spec/cassettes/Notu_LovedTracks/_each/returns_some_tracks.yml +5113 -0
  30. data/spec/cassettes/Notu_LovedTracks/_page_urls/is_correct.yml +5088 -0
  31. data/spec/cassettes/Notu_LovedTracks/_pages_count/is_correct.yml +2546 -0
  32. data/spec/cassettes/Notu_MostPlayedTracks/_each/returns_nil.yml +6532 -0
  33. data/spec/cassettes/Notu_MostPlayedTracks/_each/returns_some_tracks.yml +13455 -0
  34. data/spec/notu/error_spec.rb +40 -0
  35. data/spec/notu/html_document_spec.rb +31 -0
  36. data/spec/notu/http_download_spec.rb +39 -0
  37. data/spec/notu/library_spec.rb +130 -0
  38. data/spec/notu/loved_tracks_spec.rb +61 -0
  39. data/spec/notu/most_played_tracks_spec.rb +64 -0
  40. data/spec/notu/network_error_spec.rb +15 -0
  41. data/spec/notu/parse_error_spec.rb +15 -0
  42. data/spec/notu/track_spec.rb +67 -0
  43. data/spec/spec_helper.rb +10 -0
  44. data/spec/support/vcr.rb +8 -0
  45. metadata +252 -0
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::Error do
4
+
5
+ let(:error) { Notu::Error.new('BAM!') }
6
+ let(:original) { StandardError.new('BIM!') }
7
+
8
+ describe '#message' do
9
+
10
+ it 'is message set at initialization' do
11
+ expect(error.message).to eq('BAM!')
12
+ end
13
+
14
+ it 'message is squished' do
15
+ expect(Notu::Error.new(" hello \n world").message).to eq('hello world')
16
+ end
17
+
18
+ it 'default one if blank' do
19
+ expect(Notu::Error.new(" ").message).to eq('Notu::Error')
20
+ end
21
+
22
+ end
23
+
24
+ describe '#original' do
25
+
26
+ it 'is nil by default' do
27
+ expect(error.original).to be_nil
28
+ end
29
+
30
+ it 'is exception given at initialization' do
31
+ expect(Notu::Error.new(original).original).to be(original)
32
+ end
33
+
34
+ it 'sets message from original' do
35
+ expect(Notu::Error.new(original).message).to eq('BIM!')
36
+ end
37
+
38
+ end
39
+
40
+ end
@@ -0,0 +1,31 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::HtmlDocument, :vcr do
4
+
5
+ describe '.get' do
6
+
7
+ it 'returns document parsed' do
8
+ document = Notu::HtmlDocument.get('http://alweb.org')
9
+ expect((document/'title').text).to eq('Alexis Toulotte')
10
+ end
11
+
12
+ it 'follows redirects' do
13
+ document = Notu::HtmlDocument.get('http://www.alweb.org')
14
+ expect((document/'title').text).to eq('Alexis Toulotte')
15
+ end
16
+
17
+ it 'raise a NetworkError on 404' do
18
+ expect {
19
+ Notu::HtmlDocument.get('http://alweb.org/foo')
20
+ }.to raise_error(Notu::NetworkError, '404 "Not Found"')
21
+ end
22
+
23
+ it 'raise a ParseError if not a valid document' do
24
+ expect {
25
+ Notu::HtmlDocument.get('http://alweb.org/avatar')
26
+ }.to raise_error(Notu::ParseError, 'Invalid HTML document')
27
+ end
28
+
29
+ end
30
+
31
+ end
@@ -0,0 +1,39 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::HttpDownload, :vcr do
4
+
5
+ describe '.get' do
6
+
7
+ it 'retrives document from given URL' do
8
+ expect(Notu::HttpDownload.get('http://alweb.org')).to include('<title>Alexis Toulotte</title>')
9
+ end
10
+
11
+ it 'accepts HTTPS URL' do
12
+ expect(Notu::HttpDownload.get('https://alweb.org')).to include('<title>Alexis Toulotte</title>')
13
+ end
14
+
15
+ it 'follow redirects' do
16
+ expect(Notu::HttpDownload.get('http://www.alweb.org')).to include('<title>Alexis Toulotte</title>')
17
+ end
18
+
19
+ it 'raise an error if an invalid URL is given' do
20
+ expect {
21
+ Notu::HttpDownload.get('ftp://www.alweb.org')
22
+ }.to raise_error(Notu::NetworkError, 'Invalid URL: "ftp://www.alweb.org"')
23
+ end
24
+
25
+ it 'raise a NetworkError on 404' do
26
+ expect {
27
+ Notu::HttpDownload.get('http://alweb.org/foo', max_retries: 0)
28
+ }.to raise_error(Notu::NetworkError, '404 "Not Found"')
29
+ end
30
+
31
+ it 'raise a NetworkError if too many redirects' do
32
+ expect {
33
+ Notu::HttpDownload.get('http://www.alweb.org', max_redirects: 0, max_retries: 0)
34
+ }.to raise_error(Notu::NetworkError, 'Max redirects has been reached')
35
+ end
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,130 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::Library do
4
+
5
+ let(:library) { Notu::Library.new(username: 'alexistoulotte') }
6
+
7
+ describe '#host' do
8
+
9
+ it 'is "www.last.fm" by default' do
10
+ expect(library.host).to eq('www.last.fm')
11
+ end
12
+
13
+ it 'can be specified via option' do
14
+ expect(Notu::Library.new(host: 'www.lastfm.fr', username: 'alex').host).to eq('www.lastfm.fr')
15
+ end
16
+
17
+ it 'can be specified via option (as string)' do
18
+ expect(Notu::Library.new('host' => 'www.lastfm.fr', username: 'alex').host).to eq('www.lastfm.fr')
19
+ end
20
+
21
+ it 'is default host if blank' do
22
+ expect(Notu::Library.new(host: ' ', username: 'alex').host).to eq('www.last.fm')
23
+ end
24
+
25
+ end
26
+
27
+ describe '#loved_tracks' do
28
+
29
+ it 'returns a LovedTracks object' do
30
+ expect(library.loved_tracks).to be_a(Notu::LovedTracks)
31
+ end
32
+
33
+ end
34
+
35
+ describe '#most_played_tracks' do
36
+
37
+ it 'returns a LovedTracks object' do
38
+ most_played_tracks = library.most_played_tracks
39
+ expect(most_played_tracks).to be_a(Notu::MostPlayedTracks)
40
+ expect(most_played_tracks.period).to eq('last_week')
41
+ end
42
+
43
+ it 'accepts options' do
44
+ expect(library.most_played_tracks(period: 'last_month').period).to eq('last_month')
45
+ end
46
+
47
+ end
48
+
49
+ describe '#username' do
50
+
51
+ it 'is username set at initialization' do
52
+ expect(library.username).to eq('alexistoulotte')
53
+ end
54
+
55
+ it 'can be specified as string' do
56
+ expect(Notu::Library.new('username' => 'john42').username).to eq('john42')
57
+ end
58
+
59
+ it 'raise an error if nil' do
60
+ expect {
61
+ Notu::Library.new(username: nil)
62
+ }.to raise_error(Notu::Error, 'Invalid Last.fm username: nil')
63
+ end
64
+
65
+ it 'raise an error if blank' do
66
+ expect {
67
+ Notu::Library.new(username: ' ')
68
+ }.to raise_error(Notu::Error, 'Invalid Last.fm username: " "')
69
+ end
70
+
71
+ it 'raise an error if it contains spaces' do
72
+ expect {
73
+ Notu::Library.new(username: 'alexis toulotte')
74
+ }.to raise_error(Notu::Error, 'Invalid Last.fm username: "alexis toulotte"')
75
+ end
76
+
77
+ it 'raise an error if invalid' do
78
+ expect {
79
+ Notu::Library.new(username: 'alex$')
80
+ }.to raise_error(Notu::Error, 'Invalid Last.fm username: "alex$"')
81
+
82
+ expect {
83
+ Notu::Library.new(username: 'ALex^')
84
+ }.to raise_error(Notu::Error, 'Invalid Last.fm username: "ALex^"')
85
+ end
86
+
87
+ it 'is stripped' do
88
+ expect(Notu::Library.new(username: " alexis42 \n").username).to eq('alexis42')
89
+ end
90
+
91
+ it 'is downcased' do
92
+ expect(Notu::Library.new(username: 'AlexIsT').username).to eq('alexist')
93
+ end
94
+
95
+ end
96
+
97
+ describe '#url' do
98
+
99
+ it 'returns default url if path not given' do
100
+ expect(library.url).to eq('http://www.last.fm/user/alexistoulotte')
101
+ end
102
+
103
+ it 'returns default url if path is blank' do
104
+ expect(library.url(path: ' ')).to eq('http://www.last.fm/user/alexistoulotte')
105
+ end
106
+
107
+ it 'accepts path option as string' do
108
+ expect(library.url('path' => '/library/loved')).to eq('http://www.last.fm/user/alexistoulotte/library/loved')
109
+ end
110
+
111
+ it 'returns URL and path if given' do
112
+ expect(library.url(path: '/library/loved')).to eq('http://www.last.fm/user/alexistoulotte/library/loved')
113
+ end
114
+
115
+ it 'adds first / to given path' do
116
+ expect(library.url(path: 'library/loved')).to eq('http://www.last.fm/user/alexistoulotte/library/loved')
117
+ end
118
+
119
+ it 'use :host option set at initialization' do
120
+ library = Notu::Library.new(host: 'www.lastfm.fr', username: 'albundy02')
121
+ expect(library.url).to eq('http://www.lastfm.fr/user/albundy02')
122
+ end
123
+
124
+ it 'accepts query option' do
125
+ expect(library.url(query: { bar: 42, 'baz' => 'hello&world' })).to eq('http://www.last.fm/user/alexistoulotte?bar=42&baz=hello%26world')
126
+ end
127
+
128
+ end
129
+
130
+ end
@@ -0,0 +1,61 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::LovedTracks, :vcr do
4
+
5
+ let(:library) { Notu::Library.new(username: 'alexistoulotte') }
6
+ let(:loved_tracks) { Notu::LovedTracks.new(library) }
7
+
8
+ describe '#each' do
9
+
10
+ it 'returns some tracks' do
11
+ tracks = loved_tracks.take(42)
12
+ expect(tracks.size).to eq(42)
13
+ tracks.each do |track|
14
+ expect(track).to be_a(Notu::Track)
15
+ expect(track.artist).to be_present
16
+ expect(track.plays_count).to be_nil
17
+ expect(track.title).to be_present
18
+ end
19
+ end
20
+
21
+ it 'returns nil' do
22
+ allow(loved_tracks).to receive(:pages_count).and_return(1)
23
+ expect(loved_tracks.each {}).to be_nil
24
+ end
25
+
26
+ end
27
+
28
+ describe '#library' do
29
+
30
+ it 'is library given at initialization' do
31
+ expect(loved_tracks.library).to be(library)
32
+ end
33
+
34
+ it 'raise an error if library is nil' do
35
+ expect {
36
+ Notu::LovedTracks.new(nil)
37
+ }.to raise_error(ArgumentError, 'Notu::LovedTracks#library must be a library, nil given')
38
+ end
39
+
40
+ end
41
+
42
+ describe '#page_urls' do
43
+
44
+ it 'is correct' do
45
+ urls = loved_tracks.send(:page_urls)
46
+ expect(urls.size).to eq(loved_tracks.send(:pages_count))
47
+ expect(urls).to include('http://www.last.fm/user/alexistoulotte/library/loved?sortBy=date&sortOrder=desc&page=12')
48
+ expect(urls).to include('http://www.last.fm/user/alexistoulotte/library/loved?sortBy=date&sortOrder=desc&page=3')
49
+ end
50
+
51
+ end
52
+
53
+ describe '#pages_count' do
54
+
55
+ it 'is correct' do
56
+ expect(loved_tracks.send(:pages_count)).to be_within(10).of(30)
57
+ end
58
+
59
+ end
60
+
61
+ end
@@ -0,0 +1,64 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::MostPlayedTracks, :vcr do
4
+
5
+ let(:library) { Notu::Library.new(username: 'alexistoulotte') }
6
+ let(:most_played_tracks) { Notu::MostPlayedTracks.new(library) }
7
+
8
+ describe '#library' do
9
+
10
+ it 'is library given at initialization' do
11
+ expect(most_played_tracks.library).to be(library)
12
+ end
13
+
14
+ it 'raise an error if library is nil' do
15
+ expect {
16
+ Notu::MostPlayedTracks.new(nil)
17
+ }.to raise_error(ArgumentError, 'Notu::MostPlayedTracks#library must be a library, nil given')
18
+ end
19
+
20
+ end
21
+
22
+ describe '#each' do
23
+
24
+ it 'returns some tracks' do
25
+ allow(most_played_tracks).to receive(:period).and_return('last_month')
26
+ tracks = most_played_tracks.take(28)
27
+ expect(tracks.size).to eq(28)
28
+ tracks.each do |track|
29
+ expect(track).to be_a(Notu::Track)
30
+ expect(track.artist).to be_present
31
+ expect(track.plays_count).to be > 0
32
+ expect(track.title).to be_present
33
+ end
34
+ end
35
+
36
+ it 'returns nil' do
37
+ expect(most_played_tracks.each {}).to be_nil
38
+ end
39
+
40
+ end
41
+
42
+ describe '#period' do
43
+
44
+ it 'is "last_week" by default' do
45
+ expect(most_played_tracks.period).to eq('last_week')
46
+ end
47
+
48
+ it 'can be specified via option' do
49
+ expect(Notu::MostPlayedTracks.new(library, period: 'last_6_months').period).to eq('last_6_months')
50
+ end
51
+
52
+ it 'can be specified via option (as string)' do
53
+ expect(Notu::MostPlayedTracks.new(library, 'period' => 'last_6_months').period).to eq('last_6_months')
54
+ end
55
+
56
+ it 'raise an error if invalid' do
57
+ expect {
58
+ Notu::MostPlayedTracks.new(library, period: 'foo')
59
+ }.to raise_error(ArgumentError, 'Notu::MostPlayedTracks#period is invalid: "foo"')
60
+ end
61
+
62
+ end
63
+
64
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::NetworkError do
4
+
5
+ let(:error) { Notu::NetworkError.new('BAM!') }
6
+
7
+ describe '#message' do
8
+
9
+ it 'is message set at initialization' do
10
+ expect(error.message).to eq('BAM!')
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::ParseError do
4
+
5
+ let(:error) { Notu::ParseError.new('BAM!') }
6
+
7
+ describe '#message' do
8
+
9
+ it 'is message set at initialization' do
10
+ expect(error.message).to eq('BAM!')
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,67 @@
1
+ require 'spec_helper'
2
+
3
+ describe Notu::Track do
4
+
5
+ let(:track) { Notu::Track.new(artist: 'Serial Killaz', title: 'Good Enough') }
6
+
7
+ describe '#artist' do
8
+
9
+ it 'is value set at initialization' do
10
+ expect(track.artist).to eq('Serial Killaz')
11
+ end
12
+
13
+ it 'is squished' do
14
+ expect(Notu::Track.new(artist: 'Serial Killaz ', title: 'Good Enough').artist).to eq('Serial Killaz')
15
+ end
16
+
17
+ it 'raise an error if blank' do
18
+ expect {
19
+ Notu::Track.new(artist: ' ', title: 'Good Enough')
20
+ }.to raise_error(Notu::Error, 'Notu::Track#artist must be specified, " " given')
21
+ end
22
+
23
+ end
24
+
25
+ describe '#plays_count' do
26
+
27
+ it 'is nil by default' do
28
+ expect(track.plays_count).to be_nil
29
+ end
30
+
31
+ it 'can be specified' do
32
+ expect(Notu::Track.new(artist: 'Serial Killaz', plays_count: 42, title: 'Good Enough').plays_count).to eq(42)
33
+ end
34
+
35
+ it 'can be specified (as string)' do
36
+ expect(Notu::Track.new(artist: 'Serial Killaz', plays_count: '42', title: 'Good Enough').plays_count).to eq(42)
37
+ end
38
+
39
+ it 'is nil if invalid' do
40
+ expect(Notu::Track.new(artist: 'Serial Killaz', plays_count: 'foo', title: 'Good Enough').plays_count).to be_nil
41
+ end
42
+
43
+ it 'is 0 if negatve' do
44
+ expect(Notu::Track.new(artist: 'Serial Killaz', plays_count: -1, title: 'Good Enough').plays_count).to eq(0)
45
+ end
46
+
47
+ end
48
+
49
+ describe '#title' do
50
+
51
+ it 'is value set at initialization' do
52
+ expect(track.title).to eq('Good Enough')
53
+ end
54
+
55
+ it 'is squished' do
56
+ expect(Notu::Track.new(artist: 'Serial Killaz', title: ' Good Enough').title).to eq('Good Enough')
57
+ end
58
+
59
+ it 'raise an error if blank' do
60
+ expect {
61
+ Notu::Track.new(artist: 'Serial Killaz', title: ' ')
62
+ }.to raise_error(Notu::Error, 'Notu::Track#title must be specified, " " given')
63
+ end
64
+
65
+ end
66
+
67
+ end