Updated version sorting code and added authorization shortcuts.
git-svn-id: https://google-api-ruby-client.googlecode.com/svn/trunk@60 c1d61fac-ed7f-fcc1-18f7-ff78120a04ef
This commit is contained in:
		
							parent
							
								
									c183d6ddfd
								
							
						
					
					
						commit
						3bd7056e86
					
				
							
								
								
									
										4
									
								
								README
								
								
								
								
							
							
						
						
									
										4
									
								
								README
								
								
								
								
							|  | @ -17,6 +17,7 @@ APIs. | ||||||
|   require 'signet/oauth_1/client' |   require 'signet/oauth_1/client' | ||||||
|   client = Google::APIClient.new( |   client = Google::APIClient.new( | ||||||
|     :service => 'buzz', |     :service => 'buzz', | ||||||
|  |     # Buzz has API-specific endpoints | ||||||
|     :authorization => Signet::OAuth1::Client.new( |     :authorization => Signet::OAuth1::Client.new( | ||||||
|       :temporary_credential_uri => |       :temporary_credential_uri => | ||||||
|         'https://www.google.com/accounts/OAuthGetRequestToken', |         'https://www.google.com/accounts/OAuthGetRequestToken', | ||||||
|  | @ -48,8 +49,7 @@ APIs. | ||||||
|   # Make an API call |   # Make an API call | ||||||
|   response = client.execute( |   response = client.execute( | ||||||
|     'chili.activities.list', |     'chili.activities.list', | ||||||
|     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}, |     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'} | ||||||
|     '', [], {:signed => true} |  | ||||||
|   ) |   ) | ||||||
|   status, headers, body = response |   status, headers, body = response | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -33,11 +33,11 @@ module Google | ||||||
|       @options = { |       @options = { | ||||||
|         # TODO: What configuration options need to go here? |         # TODO: What configuration options need to go here? | ||||||
|       }.merge(options) |       }.merge(options) | ||||||
|       if !self.authorization.respond_to?(:generate_authenticated_request) |       # Force immediate type-checking and short-cut resolution | ||||||
|         raise TypeError, |       self.parser | ||||||
|           'Expected authorization mechanism to respond to ' + |       self.authorization | ||||||
|           '#generate_authenticated_request.' |       self.http_adapter | ||||||
|       end |       return self | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     ## |     ## | ||||||
|  | @ -53,8 +53,11 @@ module Google | ||||||
| 
 | 
 | ||||||
|     ## |     ## | ||||||
|     # Returns the authorization mechanism used by the client. |     # Returns the authorization mechanism used by the client. | ||||||
|  |     # | ||||||
|  |     # @return [#generate_authenticated_request] The authorization mechanism. | ||||||
|     def authorization |     def authorization | ||||||
|       unless @options[:authorization] |       case @options[:authorization] | ||||||
|  |       when :oauth_1, :oauth | ||||||
|         require 'signet/oauth_1/client' |         require 'signet/oauth_1/client' | ||||||
|         # NOTE: Do not rely on this default value, as it may change |         # NOTE: Do not rely on this default value, as it may change | ||||||
|         @options[:authorization] = Signet::OAuth1::Client.new( |         @options[:authorization] = Signet::OAuth1::Client.new( | ||||||
|  | @ -67,10 +70,29 @@ module Google | ||||||
|           :client_credential_key => 'anonymous', |           :client_credential_key => 'anonymous', | ||||||
|           :client_credential_secret => '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 |       end | ||||||
|       return @options[:authorization] |       return @options[:authorization] | ||||||
|     end |     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. |     # Returns the HTTP adapter used by the client. | ||||||
|     def http_adapter |     def http_adapter | ||||||
|  | @ -204,21 +226,15 @@ module Google | ||||||
|     # @param [String, Symbol] service_name The name of the service. |     # @param [String, Symbol] service_name The name of the service. | ||||||
|     # |     # | ||||||
|     # @return [Google::APIClient::Service] The service object. |     # @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) |       if !service_name.kind_of?(String) && !service_name.kind_of?(Symbol) | ||||||
|         raise TypeError, |         raise TypeError, | ||||||
|           "Expected String or Symbol, got #{service_name.class}." |           "Expected String or Symbol, got #{service_name.class}." | ||||||
|       end |       end | ||||||
|       service_name = service_name.to_s |       service_name = service_name.to_s | ||||||
|       versions = {} |       return (self.discovered_services.select do |service| | ||||||
|       for service in self.discovered_services |         service.name == service_name | ||||||
|         next if service.name != service_name |       end).sort.last | ||||||
|         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] |  | ||||||
|     end |     end | ||||||
| 
 | 
 | ||||||
|     ## |     ## | ||||||
|  | @ -242,25 +258,31 @@ module Google | ||||||
|     #     <code>:signed</code> is <code>true</code>. |     #     <code>:signed</code> is <code>true</code>. | ||||||
|     #   - <code>:signed</code> —  |     #   - <code>:signed</code> —  | ||||||
|     #     <code>true</code> if the request must be signed, <code>false</code> |     #     <code>true</code> if the request must be signed, <code>false</code> | ||||||
|     #     otherwise.  Defaults to <code>true</code>. |     #     otherwise.  Defaults to <code>true</code> if an authorization | ||||||
|  |     #     mechanism has been set, <code>false</code> otherwise. | ||||||
|     # |     # | ||||||
|     # @return [Array] The generated request. |     # @return [Array] The generated request. | ||||||
|     # |     # | ||||||
|     # @example |     # @example | ||||||
|     #   request = client.generate_request( |     #   request = client.generate_request( | ||||||
|     #     'chili.activities.list', |     #     'chili.activities.list', | ||||||
|     #     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}, |     #     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'} | ||||||
|     #     '', [], {:signed => true} |  | ||||||
|     #   ) |     #   ) | ||||||
|     #   method, uri, headers, body = request |     #   method, uri, headers, body = request | ||||||
|     def generate_request( |     def generate_request( | ||||||
|         api_method, parameters={}, body='', headers=[], options={}) |         api_method, parameters={}, body='', headers=[], options={}) | ||||||
|       options={ |       options={ | ||||||
|         :signed => true, |  | ||||||
|         :parser => self.parser, |         :parser => self.parser, | ||||||
|         :service_version => 'v1', |         :service_version => 'v1', | ||||||
|         :authorization => self.authorization |         :authorization => self.authorization | ||||||
|       }.merge(options) |       }.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) |       if api_method.kind_of?(String) || api_method.kind_of?(Symbol) | ||||||
|         api_method = self.discovered_method( |         api_method = self.discovered_method( | ||||||
|           api_method.to_s, options[:service_version] |           api_method.to_s, options[:service_version] | ||||||
|  | @ -310,8 +332,7 @@ module Google | ||||||
|     # @example |     # @example | ||||||
|     #   response = client.execute( |     #   response = client.execute( | ||||||
|     #     'chili.activities.list', |     #     'chili.activities.list', | ||||||
|     #     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'}, |     #     {'scope' => '@self', 'userId' => '@me', 'alt' => 'json'} | ||||||
|     #     '', [], {:signed => true} |  | ||||||
|     #   ) |     #   ) | ||||||
|     #   status, headers, body = response |     #   status, headers, body = response | ||||||
|     def execute(api_method, parameters={}, body='', headers=[], options={}) |     def execute(api_method, parameters={}, body='', headers=[], options={}) | ||||||
|  |  | ||||||
|  | @ -138,6 +138,44 @@ module Google | ||||||
|         end) |         end) | ||||||
|       end |       end | ||||||
| 
 | 
 | ||||||
|  |       ## | ||||||
|  |       # Compares two versions of a service. | ||||||
|  |       # | ||||||
|  |       # @param [Object] other The service to compare. | ||||||
|  |       # | ||||||
|  |       # @return [Integer] | ||||||
|  |       #   <code>-1</code> if the service is older than <code>other</code>. | ||||||
|  |       #   <code>0</code> if the service is the same as <code>other</code>. | ||||||
|  |       #   <code>1</code> if the service is newer than <code>other</code>. | ||||||
|  |       #   <code>nil</code> if the service cannot be compared to | ||||||
|  |       #   <code>other</code>. | ||||||
|  |       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 <code>String</code> representation of the service's state. |       # Returns a <code>String</code> representation of the service's state. | ||||||
|       # |       # | ||||||
|  |  | ||||||
|  | @ -113,13 +113,13 @@ describe Google::APIClient, 'configured for the prediction API' do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'should correctly determine the latest version' do |   it 'should correctly determine the latest version' do | ||||||
|     @client.latest_service('prediction').version.should_not == 'v1' |     @client.latest_service_version('prediction').version.should_not == 'v1' | ||||||
|     @client.latest_service(:prediction).version.should_not == 'v1' |     @client.latest_service_version(:prediction).version.should_not == 'v1' | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'should raise an error for bogus services' do |   it 'should raise an error for bogus services' do | ||||||
|     (lambda do |     (lambda do | ||||||
|       @client.latest_service(42) |       @client.latest_service_version(42) | ||||||
|     end).should raise_error(TypeError) |     end).should raise_error(TypeError) | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|  | @ -138,7 +138,7 @@ describe Google::APIClient, 'configured for the prediction API' do | ||||||
|       Google::APIClient::Service.new('magic', 'v2.1', {}) |       Google::APIClient::Service.new('magic', 'v2.1', {}) | ||||||
|     @client.discovered_services << |     @client.discovered_services << | ||||||
|       Google::APIClient::Service.new('magic', 'v10.0', {}) |       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 |   end | ||||||
| 
 | 
 | ||||||
|   it 'should correctly determine the latest version' do |   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', {}) |       Google::APIClient::Service.new('two', 'v1.1-r1c3', {}) | ||||||
|     @client.discovered_services << |     @client.discovered_services << | ||||||
|       Google::APIClient::Service.new('two', 'v2', {}) |       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 |   end | ||||||
| 
 | 
 | ||||||
|   it 'should return nil for bogus service names' do |   it 'should return nil for bogus service names' do | ||||||
|     # Sanity check the algorithm |     # Sanity check the algorithm | ||||||
|     @client.latest_service('bogus').should == nil |     @client.latest_service_version('bogus').should == nil | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'should generate valid requests' do |   it 'should generate valid requests' do | ||||||
|     request = @client.generate_request( |     request = @client.generate_request( | ||||||
|       'prediction.training.insert', |       'prediction.training.insert', | ||||||
|       {'query' => '12345'}, |       {'query' => '12345'} | ||||||
|       '', |  | ||||||
|       [], |  | ||||||
|       {:signed => false} |  | ||||||
|     ) |     ) | ||||||
|     method, uri, headers, body = request |     method, uri, headers, body = request | ||||||
|     method.should == 'POST' |     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 |   it 'should generate requests against the correct URIs' do | ||||||
|     request = @client.generate_request( |     request = @client.generate_request( | ||||||
|       :'prediction.training.insert', |       :'prediction.training.insert', | ||||||
|       {'query' => '12345'}, |       {'query' => '12345'} | ||||||
|       '', |  | ||||||
|       [], |  | ||||||
|       {:signed => false} |  | ||||||
|     ) |     ) | ||||||
|     method, uri, headers, body = request |     method, uri, headers, body = request | ||||||
|     uri.should == |     uri.should == | ||||||
|  | @ -193,10 +189,7 @@ describe Google::APIClient, 'configured for the prediction API' do | ||||||
|     prediction = @client.discovered_service('prediction', 'v1') |     prediction = @client.discovered_service('prediction', 'v1') | ||||||
|     request = @client.generate_request( |     request = @client.generate_request( | ||||||
|       prediction.training.insert, |       prediction.training.insert, | ||||||
|       {'query' => '12345'}, |       {'query' => '12345'} | ||||||
|       '', |  | ||||||
|       [], |  | ||||||
|       {:signed => false} |  | ||||||
|     ) |     ) | ||||||
|     method, uri, headers, body = request |     method, uri, headers, body = request | ||||||
|     uri.should == |     uri.should == | ||||||
|  | @ -204,14 +197,12 @@ describe Google::APIClient, 'configured for the prediction API' do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'should generate signed requests' do |   it 'should generate signed requests' do | ||||||
|  |     @client.authorization = :oauth_1 | ||||||
|     @client.authorization.token_credential_key = '12345' |     @client.authorization.token_credential_key = '12345' | ||||||
|     @client.authorization.token_credential_secret = '12345' |     @client.authorization.token_credential_secret = '12345' | ||||||
|     request = @client.generate_request( |     request = @client.generate_request( | ||||||
|       'prediction.training.insert', |       'prediction.training.insert', | ||||||
|       {'query' => '12345'}, |       {'query' => '12345'} | ||||||
|       '', |  | ||||||
|       [], |  | ||||||
|       {:signed => true} |  | ||||||
|     ) |     ) | ||||||
|     method, uri, headers, body = request |     method, uri, headers, body = request | ||||||
|     headers = Hash[headers] |     headers = Hash[headers] | ||||||
|  | @ -220,14 +211,12 @@ describe Google::APIClient, 'configured for the prediction API' do | ||||||
|   end |   end | ||||||
| 
 | 
 | ||||||
|   it 'should not be able to execute improperly authorized requests' do |   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_key = '12345' | ||||||
|     @client.authorization.token_credential_secret = '12345' |     @client.authorization.token_credential_secret = '12345' | ||||||
|     response = @client.execute( |     response = @client.execute( | ||||||
|       'prediction.training.insert', |       'prediction.training.insert', | ||||||
|       {'query' => '12345'}, |       {'query' => '12345'} | ||||||
|       '', |  | ||||||
|       [], |  | ||||||
|       {:signed => true} |  | ||||||
|     ) |     ) | ||||||
|     status, headers, body = response |     status, headers, body = response | ||||||
|     status.should == 401 |     status.should == 401 | ||||||
|  |  | ||||||
|  | @ -34,6 +34,24 @@ describe Google::APIClient, 'with default configuration' do | ||||||
|     @client.parser.should be(Google::APIClient::JSONParser) |     @client.parser.should be(Google::APIClient::JSONParser) | ||||||
|   end |   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 |   it 'should use the default OAuth1 client configuration' do | ||||||
|     @client.authorization.temporary_credential_uri.to_s.should == |     @client.authorization.temporary_credential_uri.to_s.should == | ||||||
|       'https://www.google.com/accounts/OAuthGetRequestToken' |       'https://www.google.com/accounts/OAuthGetRequestToken' | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue