zookeeper 0.9.4 → 1.0.0.beta.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.dotfiles/rvmrc +1 -0
- data/.gitignore +3 -0
- data/.gitmodules +3 -0
- data/.travis.yml +22 -0
- data/CHANGELOG +38 -5
- data/Gemfile +18 -1
- data/README.markdown +2 -0
- data/Rakefile +47 -109
- data/ext/c_zookeeper.rb +10 -6
- data/ext/zookeeper_base.rb +23 -11
- data/ext/zookeeper_c.c +14 -10
- data/java/{zookeeper_base.rb → java_base.rb} +13 -12
- data/lib/zookeeper.rb +32 -244
- data/lib/zookeeper/acls.rb +17 -13
- data/lib/zookeeper/callbacks.rb +28 -11
- data/lib/zookeeper/client.rb +30 -0
- data/lib/zookeeper/client_methods.rb +241 -0
- data/lib/zookeeper/common.rb +13 -12
- data/lib/zookeeper/common/queue_with_pipe.rb +3 -7
- data/lib/zookeeper/compatibility.rb +135 -0
- data/lib/zookeeper/constants.rb +35 -1
- data/lib/zookeeper/em_client.rb +1 -1
- data/lib/zookeeper/exceptions.rb +117 -93
- data/lib/zookeeper/rake_tasks.rb +165 -0
- data/lib/zookeeper/stat.rb +16 -16
- data/lib/zookeeper/version.rb +2 -4
- data/scripts/upgrade-1.0-sed-alike.rb +46 -0
- data/spec/c_zookeeper_spec.rb +10 -9
- data/spec/chrooted_connection_spec.rb +2 -2
- data/spec/default_watcher_spec.rb +4 -4
- data/spec/em_spec.rb +1 -1
- data/spec/shared/connection_examples.rb +52 -37
- data/spec/spec_helper.rb +22 -84
- data/spec/support/00_spawn_zookeeper.rb +20 -0
- data/spec/support/zookeeper_spec_helpers.rb +84 -0
- data/spec/zookeeper_spec.rb +1 -1
- metadata +47 -34
- data/examples/cloud_config.rb +0 -125
- data/test/test_basic.rb +0 -37
- data/test/test_callback1.rb +0 -36
- data/test/test_close.rb +0 -16
- data/test/test_esoteric.rb +0 -7
- data/test/test_watcher1.rb +0 -56
- data/test/test_watcher2.rb +0 -52
@@ -0,0 +1,30 @@
|
|
1
|
+
# figure out what platform we're on
|
2
|
+
# this way there's no ambiguity about which file to include
|
3
|
+
# or which class we're subclassing.
|
4
|
+
|
5
|
+
if defined?(::JRUBY_VERSION)
|
6
|
+
require_relative('../../java/java_base')
|
7
|
+
else
|
8
|
+
require_relative('../../ext/zookeeper_base')
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
module Zookeeper
|
13
|
+
if defined?(::JRUBY_VERSION)
|
14
|
+
class Client < Zookeeper::JavaBase
|
15
|
+
end
|
16
|
+
else
|
17
|
+
class Client < Zookeeper::ZookeeperBase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.new(*a, &b)
|
22
|
+
Zookeeper::Client.new(*a, &b)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
Zookeeper::Client.class_eval do
|
28
|
+
include Zookeeper::ClientMethods
|
29
|
+
end
|
30
|
+
|
@@ -0,0 +1,241 @@
|
|
1
|
+
module Zookeeper
|
2
|
+
module ClientMethods
|
3
|
+
include Constants
|
4
|
+
include ACLs
|
5
|
+
|
6
|
+
def reopen(timeout=10, watcher=nil)
|
7
|
+
warn "WARN: ZookeeperBase#reopen watcher argument is now ignored" if watcher
|
8
|
+
super
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(host, timeout=10, watcher=nil)
|
12
|
+
super
|
13
|
+
end
|
14
|
+
|
15
|
+
def get(options = {})
|
16
|
+
assert_open
|
17
|
+
assert_supported_keys(options, [:path, :watcher, :watcher_context, :callback, :callback_context])
|
18
|
+
assert_required_keys(options, [:path])
|
19
|
+
|
20
|
+
req_id = setup_call(:get, options)
|
21
|
+
rc, value, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
22
|
+
|
23
|
+
rv = { :req_id => req_id, :rc => rc }
|
24
|
+
options[:callback] ? rv : rv.merge(:data => value, :stat => Stat.new(stat))
|
25
|
+
end
|
26
|
+
|
27
|
+
def set(options = {})
|
28
|
+
assert_open
|
29
|
+
assert_supported_keys(options, [:path, :data, :version, :callback, :callback_context])
|
30
|
+
assert_required_keys(options, [:path])
|
31
|
+
assert_valid_data_size!(options[:data])
|
32
|
+
options[:version] ||= -1
|
33
|
+
|
34
|
+
req_id = setup_call(:set, options)
|
35
|
+
rc, stat = super(req_id, options[:path], options[:data], options[:callback], options[:version])
|
36
|
+
|
37
|
+
rv = { :req_id => req_id, :rc => rc }
|
38
|
+
options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
|
39
|
+
end
|
40
|
+
|
41
|
+
def get_children(options = {})
|
42
|
+
assert_open
|
43
|
+
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
44
|
+
assert_required_keys(options, [:path])
|
45
|
+
|
46
|
+
req_id = setup_call(:get_children, options)
|
47
|
+
rc, children, stat = super(req_id, options[:path], options[:callback], options[:watcher])
|
48
|
+
|
49
|
+
rv = { :req_id => req_id, :rc => rc }
|
50
|
+
options[:callback] ? rv : rv.merge(:children => children, :stat => Stat.new(stat))
|
51
|
+
end
|
52
|
+
|
53
|
+
def stat(options = {})
|
54
|
+
assert_open
|
55
|
+
assert_supported_keys(options, [:path, :callback, :callback_context, :watcher, :watcher_context])
|
56
|
+
assert_required_keys(options, [:path])
|
57
|
+
|
58
|
+
req_id = setup_call(:stat, options)
|
59
|
+
rc, stat = exists(req_id, options[:path], options[:callback], options[:watcher])
|
60
|
+
|
61
|
+
rv = { :req_id => req_id, :rc => rc }
|
62
|
+
options[:callback] ? rv : rv.merge(:stat => Stat.new(stat))
|
63
|
+
end
|
64
|
+
|
65
|
+
def create(options = {})
|
66
|
+
assert_open
|
67
|
+
assert_supported_keys(options, [:path, :data, :acl, :ephemeral, :sequence, :callback, :callback_context])
|
68
|
+
assert_required_keys(options, [:path])
|
69
|
+
assert_valid_data_size!(options[:data])
|
70
|
+
|
71
|
+
flags = 0
|
72
|
+
flags |= ZOO_EPHEMERAL if options[:ephemeral]
|
73
|
+
flags |= ZOO_SEQUENCE if options[:sequence]
|
74
|
+
|
75
|
+
options[:acl] ||= ZOO_OPEN_ACL_UNSAFE
|
76
|
+
|
77
|
+
req_id = setup_call(:create, options)
|
78
|
+
rc, newpath = super(req_id, options[:path], options[:data], options[:callback], options[:acl], flags)
|
79
|
+
|
80
|
+
rv = { :req_id => req_id, :rc => rc }
|
81
|
+
options[:callback] ? rv : rv.merge(:path => newpath)
|
82
|
+
end
|
83
|
+
|
84
|
+
def delete(options = {})
|
85
|
+
assert_open
|
86
|
+
assert_supported_keys(options, [:path, :version, :callback, :callback_context])
|
87
|
+
assert_required_keys(options, [:path])
|
88
|
+
options[:version] ||= -1
|
89
|
+
|
90
|
+
req_id = setup_call(:delete, options)
|
91
|
+
rc = super(req_id, options[:path], options[:version], options[:callback])
|
92
|
+
|
93
|
+
{ :req_id => req_id, :rc => rc }
|
94
|
+
end
|
95
|
+
|
96
|
+
# this method is *only* asynchronous
|
97
|
+
#
|
98
|
+
# @note There is a discrepancy between the zkc and java versions. zkc takes
|
99
|
+
# a string_callback_t, java takes a VoidCallback. You should most likely use
|
100
|
+
# the ZookeeperCallbacks::VoidCallback and not rely on the string value.
|
101
|
+
#
|
102
|
+
def sync(options = {})
|
103
|
+
assert_open
|
104
|
+
assert_supported_keys(options, [:path, :callback, :callback_context])
|
105
|
+
assert_required_keys(options, [:path, :callback])
|
106
|
+
|
107
|
+
req_id = setup_call(:sync, options)
|
108
|
+
|
109
|
+
rc = super(req_id, options[:path]) # we don't pass options[:callback] here as this method is *always* async
|
110
|
+
|
111
|
+
{ :req_id => req_id, :rc => rc }
|
112
|
+
end
|
113
|
+
|
114
|
+
def set_acl(options = {})
|
115
|
+
assert_open
|
116
|
+
assert_supported_keys(options, [:path, :acl, :version, :callback, :callback_context])
|
117
|
+
assert_required_keys(options, [:path, :acl])
|
118
|
+
options[:version] ||= -1
|
119
|
+
|
120
|
+
req_id = setup_call(:set_acl, options)
|
121
|
+
rc = super(req_id, options[:path], options[:acl], options[:callback], options[:version])
|
122
|
+
|
123
|
+
{ :req_id => req_id, :rc => rc }
|
124
|
+
end
|
125
|
+
|
126
|
+
def get_acl(options = {})
|
127
|
+
assert_open
|
128
|
+
assert_supported_keys(options, [:path, :callback, :callback_context])
|
129
|
+
assert_required_keys(options, [:path])
|
130
|
+
|
131
|
+
req_id = setup_call(:get_acl, options)
|
132
|
+
rc, acls, stat = super(req_id, options[:path], options[:callback])
|
133
|
+
|
134
|
+
rv = { :req_id => req_id, :rc => rc }
|
135
|
+
options[:callback] ? rv : rv.merge(:acl => acls, :stat => Stat.new(stat))
|
136
|
+
end
|
137
|
+
|
138
|
+
# close this client and any underyling connections
|
139
|
+
def close
|
140
|
+
super
|
141
|
+
end
|
142
|
+
|
143
|
+
def state
|
144
|
+
super
|
145
|
+
end
|
146
|
+
|
147
|
+
def connected?
|
148
|
+
super
|
149
|
+
end
|
150
|
+
|
151
|
+
def connecting?
|
152
|
+
super
|
153
|
+
end
|
154
|
+
|
155
|
+
def associating?
|
156
|
+
super
|
157
|
+
end
|
158
|
+
|
159
|
+
# There are some operations that are dangerous in the context of the event
|
160
|
+
# dispatch thread (because they would block further event delivery). This
|
161
|
+
# method allows clients to know if they're currently executing in the context of an
|
162
|
+
# event.
|
163
|
+
#
|
164
|
+
# @returns [true,false] true if the current thread is the event dispatch thread
|
165
|
+
def event_dispatch_thread?
|
166
|
+
super
|
167
|
+
end
|
168
|
+
|
169
|
+
# DEPRECATED: use the class-level method instead
|
170
|
+
def set_debug_level(val)
|
171
|
+
super
|
172
|
+
end
|
173
|
+
|
174
|
+
# has the underlying connection been closed?
|
175
|
+
def closed?
|
176
|
+
super
|
177
|
+
end
|
178
|
+
|
179
|
+
# is the event delivery system running?
|
180
|
+
def running?
|
181
|
+
super
|
182
|
+
end
|
183
|
+
|
184
|
+
# return the session id of the current connection as an Fixnum
|
185
|
+
def session_id
|
186
|
+
super
|
187
|
+
end
|
188
|
+
|
189
|
+
# Return the passwd portion of this connection's credentials as a String
|
190
|
+
def session_passwd
|
191
|
+
super
|
192
|
+
end
|
193
|
+
|
194
|
+
protected
|
195
|
+
# used during shutdown, awaken the event delivery thread if it's blocked
|
196
|
+
# waiting for the next event
|
197
|
+
def wake_event_loop!
|
198
|
+
super
|
199
|
+
end
|
200
|
+
|
201
|
+
# starts the event delivery subsystem going. after calling this method, running? will be true
|
202
|
+
def setup_dispatch_thread!
|
203
|
+
super
|
204
|
+
end
|
205
|
+
|
206
|
+
# TODO: describe what this does
|
207
|
+
def get_default_global_watcher
|
208
|
+
super
|
209
|
+
end
|
210
|
+
|
211
|
+
def logger
|
212
|
+
Zookeeper.logger
|
213
|
+
end
|
214
|
+
|
215
|
+
def assert_valid_data_size!(data)
|
216
|
+
return if data.nil?
|
217
|
+
|
218
|
+
data = data.to_s
|
219
|
+
if data.length >= 1048576 # one megabyte
|
220
|
+
raise Zookeeper::Exceptions::DataTooLargeException, "data must be smaller than 1 MiB, your data starts with: #{data[0..32].inspect}"
|
221
|
+
end
|
222
|
+
nil
|
223
|
+
end
|
224
|
+
|
225
|
+
private
|
226
|
+
# TODO: Sanitize user mistakes by unregistering watchers from ops that
|
227
|
+
# don't return ZOK (except wexists)? Make users clean up after themselves for now.
|
228
|
+
#
|
229
|
+
# XXX: is this dead code?
|
230
|
+
def unregister_watcher(req_id)
|
231
|
+
@mutex.synchronize {
|
232
|
+
@watcher_reqs.delete(req_id)
|
233
|
+
}
|
234
|
+
end
|
235
|
+
|
236
|
+
# must be supplied by parent class impl.
|
237
|
+
def assert_open
|
238
|
+
super
|
239
|
+
end
|
240
|
+
end # ClientMethods
|
241
|
+
end # Zookeeper
|
data/lib/zookeeper/common.rb
CHANGED
@@ -1,6 +1,8 @@
|
|
1
1
|
require 'zookeeper/exceptions'
|
2
|
+
require 'zookeeper/common/queue_with_pipe'
|
2
3
|
|
3
|
-
module
|
4
|
+
module Zookeeper
|
5
|
+
module Common
|
4
6
|
# sigh, i guess define this here?
|
5
7
|
ZKRB_GLOBAL_CB_REQ = -1
|
6
8
|
|
@@ -27,7 +29,7 @@ protected
|
|
27
29
|
}
|
28
30
|
req_id
|
29
31
|
end
|
30
|
-
|
32
|
+
|
31
33
|
def setup_watcher(req_id, call_opts)
|
32
34
|
@watcher_reqs[req_id] = { :watcher => call_opts[:watcher],
|
33
35
|
:context => call_opts[:watcher_context] }
|
@@ -41,7 +43,7 @@ protected
|
|
41
43
|
#
|
42
44
|
def setup_completion(req_id, meth_name, call_opts)
|
43
45
|
@completion_reqs[req_id] = { :callback => call_opts[:callback],
|
44
|
-
|
46
|
+
:context => call_opts[:callback_context] }
|
45
47
|
end
|
46
48
|
|
47
49
|
def get_watcher(req_id)
|
@@ -118,15 +120,15 @@ protected
|
|
118
120
|
|
119
121
|
is_completion = hash.has_key?(:rc)
|
120
122
|
|
121
|
-
hash[:stat] =
|
122
|
-
hash[:acl] = hash[:acl].map { |acl|
|
123
|
+
hash[:stat] = Zookeeper::Stat.new(hash[:stat]) if hash.has_key?(:stat)
|
124
|
+
hash[:acl] = hash[:acl].map { |acl| Zookeeper::ACLs::ACL.new(acl) } if hash[:acl]
|
123
125
|
|
124
126
|
callback_context = is_completion ? get_completion(hash[:req_id]) : get_watcher(hash[:req_id])
|
125
127
|
|
126
128
|
# When connectivity to the server has been lost (as indicated by SESSION_EVENT)
|
127
129
|
# we want to rerun the callback at a later time when we eventually do have
|
128
130
|
# a valid response.
|
129
|
-
if hash[:type] ==
|
131
|
+
if hash[:type] == Zookeeper::Constants::ZOO_SESSION_EVENT
|
130
132
|
is_completion ? setup_completion(hash[:req_id], callback_context) : setup_watcher(hash[:req_id], callback_context)
|
131
133
|
end
|
132
134
|
if callback_context
|
@@ -148,14 +150,14 @@ protected
|
|
148
150
|
|
149
151
|
def assert_supported_keys(args, supported)
|
150
152
|
unless (args.keys - supported).empty?
|
151
|
-
raise
|
153
|
+
raise Zookeeper::Exceptions::BadArguments, # this heirarchy is kind of retarded
|
152
154
|
"Supported arguments are: #{supported.inspect}, but arguments #{args.keys.inspect} were supplied instead"
|
153
155
|
end
|
154
156
|
end
|
155
157
|
|
156
158
|
def assert_required_keys(args, required)
|
157
159
|
unless (required - args.keys).empty?
|
158
|
-
raise
|
160
|
+
raise Zookeeper::Exceptions::BadArguments,
|
159
161
|
"Required arguments are: #{required.inspect}, but only the arguments #{args.keys.inspect} were supplied."
|
160
162
|
end
|
161
163
|
end
|
@@ -164,11 +166,10 @@ private
|
|
164
166
|
def prettify_event(hash)
|
165
167
|
hash.dup.tap do |h|
|
166
168
|
# pretty up the event display
|
167
|
-
h[:type] =
|
168
|
-
h[:state] =
|
169
|
+
h[:type] = Zookeeper::Constants::EVENT_TYPE_NAMES.fetch(h[:type]) if h[:type]
|
170
|
+
h[:state] = Zookeeper::Constants::STATE_NAMES.fetch(h[:state]) if h[:state]
|
169
171
|
h[:req_id] = :global_session if h[:req_id] == -1
|
170
172
|
end
|
171
173
|
end
|
172
174
|
end
|
173
|
-
|
174
|
-
require 'zookeeper/common/queue_with_pipe'
|
175
|
+
end
|
@@ -1,4 +1,5 @@
|
|
1
|
-
module
|
1
|
+
module Zookeeper
|
2
|
+
module Common
|
2
3
|
# Ceci n'est pas une pipe
|
3
4
|
class QueueWithPipe
|
4
5
|
extend Forwardable
|
@@ -13,14 +14,8 @@ module ZookeeperCommon
|
|
13
14
|
KILL_TOKEN = Object.new unless defined?(KILL_TOKEN)
|
14
15
|
|
15
16
|
def initialize
|
16
|
-
# r, w = IO.pipe
|
17
|
-
# @pipe = { :read => r, :write => w }
|
18
17
|
@queue = Queue.new
|
19
18
|
|
20
|
-
# with the EventMachine client, we want to let EM handle clearing the
|
21
|
-
# event pipe, so we set this to false
|
22
|
-
# @clear_reads_on_pop = true
|
23
|
-
|
24
19
|
@mutex = Mutex.new
|
25
20
|
@closed = false
|
26
21
|
@graceful = false
|
@@ -76,3 +71,4 @@ module ZookeeperCommon
|
|
76
71
|
end
|
77
72
|
end
|
78
73
|
end
|
74
|
+
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
module Zookeeper
|
2
|
+
# @private
|
3
|
+
def self.warn_about_compatability_once!
|
4
|
+
return if @warned_about_compatibility
|
5
|
+
@warned_about_compatibility = true
|
6
|
+
|
7
|
+
warn <<-EOS
|
8
|
+
|
9
|
+
-----------------------------------------------------------------------------
|
10
|
+
|
11
|
+
NOTICE: ZOOKEEPER BACKWARDS COMPATIBILTY EANBLED!!
|
12
|
+
|
13
|
+
THIS WILL NOT BE AUTOMATIC IN 1.1 !!
|
14
|
+
|
15
|
+
There was a major change to the organization of the Zookeeper gem between
|
16
|
+
0.9 and 1.0, breaking backwards compatibility. To ease the transition,
|
17
|
+
|
18
|
+
#{__FILE__}
|
19
|
+
|
20
|
+
is automatically required. This will *not* be the case in 1.1.
|
21
|
+
|
22
|
+
-----------------------------------------------------------------------------
|
23
|
+
EOS
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.warned_about_compatability?
|
27
|
+
!!@warned_about_compatability
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
Zookeeper.warn_about_compatability_once!
|
32
|
+
|
33
|
+
module Zookeeper
|
34
|
+
module Compatibility
|
35
|
+
def clean_backtrace
|
36
|
+
caller[0..-2].reject {|n| n =~ %r%/rspec/|\(eval\)|const_missing% }.map { |n| "\t#{n}" }.join("\n")
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module ZookeeperConstants
|
42
|
+
include Zookeeper::Constants
|
43
|
+
end
|
44
|
+
|
45
|
+
module ZookeeperCallbacks
|
46
|
+
include Zookeeper::Callbacks
|
47
|
+
Callback = Base
|
48
|
+
end
|
49
|
+
|
50
|
+
module ZookeeperExceptions
|
51
|
+
include Zookeeper::Exceptions
|
52
|
+
end
|
53
|
+
|
54
|
+
module ZookeeperStat
|
55
|
+
extend Zookeeper::Compatibility
|
56
|
+
def self.const_missing(sym)
|
57
|
+
if sym == :Stat
|
58
|
+
warn "\nZookeeperStat::Stat is now Zookeeper::Stat, please update your code!\n#{clean_backtrace}"
|
59
|
+
# self.const_set(sym, Zookeeper::Stat)
|
60
|
+
Zookeeper::Stat
|
61
|
+
else
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module ZookeeperACLs
|
68
|
+
extend Zookeeper::Compatibility
|
69
|
+
def self.const_missing(sym)
|
70
|
+
candidates = [Zookeeper::ACLs, Zookeeper::Constants, Zookeeper::ACLs::Constants]
|
71
|
+
|
72
|
+
candidates.each do |candidate|
|
73
|
+
if candidate.const_defined?(sym)
|
74
|
+
warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
|
75
|
+
|
76
|
+
c = candidate.const_get(sym)
|
77
|
+
# self.const_set(sym, c)
|
78
|
+
return c
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
module ZookeeperCommon
|
87
|
+
include Zookeeper::Common
|
88
|
+
extend Zookeeper::Compatibility
|
89
|
+
|
90
|
+
def self.const_missing(sym)
|
91
|
+
candidate = Zookeeper::Common
|
92
|
+
|
93
|
+
if candidate.const_defined?(sym)
|
94
|
+
warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
|
95
|
+
|
96
|
+
candidate.const_get(sym).tap do |c|
|
97
|
+
# self.const_set(sym, c)
|
98
|
+
end
|
99
|
+
else
|
100
|
+
super
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
# module Zookeeper
|
107
|
+
# include ZookeeperConstants
|
108
|
+
# include ZookeeperCallbacks
|
109
|
+
# include ZookeeperExceptions
|
110
|
+
# include ZookeeperCommon
|
111
|
+
# include ZookeeperStat
|
112
|
+
# include ZookeeperACLs
|
113
|
+
# end
|
114
|
+
|
115
|
+
module Zookeeper
|
116
|
+
extend Zookeeper::Compatibility
|
117
|
+
def self.const_missing(sym)
|
118
|
+
candidate =
|
119
|
+
case sym.to_s
|
120
|
+
when /Callback/
|
121
|
+
Zookeeper::Callbacks
|
122
|
+
end
|
123
|
+
|
124
|
+
if candidate.const_defined?(sym)
|
125
|
+
warn "\n#{self.name}::#{sym} is now located in #{candidate}::#{sym}, please update your code!\n#{clean_backtrace}"
|
126
|
+
|
127
|
+
candidate.const_get(sym).tap do |c|
|
128
|
+
# self.const_set(sym, c)
|
129
|
+
end
|
130
|
+
else
|
131
|
+
super
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|