google-api-client 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. checksums.yaml +13 -5
  2. data/CHANGELOG.md +14 -0
  3. data/Gemfile +0 -36
  4. data/README.md +12 -1
  5. data/Rakefile +1 -8
  6. data/google-api-client.gemspec +40 -0
  7. data/lib/google/api_client.rb +98 -30
  8. data/lib/google/api_client/auth/compute_service_account.rb +1 -1
  9. data/lib/google/api_client/auth/file_storage.rb +19 -44
  10. data/lib/google/api_client/auth/installed_app.rb +11 -7
  11. data/lib/google/api_client/auth/storage.rb +101 -0
  12. data/lib/google/api_client/auth/storages/file_store.rb +58 -0
  13. data/lib/google/api_client/auth/storages/redis_store.rb +54 -0
  14. data/lib/google/api_client/batch.rb +13 -11
  15. data/lib/google/api_client/charset.rb +33 -0
  16. data/lib/google/api_client/client_secrets.rb +9 -6
  17. data/lib/google/api_client/discovery/api.rb +3 -3
  18. data/lib/google/api_client/discovery/resource.rb +3 -3
  19. data/lib/google/api_client/discovery/schema.rb +3 -5
  20. data/lib/google/api_client/errors.rb +5 -0
  21. data/lib/google/api_client/railtie.rb +2 -1
  22. data/lib/google/api_client/request.rb +1 -2
  23. data/lib/google/api_client/result.rb +4 -2
  24. data/lib/google/api_client/service.rb +2 -2
  25. data/lib/google/api_client/service/batch.rb +7 -0
  26. data/lib/google/api_client/service/stub_generator.rb +4 -2
  27. data/lib/google/api_client/service_account.rb +3 -0
  28. data/lib/google/api_client/version.rb +8 -13
  29. data/spec/google/api_client/auth/storage_spec.rb +122 -0
  30. data/spec/google/api_client/auth/storages/file_store_spec.rb +40 -0
  31. data/spec/google/api_client/auth/storages/redis_store_spec.rb +70 -0
  32. data/spec/google/api_client/batch_spec.rb +29 -30
  33. data/spec/google/api_client/client_secrets_spec.rb +53 -0
  34. data/spec/google/api_client/discovery_spec.rb +101 -91
  35. data/spec/google/api_client/gzip_spec.rb +21 -9
  36. data/spec/google/api_client/media_spec.rb +31 -32
  37. data/spec/google/api_client/request_spec.rb +3 -4
  38. data/spec/google/api_client/result_spec.rb +51 -47
  39. data/spec/google/api_client/service_account_spec.rb +40 -35
  40. data/spec/google/api_client/service_spec.rb +144 -112
  41. data/spec/google/api_client/simple_file_store_spec.rb +30 -34
  42. data/spec/google/api_client_spec.rb +139 -40
  43. data/spec/spec_helper.rb +9 -1
  44. metadata +111 -88
  45. data/CONTRIBUTING.md +0 -32
  46. data/lib/cacerts.pem +0 -2183
  47. data/lib/google/inflection.rb +0 -28
  48. data/spec/fixtures/files/privatekey.p12 +0 -0
  49. data/spec/fixtures/files/sample.txt +0 -33
  50. data/spec/fixtures/files/secret.pem +0 -19
  51. data/tasks/gem.rake +0 -97
  52. data/tasks/git.rake +0 -45
  53. data/tasks/metrics.rake +0 -22
  54. data/tasks/spec.rake +0 -57
  55. data/tasks/wiki.rake +0 -82
  56. data/tasks/yard.rake +0 -29
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: f8c8eb2c42edad1bf6e5cfbee1d439954126190c
4
- data.tar.gz: fb2452e06f097f61268bd5249dc8fef45463b21a
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ YzhlMTg0N2Y1ZjlhYzcxYzM4MzM2Y2ZmMGI4NzEyNzJjMjlmYTEzYg==
5
+ data.tar.gz: !binary |-
6
+ MzcxZjIyMjAzODdlMTYxMzBhZWUxYzZjZDhiNjI1NzE1MTFkMjk5NQ==
5
7
  SHA512:
6
- metadata.gz: f93bdc644f5520cc99c072da4816b9af16d13a1694a103dbeeee39b6c16974f68c1780ff6232476bac434482adc6cdc09ff036b2a62c4eafd94977ab14855417
7
- data.tar.gz: 0d73c87dd66332a6782dd60b1aaef11ebc5d5fc440d86fe34996f661acc714dcb631e6c131be6002f1b76ba5a867ad456c5df15dd80be0b0f22a1b8137ed1837
8
+ metadata.gz: !binary |-
9
+ YzFlYThlNjUzZGI4ZTI2ZWZmY2FmMzQ1NTlmMDNlOTZkYzcxZWIwMmEzZDI5
10
+ ZjBiZjAxOTNmYzQ4YWRiM2VlNDgxOWMxODg2NzRmZWM3NTQwMTI2N2JjMmMy
11
+ YWRhYjAxNDNlY2Y2NjhhM2E2ZjMwMTQ1Mzc0NzliY2VmODc4NTY=
12
+ data.tar.gz: !binary |-
13
+ YWM2YjUzY2YyNDI1MmEwZTcxOTBiYmVjOWU4ZDQ1ZDY0MzYzMjBlZmMzMTVi
14
+ Y2IwN2UyZGVkYzdhMTNiNTA0ZDI4OTIxMGNiODQwNWJmYjA1ZmJhYTgzZDA1
15
+ OTkxZGE4NTIxODk3ZWZhNGRhZTc1OWEwZTRmZjEyOThiMWM0MDU=
@@ -1,3 +1,17 @@
1
+ # 0.8.0
2
+ * Refactored credential storage, added support for redis
3
+ * Update gem depdendencies
4
+ * Fixed retry logic to allow for auth retries independent of the overall number of retries
5
+ * Added `:force_encoding` option to set body content encoding based on the Content-Type header
6
+ * Batch requests with the service interface now inherit the service's connection
7
+ * `register_discover_document` now returns the API instance
8
+ * Added `:proxy` option to set Faraday's HTTP proxy setting
9
+ * Drop 1.8.x support
10
+ * Added `:faraday_options` option to allow passthrough settings to Faraday connection
11
+
12
+ # 0.7.1
13
+ * Minor fix to update gem dependencies
14
+
1
15
  # 0.7.0
2
16
  * Remove CLI
3
17
  * SUpport for automatic retires & backoff. Off by default, enable by setting `retries` on `APIClient`
data/Gemfile CHANGED
@@ -2,40 +2,4 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem 'signet', '>= 0.5.0'
6
- gem 'addressable', '>= 2.3.2'
7
- gem 'uuidtools', '>= 2.1.0'
8
- gem 'autoparse', '>= 0.3.3'
9
- gem 'faraday', '>= 0.9.0'
10
- gem 'multi_json', '>= 1.0.0'
11
- gem 'extlib', '>= 0.9.15'
12
- gem 'jwt', '~> 0.1.5'
13
- gem 'retriable', '>= 1.4'
14
5
  gem 'jruby-openssl', :platforms => :jruby
15
-
16
- group :development do
17
- gem 'launchy', '>= 2.1.1'
18
- gem 'yard'
19
- gem 'kramdown'
20
- end
21
-
22
-
23
- platforms :rbx do
24
- gem 'rubysl', '~> 2.0'
25
- gem 'psych'
26
- end
27
-
28
-
29
- group :examples do
30
- gem 'sinatra'
31
- end
32
-
33
- group :test, :development do
34
- gem 'json', '~> 1.7.7'
35
- gem 'rake', '>= 0.9.0'
36
- gem 'rspec', '>= 2.11.0'
37
- gem 'rcov', '>= 0.9.9', :platform => :mri_18
38
- end
39
-
40
-
41
- gem 'idn', :platform => :mri_18
data/README.md CHANGED
@@ -15,6 +15,10 @@
15
15
  The Google API Ruby Client makes it trivial to discover and access supported
16
16
  APIs.
17
17
 
18
+ ## Alpha
19
+
20
+ This library is in Alpha. We will make an effort to support the library, but we reserve the right to make incompatible changes when necessary.
21
+
18
22
  ## Install
19
23
 
20
24
  Be sure `https://rubygems.org/` is in your gem sources.
@@ -83,8 +87,13 @@ drive = client.discovered_api('drive', 'v2')
83
87
  Locally cached discovery documents may be used as well. To load an API from a local file:
84
88
 
85
89
  ```ruby
90
+ # Output discovery document to JSON
91
+ File.open('my-api.json', 'w') do |f| f.puts MultiJson.dump(client.discovery_document('myapi', 'v1')) end
92
+
93
+ # Read discovery document and load API
86
94
  doc = File.read('my-api.json')
87
- my_api = client.register_discovery_document('myapi', 'v1', doc)
95
+ client.register_discovery_document('myapi', 'v1', doc)
96
+ my_api = client.discovered_api('myapi', 'v1')
88
97
  ```
89
98
 
90
99
  ### Authorization
@@ -114,6 +123,8 @@ in the credentials. Detailed instructions on how to enable delegation for your d
114
123
 
115
124
  The API client can automatically retry requests for recoverable errors. To enable retries, set the `client.retries` property to
116
125
  the number of additional attempts. To avoid flooding servers, retries invovle a 1 second delay that increases on each subsequent retry.
126
+ In the case of authentication token expiry, the API client will attempt to refresh the token and retry the failed operation - this
127
+ is a specific exception to the retry rules.
117
128
 
118
129
  The default value for retries is 0, but will be enabled by default in future releases.
119
130
 
data/Rakefile CHANGED
@@ -33,14 +33,7 @@ list = FileList[
33
33
  end
34
34
  PKG_FILES = list
35
35
 
36
- RCOV_ENABLED = !!(RUBY_PLATFORM != 'java' && RUBY_VERSION =~ /^1\.8/)
37
- if RCOV_ENABLED
38
- task :default => 'spec:rcov'
39
- else
40
- task :default => 'spec'
41
- end
36
+ task :default => 'spec'
42
37
 
43
38
  WINDOWS = (RUBY_PLATFORM =~ /mswin|win32|mingw|bccwin|cygwin/) rescue false
44
39
  SUDO = WINDOWS ? '' : ('sudo' unless ENV['SUDOLESS'])
45
-
46
- Dir['tasks/**/*.rake'].each { |rake| load rake }
@@ -0,0 +1,40 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.join(File.dirname(__FILE__), 'lib/google/api_client', 'version')
3
+
4
+ Gem::Specification.new do |s|
5
+ s.name = "google-api-client"
6
+ s.version = Google::APIClient::VERSION::STRING
7
+
8
+ s.required_rubygems_version = ">= 1.3.5"
9
+ s.require_paths = ["lib"]
10
+ s.authors = ["Bob Aman", "Steven Bazyl"]
11
+ s.license = "Apache-2.0"
12
+ s.description = "The Google API Ruby Client makes it trivial to discover and access supported APIs."
13
+ s.email = "sbazyl@google.com"
14
+ s.extra_rdoc_files = ["README.md"]
15
+ s.files = %w(google-api-client.gemspec Rakefile LICENSE CHANGELOG.md README.md Gemfile)
16
+ s.files += Dir.glob("lib/**/*.rb")
17
+ s.files += Dir.glob("spec/**/*.{rb,opts}")
18
+ s.files += Dir.glob("vendor/**/*.rb")
19
+ s.files += Dir.glob("tasks/**/*")
20
+ s.files += Dir.glob("website/**/*")
21
+ s.homepage = "https://github.com/google/google-api-ruby-client/"
22
+ s.rdoc_options = ["--main", "README.md"]
23
+ s.summary = "The Google API Ruby Client makes it trivial to discover and access Google's REST APIs."
24
+
25
+ s.add_runtime_dependency 'addressable', '~> 2.3'
26
+ s.add_runtime_dependency 'signet', '~> 0.6'
27
+ s.add_runtime_dependency 'faraday', '~> 0.9'
28
+ s.add_runtime_dependency 'multi_json', '~> 1.10'
29
+ s.add_runtime_dependency 'autoparse', "~> 0.3"
30
+ s.add_runtime_dependency 'extlib', '~> 0.9'
31
+ s.add_runtime_dependency 'launchy', '~> 2.4'
32
+ s.add_runtime_dependency 'retriable', '~> 1.4'
33
+ s.add_runtime_dependency 'activesupport', '>= 3.2'
34
+
35
+ s.add_development_dependency 'rake', '~> 10.0'
36
+ s.add_development_dependency 'yard', '~> 0.8'
37
+ s.add_development_dependency 'rspec', '~> 3.1'
38
+ s.add_development_dependency 'kramdown', '~> 1.5'
39
+ s.add_development_dependency 'simplecov', '~> 0.9'
40
+ end
@@ -31,8 +31,9 @@ require 'google/api_client/media'
31
31
  require 'google/api_client/service_account'
32
32
  require 'google/api_client/batch'
33
33
  require 'google/api_client/gzip'
34
+ require 'google/api_client/charset'
34
35
  require 'google/api_client/client_secrets'
35
- require 'google/api_client/railtie' if defined?(Rails::Railtie)
36
+ require 'google/api_client/railtie' if defined?(Rails)
36
37
 
37
38
  module Google
38
39
 
@@ -75,6 +76,11 @@ module Google
75
76
  # @option options [String] :ca_file
76
77
  # Optional set of root certificates to use when validating SSL connections.
77
78
  # By default, a bundled set of trusted roots will be used.
79
+ # @options options[Hash] :force_encoding
80
+ # Experimental option. True if response body should be force encoded into the charset
81
+ # specified in the Content-Type header. Mostly intended for compressed content.
82
+ # @options options[Hash] :faraday_options
83
+ # Pass through of options to set on the Faraday connection
78
84
  def initialize(options={})
79
85
  logger.debug { "#{self.class} - Initializing client with options #{options}" }
80
86
 
@@ -97,6 +103,9 @@ module Google
97
103
  else
98
104
  logger.warn { "#{self.class} - Please provide :application_name and :application_version when initializing the client" }
99
105
  end
106
+
107
+ proxy = options[:proxy] || Object::ENV["http_proxy"]
108
+
100
109
  self.user_agent = options[:user_agent] || (
101
110
  "#{application_string} " +
102
111
  "google-api-ruby-client/#{Google::APIClient::VERSION::STRING} #{ENV::OS_VERSION} (gzip)"
@@ -109,17 +118,25 @@ module Google
109
118
  self.key = options[:key]
110
119
  self.user_ip = options[:user_ip]
111
120
  self.retries = options.fetch(:retries) { 0 }
121
+ self.expired_auth_retry = options.fetch(:expired_auth_retry) { true }
112
122
  @discovery_uris = {}
113
123
  @discovery_documents = {}
114
124
  @discovered_apis = {}
115
125
  ca_file = options[:ca_file] || File.expand_path('../../cacerts.pem', __FILE__)
116
126
  self.connection = Faraday.new do |faraday|
127
+ faraday.response :charset if options[:force_encoding]
117
128
  faraday.response :gzip
118
129
  faraday.options.params_encoder = Faraday::FlatParamsEncoder
119
130
  faraday.ssl.ca_file = ca_file
120
131
  faraday.ssl.verify = true
132
+ faraday.proxy proxy
121
133
  faraday.adapter Faraday.default_adapter
122
- end
134
+ if options[:faraday_option].is_a?(Hash)
135
+ options[:faraday_option].each_pair do |option, value|
136
+ faraday.options.send("#{option}=", value)
137
+ end
138
+ end
139
+ end
123
140
  return self
124
141
  end
125
142
 
@@ -239,6 +256,13 @@ module Google
239
256
  # Number of retries
240
257
  attr_accessor :retries
241
258
 
259
+ ##
260
+ # Whether or not an expired auth token should be re-acquired
261
+ # (and the operation retried) regardless of retries setting
262
+ # @return [Boolean]
263
+ # Auto retry on auth expiry
264
+ attr_accessor :expired_auth_retry
265
+
242
266
  ##
243
267
  # Returns the URI for the directory document.
244
268
  #
@@ -254,10 +278,12 @@ module Google
254
278
  # @param [String, Symbol] api The API name.
255
279
  # @param [String] version The desired version of the API.
256
280
  # @param [Addressable::URI] uri The URI of the discovery document.
281
+ # @return [Google::APIClient::API] The service object.
257
282
  def register_discovery_uri(api, version, uri)
258
283
  api = api.to_s
259
284
  version = version || 'v1'
260
285
  @discovery_uris["#{api}:#{version}"] = uri
286
+ discovered_api(api, version)
261
287
  end
262
288
 
263
289
  ##
@@ -286,6 +312,7 @@ module Google
286
312
  # @param [String] version The desired version of the API.
287
313
  # @param [String, StringIO] discovery_document
288
314
  # The contents of the discovery document.
315
+ # @return [Google::APIClient::API] The service object.
289
316
  def register_discovery_document(api, version, discovery_document)
290
317
  api = api.to_s
291
318
  version = version || 'v1'
@@ -300,6 +327,7 @@ module Google
300
327
  end
301
328
  @discovery_documents["#{api}:#{version}"] =
302
329
  MultiJson.load(discovery_document)
330
+ discovered_api(api, version)
303
331
  end
304
332
 
305
333
  ##
@@ -591,35 +619,42 @@ module Google
591
619
 
592
620
  connection = options[:connection] || self.connection
593
621
  request.authorization = options[:authorization] || self.authorization unless options[:authenticated] == false
622
+
594
623
  tries = 1 + (options[:retries] || self.retries)
624
+ attempt = 0
625
+
595
626
  Retriable.retriable :tries => tries,
596
- :on => [TransmissionError],
627
+ :on => [TransmissionError],
628
+ :on_retry => client_error_handler,
597
629
  :interval => lambda {|attempts| (2 ** attempts) + rand} do
598
- result = request.send(connection, true)
599
-
600
- case result.status
601
- when 200...300
602
- result
603
- when 301, 302, 303, 307
604
- request = generate_request(request.to_hash.merge({
605
- :uri => result.headers['location'],
606
- :api_method => nil
607
- }))
608
- raise RedirectError.new(result.headers['location'], result)
609
- when 400...500
610
- if result.status == 401 && request.authorization.respond_to?(:refresh_token) && auto_refresh_token
611
- begin
612
- logger.debug("Attempting refresh of access token & retry of request")
613
- request.authorization.fetch_access_token!
614
- rescue Signet::AuthorizationError
615
- # Ignore since we want the original error
616
- end
617
- end
618
- raise ClientError.new(result.error_message || "A client error has occurred", result)
619
- when 500...600
620
- raise ServerError.new(result.error_message || "A server error has occurred", result)
621
- else
622
- raise TransmissionError.new(result.error_message || "A transmission error has occurred", result)
630
+ attempt += 1
631
+
632
+ # This 2nd level retriable only catches auth errors, and supports 1 retry, which allows
633
+ # auth to be re-attempted without having to retry all sorts of other failures like
634
+ # NotFound, etc
635
+ Retriable.retriable :tries => ((expired_auth_retry || tries > 1) && attempt == 1) ? 2 : 1,
636
+ :on => [AuthorizationError],
637
+ :on_retry => authorization_error_handler(request.authorization) do
638
+ result = request.send(connection, true)
639
+
640
+ case result.status
641
+ when 200...300
642
+ result
643
+ when 301, 302, 303, 307
644
+ request = generate_request(request.to_hash.merge({
645
+ :uri => result.headers['location'],
646
+ :api_method => nil
647
+ }))
648
+ raise RedirectError.new(result.headers['location'], result)
649
+ when 401
650
+ raise AuthorizationError.new(result.error_message || 'Invalid/Expired Authentication', result)
651
+ when 400, 402...500
652
+ raise ClientError.new(result.error_message || "A client error has occurred", result)
653
+ when 500...600
654
+ raise ServerError.new(result.error_message || "A server error has occurred", result)
655
+ else
656
+ raise TransmissionError.new(result.error_message || "A transmission error has occurred", result)
657
+ end
623
658
  end
624
659
  end
625
660
  end
@@ -665,8 +700,41 @@ module Google
665
700
  return Addressable::Template.new(@base_uri + template).expand(mapping)
666
701
  end
667
702
 
703
+
704
+ ##
705
+ # Returns on proc for special processing of retries for authorization errors
706
+ # Only 401s should be retried and only if the credentials are refreshable
707
+ #
708
+ # @param [#fetch_access_token!] authorization
709
+ # OAuth 2 credentials
710
+ # @return [Proc]
711
+ def authorization_error_handler(authorization)
712
+ can_refresh = authorization.respond_to?(:refresh_token) && auto_refresh_token
713
+ Proc.new do |exception, tries|
714
+ next unless exception.kind_of?(AuthorizationError)
715
+ if can_refresh
716
+ begin
717
+ logger.debug("Attempting refresh of access token & retry of request")
718
+ authorization.fetch_access_token!
719
+ next
720
+ rescue Signet::AuthorizationError
721
+ end
722
+ end
723
+ raise exception
724
+ end
725
+ end
726
+
727
+ ##
728
+ # Returns on proc for special processing of retries as not all client errors
729
+ # are recoverable. Only 401s should be retried (via authorization_error_handler)
730
+ #
731
+ # @return [Proc]
732
+ def client_error_handler
733
+ Proc.new do |exception, tries|
734
+ raise exception if exception.kind_of?(ClientError)
735
+ end
736
+ end
737
+
668
738
  end
669
739
 
670
740
  end
671
-
672
- require 'google/api_client/version'
@@ -21,7 +21,7 @@ module Google
21
21
  def fetch_access_token(options={})
22
22
  connection = options[:connection] || Faraday.default_connection
23
23
  response = connection.get 'http://metadata/computeMetadata/v1beta1/instance/service-accounts/default/token'
24
- Signet::OAuth2.parse_json_credentials(response.body)
24
+ Signet::OAuth2.parse_credentials(response.body, response.headers['content-type'])
25
25
  end
26
26
  end
27
27
  end
@@ -12,47 +12,39 @@
12
12
  # See the License for the specific language governing permissions and
13
13
  # limitations under the License.
14
14
 
15
- require 'json'
16
15
  require 'signet/oauth_2/client'
16
+ require_relative 'storage'
17
+ require_relative 'storages/file_store'
17
18
 
18
19
  module Google
19
20
  class APIClient
21
+
20
22
  ##
21
23
  # Represents cached OAuth 2 tokens stored on local disk in a
22
24
  # JSON serialized file. Meant to resemble the serialized format
23
25
  # http://google-api-python-client.googlecode.com/hg/docs/epy/oauth2client.file.Storage-class.html
24
26
  #
27
+ # @deprecated
28
+ # Use {Google::APIClient::Storage} and {Google::APIClient::FileStore} instead
29
+ #
25
30
  class FileStorage
26
- # @return [String] Path to the credentials file.
27
- attr_accessor :path
28
31
 
29
- # @return [Signet::OAuth2::Client] Path to the credentials file.
30
- attr_reader :authorization
32
+ attr_accessor :storage,
33
+ :path
31
34
 
32
- ##
33
- # Initializes the FileStorage object.
34
- #
35
- # @param [String] path
36
- # Path to the credentials file.
37
35
  def initialize(path)
38
36
  @path = path
39
- self.load_credentials
37
+ store = Google::APIClient::FileStore.new(@path)
38
+ @storage = Google::APIClient::Storage.new(store)
39
+ @storage.authorize
40
40
  end
41
41
 
42
- ##
43
- # Attempt to read in credentials from the specified file.
44
42
  def load_credentials
45
- if File.exist? self.path
46
- File.open(self.path, 'r') do |file|
47
- cached_credentials = JSON.load(file)
48
- @authorization = Signet::OAuth2::Client.new(cached_credentials)
49
- @authorization.issued_at = Time.at(cached_credentials['issued_at'])
50
- if @authorization.expired?
51
- @authorization.fetch_access_token!
52
- self.write_credentials
53
- end
54
- end
55
- end
43
+ storage.authorize
44
+ end
45
+
46
+ def authorization
47
+ storage.authorization
56
48
  end
57
49
 
58
50
  ##
@@ -61,26 +53,9 @@ module Google
61
53
  # @param [Signet::OAuth2::Client] authorization
62
54
  # Optional authorization instance. If not provided, the authorization
63
55
  # already associated with this instance will be written.
64
- def write_credentials(authorization=nil)
65
- @authorization = authorization unless authorization.nil?
66
-
67
- unless @authorization.refresh_token.nil?
68
- hash = {}
69
- %w'access_token
70
- authorization_uri
71
- client_id
72
- client_secret
73
- expires_in
74
- refresh_token
75
- token_credential_uri'.each do |var|
76
- hash[var] = @authorization.instance_variable_get("@#{var}")
77
- end
78
- hash['issued_at'] = @authorization.issued_at.to_i
79
-
80
- File.open(self.path, 'w', 0600) do |file|
81
- file.write(hash.to_json)
82
- end
83
- end
56
+ def write_credentials(auth=nil)
57
+ self.authorization = auth unless auth.nil?
58
+ storage.write_credentials(self.authorization)
84
59
  end
85
60
  end
86
61
  end