diff --git a/README b/README
index 6ac35e13a..fa287b97a 100644
--- a/README
+++ b/README
@@ -17,6 +17,7 @@ APIs.
require 'signet/oauth_1/client'
client = Google::APIClient.new(
:service => 'buzz',
+ # Buzz has API-specific endpoints
:authorization => Signet::OAuth1::Client.new(
:temporary_credential_uri =>
'https://www.google.com/accounts/OAuthGetRequestToken',
@@ -48,8 +49,7 @@ APIs.
# Make an API call
response = client.execute(
'chili.activities.list',
- {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'},
- '', [], {:signed => true}
+ {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}
)
status, headers, body = response
diff --git a/lib/google/api_client.rb b/lib/google/api_client.rb
index 1f51324bf..dcf30007d 100644
--- a/lib/google/api_client.rb
+++ b/lib/google/api_client.rb
@@ -33,11 +33,11 @@ module Google
@options = {
# TODO: What configuration options need to go here?
}.merge(options)
- if !self.authorization.respond_to?(:generate_authenticated_request)
- raise TypeError,
- 'Expected authorization mechanism to respond to ' +
- '#generate_authenticated_request.'
- end
+ # Force immediate type-checking and short-cut resolution
+ self.parser
+ self.authorization
+ self.http_adapter
+ return self
end
##
@@ -53,8 +53,11 @@ module Google
##
# Returns the authorization mechanism used by the client.
+ #
+ # @return [#generate_authenticated_request] The authorization mechanism.
def authorization
- unless @options[:authorization]
+ case @options[:authorization]
+ when :oauth_1, :oauth
require 'signet/oauth_1/client'
# NOTE: Do not rely on this default value, as it may change
@options[:authorization] = Signet::OAuth1::Client.new(
@@ -67,10 +70,29 @@ module Google
:client_credential_key => 'anonymous',
:client_credential_secret => 'anonymous'
)
+ when nil
+ # No authorization mechanism
+ else
+ if !@options[:authorization].respond_to?(
+ :generate_authenticated_request)
+ raise TypeError,
+ 'Expected authorization mechanism to respond to ' +
+ '#generate_authenticated_request.'
+ end
end
return @options[:authorization]
end
+ ##
+ # Sets the authorization mechanism used by the client.
+ #
+ # @param [#generate_authenticated_request] new_authorization
+ # The new authorization mechanism.
+ def authorization=(new_authorization)
+ @options[:authorization] = new_authorization
+ return self.authorization
+ end
+
##
# Returns the HTTP adapter used by the client.
def http_adapter
@@ -204,21 +226,15 @@ module Google
# @param [String, Symbol] service_name The name of the service.
#
# @return [Google::APIClient::Service] The service object.
- def latest_service(service_name)
+ def latest_service_version(service_name)
if !service_name.kind_of?(String) && !service_name.kind_of?(Symbol)
raise TypeError,
"Expected String or Symbol, got #{service_name.class}."
end
service_name = service_name.to_s
- versions = {}
- for service in self.discovered_services
- next if service.name != service_name
- sortable_version = service.version.gsub(/^v/, '').split('.').map do |v|
- v.to_i
- end
- versions[sortable_version] = service
- end
- return versions[versions.keys.sort.last]
+ return (self.discovered_services.select do |service|
+ service.name == service_name
+ end).sort.last
end
##
@@ -242,25 +258,31 @@ module Google
# :signed
is true
.
# - :signed
—
# true
if the request must be signed, false
- # otherwise. Defaults to true
.
+ # otherwise. Defaults to true
if an authorization
+ # mechanism has been set, false
otherwise.
#
# @return [Array] The generated request.
#
# @example
# request = client.generate_request(
# 'chili.activities.list',
- # {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'},
- # '', [], {:signed => true}
+ # {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}
# )
# method, uri, headers, body = request
def generate_request(
api_method, parameters={}, body='', headers=[], options={})
options={
- :signed => true,
:parser => self.parser,
:service_version => 'v1',
:authorization => self.authorization
}.merge(options)
+ # The default value for the :signed option depends on whether an
+ # authorization mechanism has been set.
+ if options[:authorization]
+ options = {:signed => true}.merge(options)
+ else
+ options = {:signed => false}.merge(options)
+ end
if api_method.kind_of?(String) || api_method.kind_of?(Symbol)
api_method = self.discovered_method(
api_method.to_s, options[:service_version]
@@ -310,8 +332,7 @@ module Google
# @example
# response = client.execute(
# 'chili.activities.list',
- # {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'},
- # '', [], {:signed => true}
+ # {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}
# )
# status, headers, body = response
def execute(api_method, parameters={}, body='', headers=[], options={})
diff --git a/lib/google/api_client/discovery.rb b/lib/google/api_client/discovery.rb
index 8976d2f9a..5191e3f34 100644
--- a/lib/google/api_client/discovery.rb
+++ b/lib/google/api_client/discovery.rb
@@ -138,6 +138,44 @@ module Google
end)
end
+ ##
+ # Compares two versions of a service.
+ #
+ # @param [Object] other The service to compare.
+ #
+ # @return [Integer]
+ # -1
if the service is older than other
.
+ # 0
if the service is the same as other
.
+ # 1
if the service is newer than other
.
+ # nil
if the service cannot be compared to
+ # other
.
+ def <=>(other)
+ # We can only compare versions of the same service
+ if other.kind_of?(self.class) && self.name == other.name
+ split_version = lambda do |version|
+ dotted_version = version[/^v?(\d+(.\d+)*)-?(.*?)?$/, 1]
+ suffix = version[/^v?(\d+(.\d+)*)-?(.*?)?$/, 3]
+ [dotted_version.split('.').map { |v| v.to_i }, suffix]
+ end
+ self_sortable, self_suffix = split_version.call(self.version)
+ other_sortable, other_suffix = split_version.call(other.version)
+ result = self_sortable <=> other_sortable
+ if result != 0
+ return result
+ # If the dotted versions are equal, check the suffix.
+ # An omitted suffix should be sorted after an included suffix.
+ elsif self_suffix == ''
+ return 1
+ elsif other_suffix == ''
+ return -1
+ else
+ return self_suffix <=> other_suffix
+ end
+ else
+ return nil
+ end
+ end
+
##
# Returns a String
representation of the service's state.
#
diff --git a/spec/google/api_client/discovery_spec.rb b/spec/google/api_client/discovery_spec.rb
index 2b6f77ad3..305d2c9e3 100644
--- a/spec/google/api_client/discovery_spec.rb
+++ b/spec/google/api_client/discovery_spec.rb
@@ -113,13 +113,13 @@ describe Google::APIClient, 'configured for the prediction API' do
end
it 'should correctly determine the latest version' do
- @client.latest_service('prediction').version.should_not == 'v1'
- @client.latest_service(:prediction).version.should_not == 'v1'
+ @client.latest_service_version('prediction').version.should_not == 'v1'
+ @client.latest_service_version(:prediction).version.should_not == 'v1'
end
it 'should raise an error for bogus services' do
(lambda do
- @client.latest_service(42)
+ @client.latest_service_version(42)
end).should raise_error(TypeError)
end
@@ -138,7 +138,7 @@ describe Google::APIClient, 'configured for the prediction API' do
Google::APIClient::Service.new('magic', 'v2.1', {})
@client.discovered_services <<
Google::APIClient::Service.new('magic', 'v10.0', {})
- @client.latest_service('magic').version.should == 'v10.1'
+ @client.latest_service_version('magic').version.should == 'v10.1'
end
it 'should correctly determine the latest version' do
@@ -152,21 +152,20 @@ describe Google::APIClient, 'configured for the prediction API' do
Google::APIClient::Service.new('two', 'v1.1-r1c3', {})
@client.discovered_services <<
Google::APIClient::Service.new('two', 'v2', {})
- @client.latest_service('two').version.should == 'v2'
+ @client.discovered_services <<
+ Google::APIClient::Service.new('two', 'v2beta1', {})
+ @client.latest_service_version('two').version.should == 'v2'
end
it 'should return nil for bogus service names' do
# Sanity check the algorithm
- @client.latest_service('bogus').should == nil
+ @client.latest_service_version('bogus').should == nil
end
it 'should generate valid requests' do
request = @client.generate_request(
'prediction.training.insert',
- {'query' => '12345'},
- '',
- [],
- {:signed => false}
+ {'query' => '12345'}
)
method, uri, headers, body = request
method.should == 'POST'
@@ -179,10 +178,7 @@ describe Google::APIClient, 'configured for the prediction API' do
it 'should generate requests against the correct URIs' do
request = @client.generate_request(
:'prediction.training.insert',
- {'query' => '12345'},
- '',
- [],
- {:signed => false}
+ {'query' => '12345'}
)
method, uri, headers, body = request
uri.should ==
@@ -193,10 +189,7 @@ describe Google::APIClient, 'configured for the prediction API' do
prediction = @client.discovered_service('prediction', 'v1')
request = @client.generate_request(
prediction.training.insert,
- {'query' => '12345'},
- '',
- [],
- {:signed => false}
+ {'query' => '12345'}
)
method, uri, headers, body = request
uri.should ==
@@ -204,14 +197,12 @@ describe Google::APIClient, 'configured for the prediction API' do
end
it 'should generate signed requests' do
+ @client.authorization = :oauth_1
@client.authorization.token_credential_key = '12345'
@client.authorization.token_credential_secret = '12345'
request = @client.generate_request(
'prediction.training.insert',
- {'query' => '12345'},
- '',
- [],
- {:signed => true}
+ {'query' => '12345'}
)
method, uri, headers, body = request
headers = Hash[headers]
@@ -220,14 +211,12 @@ describe Google::APIClient, 'configured for the prediction API' do
end
it 'should not be able to execute improperly authorized requests' do
+ @client.authorization = :oauth_1
@client.authorization.token_credential_key = '12345'
@client.authorization.token_credential_secret = '12345'
response = @client.execute(
'prediction.training.insert',
- {'query' => '12345'},
- '',
- [],
- {:signed => true}
+ {'query' => '12345'}
)
status, headers, body = response
status.should == 401
diff --git a/spec/google/api_client_spec.rb b/spec/google/api_client_spec.rb
index e76c10e0e..50036478c 100644
--- a/spec/google/api_client_spec.rb
+++ b/spec/google/api_client_spec.rb
@@ -34,6 +34,24 @@ describe Google::APIClient, 'with default configuration' do
@client.parser.should be(Google::APIClient::JSONParser)
end
+ it 'should not use an authorization mechanism' do
+ @client.authorization.should be_nil
+ end
+end
+
+describe Google::APIClient, 'with default oauth configuration' do
+ before do
+ @client = Google::APIClient.new(:authorization => :oauth_1)
+ end
+
+ it 'should make its version number available' do
+ ::Google::APIClient::VERSION::STRING.should be_instance_of(String)
+ end
+
+ it 'should use the default JSON parser' do
+ @client.parser.should be(Google::APIClient::JSONParser)
+ end
+
it 'should use the default OAuth1 client configuration' do
@client.authorization.temporary_credential_uri.to_s.should ==
'https://www.google.com/accounts/OAuthGetRequestToken'