em-hyperdex-client 0.3.1 → 0.3.2

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.
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: