diff --git a/Rakefile b/Rakefile index a33a41286..afd7fdd08 100644 --- a/Rakefile +++ b/Rakefile @@ -23,11 +23,15 @@ The Google API Ruby Client makes it trivial to discover and access supported APIs. TEXT -PKG_FILES = FileList[ +list = FileList[ 'lib/**/*', 'spec/**/*', 'vendor/**/*', 'tasks/**/*', 'website/**/*', '[A-Z]*', 'Rakefile' -].exclude(/database\.yml/).exclude(/[_\.]git$/) +].exclude(/[_\.]git$/) +(open(".gitignore") { |file| file.read }).split("\n").each do |pattern| + list.exclude(pattern) +end +PKG_FILES = list RCOV_ENABLED = !!(RUBY_PLATFORM != 'java' && RUBY_VERSION =~ /^1\.8/) if RCOV_ENABLED diff --git a/google-api-client.gemspec b/google-api-client.gemspec index aa61b8a71..3e52c496f 100644 --- a/google-api-client.gemspec +++ b/google-api-client.gemspec @@ -6,16 +6,16 @@ Gem::Specification.new do |s| s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.authors = ["Bob Aman", "Steve Bazyl"] - s.date = "2012-10-25" + s.date = "2012-11-19" s.description = "The Google API Ruby Client makes it trivial to discover and access supported\nAPIs.\n" s.email = "sbazyl@google.com" s.executables = ["google-api"] s.extra_rdoc_files = ["README.md"] - s.files = ["lib/compat", "lib/compat/multi_json.rb", "lib/google", "lib/google/api_client", "lib/google/api_client/auth", "lib/google/api_client/auth/jwt_asserter.rb", "lib/google/api_client/auth/pkcs12.rb", "lib/google/api_client/batch.rb", "lib/google/api_client/client_secrets.rb", "lib/google/api_client/discovery", "lib/google/api_client/discovery/api.rb", "lib/google/api_client/discovery/media.rb", "lib/google/api_client/discovery/method.rb", "lib/google/api_client/discovery/resource.rb", "lib/google/api_client/discovery/schema.rb", "lib/google/api_client/discovery.rb", "lib/google/api_client/environment.rb", "lib/google/api_client/errors.rb", "lib/google/api_client/media.rb", "lib/google/api_client/reference.rb", "lib/google/api_client/request.rb", "lib/google/api_client/result.rb", "lib/google/api_client/service_account.rb", "lib/google/api_client/version.rb", "lib/google/api_client.rb", "lib/google/inflection.rb", "spec/fixtures", "spec/fixtures/files", "spec/fixtures/files/sample.txt", "spec/google", "spec/google/api_client", "spec/google/api_client/batch_spec.rb", "spec/google/api_client/discovery_spec.rb", "spec/google/api_client/media_spec.rb", "spec/google/api_client/result_spec.rb", "spec/google/api_client/service_account_spec.rb", "spec/google/api_client_spec.rb", "spec/spec_helper.rb", "tasks/gem.rake", "tasks/git.rake", "tasks/metrics.rake", "tasks/spec.rake", "tasks/wiki.rake", "tasks/yard.rake", "CHANGELOG.md", "Gemfile", "Gemfile.lock", "LICENSE", "Rakefile", "README.md", "bin/google-api"] + s.files = ["lib/compat", "lib/compat/multi_json.rb", "lib/google", "lib/google/api_client", "lib/google/api_client.rb", "lib/google/api_client/auth", "lib/google/api_client/auth/jwt_asserter.rb", "lib/google/api_client/auth/key_utils.rb", "lib/google/api_client/auth/pkcs12.rb", "lib/google/api_client/batch.rb", "lib/google/api_client/client_secrets.rb", "lib/google/api_client/discovery", "lib/google/api_client/discovery.rb", "lib/google/api_client/discovery/api.rb", "lib/google/api_client/discovery/media.rb", "lib/google/api_client/discovery/method.rb", "lib/google/api_client/discovery/resource.rb", "lib/google/api_client/discovery/schema.rb", "lib/google/api_client/environment.rb", "lib/google/api_client/errors.rb", "lib/google/api_client/media.rb", "lib/google/api_client/reference.rb", "lib/google/api_client/request.rb", "lib/google/api_client/result.rb", "lib/google/api_client/service_account.rb", "lib/google/api_client/version.rb", "lib/google/inflection.rb", "spec/fixtures", "spec/fixtures/files", "spec/fixtures/files/privatekey.p12", "spec/fixtures/files/sample.txt", "spec/fixtures/files/secret.pem", "spec/google", "spec/google/api_client", "spec/google/api_client/batch_spec.rb", "spec/google/api_client/discovery_spec.rb", "spec/google/api_client/media_spec.rb", "spec/google/api_client/result_spec.rb", "spec/google/api_client/service_account_spec.rb", "spec/google/api_client_spec.rb", "spec/spec_helper.rb", "tasks/gem.rake", "tasks/git.rake", "tasks/metrics.rake", "tasks/spec.rake", "tasks/wiki.rake", "tasks/yard.rake", "CHANGELOG.md", "Gemfile", "LICENSE", "README.md", "Rakefile", "bin/google-api"] s.homepage = "http://code.google.com/p/google-api-ruby-client/" s.rdoc_options = ["--main", "README.md"] s.require_paths = ["lib"] - s.rubygems_version = "1.8.10" + s.rubygems_version = "1.8.24" s.summary = "Package Summary" if s.respond_to? :specification_version then diff --git a/lib/compat/multi_json.rb b/lib/compat/multi_json.rb index f8267194e..3974f084b 100644 --- a/lib/compat/multi_json.rb +++ b/lib/compat/multi_json.rb @@ -1,6 +1,9 @@ require 'multi_json' -if !MultiJson.respond_to?(:load) || MultiJson.method(:load).owner == Kernel +if !MultiJson.respond_to?(:load) || [ + Kernel, + defined?(ActiveSupport::Dependencies::Loadable) && ActiveSupport::Dependencies::Loadable +].compact.include?(MultiJson.method(:load).owner) module MultiJson class <:oauth_1 #
  • :oauth_2
  • # + # @option options [Boolean] :auto_refresh_token (true) + # The setting that controls whether or not the api client attempts to + # refresh authorization when a 401 is hit in #execute. If the token does + # not support it, this option is ignored. # @option options [String] :application_name # The name of the application using the client. # @option options [String] :application_version @@ -95,6 +99,7 @@ module Google # default authentication mechanisms. self.authorization = options.key?(:authorization) ? options[:authorization] : :oauth_2 + self.auto_refresh_token = options.fetch(:auto_refresh_token){ true } self.key = options[:key] self.user_ip = options[:user_ip] @discovery_uris = {} @@ -165,6 +170,13 @@ module Google # @return [String] The API key. attr_accessor :key + ## + # The setting that controls whether or not the api client attempts to + # refresh authorization when a 401 is hit in #execute. + # + # @return [Boolean] + attr_accessor :auto_refresh_token + ## # The IP address of the user this request is being performed on behalf of. # @@ -546,7 +558,7 @@ module Google request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false result = request.send(connection) - if result.status == 401 && authorization.respond_to?(:refresh_token) + if result.status == 401 && authorization.respond_to?(:refresh_token) && auto_refresh_token begin authorization.fetch_access_token! result = request.send(connection) diff --git a/lib/google/api_client/request.rb b/lib/google/api_client/request.rb index da3fb6a65..ce2f85438 100644 --- a/lib/google/api_client/request.rb +++ b/lib/google/api_client/request.rb @@ -27,7 +27,7 @@ module Google # Represents an API request. class Request MULTIPART_BOUNDARY = "-----------RubyApiMultipartPost".freeze - + # @return [Hash] Request parameters attr_reader :parameters # @return [Hash] Additional HTTP headers @@ -42,7 +42,7 @@ module Google attr_accessor :authenticated # @return [#read, #to_str] Request body attr_accessor :body - + ## # Build a request # @@ -52,7 +52,7 @@ module Google # @option options [Google::APIClient::Method] :api_method # API method to invoke. Either :api_method or :uri must be specified # @option options [TrueClass, FalseClass] :authenticated - # True if request should include credentials. Implicitly true if + # True if request should include credentials. Implicitly true if # unspecified and :authorization present # @option options [#generate_signed_request] :authorization # OAuth credentials @@ -74,12 +74,12 @@ module Google self.api_method = options[:api_method] self.authenticated = options[:authenticated] self.authorization = options[:authorization] - + # These parameters are handled differently because they're not # parameters to the API method, but rather to the API system. self.parameters['key'] ||= options[:key] if options[:key] self.parameters['userIp'] ||= options[:user_ip] if options[:user_ip] - + if options[:media] self.initialize_media_upload(options) elsif options[:body] @@ -90,13 +90,13 @@ module Google else self.body = '' end - + unless self.api_method self.http_method = options[:http_method] || 'GET' self.uri = options[:uri] end end - + # @!attribute [r] upload_type # @return [String] protocol used for upload def upload_type @@ -128,7 +128,7 @@ module Google "Expected Google::APIClient::Method, got #{new_api_method.class}." end end - + # @!attribute uri # @return [Addressable::URI] URI to send request def uri @@ -145,15 +145,15 @@ module Google # # @api private # - # @param [Faraday::Connection] connection + # @param [Faraday::Connection] connection # the connection to transmit with - # - # @return [Google::APIClient::Result] + # + # @return [Google::APIClient::Result] # result of API request def send(connection) - http_response = connection.app.call(self.to_env(connection)) + http_response = connection.app.call(self.to_env(connection)) result = self.process_http_response(http_response) - + # Resumamble slightly different than other upload protocols in that it requires at least # 2 requests. if self.upload_type == 'resumable' @@ -164,7 +164,7 @@ module Google end return result end - + # Convert to an HTTP request. Returns components in order of method, URI, # request headers, and body # @@ -172,7 +172,7 @@ module Google # # @return [Array<(Symbol, Addressable::URI, Hash, [#read,#to_str])>] def to_http_request - request = ( + request = ( if self.uri unless self.parameters.empty? self.uri.query = Addressable::URI.form_encode(self.parameters) @@ -204,7 +204,7 @@ module Google end return options end - + ## # Prepares the request for execution, building a hash of parts # suitable for sending to Faraday::Connection. @@ -233,7 +233,7 @@ module Google request_env = http_request.to_env(connection) end - + ## # Convert HTTP response to an API Result # @@ -247,9 +247,9 @@ module Google def process_http_response(response) Result.new(self, response) end - + protected - + ## # Adjust headers & body for media uploads # @@ -269,14 +269,14 @@ module Google self.media = options[:media] case self.upload_type when "media" - if options[:body] || options[:body_object] + if options[:body] || options[:body_object] raise ArgumentError, "Can not specify body & body object for simple uploads" end self.headers['Content-Type'] ||= self.media.content_type self.body = self.media when "multipart" - unless options[:body_object] - raise ArgumentError, "Multipart requested but no body object" + unless options[:body_object] + raise ArgumentError, "Multipart requested but no body object" end metadata = StringIO.new(serialize_body(options[:body_object])) build_multipart([Faraday::UploadIO.new(metadata, 'application/json', 'file.json'), self.media]) @@ -286,13 +286,13 @@ module Google self.headers['X-Upload-Content-Length'] = file_length.to_s if options[:body_object] self.headers['Content-Type'] ||= 'application/json' - self.body = serialize_body(options[:body_object]) + self.body = serialize_body(options[:body_object]) else self.body = '' end end end - + ## # Assemble a multipart message from a set of parts # @@ -304,7 +304,7 @@ module Google # MIME type of the message # @param [String] boundary # Boundary for separating each part of the message - def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY) + def build_multipart(parts, mime_type = 'multipart/related', boundary = MULTIPART_BOUNDARY) env = { :request_headers => {'Content-Type' => "#{mime_type};boundary=#{boundary}"}, :request => { :boundary => boundary } @@ -313,10 +313,10 @@ module Google self.body = multipart.create_multipart(env, parts.map {|part| [nil, part]}) self.headers.update(env[:request_headers]) end - + ## # Serialize body object to JSON - # + # # @api private # # @param [#to_json,#to_hash] body @@ -326,7 +326,7 @@ module Google # JSON def serialize_body(body) return body.to_json if body.respond_to?(:to_json) - return MultiJson.dump(options[:body_object].to_hash) if body.respond_to?(:to_hash) + return MultiJson.dump(body.to_hash) if body.respond_to?(:to_hash) raise TypeError, 'Could not convert body object to JSON.' + 'Must respond to :to_json or :to_hash.' end diff --git a/spec/google/api_client/discovery_spec.rb b/spec/google/api_client/discovery_spec.rb index 4f8fcca7b..0872bde7f 100644 --- a/spec/google/api_client/discovery_spec.rb +++ b/spec/google/api_client/discovery_spec.rb @@ -214,6 +214,23 @@ describe Google::APIClient do conn.verify end + it 'should generate valid requests when parameter value includes semicolon' do + conn = stub_connection do |stub| + # semicolon (;) in parameter value was being converted to + # bare ampersand (&) in 0.4.7. ensure that it gets converted + # to a CGI-escaped semicolon (%3B) instead. + stub.post('/prediction/v1.2/training?data=12345%3B67890') do |env| + env[:body].should == '' + end + end + request = CLIENT.execute( + :api_method => @prediction.training.insert, + :parameters => {'data' => '12345;67890'}, + :connection => conn + ) + conn.verify + end + it 'should generate valid requests when repeated parameters are passed' do pending("This is caused by Faraday's encoding of query parameters.") conn = stub_connection do |stub|