em-hyperdex-client 0.3.1 → 0.3.2

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -1,3 +1,5 @@
1
1
  Gemfile.lock
2
2
  /pkg
3
3
  /html
4
+ /.yardoc
5
+ /doc
@@ -0,0 +1 @@
1
+ --markup markdown
data/Rakefile CHANGED
@@ -17,13 +17,10 @@ task :release do
17
17
  sh "git release"
18
18
  end
19
19
 
20
- require 'rdoc/task'
20
+ require 'yard'
21
21
 
22
- RDoc::Task.new do |rd|
23
- rd.main = "README.md"
24
- rd.title = 'em-pg-client-helper'
25
- rd.markup = "markdown"
26
- rd.rdoc_files.include("README.md", "lib/**/*.rb")
22
+ YARD::Rake::YardocTask.new :doc do |yardoc|
23
+ yardoc.files = %w{lib/**/*.rb - README.md}
27
24
  end
28
25
 
29
26
  desc "Run guard"
@@ -17,7 +17,7 @@ Gem::Specification.new do |s|
17
17
 
18
18
  s.add_runtime_dependency "eventmachine", "~> 1.0"
19
19
  s.add_runtime_dependency "git-version-bump", "~> 0.10"
20
- s.add_runtime_dependency "hyperdex", '>= 1.4.4.3'
20
+ s.add_runtime_dependency "hyperdex", '>= 1.4.5.pre', '< 2'
21
21
 
22
22
  s.add_development_dependency 'bundler'
23
23
  s.add_development_dependency 'eventmachine'
@@ -30,4 +30,5 @@ Gem::Specification.new do |s|
30
30
  s.add_development_dependency 'rake'
31
31
  s.add_development_dependency 'rdoc'
32
32
  s.add_development_dependency 'rspec'
33
+ s.add_development_dependency 'yard', '~> 0.7'
33
34
  end
@@ -1,19 +1,51 @@
1
1
  require 'hyperdex'
2
2
  require 'eventmachine'
3
3
 
4
- module EM; end
5
- module EM::HyperDex; end
4
+ module EM; end #:nodoc:
5
+ module EM::HyperDex; end #:nodoc:
6
6
 
7
+ # An EventMachine-enabled client for [HyperDex](http://hyperdex.org/).
8
+ #
9
+ # This is a fairly straightforward async-friendly interface to the hyperdex
10
+ # NoSQL data store. All of the normal (synchronous) methods that you are
11
+ # used to using are available, except that they're automatically async.
12
+ # Schweeeeeet.
13
+ #
14
+ # Using it is quite simple (for an EM client, anyway...). You just create
15
+ # an instance of `EM::HyperDex::Client`, and then call (almost) any of the
16
+ # standard HyperDex methods you know and love against it, with the same
17
+ # arguments. The only difference is that you can pass a block to the
18
+ # method, indicating what you want to do once the request is complete, and
19
+ # the method returns a Deferrable which you can define callbacks and
20
+ # errbacks. The callback will be passed whatever the HyperDex data method
21
+ # would ordinarily return, in a synchronous world.
22
+ #
23
+ # Searching methods ({#search}, {#sorted_search}) work *slightly*
24
+ # differently. Instead of the entire resultset being passed back in a
25
+ # single callback, the callback is executed *after* the result set has been
26
+ # processed. Each item in the search result is accessed via
27
+ # {EnumerableDeferrable#each} on the deferrable that is returned from the
28
+ # {#search} method. See the docs for {#search} and {#sorted_search} for
29
+ # examples of what this looks like.
30
+ #
7
31
  class EM::HyperDex::Client
8
- def initialize(host, port)
32
+ # Create a new `EM::HyperDex::Client` for you to play with.
33
+ #
34
+ # This method does **not** take a callback block; the client is created
35
+ # synchronously. However, this isn't the problem you might otherwise
36
+ # expect it to be, because initializing a client doesn't make any network
37
+ # connections or otherwise potentially-blocking calls; rather, it simply
38
+ # initializes some data structures and then returns.
39
+ #
40
+ # @param host [String] A hostname or IP address (v4 or v6) of a coordinator
41
+ # within the cluster to make initial contact.
42
+ #
43
+ # @param port [Integer] The port of the coordinator you wish to contact.
44
+ #
45
+ def initialize(host = 'localhost', port = 1982)
9
46
  @client = HyperDex::Client::Client.new(host, port)
10
47
  @failed = false
11
48
  @outstanding = {}
12
-
13
- if ::EM.reactor_running?
14
- @em_conn = ::EM.watch(@client.poll_fd, Watcher, self)
15
- @em_conn.notify_readable = true
16
- end
17
49
  end
18
50
 
19
51
  ASYNC_METHODS = HyperDex::Client::Client.
@@ -21,22 +53,22 @@ class EM::HyperDex::Client
21
53
  map(&:to_s).
22
54
  grep(/^async_/).
23
55
  map { |m| m.gsub(/^async_/, '') }
56
+ private_constant :ASYNC_METHODS
24
57
 
25
58
  ASYNC_METHODS.each do |m|
26
59
  hyperdex_method = "async_#{m}"
27
60
 
28
61
  define_method(m) do |*args, &block|
29
- df = ::EM::DefaultDeferrable.new
30
-
31
62
  if @failed
32
- return df.tap do |df|
33
- df.fail(RuntimeError.new("This client has failed. Please open a new one."))
34
- end
63
+ return failed_deferrable("This client has failed. Please open a new one.")
35
64
  end
36
65
 
66
+ df = ::EM::Completion.new
67
+ df.callback(&block) if block
68
+
37
69
  begin
38
70
  if ::EM.reactor_running?
39
- @outstanding[@client.__send__(hyperdex_method, *args)] = df
71
+ add_outstanding(@client.__send__(hyperdex_method, *args), df)
40
72
  else
41
73
  df.succeed(@client.__send__(m, *args))
42
74
  end
@@ -49,34 +81,106 @@ class EM::HyperDex::Client
49
81
  end
50
82
 
51
83
  ITERATOR_METHODS = %w{search sorted_search}
84
+ private_constant :ITERATOR_METHODS
85
+
86
+ # @!macro search_params
87
+ # @param spacename [#to_s] The name of the hyperdex space to search
88
+ #
89
+ # @param predicates [Hash<#to_s, HyperDex::Client::Predicate>] A
90
+ # collection of predicates to apply to the search.
91
+ #
92
+ # @return [EnumerableDeferrable] a deferrable which responds to
93
+ # {EnumerableDeferrable#each each} to return the search results.
94
+ #
95
+ #
96
+ # @!method search(spacename, predicates)
97
+ #
98
+ # Perform a search for all objects in the specified space that match the
99
+ # predicates provided.
100
+ #
101
+ # @macro search_params
102
+ #
103
+ # @example iterating through search results
104
+ # c = EM::HyperDex::Client.new
105
+ # c.search(:test, :towels => HyperDex::Client::GreaterThan.new(42)).each do |r|
106
+ # puts "This is an object with a high towel count: #{r.inspect}"
107
+ # end.callback do
108
+ # puts "Towel search complete"
109
+ # end.errback do |ex|
110
+ # puts "Towel search failed: #{ex.class}: #{ex.message}"
111
+ # end
112
+ #
52
113
 
114
+ # @!method sorted_search(spacename, predicates, sortby, limit, maxmin)
115
+ #
116
+ # Perform a search for all objects in the specified space that match
117
+ # the predicates provided, sorting the results and optionally returning
118
+ # only a subset of the results.
119
+ #
120
+ # @macro search_params
121
+ #
122
+ # @param sortby [#to_s] the attribute to sort the results by
123
+ #
124
+ # @param limit [Integer] the maximum number of results to return
125
+ #
126
+ # @param maxmin [String] Maximize (`"max"`) or minimize (`"min"`)
127
+ # (I shit you not, that's what the upstream docs say)
128
+ #
129
+ # @todo Document the `maxmin` parameter *properly*.
130
+ #
131
+ # @see #search
132
+ #
53
133
  ITERATOR_METHODS.each do |m|
54
134
  define_method(m) do |*args, &block|
55
135
  if @failed
56
- return ::EM::DefaultDeferrable.new.tap do |df|
57
- df.fail(RuntimeError.new("This client has failed. Please open a new one."))
136
+ return failed_deferrable("This client has failed. Please open a new one.")
137
+ end
138
+
139
+ begin
140
+ iter = @client.__send__(m, *args)
141
+ rescue StandardError => ex
142
+ return EM::Completion.new.tap do |df|
143
+ df.fail(ex)
58
144
  end
59
145
  end
60
146
 
61
- iter = @client.__send__(m, *args)
62
- df = DeferrableEnumerable.new(iter)
63
- df.callback(&block) if block_given?
147
+ df = EnumerableDeferrable.new(iter)
148
+ df.callback(&block) if block
64
149
 
65
- begin
66
- @outstanding[iter] = df
67
- rescue HyperDex::Client::HyperDexClientException => ex
68
- ::EM::DefaultDeferrable.new.fail(ex)
150
+ if ::EM.reactor_running?
151
+ add_outstanding(iter, df)
152
+ else
153
+ begin
154
+ until (item = iter.next).nil?
155
+ df.item_available(item)
156
+ end
157
+ df.item_available(nil)
158
+ rescue Exception => ex
159
+ df.fail(ex)
160
+ end
69
161
  end
162
+
163
+ df
70
164
  end
71
165
  end
72
166
 
167
+ # Callback from the `EM.watch` system, to poke us when a response is
168
+ # ready to be processed.
169
+ #
170
+ # @api private
171
+ #
73
172
  def handle_response
74
173
  begin
75
- df = @outstanding.delete(op = @client.loop(0))
174
+ op = @client.loop(0)
76
175
  rescue HyperDex::Client::HyperDexClientException
77
176
  # Something has gone wrong, and we're just going to take our bat
78
177
  # and ball and go home.
79
178
  @outstanding.values.each { |op| op.fail(ex) }
179
+ @outstanding = {}
180
+
181
+ # Call a dummy get_outstanding so EM stops watching the socket
182
+ get_outstanding(nil)
183
+
80
184
  @failed = true
81
185
  return
82
186
  end
@@ -90,9 +194,14 @@ class EM::HyperDex::Client
90
194
  return
91
195
  end
92
196
 
197
+ df = get_outstanding(op)
198
+
93
199
  begin
94
200
  if df.respond_to?(:item_available)
95
201
  df.item_available
202
+ # Put the deferrable back in the outstanding ops hash if
203
+ # there's more items to go
204
+ add_outstanding(op, df) unless df.completed?
96
205
  else
97
206
  df.succeed(op.wait)
98
207
  end
@@ -101,47 +210,133 @@ class EM::HyperDex::Client
101
210
  end
102
211
  end
103
212
 
104
- def close
105
- @outstanding.each { |o| o.wait }
106
- @em_conn.detach
107
- @client = nil
213
+ # Associate an in-progress operation with the deferrable that will be
214
+ # completed when the operation completes. Also handles telling EM to
215
+ # start watching the client's `poll_fd` if necessary.
216
+ #
217
+ def add_outstanding(op, df)
218
+ # If we don't have any operations already in progress, then
219
+ # we aren't watching the poll_fd, so we probably want to start
220
+ # doing that now
221
+ if @outstanding.empty?
222
+ @em_conn = ::EM.watch(@client.poll_fd, Watcher, self)
223
+ @em_conn.notify_readable = true
224
+ end
225
+
226
+ @outstanding[op] = df
227
+ end
228
+
229
+ # Retrieve the deferrable associated with the specified operation, if
230
+ # one exists. Also handles telling EM to stop watching the `poll_fd`,
231
+ # if there are now no more outstanding operations.
232
+ def get_outstanding(op)
233
+ @outstanding.delete(op).tap do
234
+ if @outstanding.empty?
235
+ @em_conn.detach
236
+ @em_conn = nil
237
+ end
238
+ end
239
+ end
240
+
241
+ private
242
+ # Return a new deferrable that has failed with a `RuntimeError` with the
243
+ # given message.
244
+ #
245
+ def failed_deferrable(msg)
246
+ ::EM::Completion.new.tap do |df|
247
+ df.fail(RuntimeError.new(msg))
248
+ end
108
249
  end
109
250
 
251
+ # Mix-in module for EM.watch.
252
+ #
253
+ # @api private
254
+ #
110
255
  module Watcher
256
+ # Create the watcher.
257
+ #
258
+ # @api private
111
259
  def initialize(em_client)
112
260
  @em_client = em_client
113
261
  end
114
262
 
263
+ # Handle the fact that more data is available.
264
+ #
265
+ # @api private
115
266
  def notify_readable
116
267
  @em_client.handle_response
117
268
  end
118
269
  end
119
270
 
120
- class DeferrableEnumerable
121
- include Enumerable
122
- include ::EM::Deferrable
123
-
271
+ # A deferrable that can be enumerated.
272
+ #
273
+ # This is a really *freaky* kind of a deferrable. It accepts the usual
274
+ # `callback` and `errback` blocks, but it *also* has a special {#each}
275
+ # callback, which will cause the block provided for each item in the
276
+ # search result set. Once the result set has been enumerated, the
277
+ # `callback` will be called.
278
+ #
279
+ # @todo Define a set of other Enumerable methods that can be usefully
280
+ # used asynchronously (if there are any), like perhaps `#map`,
281
+ # `#inject`, etc.
282
+ #
283
+ class EnumerableDeferrable < EM::Completion
284
+ # Create a new EnumerableDeferrable
285
+ #
286
+ # @param iter [HyperDex::Client::Iterator] What to call `#next` on
287
+ # to get the next item.
288
+ #
289
+ # @api private
290
+ #
124
291
  def initialize(iter)
125
292
  @iter = iter
293
+ @items = []
294
+ super()
126
295
  end
127
296
 
297
+ # Define a block to call for each item in the result set.
298
+ #
299
+ # @yield the next available item in the result set
300
+ #
301
+ # @yieldparam item [Hash<Symbol, Object>] the hyperdex value object
302
+ #
128
303
  def each(&blk)
129
- return self unless block_given?
304
+ return Enumeration.new(self) unless block_given?
130
305
 
131
- @each_block = blk
306
+ if state == :succeeded
307
+ @items.each { |i| blk.call(i) }
308
+ else
309
+ @each_block = blk
310
+ end
311
+
312
+ self
132
313
  end
133
314
 
134
- def item_available
135
- val = @iter.next
315
+ # Trigger whenever we know there's an item available.
316
+ #
317
+ # @api private
318
+ #
319
+ def item_available(val = NoValue)
320
+ if val == NoValue
321
+ val = @iter.next
322
+ end
323
+
136
324
  if val.nil?
137
- succeed
325
+ self.succeed
138
326
  else
139
- begin
140
- @each_block.call(val)
141
- rescue Exception => ex
142
- fail(ex)
327
+ if @each_block
328
+ begin
329
+ @each_block.call(val)
330
+ rescue Exception => ex
331
+ fail(ex)
332
+ end
333
+ else
334
+ @items << val
143
335
  end
144
336
  end
145
337
  end
338
+
339
+ NoValue = Object.new
340
+ private_constant :NoValue
146
341
  end
147
342
  end
@@ -0,0 +1,88 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe "#get" do
4
+ let(:client) { EM::HyperDex::Client.new }
5
+
6
+ it "works when standalone" do
7
+ expect(mock_client).
8
+ to receive(:get).
9
+ with(:foo, 42).
10
+ and_return("towels")
11
+
12
+ client.get(:foo, 42).callback do |v|
13
+ expect(v).to eq("towels")
14
+ end
15
+ end
16
+
17
+ it "works inside EM" do
18
+ in_em do
19
+ expect_op(:get, [:foo, 42], "towels")
20
+
21
+ df = client.get(:foo, 42) do |v|
22
+ expect(v).to eq("towels")
23
+ EM.stop
24
+ end
25
+
26
+ expect(df).to be_a(::EM::Completion)
27
+ end
28
+ end
29
+
30
+ it "works multiple times" do
31
+ in_em do
32
+ expect_op(:get, [:foo, 42], "towels")
33
+ expect_op(:get, [:bar, "baz"], "wombat")
34
+
35
+ client.get(:foo, 42) do |v|
36
+ expect(v).to eq("towels")
37
+ client.get(:bar, "baz") do |v|
38
+ expect(v).to eq("wombat")
39
+ EM.stop
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ it "works in parallel" do
46
+ in_em do
47
+ expect_op(:get, [:foo, 42], "towels")
48
+ expect_op(:get, [:bar, "baz"], "wombat", 0.1)
49
+ op_count = 2
50
+
51
+ client.get(:foo, 42) do |v|
52
+ expect(v).to eq("towels")
53
+ op_count -= 1
54
+ end
55
+
56
+ client.get(:bar, "baz") do |v|
57
+ expect(v).to eq("wombat")
58
+ op_count -= 1
59
+ end
60
+
61
+ EM.add_periodic_timer(0.0001) do
62
+ EM.stop if op_count == 0
63
+ end
64
+ end
65
+ end
66
+
67
+ it "works with out-of-order responses" do
68
+ in_em do
69
+ expect_op(:get, [:foo, 42], "towels", 0.1)
70
+ expect_op(:get, [:bar, "baz"], "wombat")
71
+ op_count = 2
72
+
73
+ client.get(:foo, 42) do |v|
74
+ expect(v).to eq("towels")
75
+ op_count -= 1
76
+ end
77
+
78
+ client.get(:bar, "baz") do |v|
79
+ expect(v).to eq("wombat")
80
+ op_count -= 1
81
+ end
82
+
83
+ EM.add_periodic_timer(0.0001) do
84
+ EM.stop if op_count == 0
85
+ end
86
+ end
87
+ end
88
+ end
@@ -0,0 +1,48 @@
1
+ require_relative './spec_helper'
2
+
3
+ describe "#search" do
4
+ let(:client) { EM::HyperDex::Client.new }
5
+
6
+ it "works when standalone" do
7
+ expect(mock_client).
8
+ to receive(:search).
9
+ with(:foo, 42).
10
+ and_return(mock_iter = double(HyperDex::Client::Iterator))
11
+
12
+ resultset = %w{alpha beta gamma delta}
13
+
14
+ expect(mock_iter).
15
+ to receive(:next).
16
+ with(no_args).
17
+ and_return(*(resultset + [nil]))
18
+
19
+ client.search(:foo, 42).each do |v|
20
+ expect(v).to eq(resultset.shift)
21
+ end.errback do
22
+ # Derpy way of saying "this should not happen"
23
+ expect(false).to be(true)
24
+ end
25
+
26
+ expect(resultset).to be_empty
27
+ end
28
+
29
+ it "works inside EM" do
30
+ resultset = %w{alpha beta gamma delta}
31
+ in_em do
32
+ expect_iter(:search, [:foo, 42], resultset)
33
+
34
+ df = client.search(:foo, 42).each do |v|
35
+ expect(v).to eq(resultset.shift)
36
+ end.callback do
37
+ EM.stop
38
+ end.errback do
39
+ # This should not happen
40
+ expect(false).to be(true)
41
+ end
42
+
43
+ expect(df).to be_a(EM::HyperDex::Client::EnumerableDeferrable)
44
+ end
45
+
46
+ expect(resultset).to be_empty
47
+ end
48
+ end
@@ -0,0 +1,98 @@
1
+ require 'spork'
2
+
3
+ Spork.prefork do
4
+ require 'bundler'
5
+ Bundler.setup(:default, :test)
6
+ require 'rspec/core'
7
+ require 'rspec/mocks'
8
+
9
+ require 'pry'
10
+
11
+ module EventMachineTestHelper
12
+ def in_em(timeout = 1)
13
+ Timeout::timeout(timeout) do
14
+ ::EM.run do
15
+ yield
16
+ end
17
+ end
18
+ rescue Timeout::Error
19
+ EM.stop
20
+ raise RuntimeError,
21
+ "EM didn't finish before the timeout"
22
+ end
23
+
24
+ def expect_op(op, args, rv, response_delay = 0.0001)
25
+ expect(mock_client).
26
+ to receive("async_#{op}".to_sym).
27
+ with(*args).
28
+ and_return(mock_op = double(HyperDex::Client::Deferred))
29
+
30
+ expect(mock_op).
31
+ to receive(:wait).
32
+ with(no_args).
33
+ and_return(rv)
34
+
35
+ ::EM.add_timer(response_delay) do
36
+ expect(mock_client).
37
+ to receive(:loop).
38
+ with(0).
39
+ and_return(mock_op)
40
+
41
+ client.__send__(:handle_response)
42
+ end
43
+ end
44
+
45
+ def expect_iter(op, args, results, response_delay = 0.0001)
46
+ expect(mock_client).
47
+ to receive(op).
48
+ with(*args).
49
+ and_return(mock_iter = double(HyperDex::Client::Iterator))
50
+
51
+ expect(mock_iter).
52
+ to receive(:next).
53
+ with(no_args).
54
+ and_return(*(results + [nil]))
55
+
56
+ (results.length + 1).times do |i|
57
+ ::EM.add_timer(response_delay * (i+1)) do
58
+ expect(mock_client).
59
+ to receive(:loop).
60
+ with(0).
61
+ and_return(mock_iter)
62
+
63
+ client.__send__(:handle_response)
64
+ end
65
+ end
66
+ end
67
+
68
+ def mock_client(host = 'localhost', port = 1982)
69
+ @mock_client ||= begin
70
+ expect(HyperDex::Client::Client).
71
+ to receive(:new).
72
+ with(host, port).
73
+ and_return(mock = double(HyperDex::Client::Client))
74
+
75
+ allow(mock).
76
+ to receive(:poll_fd).
77
+ with(no_args).
78
+ and_return(0)
79
+ mock
80
+ end
81
+ end
82
+ end
83
+
84
+ RSpec.configure do |config|
85
+ config.fail_fast = true
86
+ # config.full_backtrace = true
87
+
88
+ config.include EventMachineTestHelper
89
+
90
+ config.expect_with :rspec do |c|
91
+ c.syntax = :expect
92
+ end
93
+ end
94
+ end
95
+
96
+ Spork.each_run do
97
+ require 'em-hyperdex-client'
98
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: em-hyperdex-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.1
4
+ version: 0.3.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-11-21 00:00:00.000000000 Z
12
+ date: 2014-11-25 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
@@ -50,7 +50,10 @@ dependencies:
50
50
  requirements:
51
51
  - - ! '>='
52
52
  - !ruby/object:Gem::Version
53
- version: 1.4.4.3
53
+ version: 1.4.5.pre
54
+ - - <
55
+ - !ruby/object:Gem::Version
56
+ version: '2'
54
57
  type: :runtime
55
58
  prerelease: false
56
59
  version_requirements: !ruby/object:Gem::Requirement
@@ -58,7 +61,10 @@ dependencies:
58
61
  requirements:
59
62
  - - ! '>='
60
63
  - !ruby/object:Gem::Version
61
- version: 1.4.4.3
64
+ version: 1.4.5.pre
65
+ - - <
66
+ - !ruby/object:Gem::Version
67
+ version: '2'
62
68
  - !ruby/object:Gem::Dependency
63
69
  name: bundler
64
70
  requirement: !ruby/object:Gem::Requirement
@@ -219,6 +225,22 @@ dependencies:
219
225
  - - ! '>='
220
226
  - !ruby/object:Gem::Version
221
227
  version: '0'
228
+ - !ruby/object:Gem::Dependency
229
+ name: yard
230
+ requirement: !ruby/object:Gem::Requirement
231
+ none: false
232
+ requirements:
233
+ - - ~>
234
+ - !ruby/object:Gem::Version
235
+ version: '0.7'
236
+ type: :development
237
+ prerelease: false
238
+ version_requirements: !ruby/object:Gem::Requirement
239
+ none: false
240
+ requirements:
241
+ - - ~>
242
+ - !ruby/object:Gem::Version
243
+ version: '0.7'
222
244
  description:
223
245
  email:
224
246
  executables: []
@@ -227,6 +249,7 @@ extra_rdoc_files:
227
249
  - README.md
228
250
  files:
229
251
  - .gitignore
252
+ - .yardopts
230
253
  - Gemfile
231
254
  - Guardfile
232
255
  - LICENCE
@@ -234,6 +257,9 @@ files:
234
257
  - Rakefile
235
258
  - em-hyperdex-client.gemspec
236
259
  - lib/em-hyperdex-client.rb
260
+ - spec/get_spec.rb
261
+ - spec/search_spec.rb
262
+ - spec/spec_helper.rb
237
263
  homepage: http://github.com/mpalmer/em-hyperdex-client
238
264
  licenses: []
239
265
  post_install_message:
@@ -248,7 +274,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
248
274
  version: '0'
249
275
  segments:
250
276
  - 0
251
- hash: -1903398093042256464
277
+ hash: -1612000962635766686
252
278
  required_rubygems_version: !ruby/object:Gem::Requirement
253
279
  none: false
254
280
  requirements:
@@ -257,7 +283,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
257
283
  version: '0'
258
284
  segments:
259
285
  - 0
260
- hash: -1903398093042256464
286
+ hash: -1612000962635766686
261
287
  requirements: []
262
288
  rubyforge_project:
263
289
  rubygems_version: 1.8.23
@@ -265,3 +291,4 @@ signing_key:
265
291
  specification_version: 3
266
292
  summary: EventMachine bindings for HyperDex
267
293
  test_files: []
294
+ has_rdoc: