ruby_doozer 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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