bassnode-ruby-echonest 0.1.2

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.
@@ -0,0 +1,110 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'spec_helper'
4
+
5
+ include SpecHelper
6
+
7
+ describe Echonest::Analysis do
8
+ before do
9
+ @analysis = Echonest::Analysis.new(open(fixture('analysis.json')).read)
10
+ end
11
+
12
+ it "should have beats" do
13
+ beats = @analysis.beats
14
+
15
+ beats.size.should eql(324)
16
+ beats.first.start.should eql(0.27661)
17
+ beats.first.duration.should eql(0.36476)
18
+ beats.first.confidence.should eql(0.468)
19
+ end
20
+
21
+ it "should have segments" do
22
+ segments = @analysis.segments
23
+ segment = segments.first
24
+
25
+ segments.size.should eql(274)
26
+ segment.start.should eql(0.0)
27
+ segment.duration.should eql(0.43909)
28
+ segment.confidence.should eql(1.0)
29
+ segment.loudness.time.should eql(0.0)
30
+ segment.loudness.value.should eql(-60.0)
31
+ segment.max_loudness.time.should eql(0.11238)
32
+ segment.max_loudness.value.should eql(-33.563)
33
+ segment.pitches.size.should eql(12)
34
+ segment.pitches.first.should eql(0.138)
35
+ segment.timbre.size.should eql(12)
36
+ segment.timbre.first.should eql(11.525)
37
+ end
38
+
39
+ it "should have bars" do
40
+ bars = @analysis.bars
41
+
42
+ bars.size.should eql(80)
43
+ bars.first.start.should eql(1.00704)
44
+ bars.first.duration.should eql(1.48532)
45
+ bars.first.confidence.should eql(0.188)
46
+ end
47
+
48
+ it "should have tempo" do
49
+ @analysis.tempo.should eql(168.460)
50
+ end
51
+
52
+ it "should have sections" do
53
+ sections = @analysis.sections
54
+ section = sections.first
55
+
56
+ sections.size.should eql(7)
57
+ section.start.should eql(0.0)
58
+ section.duration.should eql(20.04271)
59
+ section.confidence.should eql(1.0)
60
+ end
61
+
62
+ it "should have durtion" do
63
+ @analysis.duration.should eql(120.68526)
64
+ end
65
+
66
+ it "should have end of fade in" do
67
+ @analysis.end_of_fade_in.should eql(0.0)
68
+ end
69
+
70
+ it "should have start of fade out" do
71
+ @analysis.start_of_fade_out.should eql(113.557)
72
+ end
73
+
74
+ it "should have key" do
75
+ @analysis.key.should eql(7)
76
+ end
77
+
78
+ it "should derive key letter from key" do
79
+ @analysis.key_letter.should eql(Echonest::Analysis::CHROMATIC[7])
80
+ end
81
+
82
+ it "should have loudness" do
83
+ @analysis.loudness.should eql(-19.140)
84
+ end
85
+
86
+ it "should have mode" do
87
+ @analysis.mode.should eql(1)
88
+ end
89
+
90
+ it "should derive major? from mode" do
91
+ @analysis.major?.should eql(true)
92
+ end
93
+
94
+ it "should derive minor? from mode" do
95
+ @analysis.minor?.should eql(false)
96
+ end
97
+
98
+ it "should have time signature" do
99
+ @analysis.time_signature.should eql(4)
100
+ end
101
+
102
+ it "should have tatums" do
103
+ tatums = @analysis.tatums
104
+
105
+ tatums.size.should eql(648)
106
+ tatums.first.start.should eql(0.09469)
107
+ tatums.first.duration.should eql(0.18193)
108
+ tatums.first.confidence.should eql(0.286)
109
+ end
110
+ end
data/spec/api_spec.rb ADDED
@@ -0,0 +1,144 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'spec_helper'
4
+ require "echonest"
5
+
6
+ include SpecHelper
7
+
8
+ describe Echonest::Api do
9
+ before do
10
+ @api = Echonest::Api.new('8TPE3VC60ODJTNTFE')
11
+ end
12
+
13
+ it "should build parameters" do
14
+ params = @api.build_params(:id => 'TRXXHTJ1294CD8F3B3')
15
+ params.keys.size.should eql(3)
16
+ params[:api_key].should eql('8TPE3VC60ODJTNTFE')
17
+ params[:id].should eql('TRXXHTJ1294CD8F3B3')
18
+ params[:format].should eql('json')
19
+ end
20
+
21
+ it "should build parameters to list" do
22
+ params = @api.build_params_to_list(:id => 'TRXXHTJ1294CD8F3B3')
23
+ params.length.should eql(3)
24
+ params[0].should eql(['id', 'TRXXHTJ1294CD8F3B3'])
25
+ params.should be_include(['api_key', '8TPE3VC60ODJTNTFE'])
26
+ params.should be_include(['format', 'json'])
27
+ end
28
+
29
+ it "should pass arguments to user agent" do
30
+ @api.user_agent.should_receive(:get_content).
31
+ with(
32
+ URI('http://developer.echonest.com/api/v4/xxx/yyy'),
33
+ [
34
+ ['foo', 'bar'],
35
+ ['api_key', '8TPE3VC60ODJTNTFE'],
36
+ ['format', 'json']
37
+ ]).and_return(open(fixture('profile.json')).read)
38
+
39
+ @api.request('xxx/yyy', :get, :foo => 'bar')
40
+ end
41
+
42
+ it "should pass arguments including a file to user agent" do
43
+ file = open(fixture('sample.mp3'))
44
+ file.should_receive(:read).and_return('content')
45
+
46
+
47
+ @api.user_agent.should_receive(:post_async).
48
+ with(
49
+ URI('http://developer.echonest.com/api/v4/xxx/zzz?api_key=8TPE3VC60ODJTNTFE&bar=baz&format=json'),
50
+ 'content',
51
+ {
52
+ 'Content-Type' => 'application/octet-stream'
53
+ }).and_return(open(fixture('profile.json')).read)
54
+
55
+ @api.request('xxx/zzz', :post, { :bar => 'baz' }, file)
56
+ end
57
+
58
+ it "should call api method" do
59
+ content = open(fixture('profile.json')).read
60
+
61
+ make_connection_stub(content, :post)
62
+ response = @api.request('track/profile', :post, :id => 'TRXXHTJ1294CD8F3B3')
63
+ response.should be_success
64
+ response.body.status.version.should eql("4.2")
65
+ end
66
+
67
+ it "should raise error when api method call was failed" do
68
+ make_connection_stub(open(fixture('profile_failure.json')).read, :post)
69
+
70
+ lambda {
71
+ @api.request('track/profile', :post, :id => 'TRXXHTJ1294CD8F3B3')
72
+ }.should raise_error(Echonest::Api::Error, 'api_key - Invalid key: "XXXXX" is not a valid, active api key')
73
+ end
74
+
75
+ it "should raise error when unknown api method was called" do
76
+ @api.user_agent.stub!('get_content').and_raise(HTTPClient::BadResponseError.new('error message'))
77
+
78
+ lambda {
79
+ @api.request('track/xxxx', :get, :id => 'TRXXHTJ1294CD8F3B3')
80
+ }.should raise_error(Echonest::Api::Error, 'track/xxxx: error message')
81
+ end
82
+
83
+ it "should make http request with agent name" do
84
+ @api.user_agent.agent_name.should eql('ruby-echonest/' + Echonest::VERSION)
85
+ end
86
+
87
+ describe '#track' do
88
+ it 'should return track methods' do
89
+ track = @api.track
90
+ track.class.should eql(Echonest::ApiMethods::Track)
91
+ track.instance_eval { @api }.should eql(@api)
92
+ end
93
+ end
94
+
95
+ describe '#artist' do
96
+ it 'should return artist methods' do
97
+ artist = @api.artist('Weezer')
98
+ artist.class.should eql(Echonest::ApiMethods::Artist)
99
+ artist.instance_eval {@api}.should eql(@api)
100
+ end
101
+
102
+ it 'should return artist methods even artist name was empty' do
103
+ artist = @api.artist
104
+ artist.class.should eql(Echonest::ApiMethods::Artist)
105
+ artist.instance_eval {@api}.should eql(@api)
106
+ end
107
+ end
108
+
109
+ describe '#song' do
110
+ it 'should return song methods' do
111
+ song = @api.song
112
+ song.class.should eql(Echonest::ApiMethods::Song)
113
+ song.instance_eval {@api}.should eql(@api)
114
+ end
115
+ end
116
+
117
+ describe '#playlist' do
118
+ it 'should return playlist methods' do
119
+ playlist = @api.playlist
120
+ playlist.class.should eql(Echonest::ApiMethods::Playlist)
121
+ playlist.instance_eval {@api}.should eql(@api)
122
+ end
123
+ end
124
+
125
+ it 'should have traditional API methods' do
126
+ filename = fixture('sample.mp3')
127
+ analysis = Echonest::Analysis.new(open(fixture('analysis.json')).read)
128
+ track = Echonest::ApiMethods::Track.new(@api)
129
+
130
+ %w/tempo duration end_of_fade_in key loudness mode start_of_fade_out time_signature bars beats sections tatums segments/.
131
+ each do |method|
132
+
133
+ @api.should_receive(:track).and_return(track)
134
+ track.should_receive(:analysis).with(filename).and_return(analysis)
135
+ analysis.should_receive(method.to_sym)
136
+
137
+ @api.send('get_' + method, filename)
138
+ end
139
+ end
140
+
141
+ def make_connection_stub(content, method)
142
+ @api.user_agent.stub!(method.to_s + '_content').and_return(content)
143
+ end
144
+ end
@@ -0,0 +1,207 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'spec_helper'
4
+ require "echonest"
5
+
6
+ include SpecHelper
7
+
8
+ describe Echonest::ApiMethods::Base do
9
+ before do
10
+ @api = Echonest::Api.new('8TPE3VC60ODJTNTFE')
11
+ @base = Echonest::ApiMethods::Base.new(@api)
12
+ end
13
+
14
+ it "should call @api.request" do
15
+ @api.should_receive(:request).with(:get, 'method_foo', {:hash => 'paramerter'})
16
+ @base.request(:get, 'method_foo', {:hash => 'paramerter'})
17
+ end
18
+
19
+ describe ".build_params_with_validation" do
20
+ it "should pass validation for required key" do
21
+ args = {
22
+ :required => {
23
+ :key1 => 'value1',
24
+ },
25
+ }
26
+ Echonest::ApiMethods::Base.build_params_with_validation(
27
+ args,
28
+ %w[key1],
29
+ [],
30
+ []).should == {:key1 => 'value1'}
31
+ end
32
+
33
+ it "should raise error if required key not exist in parametor" do
34
+ lambda {
35
+ args = {
36
+ :required => {
37
+ :key2 => 'value2',
38
+ },
39
+ }
40
+ Echonest::ApiMethods::Base.build_params_with_validation(
41
+ args,
42
+ %w[key1],
43
+ [],
44
+ [])
45
+ }.should raise_error(ArgumentError, 'key1 is required')
46
+ end
47
+
48
+ it "should pass validation for required_any key" do
49
+ args = {
50
+ :required_any => {
51
+ :key1 => 'value1',
52
+ },
53
+ }
54
+ Echonest::ApiMethods::Base.build_params_with_validation(
55
+ args,
56
+ [],
57
+ %w[key1 key2],
58
+ []).should == {:key1 => 'value1'}
59
+
60
+ args = {
61
+ :required_any => {
62
+ :key2 => 'value2',
63
+ },
64
+ }
65
+ Echonest::ApiMethods::Base.build_params_with_validation(
66
+ args,
67
+ [],
68
+ %w[key1 key2],
69
+ []).should == {:key2 => 'value2'}
70
+ end
71
+
72
+ it "should raise error if required_any key not exist in parametor" do
73
+ lambda {
74
+ args = {
75
+ :required_any => {
76
+ :key3 => 'value3',
77
+ },
78
+ }
79
+ Echonest::ApiMethods::Base.build_params_with_validation(
80
+ args,
81
+ [],
82
+ %w[key1 key2],
83
+ [])
84
+ }.should raise_error(ArgumentError, 'key1 or key2 is required')
85
+ end
86
+
87
+ it "should pass validation for option key" do
88
+ args = {
89
+ :option => {
90
+ :key1 => 'value1',
91
+ },
92
+ }
93
+ Echonest::ApiMethods::Base.build_params_with_validation(
94
+ args,
95
+ [],
96
+ [],
97
+ %w[key1 key2]).should == {:key1 => 'value1'}
98
+ end
99
+
100
+ it "should empty hash for option if keys for option not exist in parametor" do
101
+ args = {
102
+ :option => {
103
+ :key3 => 'value3',
104
+ },
105
+ }
106
+ Echonest::ApiMethods::Base.build_params_with_validation(
107
+ args,
108
+ [],
109
+ [],
110
+ %w[key1 key2]).should == {}
111
+ end
112
+
113
+ it "should pass validation for required, required_any and option keys" do
114
+ args = {
115
+ :required => {
116
+ :key1 => 'value1',
117
+ },
118
+ :required_any => {
119
+ :key3 => 'value3',
120
+ },
121
+ :option => {
122
+ :key4 => 'value4',
123
+ :key5 => 'value5',
124
+ },
125
+ }
126
+ Echonest::ApiMethods::Base.build_params_with_validation(
127
+ args,
128
+ %w[key1],
129
+ %w[key2 key3],
130
+ %w[key4 key5 key6]).should == {
131
+ :key1 => 'value1',
132
+ :key3 => 'value3',
133
+ :key4 => 'value4',
134
+ :key5 => 'value5',
135
+ }
136
+ end
137
+ end
138
+
139
+ describe ".validator" do
140
+ it "should return Proc instance" do
141
+ Echonest::ApiMethods::Base.validator(%w[required], %w[required_any], %w[option]).should be_an_instance_of(Proc)
142
+ end
143
+ end
144
+
145
+ describe ".method_with_option" do
146
+ before do
147
+ class FooBar < Echonest::ApiMethods::Base
148
+ end
149
+ @foobar = FooBar.new('dummy')
150
+ end
151
+
152
+ it "should define_method with option parametor" do
153
+ @foobar.class.class_eval do
154
+ def request(p1, p2, p3)
155
+ p1.should == 'foobar/baz'
156
+ p2.should == :get
157
+ p3.should == {:k1 => 'v1'}
158
+ 'test response'
159
+ end
160
+
161
+ method_with_option('baz', %w[k1 k2]) do |response|
162
+ response.should == 'test response'
163
+ end
164
+ end
165
+
166
+ @foobar.baz(:k1 => 'v1')
167
+ end
168
+ end
169
+
170
+ describe ".method_with_required_any" do
171
+ before do
172
+ class FooBar < Echonest::ApiMethods::Base
173
+ end
174
+ @foobar = FooBar.new('dummy')
175
+ end
176
+
177
+ it "should define_method with option parametor" do
178
+ @foobar.class.class_eval do
179
+ def request(p1, p2, p3)
180
+ p1.should == 'category/baz'
181
+ p2.should == :get
182
+ p3.should == {
183
+ :rk1 => 'rv1',
184
+ :rak1 => 'ravv1',
185
+ :ok1 => 'ov1'
186
+ }
187
+ 'test response'
188
+ end
189
+
190
+ method_with_required_any(
191
+ 'Category',
192
+ 'baz',
193
+ :get,
194
+ %w[rk1],
195
+ %w[rak1 rak2],
196
+ %w[ok1 ok2],
197
+ lambda{|s| {:rak1 => 'ravv1'}},
198
+ lambda{|response| response.should == 'test response'})
199
+ end
200
+
201
+ @foobar.baz(
202
+ :rk1 => 'rv1',
203
+ :ok1 => 'ov1')
204
+ end
205
+ end
206
+
207
+ end
@@ -0,0 +1,184 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'spec_helper'
4
+ require "echonest"
5
+
6
+ include SpecHelper
7
+
8
+ describe Echonest::ApiMethods::Artist do
9
+ before do
10
+ @api = Echonest::Api.new('8TPE3VC60ODJTNTFE')
11
+ @artist = Echonest::ApiMethods::Artist.new(@api)
12
+ end
13
+
14
+ def self.describe_bundle_for_artist(method, options=nil)
15
+ describe "#{method}" do
16
+ it "should request to artist/#{method} with name" do
17
+ @api.should_receive(:request).with(
18
+ "artist/#{method}",
19
+ :get,
20
+ :name => 'Weezer').and_return{ Echonest::Response.new('{"hello":"world"}') }
21
+
22
+ @artist.artist_name = 'Weezer'
23
+ @artist.send(method)
24
+ end
25
+
26
+ it "should request to artist/#{method} with id" do
27
+ @api.should_receive(:request).with(
28
+ "artist/#{method}",
29
+ :get,
30
+ :id => '1234').and_return{ Echonest::Response.new('{"hello":"world"}') }
31
+
32
+ @artist.artist_id = '1234'
33
+ @artist.send(method)
34
+ end
35
+
36
+ it "should request to artist/#{method} with option" do
37
+ options.each do |opt|
38
+ @api.should_receive(:request).with(
39
+ "artist/#{method}",
40
+ :get,
41
+ opt.merge(:name => 'Weezer')).and_return{ Echonest::Response.new('{"hello":"world"}') }
42
+
43
+ @artist.artist_name = 'Weezer'
44
+ @artist.send(method, opt)
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def self.describe_bundle_for_option(method, options=nil)
51
+ describe "#{method}" do
52
+ it "should request to artist/#{method}" do
53
+ @api.should_receive(:request).with(
54
+ "artist/#{method}",
55
+ :get,
56
+ {}).and_return{ Echonest::Response.new('{"hello":"world"}') }
57
+
58
+ @artist.send(method)
59
+ end
60
+
61
+ it "should request to artist/#{method} with option" do
62
+ options.each do |opt|
63
+ @api.should_receive(:request).with(
64
+ "artist/#{method}",
65
+ :get,
66
+ opt).and_return{ Echonest::Response.new('{"hello":"world"}') }
67
+
68
+ @artist.send(method, opt)
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ describe_bundle_for_artist('audio', [
75
+ {:format => 'json'},
76
+ {:format => 'json', :results => 100},
77
+ {:format => 'json', :results => 100, :start => 20}
78
+ ])
79
+
80
+ describe_bundle_for_artist('biographies', [
81
+ {:format => 'json'},
82
+ {:format => 'json', :results => 100},
83
+ {:format => 'json', :results => 100, :start => 20},
84
+
85
+ {:format => 'json', :results => 100, :start => 20, :license => 'echo-source'},
86
+ {:format => 'json', :results => 100, :start => 20, :license => ['echo-source', 'cc-by-nc']}
87
+ ])
88
+
89
+ describe_bundle_for_artist('blogs', [
90
+ {:format => 'json'},
91
+ {:format => 'json', :results => 100},
92
+ {:format => 'json', :results => 100, :start => 20}
93
+ ])
94
+
95
+ describe_bundle_for_artist('familiarity', [
96
+ {:format => 'json'},
97
+ {:format => 'json', :results => 100},
98
+ {:format => 'json', :results => 100, :start => 20}
99
+ ])
100
+
101
+ describe_bundle_for_artist('hotttnesss', [
102
+ {:format => 'json'},
103
+ {:format => 'json', :results => 100},
104
+ {:format => 'json', :results => 100, :start => 20}
105
+ ])
106
+
107
+ describe_bundle_for_artist('images', [
108
+ {:format => 'json'},
109
+ {:format => 'json', :results => 100},
110
+ {:format => 'json', :results => 100, :start => 20},
111
+ {:format => 'json', :results => 100, :start => 20, :license => 'echo-source'},
112
+ {:format => 'json', :results => 100, :start => 20, :license => ['echo-source', 'cc-by-nc']}
113
+ ])
114
+
115
+ describe_bundle_for_artist('news', [
116
+ {:format => 'json'},
117
+ {:format => 'json', :results => 100},
118
+ {:format => 'json', :results => 100, :start => 20}
119
+ ])
120
+
121
+ describe_bundle_for_artist('profile', [
122
+ {:format => 'json'},
123
+ {:format => 'json', :results => 100},
124
+ {:format => 'json', :results => 100, :start => 20},
125
+ {:format => 'json', :results => 100, :start => 20, :bucket => 'audio'},
126
+ {:format => 'json', :results => 100, :start => 20, :bucket => ['audio', 'video']}
127
+ ])
128
+
129
+ describe_bundle_for_artist('reviews', [
130
+ {:format => 'json'},
131
+ {:format => 'json', :results => 100},
132
+ {:format => 'json', :results => 100, :start => 20}
133
+ ])
134
+
135
+ describe_bundle_for_option('search', [
136
+ {:format => 'json'},
137
+ {:format => 'json', :results => 100},
138
+ {:format => 'json', :results => 100, :bucket => 'audio'},
139
+ {:format => 'json', :results => 100, :bucket => %w[audio biographies blogs id:musicbrainz]}
140
+ ])
141
+
142
+ describe_bundle_for_artist('songs', [
143
+ {:format => 'json'},
144
+ {:format => 'json', :results => 100},
145
+ {:format => 'json', :results => 100, :bucket => 'audio'},
146
+ {:format => 'json', :results => 100, :bucket => %w[audio biographies blogs id:musicbrainz]}
147
+ ])
148
+
149
+ describe_bundle_for_artist('similar', [
150
+ {:format => 'json'},
151
+ {:format => 'json', :results => 100},
152
+ {:format => 'json', :results => 100, :max_familiarity => 0.9},
153
+ {:format => 'json', :results => 100, :bucket => 'audio'},
154
+ {:format => 'json', :results => 100, :bucket => %w[audio biographies blogs id:musicbrainz]}
155
+ ])
156
+
157
+ describe_bundle_for_artist('terms', [
158
+ {:format => 'json'},
159
+ {:format => 'json', :sort => 'weight'}
160
+ ])
161
+
162
+ describe_bundle_for_option('top_hottt', [
163
+ {:format => 'json'},
164
+ {:format => 'json', :results => 100},
165
+ {:format => 'json', :results => 100, :type => 'normal'},
166
+ {:format => 'json', :results => 100, :bucket => 'audio'},
167
+ {:format => 'json', :results => 100, :bucket => %w[audio biographies blogs id:musicbrainz]}
168
+ ])
169
+
170
+ describe_bundle_for_option('top_terms', [
171
+ {:format => 'json'},
172
+ {:format => 'json', :results => 100}
173
+ ])
174
+
175
+ describe_bundle_for_artist('urls', [
176
+ {:format => 'json'}
177
+ ])
178
+
179
+ describe_bundle_for_artist('video', [
180
+ {:format => 'json'},
181
+ {:format => 'json', :results => 100},
182
+ {:format => 'json', :results => 100, :start => 20}
183
+ ])
184
+ end
@@ -0,0 +1,12 @@
1
+ $:.unshift File.dirname(__FILE__)
2
+
3
+ require 'spec_helper'
4
+ require "echonest"
5
+
6
+ include SpecHelper
7
+
8
+ describe Echonest do
9
+ it "should return an instance of Echonest::Api" do
10
+ Echonest('XXXXXXXX').should be_an_instance_of(Echonest::Api)
11
+ end
12
+ end