+== 0.2.0
+
+* updated to use v0.3 of the discovery API
+* updated to use httpadapter 1.0.0
+* added OAuth 2 support to the command line tool
+* renamed some switches in the command line tool
+* added additional configuration capabilities
+
== 0.1.3
* added support for manual overrides of the discovery URI
client.authorization.fetch_token_credential!(:verifier => '12345')
# Discover available methods
- method_names = client.discovered_service('buzz').to_h.keys
+ method_names = client.discovered_api('buzz').to_h.keys
# Make an API call
response = client.execute(
def do_GET(request, response)
$verifier ||= Addressable::URI.unencode_component(
- request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1]
+ request.request_uri.to_s[/\?.*oauth_verifier=([^&$]+)(&|$)/, 1] ||
+ request.request_uri.to_s[/\?.*code=([^&$]+)(&|$)/, 1]
)
response.status = WEBrick::HTTPStatus::RC_ACCEPTED
# This javascript will auto-close the tab after the
options[:scope] = s
end
opts.on(
- "--client-key <key>", String,
- "Set the 2-legged OAuth key") do |k|
+ "--client-id <key>", String,
+ "Set the OAuth client id or key") do |k|
options[:client_credential_key] = k
end
opts.on(
"--client-secret <secret>", String,
- "Set the 2-legged OAuth secret") do |s|
+ "Set the OAuth client secret") do |s|
options[:client_credential_secret] = s
end
opts.on(
- "-s", "--service <name>", String,
- "Perform discovery on service") do |s|
- options[:service_name] = s
+ "--api <name>", String,
+ "Perform discovery on API") do |s|
+ options[:api] = s
end
opts.on(
"--service-version <id>", String,
"Select service version") do |id|
- options[:service_version] = id
+ options[:version] = id
end
opts.on(
"--content-type <format>", String,
opts.separator(
"\nAvailable commands:\n" +
- " oauth-login Log a user into an API\n" +
- " list List the methods available for a service\n" +
- " execute Execute a method on the API\n" +
- " irb Start an interactive client session"
+ " oauth-1-login Log a user into an API with OAuth 1.0a\n" +
+ " oauth-2-login Log a user into an API with OAuth 2.0 d10\n" +
+ " list List the methods available for a service\n" +
+ " execute Execute a method on the API\n" +
+ " irb Start an interactive client session"
)
end
end
self.send(symbol)
end
+ def client
+ require 'signet/oauth_1/client'
+ require 'yaml'
+ require 'irb'
+ config_file = File.expand_path('~/.google-api.yaml')
+ authorization = nil
+ if File.exist?(config_file)
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
+ else
+ config = {}
+ end
+ if config["mechanism"]
+ authorization = config["mechanism"].to_sym
+ end
+
+ client = Google::APIClient.new(:authorization => authorization)
+
+ case authorization
+ when :oauth_1
+ if client.authorization &&
+ !client.authorization.kind_of?(Signet::OAuth1::Client)
+ STDERR.puts(
+ "Unexpected authorization mechanism: " +
+ "#{client.authorization.class}"
+ )
+ exit(1)
+ end
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
+ client.authorization.client_credential_key =
+ config["client_credential_key"]
+ client.authorization.client_credential_secret =
+ config["client_credential_secret"]
+ client.authorization.token_credential_key =
+ config["token_credential_key"]
+ client.authorization.token_credential_secret =
+ config["token_credential_secret"]
+ when :oauth_2
+ if client.authorization &&
+ !client.authorization.kind_of?(Signet::OAuth2::Client)
+ STDERR.puts(
+ "Unexpected authorization mechanism: " +
+ "#{client.authorization.class}"
+ )
+ exit(1)
+ end
+ config = open(config_file, 'r') { |file| YAML.load(file.read) }
+ client.authorization.scope = options[:scope]
+ client.authorization.client_id = config["client_id"]
+ client.authorization.client_secret = config["client_secret"]
+ client.authorization.access_token = config["access_token"]
+ client.authorization.refresh_token = config["refresh_token"]
+ else
+ # Dunno?
+ end
+
+ if options[:discovery_uri]
+ client.discovery_uri = options[:discovery_uri]
+ end
+
+ return client
+ end
+
+ def api_version(api, version)
+ v = version
+ if !version
+ if client.preferred_version(api)
+ v = client.preferred_version(api).version
+ else
+ v = 'v1'
+ end
+ end
+ return v
+ end
+
COMMANDS = [
- :oauth_login,
+ :oauth_1_login,
+ :oauth_2_login,
:list,
:execute,
:irb,
:fuzz
]
- def oauth_login
+ def oauth_1_login
require 'signet/oauth_1/client'
require 'launchy'
require 'yaml'
if options[:client_credential_key] &&
options[:client_credential_secret]
- scope = options[:scope]
config = {
- "scope" => nil,
+ "mechanism" => "oauth_1",
+ "scope" => options[:scope],
"client_credential_key" => options[:client_credential_key],
"client_credential_secret" => options[:client_credential_secret],
"token_credential_key" => nil,
:client_credential_secret => 'anonymous',
:callback => "http://localhost:#{OAUTH_SERVER_PORT}/"
)
- scope = options[:scope]
- # Special cases
- case scope
- when /https:\/\/www\.googleapis\.com\/auth\/buzz/,
- /https:\/\/www\.googleapis\.com\/auth\/buzz\.readonly/
- oauth_client.authorization_uri =
- 'https://www.google.com/buzz/api/auth/OAuthAuthorizeToken?' +
- "domain=#{oauth_client.client_credential_key}&" +
- "scope=#{scope}&" +
- "xoauth_displayname=Google%20API%20Client"
- end
oauth_client.fetch_temporary_credential!(:additional_parameters => {
- :scope => scope,
+ :scope => options[:scope],
:xoauth_displayname => 'Google API Client'
})
server.start
oauth_client.fetch_token_credential!(:verifier => $verifier)
config = {
- "scope" => scope,
+ "scope" => options[:scope],
"client_credential_key" =>
oauth_client.client_credential_key,
"client_credential_secret" =>
end
end
+ def oauth_2_login
+ require 'signet/oauth_2/client'
+ require 'launchy'
+ require 'yaml'
+ if !options[:client_credential_key] ||
+ !options[:client_credential_secret]
+ STDERR.puts('No client ID and secret supplied.')
+ exit(1)
+ end
+ if options[:access_token]
+ config = {
+ "mechanism" => "oauth_2",
+ "scope" => options[:scope],
+ "client_id" => options[:client_credential_key],
+ "client_secret" => options[:client_credential_secret],
+ "access_token" => options[:access_token],
+ "refresh_token" => options[:refresh_token]
+ }
+ config_file = File.expand_path('~/.google-api.yaml')
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
+ exit(0)
+ else
+ $verifier = nil
+ # TODO(bobaman): Cross-platform?
+ logger = WEBrick::Log.new('/dev/null')
+ server = WEBrick::HTTPServer.new(
+ :Port => OAUTH_SERVER_PORT,
+ :Logger => logger,
+ :AccessLog => logger
+ )
+ trap("INT") { server.shutdown }
+
+ server.mount("/", OAuthVerifierServlet)
+
+ oauth_client = Signet::OAuth2::Client.new(
+ :authorization_uri =>
+ 'https://www.google.com/accounts/o8/oauth2/authorization',
+ :token_credential_uri =>
+ 'https://www.google.com/accounts/o8/oauth2/token',
+ :client_id => options[:client_credential_key],
+ :client_secret => options[:client_credential_secret],
+ :redirect_uri => "http://localhost:#{OAUTH_SERVER_PORT}/",
+ :scope => options[:scope]
+ )
+
+ # Launch browser
+ Launchy::Browser.run(oauth_client.authorization_uri.to_s)
+
+ server.start
+ oauth_client.code = $verifier
+ oauth_client.fetch_access_token!
+ config = {
+ "mechanism" => "oauth_2",
+ "scope" => options[:scope],
+ "client_id" => oauth_client.client_id,
+ "client_secret" => oauth_client.client_secret,
+ "access_token" => oauth_client.access_token,
+ "refresh_token" => oauth_client.refresh_token
+ }
+ config_file = File.expand_path('~/.google-api.yaml')
+ open(config_file, 'w') { |file| file.write(YAML.dump(config)) }
+ exit(0)
+ end
+ end
+
def list
- service_name = options[:service_name]
- unless service_name
+ api = options[:api]
+ unless api
STDERR.puts('No service name supplied.')
exit(1)
end
- client = Google::APIClient.new(
- :service => service_name,
- :authorization => nil
- )
+ client = Google::APIClient.new(:authorization => nil)
if options[:discovery_uri]
client.discovery_uri = options[:discovery_uri]
end
- service_version =
- options[:service_version] ||
- client.latest_service_version(service_name).version
- service = client.discovered_service(service_name, service_version)
+ version = api_version(api, options[:version])
+ service = client.discovered_api(api, version)
rpcnames = service.to_h.keys
puts rpcnames.sort.join("\n")
exit(0)
end
def execute
- require 'signet/oauth_1/client'
- require 'yaml'
- config_file = File.expand_path('~/.google-api.yaml')
- signed = File.exist?(config_file)
- authorization_type = :oauth_1
+ client = self.client
# Setup HTTP request data
request_body = ''
headers << ['Content-Type', 'application/json']
end
- configure_authorization = lambda do |client|
- if !client.authorization.kind_of?(Signet::OAuth1::Client)
- STDERR.puts(
- "Unexpected authorization mechanism: " +
- "#{client.authorization.class}"
- )
- exit(1)
- end
- config = open(config_file, 'r') { |file| YAML.load(file.read) }
- client.authorization.client_credential_key =
- config["client_credential_key"]
- client.authorization.client_credential_secret =
- config["client_credential_secret"]
- client.authorization.token_credential_key =
- config["token_credential_key"]
- client.authorization.token_credential_secret =
- config["token_credential_secret"]
- if client.authorization.token_credential == nil
- authorization_type = :two_legged_oauth_1
- end
- end
-
if options[:uri]
# Make request with URI manually specified
uri = Addressable::URI.parse(options[:uri])
method = options[:http_method]
method ||= request_body == '' ? 'GET' : 'POST'
method.upcase!
- client = Google::APIClient.new(:authorization => authorization_type)
- if options[:discovery_uri]
- client.discovery_uri = options[:discovery_uri]
- end
- configure_authorization.call(client) if signed
request = [method, uri.to_str, headers, [request_body]]
- request = client.sign_request(request)
+ request = client.generate_authenticated_request(:request => request)
response = client.transmit_request(request)
status, headers, body = response
puts body
STDERR.puts('No rpcname supplied.')
exit(1)
end
- service_name =
- options[:service_name] || self.rpcname[/^([^\.]+)\./, 1]
- client = Google::APIClient.new(
- :service => service_name,
- :authorization => authorization_type
- )
- if options[:discovery_uri]
- client.discovery_uri = options[:discovery_uri]
- end
- configure_authorization.call(client) if signed
- service_version =
- options[:service_version] ||
- client.latest_service_version(service_name).version
- service = client.discovered_service(service_name, service_version)
+ api = options[:api] || self.rpcname[/^([^\.]+)\./, 1]
+ version = api_version(api, options[:version])
+ service = client.discovered_api(api, version)
method = service.to_h[self.rpcname]
if !method
STDERR.puts(
"Method #{self.rpcname} does not exist for " +
- "#{service_name}-#{service_version}."
+ "#{api}-#{version}."
)
exit(1)
end
end
begin
response = client.execute(
- method, parameters, request_body, headers, {:signed => signed}
+ method, parameters, request_body, headers
)
status, headers, body = response
puts body
end
def irb
- require 'signet/oauth_1/client'
- require 'yaml'
- require 'irb'
- config_file = File.expand_path('~/.google-api.yaml')
- signed = File.exist?(config_file)
-
- $client = Google::APIClient.new(
- :service => options[:service_name],
- :authorization => (signed ? :oauth_1 : nil)
- )
-
- if signed
- if $client.authorization &&
- !$client.authorization.kind_of?(Signet::OAuth1::Client)
- STDERR.puts(
- "Unexpected authorization mechanism: " +
- "#{$client.authorization.class}"
- )
- exit(1)
- end
- config = open(config_file, 'r') { |file| YAML.load(file.read) }
- $client.authorization.client_credential_key =
- config["client_credential_key"]
- $client.authorization.client_credential_secret =
- config["client_credential_secret"]
- $client.authorization.token_credential_key =
- config["token_credential_key"]
- $client.authorization.token_credential_secret =
- config["token_credential_secret"]
- end
-
+ $client = self.client
# Otherwise IRB will misinterpret command-line options
ARGV.clear
IRB.start(__FILE__)
unless service_version
service_version = client.latest_service_version(service_name).version
end
- client.discovered_service(service_name, service_version)
+ client.discovered_api(service_name, service_version)
end
get '/template/:service/:method/' do
# See the License for the specific language governing permissions and
# limitations under the License.
+
require 'httpadapter'
require 'json'
require 'stringio'
+require 'google/api_client/errors'
require 'google/api_client/discovery'
module Google
# TODO(bobaman): Document all this stuff.
+
##
- # This class manages communication with a single API.
+ # This class manages APIs communication.
class APIClient
##
- # An error which is raised when there is an unexpected response or other
- # transport error that prevents an operation from succeeding.
- class TransmissionError < StandardError
- end
-
+ # Creates a new Google API client.
+ #
+ # @param [Hash] options The configuration parameters for the client.
+ # @option options [Symbol, #generate_authenticated_request] :authorization
+ # (:oauth_1)
+ # The authorization mechanism used by the client. The following
+ # mechanisms are supported out-of-the-box:
+ # <ul>
+ # <li><code>:two_legged_oauth_1</code></li>
+ # <li><code>:oauth_1</code></li>
+ # <li><code>:oauth_2</code></li>
+ # </ul>
+ # @option options [String] :host ("www.googleapis.com")
+ # The API hostname used by the client. This rarely needs to be changed.
+ # @option options [String] :user_agent ("google-api-ruby-client/{version}")
+ # The user agent used by the client. Most developers will want to
+ # leave this value alone — the API key is the primary mechanism used to
+ # identify an application.
def initialize(options={})
- @options = {
- :user_agent => (
- 'google-api-ruby-client/' + Google::APIClient::VERSION::STRING
- )
- }.merge(options)
- # Force immediate type-checking and short-cut resolution
- self.parser
- self.authorization
- self.http_adapter
+ # Normalize key to String to allow indifferent access.
+ options = options.inject({}) do |accu, (key, value)|
+ accu[key.to_s] = value
+ accu
+ end
+ # Almost all API usage will have a host of 'www.googleapis.com'.
+ self.host = options["host"] || 'www.googleapis.com'
+ # Most developers will want to leave this value alone.
+ self.user_agent = options["user_agent"] || (
+ 'google-api-ruby-client/' + Google::APIClient::VERSION::STRING
+ )
+ # This is mostly a default for the sake of convenience.
+ # Unlike most other options, this one may be nil, so we check for
+ # the presence of the key rather than checking the value.
+ if options.has_key?("parser")
+ self.parser = options["parser"]
+ else
+ require 'google/api_client/parsers/json_parser'
+ # NOTE: Do not rely on this default value, as it may change
+ self.parser = Google::APIClient::JSONParser
+ end
+ # The writer method understands a few Symbols and will generate useful
+ # default authentication mechanisms.
+ self.authorization = options["authorization"] || :oauth_2
+ # The HTTP adapter controls all of the HTTP traffic the client generates.
+ # By default, Net::HTTP is used, but adding support for other clients
+ # is trivial.
+ if options["http_adapter"]
+ self.http_adapter = options["http_adapter"]
+ else
+ require 'httpadapter/adapters/net_http'
+ # NOTE: Do not rely on this default value, as it may change
+ self.http_adapter = HTTPAdapter::NetHTTPAdapter.new
+ end
+ @discovery_uris = {}
+ @discovery_documents = {}
+ @discovered_apis = {}
return self
end
+
##
# Returns the parser used by the client.
- def parser
- unless @options[:parser]
- require 'google/api_client/parsers/json_parser'
- # NOTE: Do not rely on this default value, as it may change
- @options[:parser] = JSONParser
+ #
+ # @return [#serialize, #parse]
+ # The parser used by the client. Any object that implements both a
+ # <code>#serialize</code> and a <code>#parse</code> method may be used.
+ # If <code>nil</code>, no parsing will be done.
+ attr_reader :parser
+
+ ##
+ # Sets the parser used by the client.
+ #
+ # @param [#serialize, #parse] new_parser
+ # The parser used by the client. Any object that implements both a
+ # <code>#serialize</code> and a <code>#parse</code> method may be used.
+ # If <code>nil</code>, no parsing will be done.
+ def parser=(new_parser)
+ if new_parser &&
+ !new_parser.respond_to?(:serialize) &&
+ !new_parser.respond_to?(:parse)
+ raise TypeError,
+ 'Expected parser object to respond to #serialize and #parse.'
end
- return @options[:parser]
+ @parser = new_parser
end
##
# Returns the authorization mechanism used by the client.
#
# @return [#generate_authenticated_request] The authorization mechanism.
- def authorization
- case @options[:authorization]
+ attr_reader :authorization
+
+ ##
+ # Sets the authorization mechanism used by the client.
+ #
+ # @param [#generate_authenticated_request] new_authorization
+ # The new authorization mechanism.
+ def authorization=(new_authorization)
+ case new_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(
+ new_authorization = Signet::OAuth1::Client.new(
:temporary_credential_uri =>
'https://www.google.com/accounts/OAuthGetRequestToken',
:authorization_uri =>
when :two_legged_oauth_1, :two_legged_oauth
require 'signet/oauth_1/client'
# NOTE: Do not rely on this default value, as it may change
- @options[:authorization] = Signet::OAuth1::Client.new(
+ new_authorization = Signet::OAuth1::Client.new(
:client_credential_key => nil,
:client_credential_secret => nil,
:two_legged => true
)
+ when :oauth_2
+ require 'signet/oauth_2/client'
+ # NOTE: Do not rely on this default value, as it may change
+ new_authorization = Signet::OAuth2::Client.new(
+ :authorization_uri =>
+ 'https://accounts.google.com/o/oauth2/auth',
+ :token_credential_uri =>
+ 'https://accounts.google.com/o/oauth2/token'
+ )
when nil
# No authorization mechanism
else
- if !@options[:authorization].respond_to?(
- :generate_authenticated_request)
+ if !new_authorization.respond_to?(:generate_authenticated_request)
raise TypeError,
'Expected authorization mechanism to respond to ' +
'#generate_authenticated_request.'
end
end
- return @options[:authorization]
+ @authorization = new_authorization
+ return @authorization
end
##
- # Sets the authorization mechanism used by the client.
+ # Returns the HTTP adapter 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
+ # @return [HTTPAdapter]
+ # The HTTP adapter object. The object must include the
+ # HTTPAdapter module and conform to its interface.
+ attr_reader :http_adapter
##
# Returns the HTTP adapter used by the client.
- def http_adapter
- return @options[:http_adapter] ||= (begin
- require 'httpadapter/adapters/net_http'
- @options[:http_adapter] = HTTPAdapter::NetHTTPRequestAdapter
- end)
+ #
+ # @return [HTTPAdapter]
+ # The HTTP adapter object. The object must include the
+ # HTTPAdapter module and conform to its interface.
+ def http_adapter=(new_http_adapter)
+ if new_http_adapter.kind_of?(HTTPAdapter)
+ @http_adapter = new_http_adapter
+ else
+ raise TypeError, "Expected HTTPAdapter, got #{new_http_adapter.class}."
+ end
+ end
+
+ ##
+ # The API hostname used by the client.
+ #
+ # @return [String]
+ # The API hostname. Should almost always be 'www.googleapis.com'.
+ attr_accessor :host
+
+ ##
+ # The user agent used by the client.
+ #
+ # @return [String]
+ # The user agent string used in the User-Agent header.
+ attr_accessor :user_agent
+
+ ##
+ # Returns the URI for the directory document.
+ #
+ # @return [Addressable::URI] The URI of the directory document.
+ def directory_uri
+ template = Addressable::Template.new(
+ "https://{host}/discovery/v0.3/directory"
+ )
+ return template.expand({
+ "host" => self.host
+ })
+ end
+
+ ##
+ # Manually registers a URI as a discovery document for a specific version
+ # of an API.
+ #
+ # @param [String, Symbol] api The service name.
+ # @param [String] version The desired version of the service.
+ # @param [Addressable::URI] uri The URI of the discovery document.
+ def register_discovery_uri(api, version, uri)
+ api = api.to_s
+ version = version || 'v1'
+ @discovery_uris["#{api}:#{version}"] = uri
end
##
# Returns the URI for the discovery document.
#
+ # @param [String, Symbol] api The service name.
+ # @param [String] version The desired version of the service.
# @return [Addressable::URI] The URI of the discovery document.
- def discovery_uri
- return @options[:discovery_uri] ||= (begin
- if @options[:service]
- service_id = @options[:service]
- service_version = @options[:service_version] || 'v1'
- Addressable::URI.parse(
- "http://www.googleapis.com/discovery/0.1/describe" +
- "?api=#{service_id}"
- )
- else
- raise ArgumentError,
- 'Missing required configuration value, :discovery_uri.'
- end
+ def discovery_uri(api, version=nil)
+ api = api.to_s
+ version = version || 'v1'
+ return @discovery_uris["#{api}:#{version}"] ||= (begin
+ template = Addressable::Template.new(
+ "https://{host}/discovery/v0.3/describe/" +
+ "{api}/{version}"
+ )
+ template.expand({
+ "host" => self.host,
+ "api" => api,
+ "version" => version
+ })
end)
end
##
- # Sets the discovery URI for the client.
+ # Manually registers a pre-loaded discovery document for a specific version
+ # of an API.
#
- # @param [Addressable::URI, #to_str, String] new_discovery_uri
- # The new discovery URI.
- def discovery_uri=(new_discovery_uri)
- @options[:discovery_uri] = Addressable::URI.parse(new_discovery_uri)
+ # @param [String, Symbol] api The service name.
+ # @param [String] version The desired version of the service.
+ # @param [String, StringIO] discovery_document
+ # The contents of the discovery document.
+ def register_discovery_document(api, version, discovery_document)
+ api = api.to_s
+ version = version || 'v1'
+ if discovery_document.kind_of?(StringIO)
+ discovery_document.rewind
+ discovery_document = discovery_document.string
+ elsif discovery_document.respond_to?(:to_str)
+ discovery_document = discovery_document.to_str
+ else
+ raise TypeError,
+ "Expected String or StringIO, got #{discovery_document.class}."
+ end
+ @discovery_documents["#{api}:#{version}"] =
+ JSON.parse(discovery_document)
+ end
+
+ ##
+ # Returns the parsed directory document.
+ #
+ # @return [Hash] The parsed JSON from the directory document.
+ def directory_document
+ return @directory_document ||= (begin
+ request_uri = self.directory_uri
+ request = ['GET', request_uri, [], []]
+ response = self.transmit_request(request)
+ status, headers, body = response
+ if status == 200 # TODO(bobaman) Better status code handling?
+ merged_body = StringIO.new
+ body.each do |chunk|
+ merged_body.write(chunk)
+ end
+ merged_body.rewind
+ JSON.parse(merged_body.string)
+ else
+ raise TransmissionError,
+ "Could not retrieve discovery document at: #{request_uri}"
+ end
+ end)
end
##
# Returns the parsed discovery document.
#
+ # @param [String, Symbol] api The service name.
+ # @param [String] version The desired version of the service.
# @return [Hash] The parsed JSON from the discovery document.
- def discovery_document
- return @discovery_document ||= (begin
- request = ['GET', self.discovery_uri.to_s, [], []]
+ def discovery_document(api, version=nil)
+ api = api.to_s
+ version = version || 'v1'
+ return @discovery_documents["#{api}:#{version}"] ||= (begin
+ request_uri = self.discovery_uri(api, version)
+ request = ['GET', request_uri, [], []]
response = self.transmit_request(request)
status, headers, body = response
if status == 200 # TODO(bobaman) Better status code handling?
JSON.parse(merged_body.string)
else
raise TransmissionError,
- "Could not retrieve discovery document at: #{self.discovery_uri}"
+ "Could not retrieve discovery document at: #{request_uri}"
end
end)
end
##
- # Returns a list of services this client instance has performed discovery
- # for. This may return multiple versions of the same service.
- #
- # @return [Array]
- # A list of discovered <code>Google::APIClient::Service</code> objects.
- def discovered_services
- return @discovered_services ||= (begin
- service_names = self.discovery_document['data'].keys()
- services = []
- for service_name in service_names
- versions = self.discovery_document['data'][service_name]
- for service_version in versions.keys()
- service_description =
- self.discovery_document['data'][service_name][service_version]
- services << ::Google::APIClient::Service.new(
- service_name,
- service_version,
- service_description
+ # Returns all APIs published in the directory document.
+ #
+ # @return [Array] The list of available APIs.
+ def discovered_apis
+ @directory_apis ||= (begin
+ document_base = self.directory_uri
+ if self.directory_document && self.directory_document['items']
+ self.directory_document['items'].map do |discovery_document|
+ ::Google::APIClient::API.new(
+ document_base,
+ discovery_document
)
end
+ else
+ []
end
- services
end)
end
##
# Returns the service object for a given service name and service version.
#
- # @param [String, Symbol] service_name The service name.
- # @param [String] service_version The desired version of the service.
+ # @param [String, Symbol] api The service name.
+ # @param [String] version The desired version of the service.
#
- # @return [Google::APIClient::Service] The service object.
- def discovered_service(service_name, service_version='v1')
- if !service_name.kind_of?(String) && !service_name.kind_of?(Symbol)
+ # @return [Google::APIClient::API] The service object.
+ def discovered_api(api, version=nil)
+ if !api.kind_of?(String) && !api.kind_of?(Symbol)
raise TypeError,
- "Expected String or Symbol, got #{service_name.class}."
+ "Expected String or Symbol, got #{api.class}."
end
- service_name = service_name.to_s
- for service in self.discovered_services
- if service.name == service_name &&
- service.version.to_s == service_version.to_s
- return service
+ api = api.to_s
+ version = version || 'v1'
+ return @discovered_apis["#{api}:#{version}"] ||= begin
+ document_base = self.discovery_uri(api, version)
+ discovery_document = self.discovery_document(api, version)
+ if document_base && discovery_document
+ ::Google::APIClient::API.new(
+ document_base,
+ discovery_document
+ )
+ else
+ nil
end
end
- return nil
end
##
# Returns the method object for a given RPC name and service version.
#
# @param [String, Symbol] rpc_name The RPC name of the desired method.
- # @param [String] service_version The desired version of the service.
+ # @param [String] version The desired version of the service.
#
# @return [Google::APIClient::Method] The method object.
- def discovered_method(rpc_name, service_version='v1')
+ def discovered_method(rpc_name, api, version=nil)
if !rpc_name.kind_of?(String) && !rpc_name.kind_of?(Symbol)
raise TypeError,
"Expected String or Symbol, got #{rpc_name.class}."
end
rpc_name = rpc_name.to_s
- for service in self.discovered_services
- # This looks kinda weird, but is not a real problem because there's
- # almost always only one service, and this is memoized anyhow.
- if service.version.to_s == service_version.to_s
- return service.to_h[rpc_name] if service.to_h[rpc_name]
- end
+ api = api.to_s
+ version = version || 'v1'
+ service = self.discovered_api(api, version)
+ if service.to_h[rpc_name]
+ return service.to_h[rpc_name]
+ else
+ return nil
end
- return nil
end
##
# Returns the service object with the highest version number.
#
- # <em>Warning</em>: This method should be used with great care. As APIs
- # are updated, minor differences between versions may cause
+ # @note <em>Warning</em>: This method should be used with great care.
+ # As APIs are updated, minor differences between versions may cause
# incompatibilities. Requesting a specific version will avoid this issue.
#
- # @param [String, Symbol] service_name The name of the service.
+ # @param [String, Symbol] api The name of the service.
#
- # @return [Google::APIClient::Service] The service object.
- def latest_service_version(service_name)
- if !service_name.kind_of?(String) && !service_name.kind_of?(Symbol)
+ # @return [Google::APIClient::API] The service object.
+ def preferred_version(api)
+ if !api.kind_of?(String) && !api.kind_of?(Symbol)
raise TypeError,
- "Expected String or Symbol, got #{service_name.class}."
+ "Expected String or Symbol, got #{api.class}."
end
- service_name = service_name.to_s
- return (self.discovered_services.select do |service|
- service.name == service_name
- end).sort.last
- end
-
- ##
- # Returns the user agent used by the client.
- #
- # @return [String]
- # The user agent string used in the User-Agent header.
- def user_agent
- return @options[:user_agent]
- end
-
- ##
- # Sets the user agent used by the client.
- #
- # @param [String, #to_str] new_user_agent
- # The new user agent string to use in the User-Agent header.
- def user_agent=(new_user_agent)
- unless new_user_agent == nil || new_user_agent.respond_to?(:to_str)
- raise TypeError, "Expected String, got #{new_user_agent.class}."
+ api = api.to_s
+ # TODO(bobaman): Update to use directory API.
+ return self.discovered_apis.detect do |a|
+ a.name == api && a.preferred == true
end
- new_user_agent = new_user_agent.to_str unless new_user_agent == nil
- @options[:user_agent] = new_user_agent
- return self.user_agent
end
##
# @param [Hash, Array] headers The HTTP headers for the request.
# @param [Hash] options
# The configuration parameters for the request.
- # - <code>:service_version</code> —
+ # - <code>:version</code> —
# The service version. Only used if <code>api_method</code> is a
# <code>String</code>. Defaults to <code>'v1'</code>.
# - <code>:parser</code> —
# The parser for the response.
# - <code>:authorization</code> —
# The authorization mechanism for the response. Used only if
- # <code>:signed</code> is <code>true</code>.
- # - <code>:signed</code> —
- # <code>true</code> if the request must be signed, <code>false</code>
+ # <code>:authenticated</code> is <code>true</code>.
+ # - <code>:authenticated</code> —
+ # <code>true</code> if the request must be signed or otherwise
+ # authenticated, <code>false</code>
# otherwise. Defaults to <code>true</code> if an authorization
# mechanism has been set, <code>false</code> otherwise.
#
api_method, parameters={}, body='', headers=[], options={})
options={
:parser => self.parser,
- :service_version => 'v1',
+ :version => 'v1',
:authorization => self.authorization
}.merge(options)
- # The default value for the :signed option depends on whether an
+ # The default value for the :authenticated option depends on whether an
# authorization mechanism has been set.
if options[:authorization]
- options = {:signed => true}.merge(options)
+ options = {:authenticated => true}.merge(options)
else
- options = {:signed => false}.merge(options)
+ options = {:authenticated => false}.merge(options)
end
if api_method.kind_of?(String) || api_method.kind_of?(Symbol)
+ api_method = api_method.to_s
+ # This method of guessing the API is unreliable. This will fail for
+ # APIs where the first segment of the RPC name does not match the
+ # service name. However, this is a fallback mechanism anyway.
+ # Developers should be passing in a reference to the method, rather
+ # than passing in a string or symbol. This should raise an error
+ # in the case of a mismatch.
+ api = api_method[/^([^.]+)\./, 1]
api_method = self.discovered_method(
- api_method.to_s, options[:service_version]
+ api_method, api, options[:version]
)
elsif !api_method.kind_of?(::Google::APIClient::Method)
raise TypeError,
raise ArgumentError, "API method could not be found."
end
request = api_method.generate_request(parameters, body, headers)
- if options[:signed]
- request = self.sign_request(request, options[:authorization])
+ if options[:authenticated]
+ request = self.generate_authenticated_request(:request => request)
end
return request
end
# @param [Hash, Array] headers The HTTP headers for the request.
# @param [Hash] options
# The configuration parameters for the request.
- # - <code>:service_version</code> —
+ # - <code>:version</code> —
# The service version. Only used if <code>api_method</code> is a
# <code>String</code>. Defaults to <code>'v1'</code>.
# - <code>:adapter</code> —
# The parser for the response.
# - <code>:authorization</code> —
# The authorization mechanism for the response. Used only if
- # <code>:signed</code> is <code>true</code>.
- # - <code>:signed</code> —
- # <code>true</code> if the request must be signed, <code>false</code>
+ # <code>:authenticated</code> is <code>true</code>.
+ # - <code>:authenticated</code> —
+ # <code>true</code> if the request must be signed or otherwise
+ # authenticated, <code>false</code>
# otherwise. Defaults to <code>true</code>.
#
# @return [Array] The response from the API.
include Enumerable
end
end
- unless headers.any? { |k, v| k.downcase == 'user-agent' }
- headers = headers.to_a.insert(0, ['User-Agent', self.user_agent])
+ if self.user_agent.kind_of?(String)
+ unless headers.any? { |k, v| k.downcase == 'User-Agent'.downcase }
+ headers = headers.to_a.insert(0, ['User-Agent', self.user_agent])
+ end
+ elsif self.user_agent != nil
+ raise TypeError,
+ "Expected User-Agent to be String, got #{self.user_agent.class}"
end
end
- ::HTTPAdapter.transmit([method, uri, headers, body], adapter)
+ adapter.transmit([method, uri, headers, body])
end
##
# Signs a request using the current authorization mechanism.
#
- # @param [Array] request The request to sign.
- # @param [#generate_authenticated_request] authorization
- # The authorization mechanism.
+ # @param [Hash] options The options to pass through.
#
- # @return [Array] The signed request.
- def sign_request(request, authorization=self.authorization)
- return authorization.generate_authenticated_request(
- :request => request
- )
+ # @return [Array] The signed or otherwise authenticated request.
+ def generate_authenticated_request(options={})
+ return authorization.generate_authenticated_request(options)
end
end
end
# See the License for the specific language governing permissions and
# limitations under the License.
+
require 'json'
require 'addressable/uri'
require 'addressable/template'
require 'google/inflection'
+require 'google/api_client/errors'
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
+ class API
##
# Creates a description of a particular version of a service.
#
- # @param [String] service_name
+ # @param [String] api
# 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
+ # @param [String] version
# The identifier for the service version.
- # @param [Hash] service_description
+ # @param [Hash] api_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
- @description = service_description
+ # @return [Google::APIClient::API] The constructed service object.
+ def initialize(document_base, discovery_document)
+ @document_base = Addressable::URI.parse(document_base)
+ @discovery_document = discovery_document
metaclass = (class <<self; self; end)
self.resources.each do |resource|
method_name = Google::INFLECTOR.underscore(resource.name).to_sym
end
end
+ ##
+ # Returns the id of the service.
+ #
+ # @return [String] The service id.
+ def id
+ return @discovery_document['id']
+ end
+
##
# Returns the identifier for the service.
#
# @return [String] The service identifier.
- attr_reader :name
+ def name
+ return @discovery_document['name']
+ end
##
# Returns the version of the service.
#
# @return [String] The service version.
- attr_reader :version
+ def version
+ return @discovery_document['version']
+ end
##
# Returns the parsed section of the discovery document that applies to
# this version of the service.
#
# @return [Hash] The service description.
- attr_reader :description
+ def description
+ return @discovery_document['description']
+ end
+
+ ##
+ # Returns true if this is the preferred version of this API.
+ #
+ # @return [TrueClass, FalseClass]
+ # Whether or not this is the preferred version of this API.
+ def preferred
+ return @discovery_document['preferred']
+ end
##
# 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'])
+ attr_reader :document_base
+
+ ##
+ # Returns the base URI for this version of the service.
+ #
+ # @return [Addressable::URI] The base URI that methods are joined to.
+ def rest_base
+ if @discovery_document['restBasePath']
+ return @rest_base ||= (
+ self.document_base +
+ Addressable::URI.parse(@discovery_document['restBasePath'])
+ ).normalize
+ else
+ return nil
+ end
end
##
#
# @param [Addressable::URI, #to_str, String] new_base
# The new base URI to use for the service.
- def base=(new_base)
- @base = Addressable::URI.parse(new_base)
+ def rest_base=(new_rest_base)
+ @rest_base = Addressable::URI.parse(new_rest_base)
self.resources.each do |resource|
- resource.base = @base
+ resource.rest_base = @rest_base
end
self.methods.each do |method|
- method.base = @base
+ method.rest_base = @rest_base
end
end
# @return [Array] A list of {Google::APIClient::Resource} objects.
def resources
return @resources ||= (
- (self.description['resources'] || []).inject([]) do |accu, (k, v)|
- accu << ::Google::APIClient::Resource.new(self.base, k, v)
+ (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
+ accu << ::Google::APIClient::Resource.new(self.rest_base, k, v)
accu
end
)
# @return [Array] A list of {Google::APIClient::Method} objects.
def methods
return @methods ||= (
- (self.description['methods'] || []).inject([]) do |accu, (k, v)|
- accu << ::Google::APIClient::Method.new(self.base, k, v)
+ (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
+ accu << ::Google::APIClient::Method.new(self.rest_base, k, v)
accu
end
)
#
# @example
# # Discover available methods
- # method_names = client.discovered_service('buzz').to_h.keys
+ # method_names = client.discovered_api('buzz').to_h.keys
def to_h
return @hash ||= (begin
methods_hash = {}
self.methods.each do |method|
- methods_hash[method.rpc_name] = method
+ methods_hash[method.rpc_method] = method
end
self.resources.each do |resource|
methods_hash.merge!(resource.to_h)
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]
- if dotted_version && suffix
- [dotted_version.split('.').map { |v| v.to_i }, suffix]
- else
- [[-1], version]
- end
- 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.
#
# 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
+ def initialize(rest_base, resource_name, discovery_document)
+ @rest_base = rest_base
@name = resource_name
- @description = resource_description
+ @discovery_document = discovery_document
metaclass = (class <<self; self; end)
self.resources.each do |resource|
method_name = Google::INFLECTOR.underscore(resource.name).to_sym
# Returns the base URI for this resource.
#
# @return [Addressable::URI] The base URI that methods are joined to.
- attr_reader :base
+ attr_reader :rest_base
##
# Updates the hierarchy of resources and methods with the new base.
#
# @param [Addressable::URI, #to_str, String] new_base
# The new base URI to use for the resource.
- def base=(new_base)
- @base = Addressable::URI.parse(new_base)
+ def rest_base=(new_rest_base)
+ @rest_base = Addressable::URI.parse(new_rest_base)
self.resources.each do |resource|
- resource.base = @base
+ resource.rest_base = @rest_base
end
self.methods.each do |method|
- method.base = @base
+ method.rest_base = @rest_base
end
end
# @return [Array] A list of {Google::APIClient::Resource} objects.
def resources
return @resources ||= (
- (self.description['resources'] || []).inject([]) do |accu, (k, v)|
- accu << ::Google::APIClient::Resource.new(self.base, k, v)
+ (@discovery_document['resources'] || []).inject([]) do |accu, (k, v)|
+ accu << ::Google::APIClient::Resource.new(self.rest_base, k, v)
accu
end
)
# @return [Array] A list of {Google::APIClient::Method} objects.
def methods
return @methods ||= (
- (self.description['methods'] || []).inject([]) do |accu, (k, v)|
- accu << ::Google::APIClient::Method.new(self.base, k, v)
+ (@discovery_document['methods'] || []).inject([]) do |accu, (k, v)|
+ accu << ::Google::APIClient::Method.new(self.rest_base, k, v)
accu
end
)
return @hash ||= (begin
methods_hash = {}
self.methods.each do |method|
- methods_hash[method.rpc_name] = method
+ methods_hash[method.rpc_method] = method
end
self.resources.each do |resource|
methods_hash.merge!(resource.to_h)
##
# Creates a description of a particular method.
#
- # @param [Addressable::URI] base
+ # @param [Addressable::URI] rest_base
# The base URI for the service.
# @param [String] method_name
# The identifier for the method.
# 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
+ def initialize(rest_base, method_name, discovery_document)
+ @rest_base = rest_base
@name = method_name
- @description = method_description
+ @discovery_document = discovery_document
end
##
#
# @return [Addressable::URI]
# The base URI that this method will be joined to.
- attr_reader :base
+ attr_reader :rest_base
##
# Updates the method with the new base.
#
# @param [Addressable::URI, #to_str, String] new_base
# The new base URI to use for the method.
- def base=(new_base)
- @base = Addressable::URI.parse(new_base)
+ def rest_base=(new_rest_base)
+ @rest_base = Addressable::URI.parse(new_rest_base)
@uri_template = nil
end
# Returns the RPC name for the method.
#
# @return [String] The RPC name.
- def rpc_name
- return self.description['rpcName']
+ def rpc_method
+ return @discovery_document['rpcMethod']
end
##
# 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'])
+ return @uri_template ||= Addressable::Template.new(
+ self.rest_base + @discovery_document['restPath']
+ )
end
##
if !headers.kind_of?(Array) && !headers.kind_of?(Hash)
raise TypeError, "Expected Hash or Array, got #{headers.class}."
end
- method = self.description['httpMethod'] || 'GET'
+ method = @discovery_document['httpMethod'] || 'GET'
uri = self.generate_uri(parameters)
headers = headers.to_a if headers.kind_of?(Hash)
return [method, uri.to_str, headers, [body]]
# @return [Hash] The parameter descriptions.
def parameter_descriptions
@parameter_descriptions ||= (
- self.description['parameters'] || {}
+ @discovery_document['parameters'] || {}
).inject({}) { |h,(k,v)| h[k]=v; h }
end
# @return [Array] The parameters.
def parameters
@parameters ||= ((
- self.description['parameters'] || {}
+ @discovery_document['parameters'] || {}
).inject({}) { |h,(k,v)| h[k]=v; h }).keys
end
end
parameters.each do |k, v|
if self.parameter_descriptions[k]
+ enum = self.parameter_descriptions[k]['enum']
+ if enum && !enum.include?(v)
+ raise ArgumentError,
+ "Parameter '#{k}' has an invalid value: #{v}. " +
+ "Must be one of #{enum.inspect}."
+ end
pattern = self.parameter_descriptions[k]['pattern']
if pattern
regexp = Regexp.new("^#{pattern}$")
# @return [String] The method's state, as a <code>String</code>.
def inspect
sprintf(
- "#<%s:%#0x NAME:%s>", self.class.to_s, self.object_id, self.rpc_name
+ "#<%s:%#0x NAME:%s>",
+ self.class.to_s, self.object_id, self.rpc_method
)
end
end
--- /dev/null
+# Copyright 2010 Google Inc.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+module Google
+ class APIClient
+ ##
+ # An error which is raised when there is an unexpected response or other
+ # transport error that prevents an operation from succeeding.
+ class TransmissionError < StandardError
+ end
+
+ ##
+ # An exception that is raised if a method is called with missing or
+ # invalid parameter values.
+ class ValidationError < StandardError
+ end
+ end
+end
# See the License for the specific language governing permissions and
# limitations under the License.
+
require 'json'
module Google
# See the License for the specific language governing permissions and
# limitations under the License.
+
module Google
class APIClient
module VERSION
MAJOR = 0
- MINOR = 1
- TINY = 3
+ MINOR = 2
+ TINY = 0
STRING = [MAJOR, MINOR, TINY].join('.')
end
# See the License for the specific language governing permissions and
# limitations under the License.
+
module Google
if defined?(ActiveSupport::Inflector)
INFLECTOR = ActiveSupport::Inflector
require 'google/api_client/version'
require 'google/api_client/parsers/json_parser'
-describe Google::APIClient, 'unconfigured' do
+describe Google::APIClient do
before do
@client = Google::APIClient.new
end
- it 'should not be able to determine the discovery URI' do
+ it 'should raise a type error for bogus authorization' do
(lambda do
- @client.discovery_uri
- end).should raise_error(ArgumentError)
- end
-end
-
-describe Google::APIClient, 'configured for a bogus API' do
- before do
- @client = Google::APIClient.new(:service => 'bogus')
+ Google::APIClient.new(:authorization => 42)
+ end).should raise_error(TypeError)
end
- it 'should not be able to retrieve the discovery document' do
+ it 'should not be able to retrieve the discovery document for a bogus API' do
(lambda do
- @client.discovery_document
+ @client.discovery_document('bogus')
end).should raise_error(Google::APIClient::TransmissionError)
- end
-end
-
-describe Google::APIClient, 'configured for bogus authorization' do
- it 'should raise a type error' do
(lambda do
- Google::APIClient.new(:service => 'prediction', :authorization => 42)
- end).should raise_error(TypeError)
- end
-end
-
-describe Google::APIClient, 'configured for the prediction API' do
- before do
- @client = Google::APIClient.new(:service => 'prediction')
- end
-
- it 'should correctly determine the discovery URI' do
- @client.discovery_uri.should ===
- 'http://www.googleapis.com/discovery/0.1/describe?api=prediction'
- end
-
- it 'should have multiple versions available' do
- @client.discovered_services.size.should > 1
- end
-
- it 'should find APIs that are in the discovery document' do
- @client.discovered_service('prediction').name.should == 'prediction'
- @client.discovered_service('prediction').version.should == 'v1'
- @client.discovered_service(:prediction).name.should == 'prediction'
- @client.discovered_service(:prediction).version.should == 'v1'
- end
-
- it 'should find API versions that are in the discovery document' do
- @client.discovered_service('prediction', 'v1.1').version.should == 'v1.1'
- end
-
- it 'should not find APIs that are not in the discovery document' do
- @client.discovered_service('bogus').should == nil
+ @client.discovered_api('bogus')
+ end).should raise_error(Google::APIClient::TransmissionError)
end
it 'should raise an error for bogus services' do
(lambda do
- @client.discovered_service(42)
+ @client.discovered_api(42)
end).should raise_error(TypeError)
end
- it 'should find methods that are in the discovery document' do
- @client.discovered_method('prediction.training.insert').name.should ==
- 'insert'
- @client.discovered_method(:'prediction.training.insert').name.should ==
- 'insert'
- end
-
- it 'should find methods for versions that are in the discovery document' do
- @client.discovered_method(
- 'prediction.training.delete', 'v1.1'
- ).should_not == nil
- end
-
- it 'should not find methods that are not in the discovery document' do
- @client.discovered_method('prediction.training.delete', 'v1').should == nil
- @client.discovered_method('prediction.bogus').should == nil
- end
-
- it 'should raise an error for bogus methods' do
- (lambda do
- @client.discovered_method(42)
- end).should raise_error(TypeError)
- end
-
- it 'should correctly determine the latest version' do
- @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_version(42)
+ @client.preferred_version(42)
end).should raise_error(TypeError)
end
- it 'should correctly determine the latest version' do
- # Sanity check the algorithm
- @client.discovered_services.clear
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v1.1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v1.10', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v10.0.1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v10.1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v2.1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('magic', 'v10.0', {})
- @client.latest_service_version('magic').version.should == 'v10.1'
- end
-
- it 'should correctly determine the latest version' do
- # Sanity check the algorithm
- @client.discovered_services.clear
- @client.discovered_services <<
- 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.discovered_services <<
- Google::APIClient::Service.new('two', 'v2beta1', {})
- @client.discovered_services <<
- Google::APIClient::Service.new('two', 'test2', {})
- @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_version('bogus').should == nil
- end
-
- it 'should generate valid requests' do
- request = @client.generate_request(
- 'prediction.training.insert',
- {'query' => '12345'}
- )
- method, uri, headers, body = request
- method.should == 'POST'
- uri.should ==
- 'https://www.googleapis.com/prediction/v1/training?query=12345'
- (headers.inject({}) { |h,(k,v)| h[k]=v; h }).should == {}
- body.should respond_to(:each)
- end
-
- it 'should generate requests against the correct URIs' do
- request = @client.generate_request(
- :'prediction.training.insert',
- {'query' => '12345'}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://www.googleapis.com/prediction/v1/training?query=12345'
- end
-
- it 'should generate requests against the correct URIs' do
- prediction = @client.discovered_service('prediction', 'v1')
- request = @client.generate_request(
- prediction.training.insert,
- {'query' => '12345'}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://www.googleapis.com/prediction/v1/training?query=12345'
- end
-
- it 'should allow modification to the base URIs for testing purposes' do
- prediction = @client.discovered_service('prediction', 'v1')
- prediction.base = 'https://testing-domain.googleapis.com/prediction/v1/'
- request = @client.generate_request(
- prediction.training.insert,
- {'query' => '123'}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://testing-domain.googleapis.com/prediction/v1/training?query=123'
- 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'}
- )
- method, uri, headers, body = request
- headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
- headers.keys.should include('Authorization')
- headers['Authorization'].should =~ /^OAuth/
- 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'}
- )
- status, headers, body = response
- status.should == 401
- end
-
it 'should raise an error for bogus methods' do
(lambda do
@client.generate_request(42)
end).should raise_error(TypeError)
end
- it 'should raise an error for bogus methods' do
- (lambda do
- @client.generate_request(@client.discovered_service('prediction'))
- end).should raise_error(TypeError)
- end
-end
-
-describe Google::APIClient, 'configured for the buzz API' do
- before do
- @client = Google::APIClient.new(:service => 'buzz')
- end
-
- it 'should correctly determine the discovery URI' do
- @client.discovery_uri.should ===
- 'http://www.googleapis.com/discovery/0.1/describe?api=buzz'
- end
-
- it 'should find APIs that are in the discovery document' do
- @client.discovered_service('buzz').name.should == 'buzz'
- @client.discovered_service('buzz').version.should == 'v1'
- end
-
- it 'should not find APIs that are not in the discovery document' do
- @client.discovered_service('bogus').should == nil
- end
-
- it 'should find methods that are in the discovery document' do
- # TODO(bobaman) Fix this when the RPC names are correct
- @client.discovered_method('chili.activities.list').name.should == 'list'
- end
-
- it 'should not find methods that are not in the discovery document' do
- @client.discovered_method('buzz.bogus').should == nil
- end
-
- it 'should generate requests against the correct URIs' do
- # TODO(bobaman) Fix this when the RPC names are correct
- request = @client.generate_request(
- 'chili.activities.list',
- {'userId' => 'hikingfan', 'scope' => '@public'},
- '',
- [],
- {:signed => false}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
- end
-
- it 'should correctly validate parameters' do
- # TODO(bobaman) Fix this when the RPC names are correct
- (lambda do
- @client.generate_request(
- 'chili.activities.list',
- {'alt' => 'json'},
+ it 'should not return a preferred version for bogus service names' do
+ @client.preferred_version('bogus').should == nil
+ end
+
+ describe 'with the prediction API' do
+ before do
+ @client.authorization = nil
+ end
+
+ it 'should correctly determine the discovery URI' do
+ @client.discovery_uri('prediction').should ===
+ 'https://www.googleapis.com/discovery/v0.3/describe/prediction/v1'
+ end
+
+ it 'should correctly generate API objects' do
+ @client.discovered_api('prediction').name.should == 'prediction'
+ @client.discovered_api('prediction').version.should == 'v1'
+ @client.discovered_api(:prediction).name.should == 'prediction'
+ @client.discovered_api(:prediction).version.should == 'v1'
+ end
+
+ it 'should discover methods' do
+ @client.discovered_method(
+ 'prediction.training.insert', 'prediction'
+ ).name.should == 'insert'
+ @client.discovered_method(
+ :'prediction.training.insert', :prediction
+ ).name.should == 'insert'
+ end
+
+ it 'should discover methods' do
+ @client.discovered_method(
+ 'prediction.training.delete', 'prediction', 'v1.1'
+ ).name.should == 'delete'
+ end
+
+ it 'should not find methods that are not in the discovery document' do
+ @client.discovered_method(
+ 'prediction.training.delete', 'prediction', 'v1'
+ ).should == nil
+ @client.discovered_method(
+ 'prediction.bogus', 'prediction', 'v1'
+ ).should == nil
+ end
+
+ it 'should raise an error for bogus methods' do
+ (lambda do
+ @client.discovered_method(42, 'prediction', 'v1')
+ end).should raise_error(TypeError)
+ end
+
+ it 'should raise an error for bogus methods' do
+ (lambda do
+ @client.generate_request(@client.discovered_api('prediction'))
+ end).should raise_error(TypeError)
+ end
+
+ it 'should correctly determine the preferred version' do
+ @client.preferred_version('prediction').version.should_not == 'v1'
+ @client.preferred_version(:prediction).version.should_not == 'v1'
+ end
+
+ it 'should generate valid requests' do
+ request = @client.generate_request(
+ 'prediction.training.insert',
+ {'data' => '12345', }
+ )
+ method, uri, headers, body = request
+ method.should == 'POST'
+ uri.should ==
+ 'https://www.googleapis.com/prediction/v1/training?data=12345'
+ (headers.inject({}) { |h,(k,v)| h[k]=v; h }).should == {}
+ body.should respond_to(:each)
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ :'prediction.training.insert',
+ {'data' => '12345'}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/prediction/v1/training?data=12345'
+ end
+
+ it 'should generate requests against the correct URIs' do
+ prediction = @client.discovered_api('prediction', 'v1')
+ request = @client.generate_request(
+ prediction.training.insert,
+ {'data' => '12345'}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/prediction/v1/training?data=12345'
+ end
+
+ it 'should allow modification to the base URIs for testing purposes' do
+ prediction = @client.discovered_api('prediction', 'v1')
+ prediction.rest_base =
+ 'https://testing-domain.googleapis.com/prediction/v1/'
+ request = @client.generate_request(
+ prediction.training.insert,
+ {'data' => '123'}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://testing-domain.googleapis.com/prediction/v1/training?data=123'
+ end
+
+ it 'should generate OAuth 1 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',
+ {'data' => '12345'}
+ )
+ method, uri, headers, body = request
+ headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
+ headers.keys.should include('Authorization')
+ headers['Authorization'].should =~ /^OAuth/
+ end
+
+ it 'should generate OAuth 2 requests' do
+ @client.authorization = :oauth_2
+ @client.authorization.access_token = '12345'
+ request = @client.generate_request(
+ 'prediction.training.insert',
+ {'data' => '12345'}
+ )
+ method, uri, headers, body = request
+ headers = headers.inject({}) { |h,(k,v)| h[k]=v; h }
+ headers.keys.should include('Authorization')
+ headers['Authorization'].should =~ /^OAuth/
+ 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',
+ {'data' => '12345'}
+ )
+ status, headers, body = response
+ status.should == 401
+ end
+
+ it 'should not be able to execute improperly authorized requests' do
+ @client.authorization = :oauth_2
+ @client.authorization.access_token = '12345'
+ response = @client.execute(
+ 'prediction.training.insert',
+ {'data' => '12345'}
+ )
+ status, headers, body = response
+ status.should == 401
+ end
+ end
+
+ describe 'with the buzz API' do
+ before do
+ @client.authorization = nil
+ @buzz = @client.discovered_api('buzz')
+ end
+
+ it 'should correctly determine the discovery URI' do
+ @client.discovery_uri('buzz').should ===
+ 'https://www.googleapis.com/discovery/v0.3/describe/buzz/v1'
+ end
+
+ it 'should find APIs that are in the discovery document' do
+ @client.discovered_api('buzz').name.should == 'buzz'
+ @client.discovered_api('buzz').version.should == 'v1'
+ @client.discovered_api(:buzz).name.should == 'buzz'
+ @client.discovered_api(:buzz).version.should == 'v1'
+ end
+
+ it 'should find methods that are in the discovery document' do
+ # TODO(bobaman) Fix this when the RPC names are correct
+ @client.discovered_method(
+ 'chili.activities.list', 'buzz'
+ ).name.should == 'list'
+ end
+
+ it 'should not find methods that are not in the discovery document' do
+ @client.discovered_method('buzz.bogus', 'buzz').should == nil
+ end
+
+ it 'should fail for string RPC names that do not match API name' do
+ (lambda do
+ @client.generate_request(
+ 'chili.activities.list',
+ {'alt' => 'json'},
+ '',
+ [],
+ {:signed => false}
+ )
+ end).should raise_error(Google::APIClient::TransmissionError)
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ @buzz.activities.list,
+ {'userId' => 'hikingfan', 'scope' => '@public'},
'',
[],
{:signed => false}
)
- end).should raise_error(ArgumentError)
- end
-
- it 'should correctly validate parameters' do
- # TODO(bobaman) Fix this when the RPC names are correct
- (lambda do
- @client.generate_request(
- 'chili.activities.list',
- {'userId' => 'hikingfan', 'scope' => '@bogus'},
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/buzz/v1/activities/hikingfan/@public'
+ end
+
+ it 'should correctly validate parameters' do
+ (lambda do
+ @client.generate_request(
+ @buzz.activities.list,
+ {'alt' => 'json'},
+ '',
+ [],
+ {:signed => false}
+ )
+ end).should raise_error(ArgumentError)
+ end
+
+ it 'should correctly validate parameters' do
+ (lambda do
+ @client.generate_request(
+ @buzz.activities.list,
+ {'userId' => 'hikingfan', 'scope' => '@bogus'},
+ '',
+ [],
+ {:signed => false}
+ )
+ end).should raise_error(ArgumentError)
+ end
+
+ it 'should be able to execute requests without authorization' do
+ response = @client.execute(
+ @buzz.activities.list,
+ {'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
'',
[],
{:signed => false}
)
- end).should raise_error(ArgumentError)
- end
-
- it 'should be able to execute requests without authorization' do
- # TODO(bobaman) Fix this when the RPC names are correct
- response = @client.execute(
- 'chili.activities.list',
- {'alt' => 'json', 'userId' => 'hikingfan', 'scope' => '@public'},
- '',
- [],
- {:signed => false}
- )
- status, headers, body = response
- status.should == 200
- end
-end
-
-describe Google::APIClient, 'configured for the latitude API' do
- before do
- @client = Google::APIClient.new(:service => 'latitude')
- end
-
- it 'should correctly determine the discovery URI' do
- @client.discovery_uri.should ===
- 'http://www.googleapis.com/discovery/0.1/describe?api=latitude'
- end
-
- it 'should find APIs that are in the discovery document' do
- @client.discovered_service('latitude').name.should == 'latitude'
- @client.discovered_service('latitude').version.should == 'v1'
- end
-
- it 'should not find APIs that are not in the discovery document' do
- @client.discovered_service('bogus').should == nil
- end
-
- it 'should find methods that are in the discovery document' do
- @client.discovered_method('latitude.currentLocation.get').name.should ==
- 'get'
- end
-
- it 'should not find methods that are not in the discovery document' do
- @client.discovered_method('latitude.bogus').should == nil
- end
-
- it 'should generate requests against the correct URIs' do
- request = @client.generate_request(
- 'latitude.currentLocation.get',
- {},
- '',
- [],
- {:signed => false}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://www.googleapis.com/latitude/v1/currentLocation'
- end
-
- it 'should not be able to execute requests without authorization' do
- response = @client.execute(
- 'latitude.currentLocation.get',
- {},
- '',
- [],
- {:signed => false}
- )
- status, headers, body = response
- status.should == 401
- end
-end
-
-describe Google::APIClient, 'configured for the moderator API' do
- before do
- @client = Google::APIClient.new(:service => 'moderator')
- end
-
- it 'should correctly determine the discovery URI' do
- @client.discovery_uri.should ===
- 'http://www.googleapis.com/discovery/0.1/describe?api=moderator'
- end
-
- it 'should find APIs that are in the discovery document' do
- @client.discovered_service('moderator').name.should == 'moderator'
- @client.discovered_service('moderator').version.should == 'v1'
- end
-
- it 'should not find APIs that are not in the discovery document' do
- @client.discovered_service('bogus').should == nil
- end
-
- it 'should find methods that are in the discovery document' do
- @client.discovered_method('moderator.profiles.get').name.should ==
- 'get'
- end
-
- it 'should not find methods that are not in the discovery document' do
- @client.discovered_method('moderator.bogus').should == nil
- end
-
- it 'should generate requests against the correct URIs' do
- request = @client.generate_request(
- 'moderator.profiles.get',
- {},
- '',
- [],
- {:signed => false}
- )
- method, uri, headers, body = request
- uri.should ==
- 'https://www.googleapis.com/moderator/v1/profiles/@me'
- end
-
- it 'should not be able to execute requests without authorization' do
- response = @client.execute(
- 'moderator.profiles.get',
- {},
- '',
- [],
- {:signed => false}
- )
- status, headers, body = response
- status.should == 401
+ status, headers, body = response
+ status.should == 200
+ end
+ end
+
+ describe 'with the latitude API' do
+ before do
+ @client.authorization = nil
+ @latitude = @client.discovered_api('latitude')
+ end
+
+ it 'should correctly determine the discovery URI' do
+ @client.discovery_uri('latitude').should ===
+ 'https://www.googleapis.com/discovery/v0.3/describe/latitude/v1'
+ end
+
+ it 'should find APIs that are in the discovery document' do
+ @client.discovered_api('latitude').name.should == 'latitude'
+ @client.discovered_api('latitude').version.should == 'v1'
+ end
+
+ it 'should find methods that are in the discovery document' do
+ @client.discovered_method(
+ 'latitude.currentLocation.get', 'latitude'
+ ).name.should == 'get'
+ end
+
+ it 'should not find methods that are not in the discovery document' do
+ @client.discovered_method('latitude.bogus', 'latitude').should == nil
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ 'latitude.currentLocation.get',
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/latitude/v1/currentLocation'
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ @latitude.current_location.get,
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/latitude/v1/currentLocation'
+ end
+
+ it 'should not be able to execute requests without authorization' do
+ response = @client.execute(
+ 'latitude.currentLocation.get',
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ status, headers, body = response
+ status.should == 401
+ end
+ end
+
+ describe 'with the moderator API' do
+ before do
+ @client.authorization = nil
+ @moderator = @client.discovered_api('moderator')
+ end
+
+ it 'should correctly determine the discovery URI' do
+ @client.discovery_uri('moderator').should ===
+ 'https://www.googleapis.com/discovery/v0.3/describe/moderator/v1'
+ end
+
+ it 'should find APIs that are in the discovery document' do
+ @client.discovered_api('moderator').name.should == 'moderator'
+ @client.discovered_api('moderator').version.should == 'v1'
+ end
+
+ it 'should find methods that are in the discovery document' do
+ @client.discovered_method(
+ 'moderator.profiles.get', 'moderator'
+ ).name.should == 'get'
+ end
+
+ it 'should not find methods that are not in the discovery document' do
+ @client.discovered_method('moderator.bogus', 'moderator').should == nil
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ 'moderator.profiles.get',
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/moderator/v1/profiles/@me'
+ end
+
+ it 'should generate requests against the correct URIs' do
+ request = @client.generate_request(
+ @moderator.profiles.get,
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ method, uri, headers, body = request
+ uri.should ==
+ 'https://www.googleapis.com/moderator/v1/profiles/@me'
+ end
+
+ it 'should not be able to execute requests without authorization' do
+ response = @client.execute(
+ 'moderator.profiles.get',
+ {},
+ '',
+ [],
+ {:signed => false}
+ )
+ status, headers, body = response
+ status.should == 401
+ end
end
end
@client.user_agent.should == nil
end
- it 'should not allow the user agent to be set to bogus values' do
+ it 'should not allow the user agent to be used with bogus values' do
(lambda do
@client.user_agent = 42
+ @client.transmit_request(
+ ['GET', 'http://www.google.com/', [], []]
+ )
end).should raise_error(TypeError)
end
it 'should transmit a User-Agent header when sending requests' do
@client.user_agent = 'Custom User Agent/1.2.3'
request = ['GET', 'http://www.google.com/', [], []]
- adapter = HTTPAdapter::MockAdapter.request_adapter do |request, connection|
- method, uri, headers, body = request
+ adapter = HTTPAdapter::MockAdapter.create do |request_ary, connection|
+ method, uri, headers, body = request_ary
headers.should be_any { |k, v| k.downcase == 'user-agent' }
headers.each do |k, v|
v.should == @client.user_agent if k.downcase == 'user-agent'
end
end
-describe Google::APIClient, 'with default configuration' do
+describe Google::APIClient do
before do
@client = Google::APIClient.new
end
@client.parser.should be(Google::APIClient::JSONParser)
end
- it 'should not use an authorization mechanism' do
- @client.authorization.should be_nil
+ it 'should default to OAuth 2' do
+ Signet::OAuth2::Client.should === @client.authorization
end
it_should_behave_like 'configurable user agent'
-end
-describe Google::APIClient, 'with default oauth configuration' do
- before do
- @client = Google::APIClient.new(:authorization => :oauth_1)
- end
+ describe 'configured for OAuth 1' do
+ before do
+ @client.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 OAuth1 client configuration' do
+ @client.authorization.temporary_credential_uri.to_s.should ==
+ 'https://www.google.com/accounts/OAuthGetRequestToken'
+ @client.authorization.authorization_uri.to_s.should include(
+ 'https://www.google.com/accounts/OAuthAuthorizeToken'
+ )
+ @client.authorization.token_credential_uri.to_s.should ==
+ 'https://www.google.com/accounts/OAuthGetAccessToken'
+ @client.authorization.client_credential_key.should == 'anonymous'
+ @client.authorization.client_credential_secret.should == 'anonymous'
+ end
- it 'should use the default JSON parser' do
- @client.parser.should be(Google::APIClient::JSONParser)
+ it_should_behave_like 'configurable user agent'
end
- it 'should use the default OAuth1 client configuration' do
- @client.authorization.temporary_credential_uri.to_s.should ==
- 'https://www.google.com/accounts/OAuthGetRequestToken'
- @client.authorization.authorization_uri.to_s.should include(
- 'https://www.google.com/accounts/OAuthAuthorizeToken'
- )
- @client.authorization.token_credential_uri.to_s.should ==
- 'https://www.google.com/accounts/OAuthGetAccessToken'
- @client.authorization.client_credential_key.should == 'anonymous'
- @client.authorization.client_credential_secret.should == 'anonymous'
+ describe 'configured for OAuth 2' do
+ before do
+ @client.authorization = :oauth_2
+ end
+
+ # TODO
+ it_should_behave_like 'configurable user agent'
end
- it_should_behave_like 'configurable user agent'
-end
+ describe 'with custom pluggable parser' do
+ before do
+ class FakeJsonParser
+ def serialize(value)
+ return "42"
+ end
-describe Google::APIClient, 'with custom pluggable parser' do
- before do
- class FakeJsonParser
+ def parse(value)
+ return 42
+ end
+ end
+
+ @client.parser = FakeJsonParser.new
end
- @client = Google::APIClient.new(:parser => FakeJsonParser.new)
- end
+ it 'should use the custom parser' do
+ @client.parser.should be_instance_of(FakeJsonParser)
+ end
- it 'should use the custom parser' do
- @client.parser.should be_instance_of(FakeJsonParser)
+ it_should_behave_like 'configurable user agent'
end
-
- it_should_behave_like 'configurable user agent'
end
s.rdoc_options.concat ['--main', 'README']
# Dependencies used in the main library
- s.add_runtime_dependency('signet', '>= 0.1.4')
- s.add_runtime_dependency('addressable', '>= 2.2.2')
- s.add_runtime_dependency('httpadapter', '>= 0.2.0')
- s.add_runtime_dependency('json', '>= 1.1.9')
+ s.add_runtime_dependency('signet', '~> 0.2.1')
+ s.add_runtime_dependency('addressable', '~> 2.2.2')
+ s.add_runtime_dependency('httpadapter', '~> 1.0.0')
+ s.add_runtime_dependency('json', '>= 1.5.1')
s.add_runtime_dependency('extlib', '>= 0.9.15')
# Dependencies used in the CLI