gcloud 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. checksums.yaml +8 -8
  2. data/CHANGELOG.md +36 -0
  3. data/lib/gcloud/backoff.rb +5 -5
  4. data/lib/gcloud/bigquery.rb +24 -0
  5. data/lib/gcloud/bigquery/connection.rb +32 -25
  6. data/lib/gcloud/bigquery/data.rb +99 -1
  7. data/lib/gcloud/bigquery/dataset.rb +5 -13
  8. data/lib/gcloud/bigquery/dataset/list.rb +124 -2
  9. data/lib/gcloud/bigquery/job/list.rb +125 -2
  10. data/lib/gcloud/bigquery/project.rb +30 -27
  11. data/lib/gcloud/bigquery/query_data.rb +102 -1
  12. data/lib/gcloud/bigquery/table.rb +17 -2
  13. data/lib/gcloud/bigquery/table/list.rb +132 -3
  14. data/lib/gcloud/datastore.rb +30 -19
  15. data/lib/gcloud/datastore/dataset.rb +2 -22
  16. data/lib/gcloud/datastore/dataset/lookup_results.rb +160 -4
  17. data/lib/gcloud/datastore/dataset/query_results.rb +229 -23
  18. data/lib/gcloud/datastore/transaction.rb +2 -5
  19. data/lib/gcloud/dns.rb +20 -0
  20. data/lib/gcloud/dns/change/list.rb +109 -6
  21. data/lib/gcloud/dns/connection.rb +18 -9
  22. data/lib/gcloud/dns/project.rb +4 -8
  23. data/lib/gcloud/dns/record/list.rb +96 -13
  24. data/lib/gcloud/dns/zone.rb +9 -24
  25. data/lib/gcloud/dns/zone/list.rb +102 -5
  26. data/lib/gcloud/dns/zone/transaction.rb +1 -1
  27. data/lib/gcloud/logging.rb +19 -0
  28. data/lib/gcloud/logging/entry/list.rb +83 -14
  29. data/lib/gcloud/logging/metric/list.rb +89 -12
  30. data/lib/gcloud/logging/project.rb +18 -30
  31. data/lib/gcloud/logging/resource_descriptor/list.rb +105 -6
  32. data/lib/gcloud/logging/sink/list.rb +89 -12
  33. data/lib/gcloud/pubsub.rb +23 -0
  34. data/lib/gcloud/pubsub/project.rb +21 -29
  35. data/lib/gcloud/pubsub/service.rb +1 -3
  36. data/lib/gcloud/pubsub/subscription/list.rb +167 -13
  37. data/lib/gcloud/pubsub/topic.rb +15 -13
  38. data/lib/gcloud/pubsub/topic/batch.rb +10 -4
  39. data/lib/gcloud/pubsub/topic/list.rb +134 -8
  40. data/lib/gcloud/resource_manager.rb +24 -0
  41. data/lib/gcloud/resource_manager/connection.rb +18 -9
  42. data/lib/gcloud/resource_manager/manager.rb +7 -4
  43. data/lib/gcloud/resource_manager/project/list.rb +93 -14
  44. data/lib/gcloud/storage.rb +63 -0
  45. data/lib/gcloud/storage/bucket.rb +100 -61
  46. data/lib/gcloud/storage/bucket/list.rb +132 -8
  47. data/lib/gcloud/storage/connection.rb +68 -44
  48. data/lib/gcloud/storage/errors.rb +9 -3
  49. data/lib/gcloud/storage/file.rb +48 -4
  50. data/lib/gcloud/storage/file/list.rb +151 -15
  51. data/lib/gcloud/storage/file/verifier.rb +3 -3
  52. data/lib/gcloud/storage/project.rb +15 -30
  53. data/lib/gcloud/translate.rb +20 -0
  54. data/lib/gcloud/translate/connection.rb +12 -3
  55. data/lib/gcloud/version.rb +1 -1
  56. data/lib/gcloud/vision.rb +20 -0
  57. data/lib/gcloud/vision/connection.rb +10 -1
  58. data/lib/gcloud/vision/image.rb +15 -18
  59. metadata +16 -2
@@ -240,6 +240,45 @@ module Gcloud
240
240
  # "avatars/heidi/400x400.png"
241
241
  # ```
242
242
  #
243
+ # ### Customer-supplied encryption keys
244
+ #
245
+ # By default, Google Cloud Storage manages server-side encryption keys on
246
+ # your behalf. However, a [customer-supplied encryption
247
+ # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
248
+ # can be provided with the `encryption_key` and `encryption_key_sha256`
249
+ # options. If given, the same key and SHA256 hash also must be provided to
250
+ # subsequently download or copy the file. If you use customer-supplied
251
+ # encryption keys, you must securely manage your keys and ensure that they are
252
+ # not lost. Also, please note that file metadata is not encrypted, with the
253
+ # exception of the CRC32C checksum and MD5 hash. The names of files and
254
+ # buckets are also not encrypted, and you can read or update the metadata of
255
+ # an encrypted file without providing the encryption key.
256
+ #
257
+ # ```ruby
258
+ # require "gcloud"
259
+ # require "digest/sha2"
260
+ #
261
+ # gcloud = Gcloud.new
262
+ # storage = gcloud.storage
263
+ # bucket = storage.bucket "my-todo-app"
264
+ #
265
+ # # Key generation shown for example purposes only. Write your own.
266
+ # cipher = OpenSSL::Cipher.new "aes-256-cfb"
267
+ # cipher.encrypt
268
+ # key = cipher.random_key
269
+ # key_hash = Digest::SHA256.digest key
270
+ #
271
+ # bucket.create_file "/var/todo-app/avatars/heidi/400x400.png",
272
+ # "avatars/heidi/400x400.png",
273
+ # encryption_key: key,
274
+ # encryption_key_sha256: key_hash
275
+ #
276
+ # # Store your key and hash securely for later use.
277
+ # file = bucket.file "avatars/heidi/400x400.png",
278
+ # encryption_key: key,
279
+ # encryption_key_sha256: key_hash
280
+ # ```
281
+ #
243
282
  # ### A note about large uploads
244
283
  #
245
284
  # You may encounter a Broken pipe (Errno::EPIPE) error when attempting to
@@ -405,6 +444,30 @@ module Gcloud
405
444
  # file.acl.public!
406
445
  # ```
407
446
  #
447
+ # ## Configuring Backoff
448
+ #
449
+ # The {Gcloud::Backoff} class allows users to globally configure how Cloud API
450
+ # requests are automatically retried in the case of some errors, such as a
451
+ # `500` or `503` status code, or a specific internal error code such as
452
+ # `rateLimitExceeded`.
453
+ #
454
+ # If an API call fails, the response will be inspected to see if the call
455
+ # should be retried. If the response matches the criteria, then the request
456
+ # will be retried after a delay. If another error occurs, the delay will be
457
+ # increased incrementally before a subsequent attempt. The first retry will be
458
+ # delayed one second, the second retry two seconds, and so on.
459
+ #
460
+ # ```ruby
461
+ # require "gcloud"
462
+ # require "gcloud/backoff"
463
+ #
464
+ # Gcloud::Backoff.retries = 5 # Raise the maximum number of retries from 3
465
+ # ```
466
+ #
467
+ # See the [Storage status and error
468
+ # codes](https://cloud.google.com/storage/docs/json_api/v1/status-codes)
469
+ # for a list of error conditions.
470
+ #
408
471
  module Storage
409
472
  end
410
473
  end
@@ -326,11 +326,7 @@ module Gcloud
326
326
  # The bucket must be empty before it can be deleted.
327
327
  #
328
328
  # The API call to delete the bucket may be retried under certain
329
- # conditions. See {Gcloud::Backoff} to control this behavior, or
330
- # specify the wanted behavior using the `retries` option.
331
- #
332
- # @param [Integer] retries The number of times the API call should be
333
- # retried. Default is Gcloud::Backoff.retries.
329
+ # conditions. See {Gcloud::Backoff} to control this behavior.
334
330
  #
335
331
  # @return [Boolean] Returns `true` if the bucket was deleted.
336
332
  #
@@ -343,19 +339,9 @@ module Gcloud
343
339
  # bucket = storage.bucket "my-bucket"
344
340
  # bucket.delete
345
341
  #
346
- # @example Specify the number of retries to attempt:
347
- # require "gcloud"
348
- #
349
- # gcloud = Gcloud.new
350
- # storage = gcloud.storage
351
- #
352
- # bucket = storage.bucket "my-bucket"
353
- # bucket.delete retries: 5
354
- #
355
- def delete retries: nil
342
+ def delete
356
343
  ensure_connection!
357
- options = { retries: retries }
358
- resp = connection.delete_bucket name, options
344
+ resp = connection.delete_bucket name
359
345
  if resp.success?
360
346
  true
361
347
  else
@@ -399,24 +385,16 @@ module Gcloud
399
385
  # puts file.name
400
386
  # end
401
387
  #
402
- # @example With pagination: (See {File::List#token})
388
+ # @example Retrieve all files: (See {File::List#all})
403
389
  # require "gcloud"
404
390
  #
405
391
  # gcloud = Gcloud.new
406
392
  # storage = gcloud.storage
407
393
  #
408
394
  # bucket = storage.bucket "my-bucket"
409
- #
410
- # all_files = []
411
- # tmp_files = bucket.files
412
- # while tmp_files.any? do
413
- # tmp_files.each do |file|
414
- # all_files << file
415
- # end
416
- # # break loop if no more buckets available
417
- # break if tmp_files.token.nil?
418
- # # get the next group of files
419
- # tmp_files = bucket.files token: tmp_files.token
395
+ # files = bucket.files
396
+ # files.all do |file|
397
+ # puts file.name
420
398
  # end
421
399
  #
422
400
  def files prefix: nil, delimiter: nil, token: nil, max: nil, versions: nil
@@ -429,20 +407,32 @@ module Gcloud
429
407
  versions: versions
430
408
  }
431
409
  resp = connection.list_files name, options
432
- if resp.success?
433
- File::List.from_response resp, connection
434
- else
435
- fail ApiError.from_response(resp)
436
- end
410
+ fail ApiError.from_response(resp) unless resp.success?
411
+ File::List.from_response resp, connection, name, prefix, delimiter, max,
412
+ versions
437
413
  end
438
414
  alias_method :find_files, :files
439
415
 
440
416
  ##
441
417
  # Retrieves a file matching the path.
442
418
  #
419
+ # If a [customer-supplied encryption
420
+ # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
421
+ # was used with {#create_file}, the `encryption_key` and
422
+ # `encryption_key_sha256` options must be provided or else the file's
423
+ # CRC32C checksum and MD5 hash will not be returned.
424
+ #
443
425
  # @param [String] path Name (path) of the file.
444
426
  # @param [Integer] generation When present, selects a specific revision of
445
427
  # this object. Default is the latest version.
428
+ # @param [String] encryption_key Optional. The customer-supplied, AES-256
429
+ # encryption key used to encrypt the file, if one was provided to
430
+ # {#create_file}. Must be provided if `encryption_key_sha256` is
431
+ # provided.
432
+ # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
433
+ # customer-supplied, AES-256 encryption key used to encrypt the file, if
434
+ # one was provided to {#create_file}. Must be provided if
435
+ # `encryption_key` is provided.
446
436
  #
447
437
  # @return [Gcloud::Storage::File, nil] Returns nil if file does not exist
448
438
  #
@@ -457,9 +447,11 @@ module Gcloud
457
447
  # file = bucket.file "path/to/my-file.ext"
458
448
  # puts file.name
459
449
  #
460
- def file path, generation: nil
450
+ def file path, generation: nil, encryption_key: nil,
451
+ encryption_key_sha256: nil
461
452
  ensure_connection!
462
- options = { generation: generation }
453
+ options = { generation: generation, encryption_key: encryption_key,
454
+ encryption_key_sha256: encryption_key_sha256 }
463
455
  resp = connection.get_file name, path, options
464
456
  if resp.success?
465
457
  File.from_gapi resp.data, connection
@@ -470,8 +462,8 @@ module Gcloud
470
462
  alias_method :find_file, :file
471
463
 
472
464
  ##
473
- # Create a new File object by providing a path to a local file to upload
474
- # and the path to store it with in the bucket.
465
+ # Creates a new {File} object by providing a path to a local file to
466
+ # upload and the path to store it with in the bucket.
475
467
  #
476
468
  # A `chunk_size` value can be provided in the options to be used
477
469
  # in resumable uploads. This value is the number of bytes per
@@ -479,6 +471,43 @@ module Gcloud
479
471
  # by 256KB then it will be lowered to the nearest acceptable
480
472
  # value.
481
473
  #
474
+ # #### Customer-supplied encryption keys
475
+ #
476
+ # By default, Google Cloud Storage manages server-side encryption keys on
477
+ # your behalf. However, a [customer-supplied encryption
478
+ # key](https://cloud.google.com/storage/docs/encryption#customer-supplied)
479
+ # can be provided with the `encryption_key` and `encryption_key_sha256`
480
+ # options. If given, the same key and SHA256 hash also must be provided to
481
+ # subsequently download or copy the file. If you use customer-supplied
482
+ # encryption keys, you must securely manage your keys and ensure that they
483
+ # are not lost. Also, please note that file metadata is not encrypted,
484
+ # with the exception of the CRC32C checksum and MD5 hash. The names of
485
+ # files and buckets are also not encrypted, and you can read or update the
486
+ # metadata of an encrypted file without providing the encryption key.
487
+ #
488
+ # #### Troubleshooting large uploads
489
+ #
490
+ # You may encounter errors while attempting to upload large files. Below
491
+ # are a couple of common cases and their solutions.
492
+ #
493
+ # ##### Handling memory errors
494
+ #
495
+ # If you encounter a memory error such as `NoMemoryError`, try performing
496
+ # a resumable upload and setting the `chunk_size` option to a value that
497
+ # works for your environment, as explained in the final example above.
498
+ #
499
+ # ##### Handling broken pipe errors
500
+ #
501
+ # To avoid broken pipe (`Errno::EPIPE`) errors when uploading, add the
502
+ # [httpclient](https://rubygems.org/gems/httpclient) gem to your project,
503
+ # and the configuration shown below. These lines must execute after you
504
+ # require gcloud but before you make your first gcloud connection. The
505
+ # first statement configures [Faraday](https://rubygems.org/gems/faraday)
506
+ # to use httpclient. The second statement, which should only be added if
507
+ # you are using a version of Faraday at or above 0.9.2, is a workaround
508
+ # for [this gzip
509
+ # issue](https://github.com/GoogleCloudPlatform/gcloud-ruby/issues/367).
510
+ #
482
511
  # @param [String] file Path of the file on the filesystem to upload.
483
512
  # @param [String] path Path to store the file in Google Cloud Storage.
484
513
  # @param [String] acl A predefined set of access controls to apply to this
@@ -532,6 +561,12 @@ module Gcloud
532
561
  # @param [Hash] metadata A hash of custom, user-provided web-safe keys and
533
562
  # arbitrary string values that will returned with requests for the file
534
563
  # as "x-goog-meta-" response headers.
564
+ # @param [String] encryption_key Optional. A customer-supplied, AES-256
565
+ # encryption key that will be used to encrypt the file. Must be provided
566
+ # if `encryption_key_sha256` is provided.
567
+ # @param [String] encryption_key_sha256 Optional. The SHA256 hash of the
568
+ # customer-supplied, AES-256 encryption key that will be used to encrypt
569
+ # the file. Must be provided if `encryption_key` is provided.
535
570
  #
536
571
  # @return [Gcloud::Storage::File]
537
572
  #
@@ -545,7 +580,7 @@ module Gcloud
545
580
  #
546
581
  # bucket.create_file "path/to/local.file.ext"
547
582
  #
548
- # @example Additionally, a destination path can be specified.
583
+ # @example Specifying a destination path:
549
584
  # require "gcloud"
550
585
  #
551
586
  # gcloud = Gcloud.new
@@ -556,7 +591,7 @@ module Gcloud
556
591
  # bucket.create_file "path/to/local.file.ext",
557
592
  # "destination/path/file.ext"
558
593
  #
559
- # @example Specify the chunk size as a number of bytes:
594
+ # @example Specifying the chunk size as a number of bytes:
560
595
  # require "gcloud"
561
596
  #
562
597
  # gcloud = Gcloud.new
@@ -568,30 +603,31 @@ module Gcloud
568
603
  # "destination/path/file.ext",
569
604
  # chunk_size: 1024*1024 # 1 MB chunk
570
605
  #
571
- # #### Troubleshooting large uploads
606
+ # @example Providing a customer-supplied encryption key:
607
+ # require "gcloud"
608
+ # require "digest/sha2"
572
609
  #
573
- # You may encounter errors while attempting to upload large files. Below
574
- # are a couple of common cases and their solutions.
610
+ # gcloud = Gcloud.new
611
+ # storage = gcloud.storage
612
+ # bucket = storage.bucket "my-bucket"
575
613
  #
576
- # ##### Handling memory errors
614
+ # # Key generation shown for example purposes only. Write your own.
615
+ # cipher = OpenSSL::Cipher.new "aes-256-cfb"
616
+ # cipher.encrypt
617
+ # key = cipher.random_key
618
+ # key_hash = Digest::SHA256.digest key
577
619
  #
578
- # If you encounter a memory error such as `NoMemoryError`, try performing
579
- # a resumable upload and setting the `chunk_size` option to a value that
580
- # works for your environment, as explained in the final example above.
581
- #
582
- # ##### Handling broken pipe errors
620
+ # bucket.create_file "path/to/local.file.ext",
621
+ # "destination/path/file.ext",
622
+ # encryption_key: key,
623
+ # encryption_key_sha256: key_hash
583
624
  #
584
- # To avoid broken pipe (`Errno::EPIPE`) errors when uploading, add the
585
- # [httpclient](https://rubygems.org/gems/httpclient) gem to your project,
586
- # and the configuration shown below. These lines must execute after you
587
- # require gcloud but before you make your first gcloud connection. The
588
- # first statement configures [Faraday](https://rubygems.org/gems/faraday)
589
- # to use httpclient. The second statement, which should only be added if
590
- # you are using a version of Faraday at or above 0.9.2, is a workaround
591
- # for [this gzip
592
- # issue](https://github.com/GoogleCloudPlatform/gcloud-ruby/issues/367).
625
+ # # Store your key and hash securely for later use.
626
+ # file = bucket.file "destination/path/file.ext",
627
+ # encryption_key: key,
628
+ # encryption_key_sha256: key_hash
593
629
  #
594
- # @example
630
+ # @example Avoiding broken pipe errors with large uploads:
595
631
  # require "gcloud"
596
632
  #
597
633
  # # Use httpclient to avoid broken pipe errors with large uploads
@@ -608,13 +644,16 @@ module Gcloud
608
644
  def create_file file, path = nil, acl: nil, cache_control: nil,
609
645
  content_disposition: nil, content_encoding: nil,
610
646
  content_language: nil, content_type: nil, chunk_size: nil,
611
- crc32c: nil, md5: nil, metadata: nil
647
+ crc32c: nil, md5: nil, metadata: nil, encryption_key: nil,
648
+ encryption_key_sha256: nil
612
649
  ensure_connection!
613
650
  options = { acl: File::Acl.predefined_rule_for(acl), md5: md5,
614
651
  cache_control: cache_control, content_type: content_type,
615
652
  content_disposition: content_disposition, crc32c: crc32c,
616
653
  content_encoding: content_encoding, chunk_size: chunk_size,
617
- content_language: content_language, metadata: metadata }
654
+ content_language: content_language, metadata: metadata,
655
+ encryption_key: encryption_key,
656
+ encryption_key_sha256: encryption_key_sha256 }
618
657
  ensure_file_exists! file
619
658
  resumable = resumable_upload?(file)
620
659
  resp = @connection.upload_file resumable, name, file, path, options
@@ -24,23 +24,147 @@ module Gcloud
24
24
  ##
25
25
  # If not empty, indicates that there are more buckets
26
26
  # that match the request and this value should be passed to
27
- # the next Gcloud::Storage::Project#buckets to continue.
27
+ # the next {Gcloud::Storage::Project#buckets} to continue.
28
28
  attr_accessor :token
29
29
 
30
30
  ##
31
- # Create a new Bucket::List with an array of values.
32
- def initialize arr = [], token = nil
31
+ # @private Create a new Bucket::List with an array of values.
32
+ def initialize arr = []
33
33
  super arr
34
- @token = token
34
+ end
35
+
36
+ ##
37
+ # Whether there is a next page of buckets.
38
+ #
39
+ # @return [Boolean]
40
+ #
41
+ # @example
42
+ # require "gcloud"
43
+ #
44
+ # gcloud = Gcloud.new
45
+ # storage = gcloud.storage
46
+ #
47
+ # buckets = storage.buckets
48
+ # if buckets.next?
49
+ # next_buckets = buckets.next
50
+ # end
51
+ #
52
+ def next?
53
+ !token.nil?
54
+ end
55
+
56
+ ##
57
+ # Retrieve the next page of buckets.
58
+ #
59
+ # @return [Bucket::List]
60
+ #
61
+ # @example
62
+ # require "gcloud"
63
+ #
64
+ # gcloud = Gcloud.new
65
+ # storage = gcloud.storage
66
+ #
67
+ # buckets = storage.buckets
68
+ # if buckets.next?
69
+ # next_buckets = buckets.next
70
+ # end
71
+ #
72
+ def next
73
+ return nil unless next?
74
+ ensure_connection!
75
+ options = { prefix: @prefix, token: @token, max: @max }
76
+ resp = @connection.list_buckets options
77
+ fail ApiError.from_response(resp) unless resp.success?
78
+ Bucket::List.from_response resp, @connection, @prefix, @max
79
+ end
80
+
81
+ ##
82
+ # Retrieves all buckets by repeatedly loading {#next} until {#next?}
83
+ # returns `false`. Calls the given block once for each bucket, which is
84
+ # passed as the parameter.
85
+ #
86
+ # An Enumerator is returned if no block is given.
87
+ #
88
+ # This method may make several API calls until all buckets are
89
+ # retrieved. Be sure to use as narrow a search criteria as possible.
90
+ # Please use with caution.
91
+ #
92
+ # @param [Integer] request_limit The upper limit of API requests to make
93
+ # to load all buckets. Default is no limit.
94
+ # @yield [bucket] The block for accessing each bucket.
95
+ # @yieldparam [Bucket] bucket The bucket object.
96
+ #
97
+ # @return [Enumerator]
98
+ #
99
+ # @example Iterating each bucket by passing a block:
100
+ # require "gcloud"
101
+ #
102
+ # gcloud = Gcloud.new
103
+ # storage = gcloud.storage
104
+ #
105
+ # buckets = storage.buckets
106
+ # buckets.all do |bucket|
107
+ # puts bucket.name
108
+ # end
109
+ #
110
+ # @example Using the enumerator by not passing a block:
111
+ # require "gcloud"
112
+ #
113
+ # gcloud = Gcloud.new
114
+ # storage = gcloud.storage
115
+ #
116
+ # buckets = storage.buckets
117
+ # all_names = buckets.all.map do |bucket|
118
+ # bucket.name
119
+ # end
120
+ #
121
+ # @example Limit the number of API calls made:
122
+ # require "gcloud"
123
+ #
124
+ # gcloud = Gcloud.new
125
+ # storage = gcloud.storage
126
+ #
127
+ # buckets = storage.buckets
128
+ # buckets.all(request_limit: 10) do |bucket|
129
+ # puts bucket.name
130
+ # end
131
+ #
132
+ def all request_limit: nil
133
+ request_limit = request_limit.to_i if request_limit
134
+ unless block_given?
135
+ return enum_for(:all, request_limit: request_limit)
136
+ end
137
+ results = self
138
+ loop do
139
+ results.each { |r| yield r }
140
+ if request_limit
141
+ request_limit -= 1
142
+ break if request_limit < 0
143
+ end
144
+ break unless results.next?
145
+ results = results.next
146
+ end
35
147
  end
36
148
 
37
149
  ##
38
150
  # @private New Bucket::List from a response object.
39
- def self.from_response resp, conn
40
- buckets = Array(resp.data["items"]).map do |gapi_object|
151
+ def self.from_response resp, conn, prefix = nil, max = nil
152
+ buckets = new(Array(resp.data["items"]).map do |gapi_object|
41
153
  Bucket.from_gapi gapi_object, conn
42
- end
43
- new buckets, resp.data["nextPageToken"]
154
+ end)
155
+ buckets.instance_variable_set "@token", resp.data["nextPageToken"]
156
+ buckets.instance_variable_set "@connection", conn
157
+ buckets.instance_variable_set "@prefix", prefix
158
+ buckets.instance_variable_set "@max", max
159
+ buckets
160
+ end
161
+
162
+ protected
163
+
164
+ ##
165
+ # Raise an error unless an active connection is available.
166
+ def ensure_connection!
167
+ fail "Must have active connection" unless @connection
44
168
  end
45
169
  end
46
170
  end