cassandra-driver 1.0.0.rc.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (42) hide show
  1. checksums.yaml +8 -8
  2. data/README.md +45 -10
  3. data/lib/cassandra.rb +82 -82
  4. data/lib/cassandra/cluster.rb +3 -0
  5. data/lib/cassandra/cluster/client.rb +17 -5
  6. data/lib/cassandra/{client/connection_manager.rb → cluster/connection_pool.rb} +3 -3
  7. data/lib/cassandra/cluster/connector.rb +101 -30
  8. data/lib/cassandra/cluster/control_connection.rb +6 -7
  9. data/lib/cassandra/{client/null_logger.rb → cluster/failed_connection.rb} +12 -14
  10. data/lib/cassandra/cluster/options.rb +8 -0
  11. data/lib/cassandra/column.rb +5 -0
  12. data/lib/cassandra/driver.rb +3 -3
  13. data/lib/cassandra/errors.rb +5 -5
  14. data/lib/cassandra/execution/options.rb +13 -6
  15. data/lib/cassandra/execution/trace.rb +4 -4
  16. data/lib/cassandra/future.rb +4 -0
  17. data/lib/cassandra/keyspace.rb +5 -0
  18. data/lib/cassandra/load_balancing/policies/dc_aware_round_robin.rb +7 -2
  19. data/lib/cassandra/load_balancing/policies/token_aware.rb +1 -3
  20. data/lib/cassandra/load_balancing/policies/white_list.rb +3 -6
  21. data/lib/cassandra/null_logger.rb +35 -0
  22. data/lib/cassandra/protocol/cql_protocol_handler.rb +4 -0
  23. data/lib/cassandra/protocol/requests/query_request.rb +1 -11
  24. data/lib/cassandra/result.rb +4 -6
  25. data/lib/cassandra/session.rb +3 -0
  26. data/lib/cassandra/statements/prepared.rb +5 -1
  27. data/lib/cassandra/table.rb +5 -0
  28. data/lib/cassandra/util.rb +130 -0
  29. data/lib/cassandra/version.rb +1 -1
  30. metadata +9 -20
  31. data/lib/cassandra/client.rb +0 -144
  32. data/lib/cassandra/client/batch.rb +0 -212
  33. data/lib/cassandra/client/client.rb +0 -591
  34. data/lib/cassandra/client/column_metadata.rb +0 -54
  35. data/lib/cassandra/client/connector.rb +0 -273
  36. data/lib/cassandra/client/execute_options_decoder.rb +0 -59
  37. data/lib/cassandra/client/peer_discovery.rb +0 -50
  38. data/lib/cassandra/client/prepared_statement.rb +0 -314
  39. data/lib/cassandra/client/query_result.rb +0 -230
  40. data/lib/cassandra/client/request_runner.rb +0 -70
  41. data/lib/cassandra/client/result_metadata.rb +0 -48
  42. data/lib/cassandra/client/void_result.rb +0 -78
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- NTA3NTE1Y2M2Y2U5MmJmNGVlODZlZmI4YjI1NWE3OGNhOTY4OTgzOA==
4
+ OTcyZDFmZGEzMGZhODU2MTRkYmRlMjhiNWIyYWI0OWVkODZmYmY3Mg==
5
5
  data.tar.gz: !binary |-
6
- ZDg0NTUxZTFmNDBjYmVjZDFlYjE1MzUwODc3MGFkODkwNTBjZmZjOQ==
6
+ MzQ5Y2M4YmI1YzQ3Yjk3MDU4YzI1YWJjYmZjYTc2YTE4NjA4ZTRmMQ==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- OGI2NTA0NDQ2ZTk2ODlmNDFkNTkyMTYxZDBmY2I3OTNhNjQ3Y2ExNGQzZDlh
10
- YzkzZDA0MGIwM2MzODRkMmJjYjI1OTRjNzYzYzg1MTNiNzFjMmJmOGUyZWEz
11
- MjczMzZmNzg1OTZjN2NjY2JhMjc3YjYxMTJhOTc2MTVjOTI1MTQ=
9
+ NmFiNzc1M2E0NTk0YmIyY2VjNTcxZjI2ZDcwMGE5NmUzZDhhZGU5NmYyMTRj
10
+ M2NiZjgwNzdmMzJjOTA4YzBjNjVlYjRlNmJmZjE3MjZhOWY1ODRlOTQwM2Qy
11
+ YzYyNzc2MTFmYzNjOWNiZmI4NjY3Yjg4ZjBjYjJkMWRmMTY2Mzg=
12
12
  data.tar.gz: !binary |-
13
- MTc1ZDhiYmMyZDYzMDhjZDQzZmUxM2MzMzQ0NDNjNWFhOTIxZGY4ZjNiZDRm
14
- Y2I2YmYzYmNkZmY0NGIyNzNkOGU3YWM4MTg3MDhjYTZhOTYyNWY2YWQ4ODI2
15
- YmU3OTQ4ZjQ4NGU4NWY0MTkzOTQ4MWFiM2U0YzRiYTI4MzVjZmE=
13
+ M2EzNzFhZDM5MTNkMTlhNzVhZTE1YzdmZGMyMWEyY2ZmZTc4N2YwMGIwMjll
14
+ ODhkNzFjODE3NmMxYTE5Y2U4MzA0ZjViMTQ3MzYyMjcwZDJkNjgyZjg1Y2Q2
15
+ NWY3MjRjM2QwY2VhMTU4MGIzOWM0YmY2MjI4ZmYyOTdhMDU0NDE=
data/README.md CHANGED
@@ -9,10 +9,10 @@ the Cassandra Query Language version 3 (CQL3) and Cassandra's native protocol.
9
9
 
10
10
  - Code: https://github.com/datastax/ruby-driver
11
11
  - Docs: http://datastax.github.io/ruby-driver/
12
- - JIRA: https://datastax-oss.atlassian.net/browse/RUBY
13
- - MAILING LIST: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
12
+ - Jira: https://datastax-oss.atlassian.net/browse/RUBY
13
+ - Mailing List: https://groups.google.com/a/lists.datastax.com/forum/#!forum/ruby-driver-user
14
14
  - IRC: #datastax-drivers on [irc.freenode.net](http://freenode.net>)
15
- - TWITTER: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
15
+ - Twitter: Follow the latest news about DataStax Drivers - [@avalanche123](http://twitter.com/avalanche123), [@mfiguiere](http://twitter.com/mfiguiere), [@al3xandru](https://twitter.com/al3xandru)
16
16
 
17
17
  This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [Theo Hultberg](https://github.com/iconara) and we added support for:
18
18
 
@@ -26,10 +26,11 @@ This driver is based on [the cql-rb gem](https://github.com/iconara/cql-rb) by [
26
26
 
27
27
  This driver works exclusively with the Cassandra Query Language v3 (CQL3) and Cassandra's native protocol. The current version works with:
28
28
 
29
- * Cassandra versions 1.2 and 2.0
30
- * Ruby 1.9.3 and 2.0
29
+ * Apache Cassandra versions 1.2 and 2.0
30
+ * DataStax Enterprise 3.1, 3.2, 4.0 and 4.5
31
+ * Ruby (MRI) 1.9.3, 2.0 and 2.1
31
32
  * JRuby 1.7
32
- * Rubinius 2.1
33
+ * Rubinius 2.2
33
34
 
34
35
  __Note__: JRuby 1.6 is not officially supported, although 1.6.8 should work.
35
36
 
@@ -75,7 +76,7 @@ gem install cassandra-driver --pre
75
76
  Install via Gemfile
76
77
 
77
78
  ```ruby
78
- gem 'cassandra-driver', '~> 1.0.0.beta'
79
+ gem 'cassandra-driver', '~> 1.0.0.rc'
79
80
  ```
80
81
 
81
82
  Note: if you want to use compression you should also install [snappy](http://rubygems.org/gems/snappy) or [lz4-ruby](http://rubygems.org/gems/lz4-ruby). [Read more about compression.](http://datastax.github.io/ruby-driver/features/#compression)
@@ -85,13 +86,45 @@ Note: if you want to use compression you should also install [snappy](http://rub
85
86
 
86
87
  Some of the new features added to the driver have unfortunately led to changes in the original cql-rb API. In the examples directory, you can find [an example of how to wrap the ruby driver to achieve almost complete interface parity with cql-rb](https://github.com/datastax/ruby-driver/blob/master/examples/cql-rb-wrapper.rb) to assist you with gradual upgrade.
87
88
 
88
- ## What's new in v1.0.0.beta.3
89
+ ## What's new in v1.0.0
89
90
 
90
91
  Current release introduces the following new features:
91
92
 
92
- * [Token-aware load balancing policy](http://datastax.github.io/ruby-driver/features/load_balancing/token_aware/)
93
+ * [Asynchronous execution](http://datastax.github.io/ruby-driver/features/asynchronous_io/)
94
+ * One-off, [prepared](http://datastax.github.io/ruby-driver/features/basics/prepared_statements/) and [batch statements](http://datastax.github.io/ruby-driver/features/basics/batch_statements/)
95
+ * Automatic peer discovery and cluster metadata with [support for change notifications](http://datastax.github.io/ruby-driver/features/state_listeners/)
96
+ * Various [load-balancing](http://datastax.github.io/ruby-driver/features/load_balancing/), [retry](http://datastax.github.io/ruby-driver/features/retry_policies/) and reconnection policies, [with ability to write your own](http://datastax.github.io/ruby-driver/features/load_balancing/implementing_a_policy/)
93
97
  * [SSL encryption](http://datastax.github.io/ruby-driver/features/security/ssl_encryption/)
94
- * Domain names
98
+ * [Flexible and robust error handling](http://datastax.github.io/ruby-driver/features/error_handling/)
99
+ * [Per-request execution information and tracing](http://datastax.github.io/ruby-driver/features/debugging/)
100
+ * [Configurable address resolution](http://datastax.github.io/ruby-driver/features/address_resolution/)
101
+
102
+ ## Code examples
103
+
104
+ The DataStax Ruby Driver uses the awesome [Cucumber Framework](http://cukes.info/) for both end-to-end, or acceptance, testing and constructing documentation. All of the features supported by the driver have appropriate acceptance tests with easy-to-copy code examples in the `features/` directory.
105
+
106
+ ## Running tests
107
+
108
+ If you don't feel like reading through the following instructions on how to run ruby-driver tests, feel free to [check out .travis.yml for the entire build code](https://github.com/datastax/ruby-driver/blob/master/.travis.yml).
109
+
110
+ * Check out the driver codebase and install test dependencies:
111
+
112
+ ```bash
113
+ git clone https://github.com/datastax/ruby-driver.git
114
+ cd ruby-driver
115
+ bundle install --without docs
116
+ ```
117
+
118
+ * [Install ccm](http://www.datastax.com/dev/blog/ccm-a-development-tool-for-creating-local-cassandra-clusters)
119
+
120
+ * Run tests:
121
+
122
+ ```bash
123
+ bundle exec cucumber # runs end-to-end tests (or bundle exec rake cucumber)
124
+ bundle exec rspec # runs unit tests (or bundle exec rake rspec)
125
+ bundle exec rake integration # run integration tests
126
+ bundle exec rake test # run both as well as integration tests
127
+ ```
95
128
 
96
129
  ## Changelog & versioning
97
130
 
@@ -105,7 +138,9 @@ Prereleases will be stable, in the sense that they will have finished and proper
105
138
 
106
139
  * JRuby 1.6 is not officially supported, although 1.6.8 should work, if you're stuck in JRuby 1.6.8 try and see if it works for you.
107
140
  * Because the driver reactor is using `IO.select`, the maximum number of tcp connections allowed is 1024.
141
+ * Because the driver uses `IO#write_nonblock`, Windows is not supported.
108
142
 
143
+ Please [refer to the usage documentation for more information on common pitfalls](http://datastax.github.io/ruby-driver/features/)
109
144
 
110
145
  ## Credits
111
146
 
@@ -66,21 +66,22 @@ module Cassandra
66
66
  # in `:hosts` option.
67
67
  #
68
68
  # @option options [Numeric] :connect_timeout (10) connection timeout in
69
- # seconds.
69
+ # seconds. Setting value to `nil` will reset it to 5 seconds.
70
70
  #
71
71
  # @option options [Numeric] :timeout (10) request execution timeout in
72
- # seconds.
72
+ # seconds. Setting value to `nil` will remove request timeout.
73
73
  #
74
74
  # @option options [Numeric] :heartbeat_interval (30) how often should a
75
75
  # heartbeat be sent to determine if a connection is alive. Several things to
76
76
  # note about this option. Only one heartbeat request will ever be
77
77
  # outstanding on a given connection. Each heatbeat will be sent in at least
78
78
  # `:heartbeat_interval` seconds after the last request has been sent on a
79
- # given connection.
79
+ # given connection. Setting value to `nil` will remove connection timeout.
80
80
  #
81
81
  # @option options [Numeric] :idle_timeout (60) period of inactivity after
82
82
  # which a connection is considered dead. Note that this value should be at
83
- # least a few times larger than `:heartbeat_interval`.
83
+ # least a few times larger than `:heartbeat_interval`. Setting value to
84
+ # `nil` will remove automatic connection termination.
84
85
  #
85
86
  # @option options [String] :username (none) username to use for
86
87
  # authentication to cassandra. Note that you must also specify `:password`.
@@ -139,15 +140,15 @@ module Cassandra
139
140
  # @option options [Boolean] :trace (false) whether or not to trace all
140
141
  # requests by default.
141
142
  #
142
- # @option options [Integer] :page_size (nil) default page size for all select
143
- # queries.
143
+ # @option options [Integer] :page_size (10000) default page size for all
144
+ # select queries. Set this value to `nil` to disable paging.
144
145
  #
145
146
  # @option options [Hash{String => String}] :credentials (none) a hash of credentials - to be used with [credentials authentication in cassandra 1.2](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v1.spec#L238-L250). Note that if you specified `:username` and `:password` options, those credentials are configured automatically.
146
147
  #
147
148
  # @option options [Cassandra::Auth::Provider] :auth_provider (none) a custom auth provider to be used with [SASL authentication in cassandra 2.0](https://github.com/apache/cassandra/blob/trunk/doc/native_protocol_v2.spec#L257-L273). Note that if you have specified `:username` and `:password`, then a {Cassandra::Auth::Providers::Password} will be used automatically.
148
149
  #
149
- # @option options [Cassandra::Compressor] :compressor (none) a custom
150
- # compressor. Note that if you have specified `:compression`, an
150
+ # @option options [Cassandra::Compression::Compressor] :compressor (none) a
151
+ # custom compressor. Note that if you have specified `:compression`, an
151
152
  # appropriate compressor will be provided automatically.
152
153
  #
153
154
  # @option options [Cassandra::AddressResolution::Policy]
@@ -157,10 +158,10 @@ module Cassandra
157
158
  # appropriate address resolution policy will be provided automatically.
158
159
  #
159
160
  # @option options [Object<#all, #error, #value, #promise>] :futures_factory
160
- # (none) a custom futures factory to assist with integration into existing
161
- # futures library. Note that promises returned by this object must conform
162
- # to {Cassandra::Promise} api, which is not yet public. Things may change,
163
- # use at your own risk.
161
+ # default: {Cassandra::Future} a futures factory to assist with integration
162
+ # into existing futures library. Note that promises returned by this object
163
+ # must conform to {Cassandra::Promise} api, which is not yet public. Things
164
+ # may change, use at your own risk.
164
165
  #
165
166
  # @example Connecting to localhost
166
167
  # cluster = Cassandra.cluster
@@ -174,6 +175,16 @@ module Cassandra
174
175
  #
175
176
  # @return [Cassandra::Cluster] a cluster instance
176
177
  def self.cluster(options = {})
178
+ cluster_async(options).get
179
+ end
180
+
181
+ # Creates a {Cassandra::Cluster} instance
182
+ #
183
+ # @see Cassandra.cluster
184
+ #
185
+ # @return [Cassandra::Future<Cassandra::Cluster>] a future resolving to the
186
+ # cluster instance.
187
+ def self.cluster_async(options = {})
177
188
  options = options.select do |key, value|
178
189
  [ :credentials, :auth_provider, :compression, :hosts, :logger, :port,
179
190
  :load_balancing_policy, :reconnection_policy, :retry_policy, :listeners,
@@ -184,6 +195,8 @@ module Cassandra
184
195
  ].include?(key)
185
196
  end
186
197
 
198
+ futures = options.fetch(:futures_factory, Future)
199
+
187
200
  has_username = options.has_key?(:username)
188
201
  has_password = options.has_key?(:password)
189
202
  if has_username || has_password
@@ -195,11 +208,13 @@ module Cassandra
195
208
  raise ::ArgumentError, "both :username and :password options must be specified, but only :password given"
196
209
  end
197
210
 
198
- username = String(options.delete(:username))
199
- password = String(options.delete(:password))
211
+ username = options.delete(:username)
212
+ password = options.delete(:password)
200
213
 
201
- raise ::ArgumentError, ":username cannot be empty" if username.empty?
202
- raise ::ArgumentError, ":password cannot be empty" if password.empty?
214
+ Util.assert_instance_of(::String, username) { ":username must be a String, #{username.inspect} given" }
215
+ Util.assert_instance_of(::String, password) { ":password must be a String, #{password.inspect} given" }
216
+ Util.assert_not_empty(username) { ":username cannot be empty" }
217
+ Util.assert_not_empty(password) { ":password cannot be empty" }
203
218
 
204
219
  options[:credentials] = {:username => username, :password => password}
205
220
  options[:auth_provider] = Auth::Providers::Password.new(username, password)
@@ -208,17 +223,13 @@ module Cassandra
208
223
  if options.has_key?(:credentials)
209
224
  credentials = options[:credentials]
210
225
 
211
- unless credentials.is_a?(Hash)
212
- raise ::ArgumentError, ":credentials must be a hash, #{credentials.inspect} given"
213
- end
226
+ Util.assert_instance_of(::Hash, credentials) { ":credentials must be a hash, #{credentials.inspect} given" }
214
227
  end
215
228
 
216
229
  if options.has_key?(:auth_provider)
217
230
  auth_provider = options[:auth_provider]
218
231
 
219
- unless auth_provider.respond_to?(:create_authenticator)
220
- raise ::ArgumentError, ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't"
221
- end
232
+ Util.assert_responds_to(:create_authenticator, auth_provider) { ":auth_provider #{auth_provider.inspect} must respond to :create_authenticator, but doesn't" }
222
233
  end
223
234
 
224
235
  has_client_cert = options.has_key?(:client_cert)
@@ -236,13 +247,8 @@ module Cassandra
236
247
  client_cert = ::File.expand_path(options[:client_cert])
237
248
  private_key = ::File.expand_path(options[:private_key])
238
249
 
239
- unless ::File.exists?(client_cert)
240
- raise ::ArgumentError, ":client_cert #{client_cert.inspect} doesn't exist"
241
- end
242
-
243
- unless ::File.exists?(private_key)
244
- raise ::ArgumentError, ":private_key #{private_key.inspect} doesn't exist"
245
- end
250
+ Util.assert_file_exists(client_cert) { ":client_cert #{client_cert.inspect} doesn't exist" }
251
+ Util.assert_file_exists(private_key) { ":private_key #{private_key.inspect} doesn't exist" }
246
252
  end
247
253
 
248
254
  has_server_cert = options.has_key?(:server_cert)
@@ -250,9 +256,7 @@ module Cassandra
250
256
  if has_server_cert
251
257
  server_cert = ::File.expand_path(options[:server_cert])
252
258
 
253
- unless ::File.exists?(server_cert)
254
- raise ::ArgumentError, ":server_cert #{server_cert.inspect} doesn't exist"
255
- end
259
+ Util.assert_file_exists(server_cert) { ":server_cert #{server_cert.inspect} doesn't exist" }
256
260
  end
257
261
 
258
262
  if has_client_cert || has_server_cert
@@ -279,9 +283,7 @@ module Cassandra
279
283
  if options.has_key?(:ssl)
280
284
  ssl = options[:ssl]
281
285
 
282
- unless ssl.is_a?(::TrueClass) || ssl.is_a?(::FalseClass) || ssl.is_a?(::OpenSSL::SSL::SSLContext)
283
- raise ::ArgumentError, ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given"
284
- end
286
+ Util.assert_instance_of_one_of([::TrueClass, ::FalseClass, ::OpenSSL::SSL::SSLContext], ssl) { ":ssl must be a boolean or an OpenSSL::SSL::SSLContext, #{ssl.inspect} given" }
285
287
  end
286
288
 
287
289
  if options.has_key?(:compression)
@@ -303,26 +305,20 @@ module Cassandra
303
305
  compressor = options[:compressor]
304
306
  methods = [:algorithm, :compress?, :compress, :decompress]
305
307
 
306
- unless methods.all? {|method| compressor.respond_to?(method)}
307
- raise ::ArgumentError, ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't"
308
- end
308
+ Util.assert_responds_to_all(methods, compressor) { ":compressor #{compressor.inspect} must respond to #{methods.inspect}, but doesn't" }
309
309
  end
310
310
 
311
311
  if options.has_key?(:logger)
312
312
  logger = options[:logger]
313
313
  methods = [:debug, :info, :warn, :error, :fatal]
314
314
 
315
- unless methods.all? {|method| logger.respond_to?(method)}
316
- raise ::ArgumentError, ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't"
317
- end
315
+ Util.assert_responds_to_all(methods, logger) { ":logger #{logger.inspect} must respond to #{methods.inspect}, but doesn't" }
318
316
  end
319
317
 
320
318
  if options.has_key?(:port)
321
319
  port = options[:port] = Integer(options[:port])
322
320
 
323
- if port < 0 || port > 65536
324
- raise ::ArgumentError, ":port must be a valid ip port, #{port.given}"
325
- end
321
+ Util.assert_one_of(0..65536, port) { ":port must be a valid ip port, #{port} given" }
326
322
  end
327
323
 
328
324
  if options.has_key?(:datacenter)
@@ -330,34 +326,38 @@ module Cassandra
330
326
  end
331
327
 
332
328
  if options.has_key?(:connect_timeout)
333
- timeout = options[:connect_timeout] = Integer(options[:connect_timeout])
329
+ timeout = options[:connect_timeout]
334
330
 
335
- if timeout < 0
336
- raise ::ArgumentError, ":connect_timeout must be a positive value, #{timeout.given}"
331
+ unless timeout.nil?
332
+ Util.assert_instance_of(::Numeric, timeout) { ":connect_timeout must be a number of seconds, #{timeout} given" }
333
+ Util.assert(timeout > 0) { ":connect_timeout must be greater than 0, #{timeout} given" }
337
334
  end
338
335
  end
339
336
 
340
337
  if options.has_key?(:timeout)
341
- timeout = options[:timeout] = Integer(options[:timeout])
338
+ timeout = options[:timeout]
342
339
 
343
- if timeout < 0
344
- raise ::ArgumentError, ":timeout must be a positive value, #{timeout.given}"
340
+ unless timeout.nil?
341
+ Util.assert_instance_of(::Numeric, timeout) { ":timeout must be a number of seconds, #{timeout} given" }
342
+ Util.assert(timeout > 0) { ":timeout must be greater than 0, #{timeout} given" }
345
343
  end
346
344
  end
347
345
 
348
346
  if options.has_key?(:heartbeat_interval)
349
- timeout = options[:heartbeat_interval] = Integer(options[:heartbeat_interval])
347
+ timeout = options[:heartbeat_interval]
350
348
 
351
- if timeout < 0
352
- raise ::ArgumentError, ":heartbeat_interval must be a positive value, #{timeout.given}"
349
+ unless timeout.nil?
350
+ Util.assert_instance_of(::Numeric, timeout) { ":heartbeat_interval must be a number of seconds, #{timeout} given" }
351
+ Util.assert(timeout > 0) { ":heartbeat_interval must be greater than 0, #{timeout} given" }
353
352
  end
354
353
  end
355
354
 
356
355
  if options.has_key?(:idle_timeout)
357
- timeout = options[:idle_timeout] = Integer(options[:idle_timeout])
356
+ timeout = options[:idle_timeout]
358
357
 
359
- if timeout < 0
360
- raise ::ArgumentError, ":idle_timeout must be a positive value, #{timeout.given}"
358
+ unless timeout.nil?
359
+ Util.assert_instance_of(::Numeric, timeout) { ":idle_timeout must be a number of seconds, #{timeout} given" }
360
+ Util.assert(timeout > 0) { ":idle_timeout must be greater than 0, #{timeout} given" }
361
361
  end
362
362
  end
363
363
 
@@ -365,42 +365,32 @@ module Cassandra
365
365
  load_balancing_policy = options[:load_balancing_policy]
366
366
  methods = [:host_up, :host_down, :host_found, :host_lost, :setup, :distance, :plan]
367
367
 
368
- unless methods.all? {|method| load_balancing_policy.respond_to?(method)}
369
- raise ::ArgumentError, ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't"
370
- end
368
+ Util.assert_responds_to_all(methods, load_balancing_policy) { ":load_balancing_policy #{load_balancing_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
371
369
  end
372
370
 
373
371
  if options.has_key?(:reconnection_policy)
374
372
  reconnection_policy = options[:reconnection_policy]
375
373
 
376
- unless reconnection_policy.respond_to?(:schedule)
377
- raise ::ArgumentError, ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't"
378
- end
374
+ Util.assert_responds_to(:schedule, reconnection_policy) { ":reconnection_policy #{reconnection_policy.inspect} must respond to :schedule, but doesn't" }
379
375
  end
380
376
 
381
377
  if options.has_key?(:retry_policy)
382
378
  retry_policy = options[:retry_policy]
383
379
  methods = [:read_timeout, :write_timeout, :unavailable]
384
380
 
385
- unless methods.all? {|method| retry_policy.respond_to?(method)}
386
- raise ::ArgumentError, ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't"
387
- end
381
+ Util.assert_responds_to_all(methods, retry_policy) { ":retry_policy #{retry_policy.inspect} must respond to #{methods.inspect}, but doesn't" }
388
382
  end
389
383
 
390
384
  if options.has_key?(:listeners)
391
385
  listeners = options[:listeners]
392
386
 
393
- unless listeners.respond_to?(:each)
394
- raise ::ArgumentError, ":listeners must be an Enumerable, #{listeners.inspect} given"
395
- end
387
+ Util.assert_instance_of(::Enumerable, listeners) { ":listeners must be an Enumerable, #{listeners.inspect} given" }
396
388
  end
397
389
 
398
390
  if options.has_key?(:consistency)
399
391
  consistency = options[:consistency]
400
392
 
401
- unless CONSISTENCIES.include?(consistency)
402
- raise ::ArgumentError, ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given"
403
- end
393
+ Util.assert_one_of(CONSISTENCIES, consistency) { ":consistency must be one of #{CONSISTENCIES.inspect}, #{consistency.inspect} given" }
404
394
  end
405
395
 
406
396
  if options.has_key?(:trace)
@@ -408,10 +398,11 @@ module Cassandra
408
398
  end
409
399
 
410
400
  if options.has_key?(:page_size)
411
- page_size = options[:page_size] = Integer(options[:page_size])
401
+ page_size = options[:page_size]
412
402
 
413
- if page_size <= 0
414
- raise ::ArgumentError, ":page_size must be a positive integer, #{page_size.inspect} given"
403
+ unless page_size.nil?
404
+ page_size = options[:page_size] = Integer(page_size)
405
+ Util.assert(page_size > 0) { ":page_size must be a positive integer, #{page_size.inspect} given" }
415
406
  end
416
407
  end
417
408
 
@@ -419,9 +410,7 @@ module Cassandra
419
410
  futures_factory = options[:futures_factory]
420
411
  methods = [:error, :value, :promise, :all]
421
412
 
422
- unless methods.all? {|method| futures_factory.respond_to?(method)}
423
- raise ::ArgumentError, ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't"
424
- end
413
+ Util.assert_responds_to_all(methods, futures_factory) { ":futures_factory #{futures_factory.inspect} must respond to #{methods.inspect}, but doesn't" }
425
414
  end
426
415
 
427
416
  if options.has_key?(:address_resolution)
@@ -429,6 +418,7 @@ module Cassandra
429
418
 
430
419
  case address_resolution
431
420
  when :none
421
+ # do nothing
432
422
  when :ec2_multi_region
433
423
  options[:address_resolution_policy] = AddressResolution::Policies::EC2MultiRegion.new
434
424
  else
@@ -439,9 +429,7 @@ module Cassandra
439
429
  if options.has_key?(:address_resolution_policy)
440
430
  address_resolver = options[:address_resolution_policy]
441
431
 
442
- unless address_resolver.respond_to?(:resolve)
443
- raise ::ArgumentError, ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't"
444
- end
432
+ Util.assert_responds_to(:resolve, address_resolver) { ":address_resolution_policy must respond to :resolve, #{address_resolver.inspect} but doesn't" }
445
433
  end
446
434
 
447
435
  hosts = []
@@ -462,8 +450,20 @@ module Cassandra
462
450
  if hosts.empty?
463
451
  raise ::ArgumentError, ":hosts #{options[:hosts].inspect} could not be resolved to any ip address"
464
452
  end
453
+ rescue => e
454
+ futures.error(e)
455
+ else
456
+ promise = futures.promise
457
+
458
+ Driver.new(options).connect(hosts).on_complete do |f|
459
+ if f.resolved?
460
+ promise.fulfill(f.value)
461
+ else
462
+ f.on_failure {|e| promise.break(e)}
463
+ end
464
+ end
465
465
 
466
- Driver.new(options).connect(hosts).value
466
+ promise.future
467
467
  end
468
468
  end
469
469
 
@@ -473,7 +473,7 @@ require 'cassandra/time_uuid'
473
473
  require 'cassandra/compression'
474
474
  require 'cassandra/protocol'
475
475
  require 'cassandra/auth'
476
- require 'cassandra/client'
476
+ require 'cassandra/null_logger'
477
477
 
478
478
  require 'cassandra/future'
479
479
  require 'cassandra/cluster'