koala 1.1.0 → 1.2.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.
- data/.travis.yml +2 -1
- data/CHANGELOG +36 -0
- data/Gemfile +6 -2
- data/Rakefile +0 -1
- data/koala.gemspec +7 -8
- data/lib/koala/batch_operation.rb +15 -15
- data/lib/koala/graph_api.rb +85 -73
- data/lib/koala/graph_batch_api.rb +21 -11
- data/lib/koala/graph_collection.rb +13 -8
- data/lib/koala/http_service.rb +176 -0
- data/lib/koala/oauth.rb +34 -24
- data/lib/koala/realtime_updates.rb +21 -18
- data/lib/koala/rest_api.rb +1 -1
- data/lib/koala/test_users.rb +33 -17
- data/lib/koala/uploadable_io.rb +49 -43
- data/lib/koala/utils.rb +11 -0
- data/lib/koala/version.rb +3 -0
- data/lib/koala.rb +47 -45
- data/readme.md +58 -38
- data/spec/cases/{api_base_spec.rb → api_spec.rb} +27 -2
- data/spec/cases/error_spec.rb +32 -0
- data/spec/cases/graph_and_rest_api_spec.rb +12 -21
- data/spec/cases/graph_api_batch_spec.rb +92 -119
- data/spec/cases/graph_api_spec.rb +11 -14
- data/spec/cases/graph_collection_spec.rb +116 -0
- data/spec/cases/http_service_spec.rb +446 -0
- data/spec/cases/koala_spec.rb +36 -37
- data/spec/cases/oauth_spec.rb +318 -212
- data/spec/cases/realtime_updates_spec.rb +45 -31
- data/spec/cases/rest_api_spec.rb +23 -7
- data/spec/cases/test_users_spec.rb +123 -75
- data/spec/cases/uploadable_io_spec.rb +77 -36
- data/spec/cases/utils_spec.rb +10 -0
- data/spec/fixtures/facebook_data.yml +26 -24
- data/spec/fixtures/mock_facebook_responses.yml +131 -101
- data/spec/spec_helper.rb +29 -5
- data/spec/support/graph_api_shared_examples.rb +80 -120
- data/spec/support/json_testing_fix.rb +35 -11
- data/spec/support/koala_test.rb +187 -0
- data/spec/support/mock_http_service.rb +8 -5
- data/spec/support/ordered_hash.rb +205 -0
- data/spec/support/rest_api_shared_examples.rb +37 -37
- data/spec/support/uploadable_io_shared_examples.rb +2 -8
- metadata +72 -83
- data/lib/koala/http_services/net_http_service.rb +0 -92
- data/lib/koala/http_services/typhoeus_service.rb +0 -37
- data/lib/koala/http_services.rb +0 -46
- data/spec/cases/http_services/http_service_spec.rb +0 -129
- data/spec/cases/http_services/net_http_service_spec.rb +0 -532
- data/spec/cases/http_services/typhoeus_service_spec.rb +0 -152
- data/spec/support/live_testing_data_helper.rb +0 -40
- data/spec/support/setup_mocks_or_live.rb +0 -51
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
require "net/http" unless defined?(Net::HTTP)
|
|
2
|
-
require "net/https"
|
|
3
|
-
require "net/http/post/multipart"
|
|
4
|
-
|
|
5
|
-
module Koala
|
|
6
|
-
module NetHTTPService
|
|
7
|
-
# this service uses Net::HTTP to send requests to the graph
|
|
8
|
-
include Koala::HTTPService
|
|
9
|
-
|
|
10
|
-
# Net::HTTP-specific values
|
|
11
|
-
class << self
|
|
12
|
-
attr_accessor :ca_file, :ca_path, :verify_mode
|
|
13
|
-
end
|
|
14
|
-
|
|
15
|
-
def self.make_request(path, args, verb, options = {})
|
|
16
|
-
# We translate args to a valid query string. If post is specified,
|
|
17
|
-
# we send a POST request to the given path with the given arguments.
|
|
18
|
-
|
|
19
|
-
# by default, we use SSL only for private requests
|
|
20
|
-
# this makes public requests faster
|
|
21
|
-
private_request = args["access_token"] || @always_use_ssl || options[:use_ssl]
|
|
22
|
-
|
|
23
|
-
# if the verb isn't get or post, send it as a post argument
|
|
24
|
-
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
|
25
|
-
|
|
26
|
-
http = create_http(server(options), private_request, options)
|
|
27
|
-
|
|
28
|
-
response = http.start do |http|
|
|
29
|
-
if verb == "post"
|
|
30
|
-
if params_require_multipart? args
|
|
31
|
-
http.request Net::HTTP::Post::Multipart.new path, encode_multipart_params(args)
|
|
32
|
-
else
|
|
33
|
-
http.post(path, encode_params(args))
|
|
34
|
-
end
|
|
35
|
-
else
|
|
36
|
-
http.get("#{path}?#{encode_params(args)}")
|
|
37
|
-
end
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
Koala::Response.new(response.code.to_i, response.body, response)
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
protected
|
|
44
|
-
def self.encode_params(param_hash)
|
|
45
|
-
# unfortunately, we can't use to_query because that's Rails, not Ruby
|
|
46
|
-
# if no hash (e.g. no auth token) return empty string
|
|
47
|
-
((param_hash || {}).collect do |key_and_value|
|
|
48
|
-
key_and_value[1] = MultiJson.encode(key_and_value[1]) if key_and_value[1].class != String
|
|
49
|
-
"#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
|
|
50
|
-
end).join("&")
|
|
51
|
-
end
|
|
52
|
-
|
|
53
|
-
def self.encode_multipart_params(param_hash)
|
|
54
|
-
Hash[*param_hash.collect do |key, value|
|
|
55
|
-
[key, value.kind_of?(Koala::UploadableIO) ? value.to_upload_io : value]
|
|
56
|
-
end.flatten]
|
|
57
|
-
end
|
|
58
|
-
|
|
59
|
-
def self.create_http(server, private_request, options)
|
|
60
|
-
if proxy_server = options[:proxy] || proxy
|
|
61
|
-
proxy = URI.parse(proxy_server)
|
|
62
|
-
http = Net::HTTP.new(server, private_request ? 443 : nil,
|
|
63
|
-
proxy.host, proxy.port, proxy.user, proxy.password)
|
|
64
|
-
else
|
|
65
|
-
http = Net::HTTP.new(server, private_request ? 443 : nil)
|
|
66
|
-
end
|
|
67
|
-
|
|
68
|
-
if timeout_value = options[:timeout] || timeout
|
|
69
|
-
http.open_timeout = timeout_value
|
|
70
|
-
http.read_timeout = timeout_value
|
|
71
|
-
end
|
|
72
|
-
|
|
73
|
-
# For HTTPS requests, set the proper CA certificates
|
|
74
|
-
if private_request
|
|
75
|
-
http.use_ssl = true
|
|
76
|
-
http.verify_mode = options[:verify_mode] || verify_mode || OpenSSL::SSL::VERIFY_PEER
|
|
77
|
-
|
|
78
|
-
if cert_file = options[:ca_file] || ca_file
|
|
79
|
-
raise Errno::ENOENT, "Certificate file #{cert_file.inspect} does not exist!" unless File.exists?(cert_file)
|
|
80
|
-
http.ca_file = cert_file
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
if cert_path = options[:ca_path] || ca_path
|
|
84
|
-
raise Errno::ENOENT, "Certificate path #{cert_path.inspect} does not exist!" unless File.directory?(cert_path)
|
|
85
|
-
http.ca_path = cert_path
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
http
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
end
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
require "typhoeus" unless defined?(Typhoeus)
|
|
2
|
-
|
|
3
|
-
module Koala
|
|
4
|
-
module TyphoeusService
|
|
5
|
-
# this service uses Typhoeus to send requests to the graph
|
|
6
|
-
include Typhoeus
|
|
7
|
-
include Koala::HTTPService
|
|
8
|
-
|
|
9
|
-
def self.make_request(path, args, verb, options = {})
|
|
10
|
-
# if the verb isn't get or post, send it as a post argument
|
|
11
|
-
args.merge!({:method => verb}) && verb = "post" if verb != "get" && verb != "post"
|
|
12
|
-
|
|
13
|
-
# switch any UploadableIOs to the files Typhoeus expects
|
|
14
|
-
args.each_pair {|key, value| args[key] = value.to_file if value.is_a?(UploadableIO)}
|
|
15
|
-
|
|
16
|
-
# you can pass arguments directly to Typhoeus using the :typhoeus_options key
|
|
17
|
-
typhoeus_options = {:params => args}.merge(options[:typhoeus_options] || {})
|
|
18
|
-
|
|
19
|
-
# if proxy/timeout options aren't passed, check if defaults are set
|
|
20
|
-
typhoeus_options[:proxy] ||= proxy
|
|
21
|
-
typhoeus_options[:timeout] ||= timeout
|
|
22
|
-
|
|
23
|
-
# by default, we use SSL only for private requests (e.g. with access token)
|
|
24
|
-
# this makes public requests faster
|
|
25
|
-
prefix = (args["access_token"] || @always_use_ssl || options[:use_ssl]) ? "https" : "http"
|
|
26
|
-
|
|
27
|
-
response = Typhoeus::Request.send(verb, "#{prefix}://#{server(options)}#{path}", typhoeus_options)
|
|
28
|
-
Koala::Response.new(response.code, response.body, response.headers_hash)
|
|
29
|
-
end
|
|
30
|
-
|
|
31
|
-
protected
|
|
32
|
-
|
|
33
|
-
def self.multipart_requires_content_type?
|
|
34
|
-
false # Typhoeus handles multipart file types, we don't have to require it
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
end
|
data/lib/koala/http_services.rb
DELETED
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
module Koala
|
|
2
|
-
class Response
|
|
3
|
-
attr_reader :status, :body, :headers
|
|
4
|
-
def initialize(status, body, headers)
|
|
5
|
-
@status = status
|
|
6
|
-
@body = body
|
|
7
|
-
@headers = headers
|
|
8
|
-
end
|
|
9
|
-
end
|
|
10
|
-
|
|
11
|
-
module HTTPService
|
|
12
|
-
# common functionality for all HTTP services
|
|
13
|
-
def self.included(base)
|
|
14
|
-
base.class_eval do
|
|
15
|
-
class << self
|
|
16
|
-
attr_accessor :always_use_ssl, :proxy, :timeout
|
|
17
|
-
end
|
|
18
|
-
|
|
19
|
-
def self.server(options = {})
|
|
20
|
-
server = "#{options[:rest_api] ? Facebook::REST_SERVER : Facebook::GRAPH_SERVER}"
|
|
21
|
-
server.gsub!(/\.facebook/, "-video.facebook") if options[:video]
|
|
22
|
-
"#{options[:beta] ? "beta." : ""}#{server}"
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
def self.encode_params(param_hash)
|
|
26
|
-
# unfortunately, we can't use to_query because that's Rails, not Ruby
|
|
27
|
-
# if no hash (e.g. no auth token) return empty string
|
|
28
|
-
((param_hash || {}).collect do |key_and_value|
|
|
29
|
-
key_and_value[1] = MultiJson.encode(key_and_value[1]) unless key_and_value[1].is_a? String
|
|
30
|
-
"#{key_and_value[0].to_s}=#{CGI.escape key_and_value[1]}"
|
|
31
|
-
end).join("&")
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
protected
|
|
35
|
-
|
|
36
|
-
def self.params_require_multipart?(param_hash)
|
|
37
|
-
param_hash.any? { |key, value| value.kind_of?(Koala::UploadableIO) }
|
|
38
|
-
end
|
|
39
|
-
|
|
40
|
-
def self.multipart_requires_content_type?
|
|
41
|
-
true
|
|
42
|
-
end
|
|
43
|
-
end
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|
|
@@ -1,129 +0,0 @@
|
|
|
1
|
-
require 'spec_helper'
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
class Bear
|
|
5
|
-
include Koala::HTTPService
|
|
6
|
-
end
|
|
7
|
-
|
|
8
|
-
describe "Koala::HTTPService" do
|
|
9
|
-
|
|
10
|
-
describe "common methods" do
|
|
11
|
-
describe "always_use_ssl accessor" do
|
|
12
|
-
it "should be added" do
|
|
13
|
-
# in Ruby 1.8, .methods returns strings
|
|
14
|
-
# in Ruby 1.9, .method returns symbols
|
|
15
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl)
|
|
16
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:always_use_ssl=)
|
|
17
|
-
end
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
describe "proxy accessor" do
|
|
21
|
-
it "should be added" do
|
|
22
|
-
# in Ruby 1.8, .methods returns strings
|
|
23
|
-
# in Ruby 1.9, .method returns symbols
|
|
24
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:proxy)
|
|
25
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:proxy=)
|
|
26
|
-
end
|
|
27
|
-
end
|
|
28
|
-
|
|
29
|
-
describe "timeout accessor" do
|
|
30
|
-
it "should be added" do
|
|
31
|
-
# in Ruby 1.8, .methods returns strings
|
|
32
|
-
# in Ruby 1.9, .method returns symbols
|
|
33
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:timeout)
|
|
34
|
-
Bear.methods.collect {|m| m.to_sym}.should include(:timeout=)
|
|
35
|
-
end
|
|
36
|
-
end
|
|
37
|
-
|
|
38
|
-
describe "server" do
|
|
39
|
-
describe "with no options" do
|
|
40
|
-
it "returns the REST server if options[:rest_api]" do
|
|
41
|
-
Bear.server(:rest_api => true).should == Koala::Facebook::REST_SERVER
|
|
42
|
-
end
|
|
43
|
-
|
|
44
|
-
it "returns the graph server if !options[:rest_api]" do
|
|
45
|
-
Bear.server(:rest_api => false).should == Koala::Facebook::GRAPH_SERVER
|
|
46
|
-
Bear.server({}).should == Koala::Facebook::GRAPH_SERVER
|
|
47
|
-
end
|
|
48
|
-
end
|
|
49
|
-
|
|
50
|
-
describe "with options[:beta]" do
|
|
51
|
-
before :each do
|
|
52
|
-
@options = {:beta => true}
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
it "returns the beta REST server if options[:rest_api]" do
|
|
56
|
-
server = Bear.server(@options.merge(:rest_api => true))
|
|
57
|
-
server.should =~ Regexp.new("beta.#{Koala::Facebook::REST_SERVER}")
|
|
58
|
-
end
|
|
59
|
-
|
|
60
|
-
it "returns the beta rest server if !options[:rest_api]" do
|
|
61
|
-
server = Bear.server(@options)
|
|
62
|
-
server.should =~ Regexp.new("beta.#{Koala::Facebook::GRAPH_SERVER}")
|
|
63
|
-
end
|
|
64
|
-
end
|
|
65
|
-
|
|
66
|
-
describe "with options[:video]" do
|
|
67
|
-
before :each do
|
|
68
|
-
@options = {:video => true}
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
it "should return the REST video server if options[:rest_api]" do
|
|
72
|
-
server = Bear.server(@options.merge(:rest_api => true))
|
|
73
|
-
server.should =~ Regexp.new(Koala::Facebook::REST_SERVER.gsub(/\.facebook/, "-video.facebook"))
|
|
74
|
-
end
|
|
75
|
-
|
|
76
|
-
it "should return the graph video server if !options[:rest_api]" do
|
|
77
|
-
server = Bear.server(@options)
|
|
78
|
-
server.should =~ Regexp.new(Koala::Facebook::GRAPH_SERVER.gsub(/\.facebook/, "-video.facebook"))
|
|
79
|
-
end
|
|
80
|
-
end
|
|
81
|
-
end
|
|
82
|
-
|
|
83
|
-
describe "#encode_params" do
|
|
84
|
-
it "should return an empty string if param_hash evaluates to false" do
|
|
85
|
-
Bear.encode_params(nil).should == ''
|
|
86
|
-
end
|
|
87
|
-
|
|
88
|
-
it "should convert values to JSON if the value is not a String" do
|
|
89
|
-
val = 'json_value'
|
|
90
|
-
not_a_string = 'not_a_string'
|
|
91
|
-
not_a_string.stub(:is_a?).and_return(false)
|
|
92
|
-
MultiJson.should_receive(:encode).with(not_a_string).and_return(val)
|
|
93
|
-
|
|
94
|
-
string = "hi"
|
|
95
|
-
|
|
96
|
-
args = {
|
|
97
|
-
not_a_string => not_a_string,
|
|
98
|
-
string => string
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
result = Bear.encode_params(args)
|
|
102
|
-
result.split('&').find do |key_and_val|
|
|
103
|
-
key_and_val.match("#{not_a_string}=#{val}")
|
|
104
|
-
end.should be_true
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
it "should escape all values" do
|
|
108
|
-
args = Hash[*(1..4).map {|i| [i.to_s, "Value #{i}($"]}.flatten]
|
|
109
|
-
|
|
110
|
-
result = Bear.encode_params(args)
|
|
111
|
-
result.split('&').each do |key_val|
|
|
112
|
-
key, val = key_val.split('=')
|
|
113
|
-
val.should == CGI.escape(args[key])
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
it "should convert all keys to Strings" do
|
|
118
|
-
args = Hash[*(1..4).map {|i| [i, "val#{i}"]}.flatten]
|
|
119
|
-
|
|
120
|
-
result = Bear.encode_params(args)
|
|
121
|
-
result.split('&').each do |key_val|
|
|
122
|
-
key, val = key_val.split('=')
|
|
123
|
-
key.should == args.find{|key_val_arr| key_val_arr.last == val}.first.to_s
|
|
124
|
-
end
|
|
125
|
-
end
|
|
126
|
-
end
|
|
127
|
-
end
|
|
128
|
-
|
|
129
|
-
end
|