ruby_doozer 0.1.0 → 0.2.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3820705ac3d8550a61d136be5b7134c806dab86e
4
- data.tar.gz: 35612961ac704ed090141234b65ab42490f1998c
3
+ metadata.gz: ca8f8f8ae259ceb2da7979c8ca5c7a2307b6fcc7
4
+ data.tar.gz: 4faf064cc2e33a25a3e612f66d59c528c948e491
5
5
  SHA512:
6
- metadata.gz: 86f04267b25ba51ef9c7a935b45b41265c8faa124df655d7d10c626e93bc3d462637ab6a6b5f0d7c85678ce935a1e995897379c07ef723f5476daaafbe430ff2
7
- data.tar.gz: 7890530ad60348d8483ee03208b67a10a89a76e86144618742ab0dccd09399bb23aad84fd2a5ae8357bef7d83bf56a8e32c072ee9ada47a50c8241a475531793
6
+ metadata.gz: 2f085c6219b6a3901d37937079036df515e5ad9fe4e54253147109e10cb3d8b51fa74cab823336883f7ad0d049d53149474f8d1fa31384a167137be7574b8a2f
7
+ data.tar.gz: 1a3c63775c7587c24f984b5d130c9aa17c464d338c305434df7f4127a472a154891f229f4639f96728b538db3bad9f89b55d9d44eba4d5cb7984d2f275d602fa
data/Gemfile CHANGED
@@ -2,10 +2,10 @@ source :rubygems
2
2
 
3
3
  group :test do
4
4
  gem "shoulda"
5
- gem "mocha", :require => false
6
5
  end
7
6
 
8
7
  gem "rake"
9
8
  gem "semantic_logger"
10
9
  gem "resilient_socket"
11
10
  gem "ruby_protobuf"
11
+ gem "gene_pool"
@@ -7,6 +7,7 @@ GEM
7
7
  atomic (1.0.1)
8
8
  bourne (1.4.0)
9
9
  mocha (~> 0.13.2)
10
+ gene_pool (1.3.0)
10
11
  i18n (0.6.1)
11
12
  metaclass (0.0.1)
12
13
  mocha (0.13.3)
@@ -34,7 +35,7 @@ PLATFORMS
34
35
  ruby
35
36
 
36
37
  DEPENDENCIES
37
- mocha
38
+ gene_pool
38
39
  rake
39
40
  resilient_socket
40
41
  ruby_protobuf
data/README.md CHANGED
@@ -19,22 +19,62 @@ client.close
19
19
 
20
20
  ### Logging
21
21
 
22
- Since ruby_skynet uses SemanticLogger, trace level logging of all TCP/IP
22
+ Since ruby_doozer uses SemanticLogger, trace level logging of all TCP/IP
23
23
  calls can be enabled as follows:
24
24
 
25
25
  ```ruby
26
26
  require 'rubygems'
27
- require 'ruby_skynet'
27
+ require 'ruby_doozer'
28
28
 
29
29
  SemanticLogger::Logger.default_level = :trace
30
- SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('skynet.log')
30
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('doozer.log')
31
+
32
+ client = RubyDoozer::Client.new(:server => '127.0.0.1:8046')
33
+ client.set('/test/foo', 'value')
34
+ result = client.get('/test/foo')
35
+ client.close
36
+ ```
37
+
38
+ ### Registry
39
+
40
+ RubyDoozer also includes a Registry class to support storing all configuration
41
+ information in doozer. This Centralized Configuration allows configuration changes
42
+ to be made dynamically at run-time and all interested parties will be notified
43
+ of the changes.
44
+
45
+ For example, making a change to the central database configuration will notify
46
+ all application servers to drop their database connections and re-establish them
47
+ to the new servers:
48
+
49
+ ```ruby
50
+ require 'rubygems'
51
+ require 'ruby_doozer'
52
+
53
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('registry.log')
54
+
55
+ region = "Development"
56
+ application = "sprites"
57
+ path = "/#{region}/#{application}/config/resources".downcase
58
+
59
+ config_registry = RubyDoozer::Registry.new(:root_path => path)
60
+
61
+ # Store the configuration information in doozer as a serialized string
62
+ config_registry['master'] = "Some JSON config string"
63
+
64
+ # Allow time for Doozer to publish the new config
65
+ sleep 0.5
66
+
67
+ # Retrieve the current configuration
68
+ database_config = config_registry['master']
69
+ slave_database_config = config_registry['secondary']
31
70
 
32
- class EchoService
33
- include RubySkynet::Base
71
+ # Register for any changes to the configuration
72
+ config_registry.on_update('master') do |path, value|
73
+ puts "Time to re-establish database connections to new server: #{value}"
34
74
  end
35
75
 
36
- client = EchoService.new
37
- p client.echo(:hello => 'world')
76
+ # Change the configuration and all subscribers will be notified
77
+ config_registry['master'] = "Some updated JSON config string"
38
78
  ```
39
79
 
40
80
  ### Notes
data/Rakefile CHANGED
@@ -6,7 +6,6 @@ require 'rubygems/package'
6
6
  require 'rake/clean'
7
7
  require 'rake/testtask'
8
8
  require 'date'
9
- require 'semantic_logger'
10
9
  require 'ruby_doozer/version'
11
10
 
12
11
  desc "Build gem"
@@ -27,6 +26,7 @@ task :gem do |t|
27
26
  spec.add_dependency 'semantic_logger'
28
27
  spec.add_dependency 'resilient_socket'
29
28
  spec.add_dependency 'ruby_protobuf'
29
+ spec.add_dependency 'gene_pool'
30
30
  end
31
31
  Gem::Package.build gemspec
32
32
  end
@@ -1,3 +1,6 @@
1
+ require 'semantic_logger'
2
+
1
3
  module RubyDoozer
2
4
  autoload :Client, 'ruby_doozer/client'
5
+ autoload :Registry, 'ruby_doozer/registry'
3
6
  end
@@ -0,0 +1,379 @@
1
+ require 'thread_safe'
2
+ require 'gene_pool'
3
+ require 'semantic_logger'
4
+
5
+ #
6
+ # Registry
7
+ #
8
+ # Store information in doozer and subscribe to future changes
9
+ #
10
+ # Notifies registered subscribers when information has changed
11
+ #
12
+ # All paths specified are relative to the root_path. As such the root path
13
+ # is never returned, nor is it required when a path is supplied as input.
14
+ # For example, with a root_path of /foo/bar, any paths passed in will leave
15
+ # out the root_path: host/name
16
+ #
17
+ module RubyDoozer
18
+ class Registry
19
+ # Logging instance for this class
20
+ include SemanticLogger::Loggable
21
+
22
+ attr_reader :doozer_config, :doozer_pool
23
+
24
+ # Create a Registry instance to manage a path of information within doozer
25
+ #
26
+ # :root_path [String]
27
+ # Root path to load and then monitor for changes
28
+ # It is not recommended to set the root_path to "/" as it will generate
29
+ # significant traffic since it will also monitor Doozer Admin changes
30
+ # Mandatory
31
+ #
32
+ # :cache [Boolean]
33
+ # Keep a local copy in memory of all descendant values of the supplied root_path
34
+ # Allows high-frequency calls to retrieve registry data
35
+ # The cache will be kept in synch with any changes on the server
36
+ # Default: true
37
+ #
38
+ # :doozer [Hash]
39
+ # Doozer configuration information
40
+ #
41
+ # :servers [Array of String]
42
+ # Array of URL's of doozer servers to connect to with port numbers
43
+ # ['server1:2000', 'server2:2000']
44
+ #
45
+ # An attempt will be made to connect to alternative servers when the
46
+ # current server cannot be connected to
47
+ # Default: ['127.0.0.1:8046']
48
+ #
49
+ # :read_timeout [Float]
50
+ # Time in seconds to timeout on read
51
+ # Can be overridden by supplying a timeout in the read call
52
+ # Default: 5
53
+ #
54
+ # :connect_timeout [Float]
55
+ # Time in seconds to timeout when trying to connect to the server
56
+ # Default: 3
57
+ #
58
+ # :connect_retry_count [Fixnum]
59
+ # Number of times to retry connecting when a connection fails
60
+ # Default: 10
61
+ #
62
+ # :connect_retry_interval [Float]
63
+ # Number of seconds between connection retry attempts after the first failed attempt
64
+ # Default: 0.5
65
+ #
66
+ # :server_selector [Symbol|Proc]
67
+ # When multiple servers are supplied using :servers, this option will
68
+ # determine which server is selected from the list
69
+ # :ordered
70
+ # Select a server in the order supplied in the array, with the first
71
+ # having the highest priority. The second server will only be connected
72
+ # to if the first server is unreachable
73
+ # :random
74
+ # Randomly select a server from the list every time a connection
75
+ # is established, including during automatic connection recovery.
76
+ # Proc:
77
+ # When a Proc is supplied, it will be called passing in the list
78
+ # of servers. The Proc must return one server name
79
+ # Example:
80
+ # :server_selector => Proc.new do |servers|
81
+ # servers.last
82
+ # end
83
+ # Default: :random
84
+ #
85
+ # :pool_size [Integer]
86
+ # Maximum size of the connection pool to doozer
87
+ # Default: 10
88
+ #
89
+ def initialize(params)
90
+ params = params.dup
91
+ @root_path = params.delete(:root_path)
92
+ raise "Missing mandatory parameter :root_path" unless @root_path
93
+
94
+ # Add leading '/' to root_path if missing
95
+ @root_path = "/#{@root_path}" unless @root_path.start_with?('/')
96
+
97
+ # Strip trailing '/' if supplied
98
+ @root_path = @root_path[0..-2] if @root_path.end_with?("/")
99
+ @root_path_with_trail = "#{@root_path}/"
100
+
101
+ local_copy = params.delete(:cache)
102
+ @registry = (local_copy == false) ? nil : ThreadSafe::Hash.new
103
+
104
+ @doozer_config = params.delete(:doozer) || {}
105
+ @doozer_config[:servers] ||= ['127.0.0.1:8046']
106
+ @doozer_config[:read_timeout] ||= 5
107
+ @doozer_config[:connect_timeout] ||= 3
108
+ @doozer_config[:connect_retry_interval] ||= 0.5
109
+ @doozer_config[:connect_retry_count] ||= 10
110
+ @doozer_config[:server_selector] ||= :random
111
+
112
+ # Connection pool settings
113
+ @doozer_pool = GenePool.new(
114
+ :name =>"Doozer Connection Pool",
115
+ :pool_size => @doozer_config.delete(:pool_size) || 10,
116
+ :timeout => @doozer_config.delete(:pool_timeout) || 30,
117
+ :warn_timeout => @doozer_config.delete(:pool_warn_timeout) || 5,
118
+ :idle_timeout => @doozer_config.delete(:pool_idle_timeout) || 600,
119
+ :logger => logger,
120
+ :close_proc => :close
121
+ ) do
122
+ RubyDoozer::Client.new(@doozer_config)
123
+ end
124
+
125
+ @create_subscribers = ThreadSafe::Hash.new
126
+ @update_subscribers = ThreadSafe::Hash.new
127
+ @delete_subscribers = ThreadSafe::Hash.new
128
+
129
+ revision = nil
130
+ path = "#{@root_path}/**"
131
+ doozer_pool.with_connection do |doozer|
132
+ revision = doozer.current_revision
133
+ if @registry
134
+ # Fetch all the configuration information from Doozer and set the internal copy
135
+ doozer.walk(path, revision).each do |node|
136
+ @registry[relative_path(node.path)] = node.value
137
+ end
138
+ end
139
+ end
140
+
141
+ # Start monitoring thread to keep the registry in synch with doozer
142
+ @monitor_thread = Thread.new { watch_registry(path, revision + 1) }
143
+
144
+ # Generate warning log entries for any unknown configuration options
145
+ params.each_pair {|k,v| logger.warn "Ignoring unknown configuration option: #{k}"}
146
+ end
147
+
148
+ # Retrieve the latest value from a specific path from the registry
149
+ # If :cache was set to false on the initializer this call will
150
+ # make a network call to doozer to retrieve the current value
151
+ # Otherwise it is an in memory call and can be called frequently
152
+ def [](path)
153
+ if @registry
154
+ @registry[path]
155
+ else
156
+ doozer_pool.with_connection do |doozer|
157
+ doozer[full_path(path)]
158
+ end
159
+ end
160
+ end
161
+
162
+ # Replace the latest value at a specific path
163
+ # The in-memory copy will be updated when doozer sends out the change
164
+ # TODO Should we also update the in memory copy rather than wait for the change
165
+ # notification?
166
+ def []=(path,value)
167
+ doozer_pool.with_connection do |doozer|
168
+ doozer[full_path(path)] = value
169
+ end
170
+ end
171
+
172
+ # Delete the value at a specific path
173
+ # The in-memory copy will be updated when doozer sends out the change
174
+ # TODO Should we also delete the in memory copy rather than wait for the change
175
+ # notification?
176
+ def delete(path)
177
+ old_value = @registry[path] if @registry
178
+ doozer_pool.with_connection do |doozer|
179
+ doozer.delete(full_path(path))
180
+ end
181
+ old_value
182
+ end
183
+
184
+ # Iterate over every key, value pair in the registry at the root_path
185
+ #
186
+ # If :cache was set to false on the initializer this call will
187
+ # make network calls to doozer to retrieve the current values
188
+ # Otherwise it is an in memory call against a duplicate of the registry
189
+ #
190
+ # Example:
191
+ # registry.each_pair {|k,v| puts "#{k} => #{v}"}
192
+ def each_pair(&block)
193
+ if @registry
194
+ @registry.dup.each_pair(&block)
195
+ else
196
+ path = "#{@root_path}/**"
197
+ doozer_pool.with_connection do |doozer|
198
+ doozer.walk(path, revision).each do |node|
199
+ block.call(relative_path(node.path), node.value)
200
+ end
201
+ end
202
+ end
203
+ end
204
+
205
+ # Returns a copy of the registry as a Hash
206
+ def to_h
207
+ if @registry
208
+ @registry.dup
209
+ else
210
+ h = {}
211
+ each_pair {|k,v| h[k] = v}
212
+ h
213
+ end
214
+ end
215
+
216
+ # Cleanup on process termination
217
+ def finalize
218
+ logger.info "Finalizing"
219
+ if @monitor_thread
220
+ @monitor_thread.kill
221
+ @monitor_thread = nil
222
+ end
223
+ @doozer_pool.close if @doozer_pool
224
+ @doozer_pool = nil
225
+ end
226
+
227
+ # When an entry is created the block will be called
228
+ # Parameters
229
+ # path
230
+ # The relative path _excluding_ the root_path to watch for changes
231
+ # #TODO Or a regular expression
232
+ # block
233
+ # The block to be called
234
+ #
235
+ # Parameters passed to the block:
236
+ # path
237
+ # The path that was created
238
+ #
239
+ # value
240
+ # New value from doozer
241
+ #
242
+ # Example:
243
+ # registry.on_update do |path, value|
244
+ # puts "#{path} was created with #{value}"
245
+ # end
246
+ def on_create(path, &block)
247
+ (@create_subscribers[path] ||= ThreadSafe::Array.new) << block
248
+ end
249
+
250
+ # When an entry is updated the block will be called
251
+ # Parameters
252
+ # path
253
+ # The relative path _excluding_ the root_path to watch for changes
254
+ # block
255
+ # The block to be called
256
+ #
257
+ # Parameters passed to the block:
258
+ # path
259
+ # The path that was deleted from doozer
260
+ #
261
+ # value
262
+ # New value from doozer
263
+ #
264
+ # old_value
265
+ # nil if :cache is false
266
+ # otherwise the last value for this path in the local copy of the registry
267
+ #
268
+ # Example:
269
+ # registry.on_update do |path, value, old_value|
270
+ # puts "#{path} was updated to #{value} with previous value #{old_value}"
271
+ # end
272
+ #
273
+ # Warning:
274
+ # If :cache is set to false then on_update will never be called
275
+ # Every change will go to subscribers of #on_create()
276
+ def on_update(path, &block)
277
+ (@update_subscribers[path] ||= ThreadSafe::Array.new) << block
278
+ end
279
+
280
+ # When an entry is deleted the block will be called
281
+ # Parameters
282
+ # path
283
+ # The relative path _excluding_ the root_path to watch for changes
284
+ # block
285
+ # The block to be called
286
+ #
287
+ # Parameters passed to the block:
288
+ # path
289
+ # The path that was deleted from doozer
290
+ #
291
+ # old_value
292
+ # nil if :cache is false
293
+ # otherwise the last value for this path in the local copy of the registry
294
+ #
295
+ # Example:
296
+ # registry.on_delete do |path, old_value|
297
+ # puts "#{path} was deleted with previous value #{old_value}"
298
+ # end
299
+ def on_delete(path, &block)
300
+ (@delete_subscribers[path] ||= ThreadSafe::Array.new) << block
301
+ end
302
+
303
+ ############################
304
+ protected
305
+
306
+ #Subscription = Struct.new(:path, :block, :reg_exp)
307
+
308
+
309
+ # Returns the full path given a relative path
310
+ def full_path(relative_path)
311
+ "#{@root_path}/#{relative_path}"
312
+ end
313
+
314
+ # Returns the full path given a relative path
315
+ def relative_path(full_path)
316
+ full_path.sub(@root_path_with_trail, '')
317
+ end
318
+
319
+ # The path has been added or updated in the registry
320
+ def changed(path, value)
321
+ logger.debug { "Changed: #{path} => #{value}" }
322
+ old_value = nil
323
+
324
+ # Keeping a local copy of the registry?
325
+ if @registry
326
+ # Already have a value?
327
+ old_value = @registry[path]
328
+
329
+ # Update in memory copy
330
+ @registry[path] = value
331
+ end
332
+
333
+ if subscribers = old_value ? @update_subscribers[path] : @create_subscribers[path]
334
+ subscribers.each{|subscriber| subscriber.call(path, value, old_value)}
335
+ end
336
+ end
337
+
338
+ # Existing data has been removed from the registry
339
+ def deleted(path)
340
+ logger.debug { "Deleted: #{path}" }
341
+ old_value = @registry.delete(path) if @registry
342
+ if subscribers = @delete_subscribers[path]
343
+ subscribers.each{|subscriber| subscriber.call(path, old_value)}
344
+ end
345
+ end
346
+
347
+ # Waits for any updates from Doozer and updates the internal service registry
348
+ def watch_registry(watch_path, revision)
349
+ logger.info "Start monitoring #{watch_path}"
350
+ # This thread must use its own dedicated doozer connection
351
+ doozer = RubyDoozer::Client.new(@doozer_config)
352
+
353
+ # Watch for any changes
354
+ doozer.watch(watch_path, revision) do |node|
355
+ logger.trace "Registry Change Notification", node
356
+
357
+ # Remove the Root path
358
+ path = relative_path(node.path)
359
+
360
+ case node.flags
361
+ when 4
362
+ changed(path, node.value)
363
+ when 8
364
+ deleted(path)
365
+ else
366
+ logger.error "Unknown flags returned by doozer:#{node.flags}"
367
+ end
368
+ logger.trace "Updated registry", @registry
369
+ end
370
+ logger.info "Stopping monitoring thread normally"
371
+ rescue Exception => exc
372
+ logger.error "Exception in monitoring thread", exc
373
+ ensure
374
+ doozer.close if doozer
375
+ logger.info "Stopped monitoring for changes in the doozer registry"
376
+ end
377
+
378
+ end
379
+ end
@@ -1,3 +1,3 @@
1
1
  module RubyDoozer #:nodoc
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -9,6 +9,12 @@ require 'ruby_doozer/client'
9
9
  # NOTE:
10
10
  # This test assumes that doozerd is running locally on the default port of 8046
11
11
 
12
+ # Register an appender if one is not already registered
13
+ if SemanticLogger::Logger.appenders.size == 0
14
+ SemanticLogger::Logger.default_level = :trace
15
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('test.log')
16
+ end
17
+
12
18
  # Unit Test for RubyDoozer::Client
13
19
  class ClientTest < Test::Unit::TestCase
14
20
  context RubyDoozer::Client do
@@ -0,0 +1,120 @@
1
+ # Allow test to be run in-place without requiring a gem install
2
+ $LOAD_PATH.unshift File.dirname(__FILE__) + '/../lib'
3
+
4
+ require 'rubygems'
5
+ require 'test/unit'
6
+ require 'shoulda'
7
+ require 'ruby_doozer'
8
+
9
+ # NOTE:
10
+ # This test assumes that doozerd is running locally on the default port of 8046
11
+
12
+ # Register an appender if one is not already registered
13
+ if SemanticLogger::Logger.appenders.size == 0
14
+ SemanticLogger::Logger.default_level = :trace
15
+ SemanticLogger::Logger.appenders << SemanticLogger::Appender::File.new('test.log')
16
+ end
17
+
18
+ # Unit Test for RubyDoozer::Client
19
+ class RegistryTest < Test::Unit::TestCase
20
+ context RubyDoozer::Registry do
21
+ context "with test data" do
22
+ setup do
23
+ @test_data = {
24
+ 'bar' => 'test',
25
+ 'one' => 'one',
26
+ 'two' => 'two',
27
+ }
28
+ # Doozer does not allow '_' in path names
29
+ @root_path = "/registrytest"
30
+ @client = RubyDoozer::Client.new(:server => 'localhost:8046')
31
+ @test_data.each_pair {|k,v| @client.set("#{@root_path}/#{k}",v)}
32
+
33
+ @registry = RubyDoozer::Registry.new(:root_path => @root_path)
34
+ end
35
+
36
+ def teardown
37
+ @registry.finalize if @registry
38
+ if @client
39
+ @test_data.each_pair do |k,v|
40
+ @client.delete("#{@root_path}/#{k}")
41
+ end
42
+ @client.delete("#{@root_path}/three")
43
+ @client.close
44
+ end
45
+ end
46
+
47
+ # Run tests with and without a local cache
48
+ [true, false].each do |cache|
49
+ context "cache:#{cache}" do
50
+ should "have complete registry" do
51
+ @test_data.each_pair do |k,v|
52
+ assert_equal v, @registry[k], "Expected #{k}=>#{v}, #{@registry.to_h.inspect}"
53
+ end
54
+ end
55
+
56
+ should "iterate over complete registry" do
57
+ @registry.each_pair do |k,v|
58
+ assert_equal v, @test_data[k], "Registry #{k}=>#{v}, #{@registry.to_h.inspect}"
59
+ end
60
+ end
61
+
62
+ should "successfully set and retrieve data" do
63
+ @registry['three'] = 'value'
64
+ # Allow doozer to send back the change
65
+ sleep 0.5
66
+ result = @registry['three']
67
+ assert_equal 'value', result
68
+ end
69
+
70
+ should "invoke callbacks on create" do
71
+ created_path = nil
72
+ created_value = nil
73
+ @registry.on_create('three') do |path, value|
74
+ created_path = path
75
+ created_value = value
76
+ end
77
+ @registry['three'] = 'created'
78
+ # Allow doozer to send back the change
79
+ sleep 0.5
80
+ assert_equal 'three', created_path
81
+ assert_equal 'created', created_value
82
+ end
83
+
84
+ should "invoke callbacks on update" do
85
+ # Update only triggers when the cache is enabled
86
+ if cache
87
+ updated_path = nil
88
+ updated_value = nil
89
+ @registry.on_update('bar') do |path, value|
90
+ updated_path = path
91
+ updated_value = value
92
+ end
93
+ @registry['bar'] = 'updated'
94
+ # Allow doozer to send back the change
95
+ sleep 0.5
96
+ assert_equal 'bar', updated_path
97
+ assert_equal 'updated', updated_value
98
+ end
99
+ end
100
+
101
+ should "invoke callbacks on delete" do
102
+ deleted_path = nil
103
+ deleted_value = nil
104
+ @registry.on_delete('bar') do |path, old_value|
105
+ deleted_path = path
106
+ deleted_value = old_value
107
+ end
108
+ # Allow doozer to send back the change
109
+ @registry.delete('bar')
110
+ sleep 0.5
111
+ assert_equal 'bar', deleted_path
112
+ assert_equal 'test', deleted_value
113
+ end
114
+
115
+ end
116
+ end
117
+
118
+ end
119
+ end
120
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby_doozer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-03-28 00:00:00.000000000 Z
11
+ date: 2013-03-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semantic_logger
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - '>='
53
53
  - !ruby/object:Gem::Version
54
54
  version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: gene_pool
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - '>='
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - '>='
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  description: Ruby Client for doozer
56
70
  email:
57
71
  - reidmo@gmail.com
@@ -68,8 +82,10 @@ files:
68
82
  - lib/ruby_doozer/client.rb
69
83
  - lib/ruby_doozer/exceptions.rb
70
84
  - lib/ruby_doozer/msg.pb.rb
85
+ - lib/ruby_doozer/registry.rb
71
86
  - lib/ruby_doozer/version.rb
72
87
  - test/client_test.rb
88
+ - test/registry_test.rb
73
89
  homepage: https://github.com/ClarityServices/ruby_doozer
74
90
  licenses:
75
91
  - Apache License V2.0