diff --git a/README b/README index 9ac40b712..9582150d6 100644 --- a/README +++ b/README @@ -7,11 +7,8 @@ License:: Apache 2.0 == Description -The Google API Ruby Client makes it trivial to discover and access supported APIs. - -== Features - -* A feature list goes here. +The Google API Ruby Client makes it trivial to discover and access supported +APIs. == Example Usage diff --git a/lib/google/api_client/discovery.rb b/lib/google/api_client/discovery.rb index 96627e16b..2a14295fd 100644 --- a/lib/google/api_client/discovery.rb +++ b/lib/google/api_client/discovery.rb @@ -19,10 +19,30 @@ require 'extlib/inflection' module Google class APIClient + ## + # An exception that is raised if a method is called with missing or + # invalid parameter values. class ValidationError < StandardError end + ## + # A service that has been described by a discovery document. class Service + + ## + # Creates a description of a particular version of a service. + # + # @param [String] service_name + # The identifier for the service. Note that while this frequently + # matches the first segment of all of the service's RPC names, this + # should not be assumed. There is no requirement that these match. + # @param [String] service_version + # The identifier for the service version. + # @param [Hash] service_description + # The section of the discovery document that applies to this service + # version. + # + # @return [Google::APIClient::Service] The constructed service object. def initialize(service_name, service_version, service_description) @name = service_name @version = service_version @@ -42,12 +62,38 @@ module Google end end - attr_reader :name, :version, :description + ## + # Returns the identifier for the service. + # + # @return [String] The service identifier. + attr_reader :name + ## + # Returns the version of the service. + # + # @return [String] The service version. + attr_reader :version + + ## + # Returns the parsed section of the discovery document that applies to + # this version of the service. + # + # @return [Hash] The service description. + attr_reader :description + + ## + # Returns the base URI for this version of the service. + # + # @return [Addressable::URI] The base URI that methods are joined to. def base return @base ||= Addressable::URI.parse(self.description['baseUrl']) end + ## + # A list of resources available at the root level of this version of the + # service. + # + # @return [Array] A list of {Google::APIClient::Resource} objects. def resources return @resources ||= ( (self.description['resources'] || []).inject([]) do |accu, (k, v)| @@ -57,6 +103,11 @@ module Google ) end + ## + # A list of methods available at the root level of this version of the + # service. + # + # @return [Array] A list of {Google::APIClient::Method} objects. def methods return @methods ||= ( (self.description['methods'] || []).inject([]) do |accu, (k, v)| @@ -66,6 +117,10 @@ module Google ) end + ## + # Converts the service to a flat mapping of RPC names and method objects. + # + # @return [Hash] All methods available on the service. def to_h return @hash ||= (begin methods_hash = {} @@ -90,7 +145,21 @@ module Google end end + ## + # A resource that has been described by a discovery document. class Resource + + ## + # Creates a description of a particular version of a resource. + # + # @param [Addressable::URI] base + # The base URI for the service. + # @param [String] resource_name + # The identifier for the resource. + # @param [Hash] resource_description + # The section of the discovery document that applies to this resource. + # + # @return [Google::APIClient::Resource] The constructed resource object. def initialize(base, resource_name, resource_description) @base = base @name = resource_name @@ -110,8 +179,29 @@ module Google end end - attr_reader :name, :description, :base + ## + # Returns the identifier for the resource. + # + # @return [String] The resource identifier. + attr_reader :name + ## + # Returns the parsed section of the discovery document that applies to + # this resource. + # + # @return [Hash] The resource description. + attr_reader :description + + ## + # Returns the base URI for this resource. + # + # @return [Addressable::URI] The base URI that methods are joined to. + attr_reader :base + + ## + # A list of sub-resources available on this resource. + # + # @return [Array] A list of {Google::APIClient::Resource} objects. def resources return @resources ||= ( (self.description['resources'] || []).inject([]) do |accu, (k, v)| @@ -121,6 +211,10 @@ module Google ) end + ## + # A list of methods available on this resource. + # + # @return [Array] A list of {Google::APIClient::Method} objects. def methods return @methods ||= ( (self.description['methods'] || []).inject([]) do |accu, (k, v)| @@ -130,6 +224,11 @@ module Google ) end + ## + # Converts the resource to a flat mapping of RPC names and method + # objects. + # + # @return [Hash] All methods available on the resource. def to_h return @hash ||= (begin methods_hash = {} @@ -154,30 +253,82 @@ module Google end end + ## + # A method that has been described by a discovery document. class Method + + ## + # Creates a description of a particular method. + # + # @param [Addressable::URI] base + # The base URI for the service. + # @param [String] method_name + # The identifier for the method. + # @param [Hash] method_description + # The section of the discovery document that applies to this method. + # + # @return [Google::APIClient::Method] The constructed method object. def initialize(base, method_name, method_description) @base = base @name = method_name @description = method_description end - attr_reader :name, :description, :base + ## + # Returns the identifier for the method. + # + # @return [String] The method identifier. + attr_reader :name + ## + # Returns the parsed section of the discovery document that applies to + # this method. + # + # @return [Hash] The method description. + attr_reader :description + + ## + # Returns the base URI for the method. + # + # @return [Addressable::URI] + # The base URI that this method will be joined to. + attr_reader :base + + ## + # Returns the RPC name for the method. + # + # @return [String] The RPC name. def rpc_name return self.description['rpcName'] end + ## + # Returns the URI template for the method. A parameter list can be + # used to expand this into a URI. + # + # @return [Addressable::Template] The URI template. def uri_template # TODO(bobaman) We shouldn't be calling #to_s here, this should be # a join operation on a URI, but we have to treat these as Strings # because of the way the discovery document provides the URIs. + # This should be fixed soon. return @uri_template ||= Addressable::Template.new(base.to_s + self.description['pathUrl']) end + ## + # Normalizes parameters, converting to the appropriate types. + # + # @param [Hash, Array] parameters + # The parameters to normalize. + # + # @return [Hash] The normalized parameters. def normalize_parameters(parameters={}) # Convert keys to Strings when appropriate if parameters.kind_of?(Hash) || parameters.kind_of?(Array) + # Is a Hash or an Array a better return type? Do we ever need to + # worry about the same parameter being sent twice with different + # values? parameters = parameters.inject({}) do |accu, (k, v)| k = k.to_s if k.kind_of?(Symbol) k = k.to_str if k.respond_to?(:to_str) @@ -194,6 +345,13 @@ module Google return parameters end + ## + # Expands the method's URI template using a parameter list. + # + # @param [Hash, Array] parameters + # The parameter list to use. + # + # @return [Addressable::URI] The URI after expansion. def generate_uri(parameters={}) parameters = self.normalize_parameters(parameters) self.validate_parameters(parameters) @@ -210,12 +368,29 @@ module Google return uri.normalize end + ## + # Generates an HTTP request for this method. + # + # @param [Hash, Array] parameters + # The parameters to send. + # @param [String] body The body for the HTTP request. + # @param [Hash, Array] headers The HTTP headers for the request. + # + # @return [Array] The generated HTTP request. def generate_request(parameters={}, body='', headers=[]) method = self.description['httpMethod'] || 'GET' uri = self.generate_uri(parameters) return [method, uri.to_str, headers, [body]] end + ## + # Verifies that the parameters are valid for this method. Raises an + # exception if validation fails. + # + # @param [Hash, Array] parameters + # The parameters to verify. + # + # @return [NilClass] nil if validation passes. def validate_parameters(parameters={}) parameters = self.normalize_parameters(parameters) parameter_description = self.description['parameters'] || {} diff --git a/spec/google/api_client/discovery_spec.rb b/spec/google/api_client/discovery_spec.rb index 7865d4415..f12fa12e3 100644 --- a/spec/google/api_client/discovery_spec.rb +++ b/spec/google/api_client/discovery_spec.rb @@ -148,6 +148,8 @@ describe Google::APIClient, 'configured for the prediction API' do Google::APIClient::Service.new('one', 'v3', {}) @client.discovered_services << Google::APIClient::Service.new('two', 'v1', {}) + @client.discovered_services << + Google::APIClient::Service.new('two', 'v1.1-r1c3', {}) @client.discovered_services << Google::APIClient::Service.new('two', 'v2', {}) @client.latest_service('two').version.should == 'v2'