gcloud 0.11.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (121) hide show
  1. checksums.yaml +8 -8
  2. data/AUTHENTICATION.md +3 -3
  3. data/CHANGELOG.md +92 -0
  4. data/OVERVIEW.md +3 -3
  5. data/lib/gcloud.rb +75 -25
  6. data/lib/gcloud/backoff.rb +5 -1
  7. data/lib/gcloud/bigquery.rb +25 -43
  8. data/lib/gcloud/bigquery/copy_job.rb +13 -13
  9. data/lib/gcloud/bigquery/data.rb +20 -16
  10. data/lib/gcloud/bigquery/dataset.rb +202 -177
  11. data/lib/gcloud/bigquery/dataset/access.rb +118 -104
  12. data/lib/gcloud/bigquery/dataset/list.rb +14 -18
  13. data/lib/gcloud/bigquery/extract_job.rb +12 -12
  14. data/lib/gcloud/bigquery/insert_response.rb +12 -14
  15. data/lib/gcloud/bigquery/job.rb +45 -57
  16. data/lib/gcloud/bigquery/job/list.rb +18 -24
  17. data/lib/gcloud/bigquery/load_job.rb +35 -27
  18. data/lib/gcloud/bigquery/project.rb +53 -73
  19. data/lib/gcloud/bigquery/query_data.rb +28 -35
  20. data/lib/gcloud/bigquery/query_job.rb +18 -18
  21. data/lib/gcloud/bigquery/schema.rb +359 -0
  22. data/lib/gcloud/bigquery/service.rb +506 -0
  23. data/lib/gcloud/bigquery/table.rb +185 -266
  24. data/lib/gcloud/bigquery/table/list.rb +15 -19
  25. data/lib/gcloud/bigquery/view.rb +126 -81
  26. data/lib/gcloud/datastore.rb +39 -27
  27. data/lib/gcloud/datastore/commit.rb +2 -2
  28. data/lib/gcloud/datastore/dataset.rb +8 -19
  29. data/lib/gcloud/datastore/dataset/lookup_results.rb +2 -4
  30. data/lib/gcloud/datastore/dataset/query_results.rb +0 -2
  31. data/lib/gcloud/datastore/entity.rb +7 -1
  32. data/lib/gcloud/datastore/errors.rb +5 -27
  33. data/lib/gcloud/datastore/grpc_utils.rb +4 -3
  34. data/lib/gcloud/datastore/key.rb +6 -0
  35. data/lib/gcloud/datastore/service.rb +18 -12
  36. data/lib/gcloud/datastore/transaction.rb +0 -10
  37. data/lib/gcloud/dns.rb +29 -19
  38. data/lib/gcloud/dns/change.rb +10 -15
  39. data/lib/gcloud/dns/change/list.rb +4 -4
  40. data/lib/gcloud/dns/importer.rb +1 -1
  41. data/lib/gcloud/dns/project.rb +32 -49
  42. data/lib/gcloud/dns/record.rb +8 -2
  43. data/lib/gcloud/dns/record/list.rb +4 -4
  44. data/lib/gcloud/dns/service.rb +167 -0
  45. data/lib/gcloud/dns/zone.rb +33 -52
  46. data/lib/gcloud/dns/zone/list.rb +12 -16
  47. data/lib/gcloud/errors.rb +31 -19
  48. data/lib/gcloud/logging.rb +50 -39
  49. data/lib/gcloud/logging/entry.rb +197 -24
  50. data/lib/gcloud/logging/entry/list.rb +0 -2
  51. data/lib/gcloud/logging/logger.rb +1 -1
  52. data/lib/gcloud/logging/metric.rb +3 -9
  53. data/lib/gcloud/logging/metric/list.rb +0 -2
  54. data/lib/gcloud/logging/project.rb +58 -54
  55. data/lib/gcloud/logging/resource_descriptor.rb +2 -2
  56. data/lib/gcloud/logging/resource_descriptor/list.rb +0 -2
  57. data/lib/gcloud/logging/service.rb +32 -23
  58. data/lib/gcloud/logging/sink.rb +8 -14
  59. data/lib/gcloud/logging/sink/list.rb +0 -2
  60. data/lib/gcloud/pubsub.rb +21 -16
  61. data/lib/gcloud/pubsub/policy.rb +204 -0
  62. data/lib/gcloud/pubsub/project.rb +26 -38
  63. data/lib/gcloud/pubsub/service.rb +39 -31
  64. data/lib/gcloud/pubsub/subscription.rb +56 -59
  65. data/lib/gcloud/pubsub/subscription/list.rb +4 -4
  66. data/lib/gcloud/pubsub/topic.rb +69 -66
  67. data/lib/gcloud/pubsub/topic/list.rb +0 -2
  68. data/lib/gcloud/pubsub/topic/{batch.rb → publisher.rb} +15 -2
  69. data/lib/gcloud/resource_manager.rb +27 -26
  70. data/lib/gcloud/resource_manager/manager.rb +19 -39
  71. data/lib/gcloud/resource_manager/policy.rb +211 -0
  72. data/lib/gcloud/resource_manager/project.rb +97 -121
  73. data/lib/gcloud/resource_manager/project/list.rb +7 -7
  74. data/lib/gcloud/resource_manager/project/updater.rb +4 -9
  75. data/lib/gcloud/resource_manager/service.rb +127 -0
  76. data/lib/gcloud/storage.rb +24 -42
  77. data/lib/gcloud/storage/bucket.rb +104 -192
  78. data/lib/gcloud/storage/bucket/acl.rb +47 -143
  79. data/lib/gcloud/storage/bucket/cors.rb +55 -11
  80. data/lib/gcloud/storage/bucket/list.rb +14 -14
  81. data/lib/gcloud/storage/errors.rb +3 -43
  82. data/lib/gcloud/storage/file.rb +114 -111
  83. data/lib/gcloud/storage/file/acl.rb +27 -113
  84. data/lib/gcloud/storage/file/list.rb +21 -21
  85. data/lib/gcloud/storage/project.rb +49 -59
  86. data/lib/gcloud/storage/service.rb +347 -0
  87. data/lib/gcloud/translate.rb +24 -14
  88. data/lib/gcloud/translate/api.rb +12 -21
  89. data/lib/gcloud/translate/detection.rb +5 -5
  90. data/lib/gcloud/translate/language.rb +1 -1
  91. data/lib/gcloud/translate/service.rb +80 -0
  92. data/lib/gcloud/translate/translation.rb +6 -6
  93. data/lib/gcloud/version.rb +1 -1
  94. data/lib/gcloud/vision.rb +24 -15
  95. data/lib/gcloud/vision/annotate.rb +24 -21
  96. data/lib/gcloud/vision/annotation.rb +9 -9
  97. data/lib/gcloud/vision/annotation/entity.rb +11 -11
  98. data/lib/gcloud/vision/annotation/face.rb +25 -25
  99. data/lib/gcloud/vision/annotation/properties.rb +8 -8
  100. data/lib/gcloud/vision/annotation/safe_search.rb +4 -4
  101. data/lib/gcloud/vision/annotation/text.rb +7 -7
  102. data/lib/gcloud/vision/annotation/vertex.rb +1 -1
  103. data/lib/gcloud/vision/image.rb +11 -11
  104. data/lib/gcloud/vision/location.rb +5 -2
  105. data/lib/gcloud/vision/project.rb +14 -16
  106. data/lib/gcloud/vision/service.rb +66 -0
  107. data/lib/google/api_client.rb +0 -0
  108. metadata +27 -24
  109. data/lib/gcloud/bigquery/connection.rb +0 -624
  110. data/lib/gcloud/bigquery/errors.rb +0 -68
  111. data/lib/gcloud/bigquery/table/schema.rb +0 -234
  112. data/lib/gcloud/dns/connection.rb +0 -173
  113. data/lib/gcloud/dns/errors.rb +0 -68
  114. data/lib/gcloud/resource_manager/connection.rb +0 -134
  115. data/lib/gcloud/resource_manager/errors.rb +0 -68
  116. data/lib/gcloud/storage/connection.rb +0 -444
  117. data/lib/gcloud/translate/connection.rb +0 -85
  118. data/lib/gcloud/translate/errors.rb +0 -68
  119. data/lib/gcloud/upload.rb +0 -95
  120. data/lib/gcloud/vision/connection.rb +0 -63
  121. data/lib/gcloud/vision/errors.rb +0 -69
@@ -49,7 +49,7 @@ module Gcloud
49
49
  class File
50
50
  ##
51
51
  # @private The Connection object.
52
- attr_accessor :connection
52
+ attr_accessor :service
53
53
 
54
54
  ##
55
55
  # @private The Google API Client object.
@@ -58,40 +58,40 @@ module Gcloud
58
58
  ##
59
59
  # @private Create an empty File object.
60
60
  def initialize
61
- @connection = nil
62
- @gapi = {}
61
+ @service = nil
62
+ @gapi = Google::Apis::StorageV1::Object.new
63
63
  end
64
64
 
65
65
  ##
66
66
  # The kind of item this is.
67
67
  # For files, this is always storage#object.
68
68
  def kind
69
- @gapi["kind"]
69
+ @gapi.kind
70
70
  end
71
71
 
72
72
  ##
73
73
  # The ID of the file.
74
74
  def id
75
- @gapi["id"]
75
+ @gapi.id
76
76
  end
77
77
 
78
78
  ##
79
79
  # The name of this file.
80
80
  def name
81
- @gapi["name"]
81
+ @gapi.name
82
82
  end
83
83
 
84
84
  ##
85
85
  # The name of the {Bucket} containing this file.
86
86
  def bucket
87
- @gapi["bucket"]
87
+ @gapi.bucket
88
88
  end
89
89
 
90
90
  ##
91
91
  # The content generation of this file.
92
92
  # Used for object versioning.
93
93
  def generation
94
- @gapi["generation"]
94
+ @gapi.generation
95
95
  end
96
96
 
97
97
  ##
@@ -100,31 +100,31 @@ module Gcloud
100
100
  # A metageneration number is only meaningful in the context of a
101
101
  # particular generation of a particular file.
102
102
  def metageneration
103
- @gapi["metageneration"]
103
+ @gapi.metageneration
104
104
  end
105
105
 
106
106
  ##
107
107
  # A URL that can be used to access the file using the REST API.
108
108
  def api_url
109
- @gapi["selfLink"]
109
+ @gapi.self_link
110
110
  end
111
111
 
112
112
  ##
113
113
  # A URL that can be used to download the file using the REST API.
114
114
  def media_url
115
- @gapi["mediaLink"]
115
+ @gapi.media_link
116
116
  end
117
117
 
118
118
  ##
119
119
  # Content-Length of the data in bytes.
120
120
  def size
121
- @gapi["size"]
121
+ @gapi.size.to_i if @gapi.size
122
122
  end
123
123
 
124
124
  ##
125
125
  # Creation time of the file.
126
126
  def created_at
127
- @gapi["timeCreated"]
127
+ @gapi.time_created
128
128
  end
129
129
 
130
130
  ##
@@ -132,13 +132,13 @@ module Gcloud
132
132
  # For buckets with versioning enabled, changing an object's
133
133
  # metadata does not change this property.
134
134
  def updated_at
135
- @gapi["updated"]
135
+ @gapi.updated
136
136
  end
137
137
 
138
138
  ##
139
139
  # MD5 hash of the data; encoded using base64.
140
140
  def md5
141
- @gapi["md5Hash"]
141
+ @gapi.md5_hash
142
142
  end
143
143
 
144
144
  ##
@@ -146,20 +146,20 @@ module Gcloud
146
146
  # [RFC 4960, Appendix B](http://tools.ietf.org/html/rfc4960#appendix-B).
147
147
  # Encoded using base64 in big-endian byte order.
148
148
  def crc32c
149
- @gapi["crc32c"]
149
+ @gapi.crc32c
150
150
  end
151
151
 
152
152
  ##
153
153
  # HTTP 1.1 Entity tag for the file.
154
154
  def etag
155
- @gapi["etag"]
155
+ @gapi.etag
156
156
  end
157
157
 
158
158
  ##
159
159
  # The [Cache-Control](https://tools.ietf.org/html/rfc7234#section-5.2)
160
160
  # directive for the file data.
161
161
  def cache_control
162
- @gapi["cacheControl"]
162
+ @gapi.cache_control
163
163
  end
164
164
 
165
165
  ##
@@ -167,56 +167,60 @@ module Gcloud
167
167
  # [Cache-Control](https://tools.ietf.org/html/rfc7234#section-5.2)
168
168
  # directive for the file data.
169
169
  def cache_control= cache_control
170
- patch_gapi! cache_control: cache_control
170
+ @gapi.cache_control = cache_control
171
+ patch_gapi! :cache_control
171
172
  end
172
173
 
173
174
  ##
174
175
  # The [Content-Disposition](https://tools.ietf.org/html/rfc6266) of the
175
176
  # file data.
176
177
  def content_disposition
177
- @gapi["contentDisposition"]
178
+ @gapi.content_disposition
178
179
  end
179
180
 
180
181
  ##
181
182
  # Updates the [Content-Disposition](https://tools.ietf.org/html/rfc6266)
182
183
  # of the file data.
183
184
  def content_disposition= content_disposition
184
- patch_gapi! content_disposition: content_disposition
185
+ @gapi.content_disposition = content_disposition
186
+ patch_gapi! :content_disposition
185
187
  end
186
188
 
187
189
  ##
188
190
  # The [Content-Encoding
189
191
  # ](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) of the file data.
190
192
  def content_encoding
191
- @gapi["contentEncoding"]
193
+ @gapi.content_encoding
192
194
  end
193
195
 
194
196
  ##
195
197
  # Updates the [Content-Encoding
196
198
  # ](https://tools.ietf.org/html/rfc7231#section-3.1.2.2) of the file data.
197
199
  def content_encoding= content_encoding
198
- patch_gapi! content_encoding: content_encoding
200
+ @gapi.content_encoding = content_encoding
201
+ patch_gapi! :content_encoding
199
202
  end
200
203
 
201
204
  ##
202
205
  # The [Content-Language](http://tools.ietf.org/html/bcp47) of the file
203
206
  # data.
204
207
  def content_language
205
- @gapi["contentLanguage"]
208
+ @gapi.content_language
206
209
  end
207
210
 
208
211
  ##
209
212
  # Updates the [Content-Language](http://tools.ietf.org/html/bcp47) of the
210
213
  # file data.
211
214
  def content_language= content_language
212
- patch_gapi! content_language: content_language
215
+ @gapi.content_language = content_language
216
+ patch_gapi! :content_language
213
217
  end
214
218
 
215
219
  ##
216
220
  # The [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17) of
217
221
  # the file data.
218
222
  def content_type
219
- @gapi["contentType"]
223
+ @gapi.content_type
220
224
  end
221
225
 
222
226
  ##
@@ -224,7 +228,8 @@ module Gcloud
224
228
  # [Content-Type](https://tools.ietf.org/html/rfc2616#section-14.17) of the
225
229
  # file data.
226
230
  def content_type= content_type
227
- patch_gapi! content_type: content_type
231
+ @gapi.content_type = content_type
232
+ patch_gapi! :content_type
228
233
  end
229
234
 
230
235
  ##
@@ -232,9 +237,9 @@ module Gcloud
232
237
  # values that will returned with requests for the file as "x-goog-meta-"
233
238
  # response headers.
234
239
  def metadata
235
- m = @gapi["metadata"]
236
- m = m.to_hash if m.respond_to? :to_hash
237
- m.freeze
240
+ m = @gapi.metadata
241
+ m = m.to_h if m.respond_to? :to_h
242
+ m.dup.freeze
238
243
  end
239
244
 
240
245
  ##
@@ -242,7 +247,8 @@ module Gcloud
242
247
  # string values that will returned with requests for the file as
243
248
  # "x-goog-meta-" response headers.
244
249
  def metadata= metadata
245
- patch_gapi! metadata: metadata
250
+ @gapi.metadata = metadata
251
+ patch_gapi! :metadata
246
252
  end
247
253
 
248
254
  ##
@@ -252,8 +258,8 @@ module Gcloud
252
258
  # You can use this SHA256 hash to uniquely identify the AES-256 encryption
253
259
  # key required to decrypt this file.
254
260
  def encryption_key_sha256
255
- return nil unless @gapi["customerEncryption"]
256
- Base64.decode64 @gapi["customerEncryption"]["keySha256"]
261
+ return nil unless @gapi.customer_encryption
262
+ Base64.decode64 @gapi.customer_encryption.key_sha256
257
263
  end
258
264
 
259
265
  ##
@@ -286,8 +292,9 @@ module Gcloud
286
292
  # end
287
293
  #
288
294
  def update
289
- updater = Updater.new metadata
295
+ updater = Updater.new gapi
290
296
  yield updater
297
+ updater.check_for_changed_metadata!
291
298
  patch_gapi! updater.updates unless updater.updates.empty?
292
299
  end
293
300
 
@@ -298,7 +305,7 @@ module Gcloud
298
305
  #
299
306
  # If a [customer-supplied encryption
300
307
  # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
301
- # was used with {#create_file}, the `encryption_key` and
308
+ # was used with {Bucket#create_file}, the `encryption_key` and
302
309
  # `encryption_key_sha256` options must be provided.
303
310
  #
304
311
  # @param [String] path The path on the local file system to write the data
@@ -315,11 +322,11 @@ module Gcloud
315
322
  #
316
323
  # @param [String] encryption_key Optional. The customer-supplied, AES-256
317
324
  # encryption key used to encrypt the file, if one was provided to
318
- # {#create_file}. Must be provided if `encryption_key_sha256` is
325
+ # {Bucket#create_file}. Must be provided if `encryption_key_sha256` is
319
326
  # provided.
320
327
  # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
321
328
  # customer-supplied, AES-256 encryption key used to encrypt the file, if
322
- # one was provided to {#create_file}. Must be provided if
329
+ # one was provided to {Bucket#create_file}. Must be provided if
323
330
  # `encryption_key` is provided.
324
331
  #
325
332
  # @return [File] Returns a `::File` object on the local file system
@@ -370,18 +377,11 @@ module Gcloud
370
377
  #
371
378
  def download path, verify: :md5, encryption_key: nil,
372
379
  encryption_key_sha256: nil
373
- ensure_connection!
374
- options = { encryption_key: encryption_key,
375
- encryption_key_sha256: encryption_key_sha256 }
376
- resp = connection.download_file bucket, name, options
377
- if resp.success?
378
- ::File.open path, "wb+" do |f|
379
- f.write resp.body
380
- end
381
- verify_file! ::File.new(path), verify
382
- else
383
- fail ApiError.from_response(resp)
384
- end
380
+ ensure_service!
381
+ service.download_file \
382
+ bucket, name, path,
383
+ key: encryption_key, key_sha256: encryption_key_sha256
384
+ verify_file! ::File.new(path), verify
385
385
  end
386
386
 
387
387
  ##
@@ -389,7 +389,7 @@ module Gcloud
389
389
  #
390
390
  # If a [customer-supplied encryption
391
391
  # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
392
- # was used with {#create_file}, the `encryption_key` and
392
+ # was used with {Bucket#create_file}, the `encryption_key` and
393
393
  # `encryption_key_sha256` options must be provided.
394
394
  #
395
395
  # @param [String] dest_bucket_or_path Either the bucket to copy the file
@@ -418,11 +418,11 @@ module Gcloud
418
418
  # copy. The default is the latest version.
419
419
  # @param [String] encryption_key Optional. The customer-supplied, AES-256
420
420
  # encryption key used to encrypt the file, if one was provided to
421
- # {#create_file}. Must be provided if `encryption_key_sha256` is
421
+ # {Bucket#create_file}. Must be provided if `encryption_key_sha256` is
422
422
  # provided.
423
423
  # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
424
424
  # customer-supplied, AES-256 encryption key used to encrypt the file, if
425
- # one was provided to {#create_file}. Must be provided if
425
+ # one was provided to {Bucket#create_file}. Must be provided if
426
426
  # `encryption_key` is provided.
427
427
  #
428
428
  # @return [Gcloud::Storage::File]
@@ -456,20 +456,15 @@ module Gcloud
456
456
  #
457
457
  def copy dest_bucket_or_path, dest_path = nil, acl: nil, generation: nil,
458
458
  encryption_key: nil, encryption_key_sha256: nil
459
- ensure_connection!
459
+ ensure_service!
460
460
  options = { acl: acl, generation: generation,
461
- encryption_key: encryption_key,
462
- encryption_key_sha256: encryption_key_sha256 }
461
+ key: encryption_key, key_sha256: encryption_key_sha256 }
463
462
  dest_bucket, dest_path, options = fix_copy_args dest_bucket_or_path,
464
463
  dest_path, options
465
464
 
466
- resp = connection.copy_file bucket, name,
467
- dest_bucket, dest_path, options
468
- if resp.success?
469
- File.from_gapi resp.data, connection
470
- else
471
- fail ApiError.from_response(resp)
472
- end
465
+ gapi = service.copy_file bucket, name,
466
+ dest_bucket, dest_path, options
467
+ File.from_gapi gapi, service
473
468
  end
474
469
 
475
470
  ##
@@ -489,13 +484,9 @@ module Gcloud
489
484
  # file.delete
490
485
  #
491
486
  def delete
492
- ensure_connection!
493
- resp = connection.delete_file bucket, name
494
- if resp.success?
495
- true
496
- else
497
- fail ApiError.from_response(resp)
498
- end
487
+ ensure_service!
488
+ service.delete_file bucket, name
489
+ true
499
490
  end
500
491
 
501
492
  ##
@@ -607,7 +598,7 @@ module Gcloud
607
598
  def signed_url method: nil, expires: nil, content_type: nil,
608
599
  content_md5: nil, issuer: nil, client_email: nil,
609
600
  signing_key: nil, private_key: nil
610
- ensure_connection!
601
+ ensure_service!
611
602
  options = { method: method, expires: expires,
612
603
  content_type: content_type, content_md5: content_md5,
613
604
  issuer: issuer, client_email: client_email,
@@ -668,13 +659,8 @@ module Gcloud
668
659
  ##
669
660
  # Reloads the file with current data from the Storage service.
670
661
  def reload!
671
- ensure_connection!
672
- resp = connection.get_file bucket, name
673
- if resp.success?
674
- @gapi = resp.data
675
- else
676
- fail ApiError.from_response(resp)
677
- end
662
+ ensure_service!
663
+ @gapi = service.get_file bucket, name
678
664
  end
679
665
  alias_method :refresh!, :reload!
680
666
 
@@ -687,29 +673,30 @@ module Gcloud
687
673
 
688
674
  ##
689
675
  # @private New File from a Google API Client object.
690
- def self.from_gapi gapi, conn
676
+ def self.from_gapi gapi, service
691
677
  new.tap do |f|
692
678
  f.gapi = gapi
693
- f.connection = conn
679
+ f.service = service
694
680
  end
695
681
  end
696
682
 
697
683
  protected
698
684
 
699
685
  ##
700
- # Raise an error unless an active connection is available.
701
- def ensure_connection!
702
- fail "Must have active connection" unless connection
686
+ # Raise an error unless an active service is available.
687
+ def ensure_service!
688
+ fail "Must have active connection" unless service
703
689
  end
704
690
 
705
- def patch_gapi! options = {}
706
- ensure_connection!
707
- resp = connection.patch_file bucket, name, options
708
- if resp.success?
709
- @gapi = resp.data
710
- else
711
- fail ApiError.from_response(resp)
712
- end
691
+ def patch_gapi! *attributes
692
+ attributes.flatten!
693
+ return if attributes.empty?
694
+ ensure_service!
695
+ patch_args = Hash[attributes.map do |attr|
696
+ [attr, @gapi.send(attr)]
697
+ end]
698
+ patch_gapi = Google::Apis::StorageV1::Object.new patch_args
699
+ @gapi = service.patch_file bucket, name, patch_gapi
713
700
  end
714
701
 
715
702
  def fix_copy_args dest_bucket, dest_path, options = {}
@@ -768,12 +755,12 @@ module Gcloud
768
755
 
769
756
  def determine_signing_key options = {}
770
757
  options[:signing_key] || options[:private_key] ||
771
- @file.connection.credentials.signing_key
758
+ @file.service.credentials.signing_key
772
759
  end
773
760
 
774
761
  def determine_issuer options = {}
775
762
  options[:issuer] || options[:client_email] ||
776
- @file.connection.credentials.issuer
763
+ @file.service.credentials.issuer
777
764
  end
778
765
 
779
766
  def signed_url options
@@ -796,7 +783,7 @@ module Gcloud
796
783
  end
797
784
 
798
785
  def generate_signed_url issuer, signed_string, expires
799
- signature = Base64.encode64(signed_string).delete("\n")
786
+ signature = Base64.strict_encode64(signed_string).delete("\n")
800
787
  "#{ext_url}?GoogleAccessId=#{CGI.escape issuer}" \
801
788
  "&Expires=#{expires}" \
802
789
  "&Signature=#{CGI.escape signature}"
@@ -805,33 +792,49 @@ module Gcloud
805
792
 
806
793
  ##
807
794
  # Yielded to a block to accumulate changes for a patch request.
808
- class Updater
795
+ class Updater < File
809
796
  attr_reader :updates
810
797
  ##
811
798
  # Create an Updater object.
812
- def initialize metadata
813
- @metadata = if metadata.nil?
814
- {}
815
- else
816
- metadata.dup
817
- end
818
- @updates = {}
799
+ def initialize gapi
800
+ @updates = []
801
+ @gapi = gapi
802
+ end
803
+
804
+ ##
805
+ # A hash of custom, user-provided web-safe keys and arbitrary string
806
+ # values that will returned with requests for the file as "x-goog-meta-"
807
+ # response headers.
808
+ def metadata
809
+ # do not freeze metadata
810
+ @metadata ||= @gapi.metadata.to_h.dup
819
811
  end
820
812
 
821
- ATTRS = [:cache_control, :content_disposition, :content_encoding,
822
- :content_language, :content_type, :metadata]
813
+ ##
814
+ # Updates the hash of custom, user-provided web-safe keys and arbitrary
815
+ # string values that will returned with requests for the file as
816
+ # "x-goog-meta-" response headers.
817
+ def metadata= metadata
818
+ @metadata = metadata
819
+ @gapi.metadata = @metadata
820
+ patch_gapi! :metadata
821
+ end
823
822
 
824
- ATTRS.each do |attr|
825
- define_method "#{attr}=" do |arg|
826
- updates[attr] = arg
827
- end
823
+ ##
824
+ # @private Make sure any metadata changes are saved
825
+ def check_for_changed_metadata!
826
+ return if @metadata == @gapi.metadata
827
+ @gapi.metadata = @metadata
828
+ patch_gapi! :metadata
828
829
  end
829
830
 
831
+ protected
832
+
830
833
  ##
831
- # Return metadata for mutation. Also adds metadata to @updates so that
832
- # it is included in the patch request.
833
- def metadata
834
- updates[:metadata] ||= @metadata
834
+ # Queue up all the updates instead of making them.
835
+ def patch_gapi! attribute
836
+ @updates << attribute
837
+ @updates.uniq!
835
838
  end
836
839
  end
837
840
  end