zk 0.8.1 → 0.8.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/README.markdown CHANGED
@@ -41,10 +41,12 @@ ZK provides:
41
41
  * a recursive Find class (like the Find module in ruby-core)
42
42
  * unix-like rm\_rf and mkdir\_p methods (useful for functional testing)
43
43
 
44
- In addition to all of that, I would like to think that the public API the ZK::Client provides is more convenient to use for the common (synchronous) case.
44
+ In addition to all of that, I would like to think that the public API the ZK::Client provides is more convenient to use for the common (synchronous) case. For use with [EventMachine][] there is [zk-eventmachine][] which provides a convenient API for writing evented code that uses the ZooKeeper server.
45
45
 
46
46
  [recipes]: http://zookeeper.apache.org/doc/current/recipes.html
47
47
  [Mongoid]: http://mongoid.org/
48
+ [EventMachine]: https://github.com/eventmachine/eventmachine
49
+ [zk-eventmachine]: https://github.com/slyphon/zk-eventmachine
48
50
 
49
51
  ## Caveats
50
52
 
@@ -52,11 +54,11 @@ ZK strives to be a complete, correct, and convenient way of interacting with Zoo
52
54
 
53
55
  * _ACLS: HOW DO THEY WORK?!_ ACL support is mainly faith-based now. I have not had a need for ACLs, and the authors of the upstream [twitter/zookeeper][] code also don't seem to have much experience with them/use for them (purely my opinion, no offense intended). If you are using ACLs and you find bugs or have suggestions, I would much appreciate feedback or examples of how they *should* work so that support and tests can be added.
54
56
 
55
- * ZK::Client supports asynchronous calls of all basic methods (get, set, delete, etc.) however these versions are kind of inconvenient to use. There is a [branch][async-branch] for making improvements in this regard. This will be improved in the near-term as a related EventMachine-based project will be making use of these.
57
+ * ZK::Client supports asynchronous calls of all basic methods (get, set, delete, etc.) however these versions are kind of inconvenient to use. For a fully evented stack, try [zk-eventmachine][], which is designed to be compatible and convenient to use in event-driven code.
56
58
 
57
59
  * ZooKeeper "chroot" [connection syntax][chroot] _(search for "chroot" in page)_ is not currently working in the C drivers, and I don't have tests for the Java version. This hasn't been an incredibly high priority item, but support for this feature is intended.
58
60
 
59
- * I am currently in the process of cleaning up the API documentation and converting it to use [YARD][]. You can follow along on [this branch][dev/yard] which will be merged into master and released ASAP.
61
+ * I am currently in the process of cleaning up the API documentation and converting it to use [YARD][].
60
62
 
61
63
  [twitter/zookeeper]: https://github.com/twitter/zookeeper
62
64
  [async-branch]: https://github.com/slyphon/zk/tree/dev%2Fasync-conveniences
@@ -1,24 +1,28 @@
1
1
  module ZK
2
2
  module Client
3
3
  class Base
4
+ # The Eventhandler is used by client code to register callbacks to handle
5
+ # events triggerd for given paths.
6
+ #
7
+ # @see ZK::EventHandler#register
4
8
  attr_reader :event_handler
5
9
 
6
10
  # @private the wrapped connection object
7
11
  attr_reader :cnx
8
12
 
9
13
 
10
- # @deprecated: for backwards compatibility only
14
+ # @deprecated for backwards compatibility only
11
15
  def watcher
12
16
  event_handler
13
17
  end
14
18
 
15
19
  # returns true if the connection has been closed
16
- #--
17
- # XXX: should this be *our* idea of closed or ZOO_CLOSED_STATE ?
18
20
  def closed?
21
+ # XXX: should this be *our* idea of closed or ZOO_CLOSED_STATE ?
19
22
  defined?(::JRUBY_VERSION) ? jruby_closed? : mri_closed?
20
23
  end
21
24
 
25
+ # @private
22
26
  def inspect
23
27
  "#<#{self.class.name}:#{object_id} ...>"
24
28
  end
@@ -44,6 +48,7 @@ module ZK
44
48
  state
45
49
  end
46
50
 
51
+ # close the underlying connection and clear all pending events.
47
52
  def close!
48
53
  event_handler.clear!
49
54
  wrap_state_closed_error { @cnx.close unless @cnx.closed? }
@@ -647,11 +652,12 @@ module ZK
647
652
 
648
653
  protected
649
654
  def check_rc(hash, inputs=nil)
650
- hash.tap do |h|
651
- if code = h[:rc]
652
- msg = inputs ? "inputs: #{inputs.inspect}" : nil
653
- raise Exceptions::KeeperException.by_code(code), msg unless code == Zookeeper::ZOK
654
- end
655
+ code = hash[:rc]
656
+ if code && (code != Zookeeper::ZOK)
657
+ msg = inputs ? "inputs: #{inputs.inspect}" : nil
658
+ raise Exceptions::KeeperException.by_code(code), msg
659
+ else
660
+ hash
655
661
  end
656
662
  end
657
663
 
@@ -26,8 +26,8 @@ module ZK
26
26
 
27
27
  # closes the underlying connection and deregisters all callbacks
28
28
  def close!
29
- super
30
29
  @threadpool.shutdown
30
+ super
31
31
  nil
32
32
  end
33
33
  end
@@ -1,7 +1,8 @@
1
1
  module ZK
2
- # this is the default watcher provided by the zookeeper connection
2
+ # This is the default watcher provided by the zookeeper connection
3
3
  # watchers are implemented by adding the :watch => true flag to
4
4
  # any #children or #get or #exists calls
5
+ #
5
6
  # you never really need to initialize this yourself
6
7
  class EventHandler
7
8
  include org.apache.zookeeper.Watcher if defined?(JRUBY_VERSION)
@@ -32,16 +33,50 @@ module ZK
32
33
  end
33
34
 
34
35
  # register a path with the handler
36
+ #
35
37
  # your block will be called with all events on that path.
36
- # aliased as #subscribe
38
+ #
39
+ # @note All watchers are one-shot handlers. After an event is delivered to
40
+ # your handler, you *must* re-watch the node to receive more events. This
41
+ # leads to a pattern you will find throughout ZK code that avoids races,
42
+ # see the example below "avoiding a race"
43
+ #
44
+ # @example avoiding a race waiting for a node to be deleted
45
+ #
46
+ # # we expect that '/path/to/node' exists currently and want to be notified
47
+ # # when it's deleted
48
+ #
49
+ # # register a handler that will be called back when an event occurs on
50
+ # # node
51
+ # #
52
+ # node_subscription = zk.event_handler.register('/path/to/node') do |event|
53
+ # if event.node_deleted?
54
+ # do_something_when_node_deleted
55
+ # end
56
+ # end
57
+ #
58
+ # # check to see if our condition is true *while* setting a watch on the node
59
+ # # if our condition happens to be true while setting the watch
60
+ # #
61
+ # unless exists?('/path/to/node', :watch => true)
62
+ # node_subscription.unsubscribe # cancel the watch
63
+ # do_something_when_node_deleted # call the callback
64
+ # end
65
+ #
66
+ #
37
67
  # @param [String] path the path you want to listen to
68
+ #
38
69
  # @param [Block] block the block to execute when a watch event happpens
39
- # @yield [connection, event] We will call your block with the connection the
40
- # watch event occured on and the event object
70
+ #
71
+ # @yield [event] We will call your block with the watch event object (which
72
+ # has the connection the event occurred on as its #zk attribute)
73
+ #
41
74
  # @return [ZooKeeper::EventHandlerSubscription] the subscription object
42
75
  # you can use to to unsubscribe from an event
76
+ #
43
77
  # @see ZooKeeper::WatcherEvent
44
- # @see ZooKeeper::EventHandlerSubscription
78
+ # @see ZK::EventHandlerSubscription
79
+ #
45
80
  def register(path, &block)
46
81
  # logger.debug { "EventHandler#register path=#{path.inspect}" }
47
82
  EventHandlerSubscription.new(self, path, block).tap do |subscription|
@@ -54,13 +89,14 @@ module ZK
54
89
  #
55
90
  # @param [String] state the state you want to register for
56
91
  # @param [Block] block the block to execute on state changes
57
- # @yield [connection, event] yields your block with
92
+ # @yield [event] yields your block with
93
+ #
58
94
  def register_state_handler(state, &block)
59
95
  register(state_key(state), &block)
60
96
  end
61
97
 
62
98
  # @deprecated use #unsubscribe on the subscription object
63
- # @see ZooKeeper::EventHandlerSubscription#unsubscribe
99
+ # @see ZK::EventHandlerSubscription#unsubscribe
64
100
  def unregister_state_handler(*args)
65
101
  if args.first.is_a?(EventHandlerSubscription)
66
102
  unregister(args.first)
@@ -70,7 +106,7 @@ module ZK
70
106
  end
71
107
 
72
108
  # @deprecated use #unsubscribe on the subscription object
73
- # @see ZooKeeper::EventHandlerSubscription#unsubscribe
109
+ # @see ZK::EventHandlerSubscription#unsubscribe
74
110
  def unregister(*args)
75
111
  if args.first.is_a?(EventHandlerSubscription)
76
112
  subscription = args.first
@@ -93,7 +129,8 @@ module ZK
93
129
  alias :unsubscribe :unregister
94
130
 
95
131
  # called from the client-registered callback when an event fires
96
- def process(event) #:nodoc:
132
+ # @private
133
+ def process(event)
97
134
  # logger.debug { "EventHandler#process dispatching event: #{event.inspect}" }# unless event.type == -1
98
135
  event.zk = @zk
99
136
 
@@ -127,6 +164,7 @@ module ZK
127
164
  end
128
165
 
129
166
  # used during shutdown to clear registered listeners
167
+ # @private
130
168
  def clear! #:nodoc:
131
169
  synchronize do
132
170
  @callbacks.clear
@@ -134,10 +172,12 @@ module ZK
134
172
  end
135
173
  end
136
174
 
137
- def synchronize #:nodoc:
175
+ # @private
176
+ def synchronize
138
177
  @mutex.synchronize { yield }
139
178
  end
140
179
 
180
+ # @private
141
181
  def get_default_watcher_block
142
182
  @default_watcher_block ||= lambda do |hash|
143
183
  watcher_callback.tap do |cb|
@@ -151,6 +191,8 @@ module ZK
151
191
  # doesn't re-register the watcher with the server until a response has been
152
192
  # fired. This prevents one event delivery to *every* callback per :watch => true
153
193
  # argument.
194
+ #
195
+ # @private
154
196
  def setup_watcher!(watch_type, opts)
155
197
  return unless opts.delete(:watch)
156
198
 
@@ -169,10 +211,12 @@ module ZK
169
211
  end
170
212
 
171
213
  protected
214
+ # @private
172
215
  def watcher_callback
173
216
  ZookeeperCallbacks::WatcherCallback.create { |event| process(event) }
174
217
  end
175
218
 
219
+ # @private
176
220
  def state_key(arg)
177
221
  int =
178
222
  case arg
@@ -189,6 +233,7 @@ module ZK
189
233
  raise ArgumentError, "#{arg} is not a valid zookeeper state", caller
190
234
  end
191
235
 
236
+ # @private
192
237
  def safe_call(callbacks, *args)
193
238
  while cb = callbacks.shift
194
239
  begin
@@ -127,7 +127,9 @@ ZookeeperStat::Stat.send(:include, ZK::Extensions::Stat)
127
127
  class ::Exception
128
128
  unless method_defined?(:to_std_format)
129
129
  def to_std_format
130
- "#{self.class}: #{message}\n\t" + backtrace.join("\n\t")
130
+ ary = ["#{self.class}: #{message}"]
131
+ ary.concat(backtrace || [])
132
+ ary.join("\n\t")
131
133
  end
132
134
  end
133
135
  end
data/lib/z_k/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module ZK
2
- VERSION = "0.8.1"
2
+ VERSION = "0.8.2"
3
3
  end
@@ -0,0 +1,15 @@
1
+ require 'spec_helper'
2
+
3
+ module ZK
4
+ describe 'Extensions' do
5
+ describe 'Exception#to_std_format' do
6
+
7
+ it %[should not barf if backtrace is nil] do
8
+ exc = StandardError.new
9
+ exc.backtrace.should be_nil
10
+ lambda { exc.to_std_format }.should_not raise_error
11
+ end
12
+ end
13
+ end
14
+ end
15
+
data/zk.gemspec CHANGED
@@ -12,7 +12,7 @@ Gem::Specification.new do |s|
12
12
  s.summary = %q{A high-level wrapper around the zookeeper driver}
13
13
  s.description = s.summary
14
14
 
15
- s.add_runtime_dependency 'slyphon-zookeeper', '~> 0.2.0'
15
+ s.add_runtime_dependency 'slyphon-zookeeper', '~> 0.2.1'
16
16
 
17
17
  s.add_development_dependency 'rspec', '~> 2.4.0'
18
18
  s.add_development_dependency 'wirble'
metadata CHANGED
@@ -1,78 +1,106 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: zk
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 59
4
5
  prerelease:
5
- version: 0.8.1
6
+ segments:
7
+ - 0
8
+ - 8
9
+ - 2
10
+ version: 0.8.2
6
11
  platform: ruby
7
12
  authors:
8
- - Jonathan D. Simms
9
- - Topper Bowers
13
+ - Jonathan D. Simms
14
+ - Topper Bowers
10
15
  autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2011-06-17 00:00:00 +00:00
19
+ date: 2011-06-27 00:00:00 +00:00
15
20
  default_executable:
16
21
  dependencies:
17
- - !ruby/object:Gem::Dependency
18
- name: slyphon-zookeeper
19
- prerelease: false
20
- requirement: &id001 !ruby/object:Gem::Requirement
21
- none: false
22
- requirements:
23
- - - ~>
24
- - !ruby/object:Gem::Version
25
- version: 0.2.0
26
- type: :runtime
27
- version_requirements: *id001
28
- - !ruby/object:Gem::Dependency
29
- name: rspec
30
- prerelease: false
31
- requirement: &id002 !ruby/object:Gem::Requirement
32
- none: false
33
- requirements:
34
- - - ~>
35
- - !ruby/object:Gem::Version
36
- version: 2.4.0
37
- type: :development
38
- version_requirements: *id002
39
- - !ruby/object:Gem::Dependency
40
- name: wirble
41
- prerelease: false
42
- requirement: &id003 !ruby/object:Gem::Requirement
43
- none: false
44
- requirements:
45
- - - ">="
46
- - !ruby/object:Gem::Version
47
- version: "0"
48
- type: :development
49
- version_requirements: *id003
50
- - !ruby/object:Gem::Dependency
51
- name: flexmock
52
- prerelease: false
53
- requirement: &id004 !ruby/object:Gem::Requirement
54
- none: false
55
- requirements:
56
- - - ~>
57
- - !ruby/object:Gem::Version
58
- version: 0.8.10
59
- type: :development
60
- version_requirements: *id004
61
- - !ruby/object:Gem::Dependency
62
- name: ZenTest
63
- prerelease: false
64
- requirement: &id005 !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ~>
68
- - !ruby/object:Gem::Version
69
- version: 4.5.0
70
- type: :development
71
- version_requirements: *id005
22
+ - !ruby/object:Gem::Dependency
23
+ name: slyphon-zookeeper
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
26
+ none: false
27
+ requirements:
28
+ - - ~>
29
+ - !ruby/object:Gem::Version
30
+ hash: 21
31
+ segments:
32
+ - 0
33
+ - 2
34
+ - 1
35
+ version: 0.2.1
36
+ type: :runtime
37
+ version_requirements: *id001
38
+ - !ruby/object:Gem::Dependency
39
+ name: rspec
40
+ prerelease: false
41
+ requirement: &id002 !ruby/object:Gem::Requirement
42
+ none: false
43
+ requirements:
44
+ - - ~>
45
+ - !ruby/object:Gem::Version
46
+ hash: 31
47
+ segments:
48
+ - 2
49
+ - 4
50
+ - 0
51
+ version: 2.4.0
52
+ type: :development
53
+ version_requirements: *id002
54
+ - !ruby/object:Gem::Dependency
55
+ name: wirble
56
+ prerelease: false
57
+ requirement: &id003 !ruby/object:Gem::Requirement
58
+ none: false
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ hash: 3
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ type: :development
67
+ version_requirements: *id003
68
+ - !ruby/object:Gem::Dependency
69
+ name: flexmock
70
+ prerelease: false
71
+ requirement: &id004 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ~>
75
+ - !ruby/object:Gem::Version
76
+ hash: 43
77
+ segments:
78
+ - 0
79
+ - 8
80
+ - 10
81
+ version: 0.8.10
82
+ type: :development
83
+ version_requirements: *id004
84
+ - !ruby/object:Gem::Dependency
85
+ name: ZenTest
86
+ prerelease: false
87
+ requirement: &id005 !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ~>
91
+ - !ruby/object:Gem::Version
92
+ hash: 43
93
+ segments:
94
+ - 4
95
+ - 5
96
+ - 0
97
+ version: 4.5.0
98
+ type: :development
99
+ version_requirements: *id005
72
100
  description: A high-level wrapper around the zookeeper driver
73
101
  email:
74
- - simms@hp.com
75
- - tobowers@hp.com
102
+ - simms@hp.com
103
+ - tobowers@hp.com
76
104
  executables: []
77
105
 
78
106
  extensions: []
@@ -80,50 +108,51 @@ extensions: []
80
108
  extra_rdoc_files: []
81
109
 
82
110
  files:
83
- - .dotfiles/rspec-logging
84
- - .gitignore
85
- - .yardopts
86
- - Gemfile
87
- - LICENSE
88
- - README.markdown
89
- - Rakefile
90
- - lib/z_k.rb
91
- - lib/z_k/client.rb
92
- - lib/z_k/client/base.rb
93
- - lib/z_k/client/conveniences.rb
94
- - lib/z_k/client/state_mixin.rb
95
- - lib/z_k/client/threaded.rb
96
- - lib/z_k/client/unixisms.rb
97
- - lib/z_k/election.rb
98
- - lib/z_k/event_handler.rb
99
- - lib/z_k/event_handler_subscription.rb
100
- - lib/z_k/exceptions.rb
101
- - lib/z_k/extensions.rb
102
- - lib/z_k/find.rb
103
- - lib/z_k/locker.rb
104
- - lib/z_k/logging.rb
105
- - lib/z_k/message_queue.rb
106
- - lib/z_k/mongoid.rb
107
- - lib/z_k/pool.rb
108
- - lib/z_k/threadpool.rb
109
- - lib/z_k/version.rb
110
- - lib/zk.rb
111
- - spec/log4j.properties
112
- - spec/message_queue_spec.rb
113
- - spec/spec_helper.rb
114
- - spec/support/bogus_mongoid.rb
115
- - spec/support/logging_progress_bar_formatter.rb
116
- - spec/support/queuey_thread.rb
117
- - spec/test_file.txt
118
- - spec/watch_spec.rb
119
- - spec/z_k/client_spec.rb
120
- - spec/z_k/election_spec.rb
121
- - spec/z_k/locker_spec.rb
122
- - spec/z_k/mongoid_spec.rb
123
- - spec/z_k/pool_spec.rb
124
- - spec/z_k/threadpool_spec.rb
125
- - spec/zookeeper_spec.rb
126
- - zk.gemspec
111
+ - .dotfiles/rspec-logging
112
+ - .gitignore
113
+ - .yardopts
114
+ - Gemfile
115
+ - LICENSE
116
+ - README.markdown
117
+ - Rakefile
118
+ - lib/z_k.rb
119
+ - lib/z_k/client.rb
120
+ - lib/z_k/client/base.rb
121
+ - lib/z_k/client/conveniences.rb
122
+ - lib/z_k/client/state_mixin.rb
123
+ - lib/z_k/client/threaded.rb
124
+ - lib/z_k/client/unixisms.rb
125
+ - lib/z_k/election.rb
126
+ - lib/z_k/event_handler.rb
127
+ - lib/z_k/event_handler_subscription.rb
128
+ - lib/z_k/exceptions.rb
129
+ - lib/z_k/extensions.rb
130
+ - lib/z_k/find.rb
131
+ - lib/z_k/locker.rb
132
+ - lib/z_k/logging.rb
133
+ - lib/z_k/message_queue.rb
134
+ - lib/z_k/mongoid.rb
135
+ - lib/z_k/pool.rb
136
+ - lib/z_k/threadpool.rb
137
+ - lib/z_k/version.rb
138
+ - lib/zk.rb
139
+ - spec/log4j.properties
140
+ - spec/message_queue_spec.rb
141
+ - spec/spec_helper.rb
142
+ - spec/support/bogus_mongoid.rb
143
+ - spec/support/logging_progress_bar_formatter.rb
144
+ - spec/support/queuey_thread.rb
145
+ - spec/test_file.txt
146
+ - spec/watch_spec.rb
147
+ - spec/z_k/client_spec.rb
148
+ - spec/z_k/election_spec.rb
149
+ - spec/z_k/extensions_spec.rb
150
+ - spec/z_k/locker_spec.rb
151
+ - spec/z_k/mongoid_spec.rb
152
+ - spec/z_k/pool_spec.rb
153
+ - spec/z_k/threadpool_spec.rb
154
+ - spec/zookeeper_spec.rb
155
+ - zk.gemspec
127
156
  has_rdoc: true
128
157
  homepage: ""
129
158
  licenses: []
@@ -132,39 +161,46 @@ post_install_message:
132
161
  rdoc_options: []
133
162
 
134
163
  require_paths:
135
- - lib
164
+ - lib
136
165
  required_ruby_version: !ruby/object:Gem::Requirement
137
166
  none: false
138
167
  requirements:
139
- - - ">="
140
- - !ruby/object:Gem::Version
141
- version: "0"
168
+ - - ">="
169
+ - !ruby/object:Gem::Version
170
+ hash: 3
171
+ segments:
172
+ - 0
173
+ version: "0"
142
174
  required_rubygems_version: !ruby/object:Gem::Requirement
143
175
  none: false
144
176
  requirements:
145
- - - ">="
146
- - !ruby/object:Gem::Version
147
- version: "0"
177
+ - - ">="
178
+ - !ruby/object:Gem::Version
179
+ hash: 3
180
+ segments:
181
+ - 0
182
+ version: "0"
148
183
  requirements: []
149
184
 
150
185
  rubyforge_project:
151
- rubygems_version: 1.5.1
186
+ rubygems_version: 1.6.2
152
187
  signing_key:
153
188
  specification_version: 3
154
189
  summary: A high-level wrapper around the zookeeper driver
155
190
  test_files:
156
- - spec/log4j.properties
157
- - spec/message_queue_spec.rb
158
- - spec/spec_helper.rb
159
- - spec/support/bogus_mongoid.rb
160
- - spec/support/logging_progress_bar_formatter.rb
161
- - spec/support/queuey_thread.rb
162
- - spec/test_file.txt
163
- - spec/watch_spec.rb
164
- - spec/z_k/client_spec.rb
165
- - spec/z_k/election_spec.rb
166
- - spec/z_k/locker_spec.rb
167
- - spec/z_k/mongoid_spec.rb
168
- - spec/z_k/pool_spec.rb
169
- - spec/z_k/threadpool_spec.rb
170
- - spec/zookeeper_spec.rb
191
+ - spec/log4j.properties
192
+ - spec/message_queue_spec.rb
193
+ - spec/spec_helper.rb
194
+ - spec/support/bogus_mongoid.rb
195
+ - spec/support/logging_progress_bar_formatter.rb
196
+ - spec/support/queuey_thread.rb
197
+ - spec/test_file.txt
198
+ - spec/watch_spec.rb
199
+ - spec/z_k/client_spec.rb
200
+ - spec/z_k/election_spec.rb
201
+ - spec/z_k/extensions_spec.rb
202
+ - spec/z_k/locker_spec.rb
203
+ - spec/z_k/mongoid_spec.rb
204
+ - spec/z_k/pool_spec.rb
205
+ - spec/z_k/threadpool_spec.rb
206
+ - spec/zookeeper_spec.rb