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' | ||||
|   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 | ||||
| 
 | ||||
|  |  | |||
|  | @ -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 | |||
|     #     <code>:signed</code> is <code>true</code>. | ||||
|     #   - <code>:signed</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. | ||||
|     # | ||||
|     # @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={}) | ||||
|  |  | |||
|  | @ -138,6 +138,44 @@ module Google | |||
|         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. | ||||
|       # | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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' | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue