freesound-ruby 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.
- data/.document +5 -0
- data/.gitignore +48 -0
- data/.rspec +1 -0
- data/Gemfile +13 -0
- data/Gemfile.lock +28 -0
- data/LICENSE.txt +20 -0
- data/README.md +4 -0
- data/Rakefile +25 -0
- data/data/sample.json +45 -0
- data/data/sample.xml +46 -0
- data/data/sample.yaml +34 -0
- data/data/sample_query.json +426 -0
- data/freesound-ruby.gemspec +25 -0
- data/lib/core_ext.rb +50 -0
- data/lib/freesound.rb +58 -0
- data/lib/freesound/client.rb +27 -0
- data/lib/freesound/request.rb +27 -0
- data/lib/freesound/response.rb +27 -0
- data/lib/freesound/response_parser.rb +43 -0
- data/lib/freesound/sound.rb +10 -0
- data/lib/freesound/uri_compiler.rb +32 -0
- data/lib/freesound/version.rb +3 -0
- data/spec/core_ext_spec.rb +71 -0
- data/spec/freesound/client_spec.rb +49 -0
- data/spec/freesound/request_spec.rb +26 -0
- data/spec/freesound/response_parser_spec.rb +48 -0
- data/spec/freesound/response_spec.rb +27 -0
- data/spec/freesound/sound_spec.rb +15 -0
- data/spec/freesound/uri_compiler_spec.rb +21 -0
- data/spec/freesound_spec.rb +45 -0
- data/spec/spec_helper.rb +17 -0
- metadata +121 -0
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "freesound/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "freesound-ruby"
|
7
|
+
s.version = Freesound::VERSION
|
8
|
+
s.authors = ["Alex Genco"]
|
9
|
+
s.email = ["alexgenco@gmail.com"]
|
10
|
+
s.homepage = ""
|
11
|
+
s.summary = %q{Freesound.org API wrapper in Ruby.}
|
12
|
+
s.description = %q{Freesound.org API wrapper in Ruby.}
|
13
|
+
|
14
|
+
s.rubyforge_project = "freesound-ruby"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {spec}/*`.split("\n")
|
18
|
+
#s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency("rspec")
|
22
|
+
s.add_development_dependency("bundler", "~> 1.0.0")
|
23
|
+
s.add_development_dependency("webmock")
|
24
|
+
s.add_runtime_dependency("crack")
|
25
|
+
end
|
data/lib/core_ext.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
class Hash
|
2
|
+
def symbolize_keys
|
3
|
+
Hash[ map { |k, v| [k.to_sym, v] } ]
|
4
|
+
end
|
5
|
+
|
6
|
+
# converting xml into a hash sometimes gives you things like:
|
7
|
+
# { 'element' => ['just_one_value'] }
|
8
|
+
# this method converts this to the more useful
|
9
|
+
# { 'element' => 'just_one_value' }
|
10
|
+
def flatten_single_element_array_values
|
11
|
+
Hash[ map do |k, v|
|
12
|
+
[k, (v.is_a?(Array) && v.size == 1) ? v[0] : v]
|
13
|
+
end ]
|
14
|
+
end
|
15
|
+
|
16
|
+
# convert to a uri string
|
17
|
+
def to_uri
|
18
|
+
map { |k, v| "#{k}=#{v}" }.join("&")
|
19
|
+
end
|
20
|
+
|
21
|
+
def numberize_values
|
22
|
+
Hash[ map { |k, v| [k, ( (v.numberizeable? rescue false) ? v.numberize : v )] } ]
|
23
|
+
end
|
24
|
+
|
25
|
+
def underscore_keys
|
26
|
+
Hash[ map { |k, v| [(k.underscore rescue k), v] } ]
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
class String
|
31
|
+
def numberize
|
32
|
+
if numberizeable?
|
33
|
+
float? ? to_f : to_i
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def numberizeable?
|
38
|
+
!scan(/^\-?\d*\.?\d*$/).empty?
|
39
|
+
end
|
40
|
+
|
41
|
+
def underscore
|
42
|
+
gsub(/\W/, '_')
|
43
|
+
end
|
44
|
+
|
45
|
+
private
|
46
|
+
|
47
|
+
def float?
|
48
|
+
scan(/\./).size == 1
|
49
|
+
end
|
50
|
+
end
|
data/lib/freesound.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
require 'uri'
|
3
|
+
require 'crack'
|
4
|
+
require 'core_ext'
|
5
|
+
|
6
|
+
YAML::ENGINE.yamler = 'syck'
|
7
|
+
|
8
|
+
module Freesound
|
9
|
+
def self.root_dir
|
10
|
+
File.expand_path('..', File.dirname(__FILE__))
|
11
|
+
end
|
12
|
+
|
13
|
+
class InvalidConfigurationParameterError < ArgumentError; end
|
14
|
+
|
15
|
+
module Configuration
|
16
|
+
DEFAULTS = {
|
17
|
+
:api_key => ENV['FREESOUND_KEY'],
|
18
|
+
:base_url => 'http://www.freesound.org/api',
|
19
|
+
:sounds_url => 'http://www.freesound.org/api/sounds'
|
20
|
+
}
|
21
|
+
|
22
|
+
DEFAULTS.each_key do |key|
|
23
|
+
eval <<-EOS
|
24
|
+
def self.#{key}
|
25
|
+
@@#{key} ||= DEFAULTS[:#{key}]
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.#{key}=(val)
|
29
|
+
@@#{key} = val
|
30
|
+
end
|
31
|
+
EOS
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.method_missing(name, *args)
|
35
|
+
raise(InvalidConfigurationParameterError, "#{name} is not a recognized configuration parameter")
|
36
|
+
end
|
37
|
+
end # module Configuration
|
38
|
+
|
39
|
+
def self.configure(params={})
|
40
|
+
params.each do |key, value|
|
41
|
+
Configuration.send("#{key}=", value)
|
42
|
+
end
|
43
|
+
|
44
|
+
yield Configuration if block_given?
|
45
|
+
end
|
46
|
+
|
47
|
+
def self.config
|
48
|
+
Configuration
|
49
|
+
end
|
50
|
+
end # module Freesound
|
51
|
+
|
52
|
+
require 'freesound/version'
|
53
|
+
require 'freesound/client'
|
54
|
+
require 'freesound/request'
|
55
|
+
require 'freesound/uri_compiler'
|
56
|
+
require 'freesound/response'
|
57
|
+
require 'freesound/response_parser'
|
58
|
+
require 'freesound/sound'
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Freesound
|
2
|
+
class InvalidApiKeyError < ArgumentError; end
|
3
|
+
|
4
|
+
class Client
|
5
|
+
attr_reader :api_key, :requests, :responses
|
6
|
+
|
7
|
+
def initialize(api_key, options={})
|
8
|
+
@api_key = api_key
|
9
|
+
@requests = []
|
10
|
+
@responses = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_sound(id)
|
14
|
+
request = Request.new(:sound_id => id)
|
15
|
+
response = request.get!
|
16
|
+
@requests << request
|
17
|
+
@responses << response
|
18
|
+
response.sounds.first
|
19
|
+
end
|
20
|
+
|
21
|
+
def search_sounds(query, options={})
|
22
|
+
request = Request.new(:search => {:q => query})
|
23
|
+
response = request.get!
|
24
|
+
response.sounds
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Freesound
|
2
|
+
class InvalidRequestFormatError < ArgumentError; end
|
3
|
+
|
4
|
+
class Request
|
5
|
+
attr_reader :uri, :params, :response, :format
|
6
|
+
|
7
|
+
def initialize(params={})
|
8
|
+
self.format = params[:format] || :json
|
9
|
+
@params = params
|
10
|
+
@response = nil
|
11
|
+
end
|
12
|
+
|
13
|
+
def format=(format)
|
14
|
+
raise(InvalidRequestFormatError, "#{format} is not a valid request format") unless [:json, :xml, :yaml, :yml].include?(format.to_sym)
|
15
|
+
@format = format.to_sym
|
16
|
+
end
|
17
|
+
|
18
|
+
def uri
|
19
|
+
@uri ||= URICompiler.new(@params.dup.merge({:format => @format})).uri
|
20
|
+
end
|
21
|
+
|
22
|
+
def get!
|
23
|
+
response_body = Net::HTTP.get_response(self.uri).body
|
24
|
+
@response ||= Response.new(response_body, @format)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Freesound
|
2
|
+
class Response
|
3
|
+
attr_reader :content, :parser
|
4
|
+
|
5
|
+
def initialize(raw, format=:json)
|
6
|
+
@content = raw
|
7
|
+
@format = format
|
8
|
+
@parser = ResponseParser.new(format)
|
9
|
+
end
|
10
|
+
|
11
|
+
def data
|
12
|
+
@data ||= @parser.parse(@content)
|
13
|
+
end
|
14
|
+
|
15
|
+
def num_results
|
16
|
+
self.data[:num_results] || 1
|
17
|
+
end
|
18
|
+
|
19
|
+
def sounds
|
20
|
+
@sounds ||= if num_results == 1
|
21
|
+
[ Sound.new(*self.data.values) ]
|
22
|
+
else
|
23
|
+
self.data[:sounds].map { |data| Sound.new(data) }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Freesound
|
2
|
+
class ResponseParser
|
3
|
+
attr_reader :format
|
4
|
+
|
5
|
+
def initialize(format)
|
6
|
+
@format = format
|
7
|
+
end
|
8
|
+
|
9
|
+
def parse(raw)
|
10
|
+
case @format
|
11
|
+
when :xml
|
12
|
+
parse_xml(raw)
|
13
|
+
when :yaml, :yml
|
14
|
+
parse_yaml(raw)
|
15
|
+
else
|
16
|
+
parse_json(raw)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def parse_json(raw)
|
23
|
+
::Crack::JSON.parse(raw).underscore_keys.symbolize_keys
|
24
|
+
end
|
25
|
+
|
26
|
+
# xml gets parsed slightly differently than json and yaml.
|
27
|
+
# the result needs to convert single element arrays to strings,
|
28
|
+
# convert strings like "2" to their corresponding number object i.e. 2
|
29
|
+
# and remove the nesting of the :tags key under "resource"
|
30
|
+
def parse_xml(raw)
|
31
|
+
result = ::Crack::XML.parse(raw)["response"].underscore_keys
|
32
|
+
.symbolize_keys
|
33
|
+
.flatten_single_element_array_values
|
34
|
+
.numberize_values
|
35
|
+
result[:tags] = result[:tags]["resource"]
|
36
|
+
result
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_yaml(raw)
|
40
|
+
::YAML::load(raw).underscore_keys.symbolize_keys
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
module Freesound
|
2
|
+
Sound = Struct.new(
|
3
|
+
:similarity, :num_ratings, :duration, :samplerate, :preview_hq_ogg,
|
4
|
+
:id, :preview_lq_ogg, :bitdepth, :num_comments, :filesize,
|
5
|
+
:preview_hq_mp3, :type, :analysis_stats, :description, :tags,
|
6
|
+
:serve, :spectral_m, :spectral_l, :user, :bitrate, :num_downloads,
|
7
|
+
:analysis_frames, :channels, :license, :created, :url, :ref,:avg_rating,
|
8
|
+
:preview_lq_mp3, :original_filename, :waveform_l, :waveform_m, :pack
|
9
|
+
)
|
10
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Freesound
|
2
|
+
class Freesound::URICompiler
|
3
|
+
attr_reader :uri
|
4
|
+
|
5
|
+
def initialize(params)
|
6
|
+
search_params = params.delete(:search)
|
7
|
+
sound_id = params.delete(:sound_id)
|
8
|
+
format = params.delete(:format)
|
9
|
+
@uri = URI.parse(compile_uri_string(search_params, sound_id, format))
|
10
|
+
end
|
11
|
+
|
12
|
+
def compile_uri_string(search_params, sound_id, format)
|
13
|
+
format_string = format ? "&format=#{format}" : ""
|
14
|
+
|
15
|
+
if search_params
|
16
|
+
search_uri(search_params, format_string)
|
17
|
+
elsif sound_id
|
18
|
+
sound_id_uri(sound_id, format_string)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def search_uri(search_params, format_string)
|
25
|
+
"#{Freesound.config.sounds_url}/search/?api_key=#{Freesound.config.api_key}#{format_string}&#{search_params.to_uri}"
|
26
|
+
end
|
27
|
+
|
28
|
+
def sound_id_uri(id, format_string)
|
29
|
+
"#{Freesound.config.sounds_url}/#{id}/?api_key=#{Freesound.config.api_key}#{format_string}"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,71 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe Hash do
|
4
|
+
describe '#symbolize_keys' do
|
5
|
+
it 'symbolizes keys' do
|
6
|
+
{"one" => 1, "two" => 2}.symbolize_keys.should == {:one => 1, :two => 2}
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#flatten_single_element_array_values' do
|
11
|
+
it 'converts values that are single element arrays into just the first element of that array' do
|
12
|
+
{"one" => [1], "two_and_three" => [2, 3], "four" => 4}
|
13
|
+
.flatten_single_element_array_values.should == {"one" => 1, "two_and_three" => [2, 3], "four" => 4}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe '#to_uri' do
|
18
|
+
it 'converts hash to a uri string' do
|
19
|
+
{"one" => 1, :api_key => "1234"}.to_uri.should == "one=1&api_key=1234"
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe '#numberize_values' do
|
24
|
+
it 'turns all numerical string values to ints or floats' do
|
25
|
+
{:one => "1", :one_point_two => "1.2", :negative_three => "-3", :something => "anything"}.numberize_values.should ==
|
26
|
+
{:one => 1, :one_point_two => 1.2, :negative_three => -3, :something => "anything"}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#underscore_keys' do
|
31
|
+
it 'underscores keys' do
|
32
|
+
{"one-two" => 12}.underscore_keys.should == {"one_two" => 12}
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe String do
|
38
|
+
describe '#numberize' do
|
39
|
+
it 'converts to an integer' do
|
40
|
+
'123'.numberize.should == 123
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'converts to a float' do
|
44
|
+
'123.456'.numberize.should == 123.456
|
45
|
+
end
|
46
|
+
|
47
|
+
it 'returns nil for non-numerical strings' do
|
48
|
+
'abc123'.numberize.should be_nil
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe '#numberizeable?' do
|
53
|
+
it 'returns true' do
|
54
|
+
%w{ 123 -2 1.23 -1.56 .900 23. 023 }.each { |str| str.should be_numberizeable }
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'returns false' do
|
58
|
+
%w{ 1.2.3 12a3 alex 1-23 --345 ..45 98..}.each { |str| str.should_not be_numberizeable }
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#underscore' do
|
63
|
+
it 'underscores -s' do
|
64
|
+
'one-two'.underscore.should == 'one_two'
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'underscores whitespace' do
|
68
|
+
'one two'.underscore.should == 'one_two'
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Client do
|
4
|
+
it 'has an api key' do
|
5
|
+
Client.new('123abc').api_key.should == '123abc'
|
6
|
+
end
|
7
|
+
|
8
|
+
context 'with valid api key' do
|
9
|
+
subject { Client.new(Freesound.config.api_key) }
|
10
|
+
|
11
|
+
before do
|
12
|
+
json = File.read("#{Freesound.root_dir}/data/sample.json")
|
13
|
+
path = "http://www.freesound.org/api/sounds/10/?api_key=#{Freesound.config.api_key}&format=json"
|
14
|
+
|
15
|
+
stub_request(:get, path).to_return(:body => json)
|
16
|
+
end
|
17
|
+
|
18
|
+
describe '#get_sound' do
|
19
|
+
it 'returns a Sound' do
|
20
|
+
subject.get_sound(10).should be_a(Sound)
|
21
|
+
end
|
22
|
+
|
23
|
+
it 'returns a Response corresponding to the given id' do
|
24
|
+
subject.get_sound(10).id.should == 10
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'adds to @requests' do
|
28
|
+
expect { subject.get_sound(10) }.to change(subject.requests, :size).by(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'adds to @responses' do
|
32
|
+
expect { subject.get_sound(10) }.to change(subject.responses, :size).by(1)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '#search_sounds' do
|
37
|
+
before do
|
38
|
+
json = File.read("#{Freesound.root_dir}/data/sample_query.json")
|
39
|
+
path = "http://www.freesound.org/api/sounds/search/?api_key=#{Freesound.config.api_key}&format=json&q=badass"
|
40
|
+
stub_request(:get, path).to_return(:body => json)
|
41
|
+
end
|
42
|
+
|
43
|
+
it 'returns a response' do
|
44
|
+
subject.search_sounds("badass").should be_a(Array)
|
45
|
+
subject.search_sounds("badass").first.should be_a(Sound)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
|
2
|
+
|
3
|
+
describe Request do
|
4
|
+
subject { Request.new({:sound_id => 10}) }
|
5
|
+
|
6
|
+
it 'initializes with a params hash' do
|
7
|
+
subject.params.should == {:sound_id => 10}
|
8
|
+
end
|
9
|
+
|
10
|
+
it 'fails with invalid format' do
|
11
|
+
expect { Request.new({:format => :pdf}) }.to raise_error(InvalidRequestFormatError)
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#get!' do
|
15
|
+
before do
|
16
|
+
json = File.read("#{Freesound.root_dir}/data/sample.json")
|
17
|
+
path = "http://www.freesound.org/api/sounds/10/?api_key=#{Freesound.config.api_key}&format=json"
|
18
|
+
|
19
|
+
stub_request(:get, path).to_return(:body => json)
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'returns a Response' do
|
23
|
+
subject.get!.should be_a(Response)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|