ls4 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/AUTHORS +1 -0
  2. data/COPYING +661 -0
  3. data/ChangeLog +9 -0
  4. data/NOTICE +8 -0
  5. data/README.rdoc +61 -0
  6. data/bin/ls4-cs +3 -0
  7. data/bin/ls4-ds +3 -0
  8. data/bin/ls4-gw +3 -0
  9. data/bin/ls4-standalone +3 -0
  10. data/bin/ls4cmd +3 -0
  11. data/bin/ls4ctl +3 -0
  12. data/bin/ls4rpc +3 -0
  13. data/bin/ls4stat +3 -0
  14. data/bin/ls4top +3 -0
  15. data/lib/ls4/command/cmd.rb +241 -0
  16. data/lib/ls4/command/cs.rb +190 -0
  17. data/lib/ls4/command/ctl.rb +278 -0
  18. data/lib/ls4/command/ds.rb +335 -0
  19. data/lib/ls4/command/gw.rb +256 -0
  20. data/lib/ls4/command/rpc.rb +172 -0
  21. data/lib/ls4/command/standalone.rb +318 -0
  22. data/lib/ls4/command/stat.rb +244 -0
  23. data/lib/ls4/command/top.rb +291 -0
  24. data/lib/ls4/default.rb +26 -0
  25. data/lib/ls4/lib/cclog.rb +220 -0
  26. data/lib/ls4/lib/ebus.rb +553 -0
  27. data/lib/ls4/lib/vbcode.rb +228 -0
  28. data/lib/ls4/logic/fault_detector.rb +212 -0
  29. data/lib/ls4/logic/membership.rb +253 -0
  30. data/lib/ls4/logic/node.rb +66 -0
  31. data/lib/ls4/logic/okey.rb +45 -0
  32. data/lib/ls4/logic/tsv_data.rb +81 -0
  33. data/lib/ls4/logic/weight.rb +166 -0
  34. data/lib/ls4/service/balance.rb +62 -0
  35. data/lib/ls4/service/base.rb +29 -0
  36. data/lib/ls4/service/bus.rb +37 -0
  37. data/lib/ls4/service/config.rb +63 -0
  38. data/lib/ls4/service/config_cs.rb +33 -0
  39. data/lib/ls4/service/config_ds.rb +56 -0
  40. data/lib/ls4/service/config_gw.rb +42 -0
  41. data/lib/ls4/service/data_client.rb +122 -0
  42. data/lib/ls4/service/data_server.rb +168 -0
  43. data/lib/ls4/service/data_server_url.rb +83 -0
  44. data/lib/ls4/service/gateway.rb +375 -0
  45. data/lib/ls4/service/gateway_ro.rb +91 -0
  46. data/lib/ls4/service/gw_http.rb +821 -0
  47. data/lib/ls4/service/heartbeat.rb +182 -0
  48. data/lib/ls4/service/log.rb +81 -0
  49. data/lib/ls4/service/master_select.rb +148 -0
  50. data/lib/ls4/service/mds.rb +292 -0
  51. data/lib/ls4/service/mds_cache.rb +294 -0
  52. data/lib/ls4/service/mds_cache_mem.rb +63 -0
  53. data/lib/ls4/service/mds_cache_memcached.rb +65 -0
  54. data/lib/ls4/service/mds_ha.rb +176 -0
  55. data/lib/ls4/service/mds_memcache.rb +209 -0
  56. data/lib/ls4/service/mds_tc.rb +508 -0
  57. data/lib/ls4/service/mds_tt.rb +472 -0
  58. data/lib/ls4/service/membership.rb +331 -0
  59. data/lib/ls4/service/process.rb +90 -0
  60. data/lib/ls4/service/rpc.rb +50 -0
  61. data/lib/ls4/service/rpc_cs.rb +101 -0
  62. data/lib/ls4/service/rpc_ds.rb +96 -0
  63. data/lib/ls4/service/rpc_gw.rb +255 -0
  64. data/lib/ls4/service/rts.rb +94 -0
  65. data/lib/ls4/service/rts_file.rb +76 -0
  66. data/lib/ls4/service/rts_memory.rb +55 -0
  67. data/lib/ls4/service/slave.rb +132 -0
  68. data/lib/ls4/service/stat.rb +91 -0
  69. data/lib/ls4/service/stat_cs.rb +25 -0
  70. data/lib/ls4/service/stat_ds.rb +40 -0
  71. data/lib/ls4/service/stat_gw.rb +25 -0
  72. data/lib/ls4/service/storage.rb +116 -0
  73. data/lib/ls4/service/storage_dir.rb +201 -0
  74. data/lib/ls4/service/sync.rb +206 -0
  75. data/lib/ls4/service/time_check.rb +80 -0
  76. data/lib/ls4/service/ulog.rb +159 -0
  77. data/lib/ls4/service/ulog_file.rb +398 -0
  78. data/lib/ls4/service/ulog_memory.rb +53 -0
  79. data/lib/ls4/service/weight.rb +134 -0
  80. data/lib/ls4/version.rb +5 -0
  81. data/test/01_add_get_remove.rt +84 -0
  82. data/test/02_read.rt +61 -0
  83. data/test/03_getd_readd.rt +69 -0
  84. data/test/04_version_time.rt +170 -0
  85. data/test/05_version_name.rt +161 -0
  86. data/test/06_http_get_set_remove_1.rt +119 -0
  87. data/test/07_http_get_set_remove_2.rt +116 -0
  88. data/test/08_read_only_time.rt +177 -0
  89. data/test/09_read_only_name.rt +173 -0
  90. data/test/10_http_get_set_remove_3.rt +73 -0
  91. data/test/11_mds_cache_memcached.rt +88 -0
  92. data/test/12_mds_cache_local_memory.rt +86 -0
  93. data/test/13_memcache_mds.rt +84 -0
  94. data/test/14_delete.rt +63 -0
  95. data/test/15_standalone.rt +71 -0
  96. data/test/chukan.rb +516 -0
  97. data/test/common.rb +250 -0
  98. data/test/load_test.rb +79 -0
  99. data/test/load_test_offload.rb +86 -0
  100. metadata +295 -0
@@ -0,0 +1,26 @@
1
+ #
2
+ # LS4
3
+ # Copyright (C) 2010-2011 FURUHASHI Sadayuki
4
+ #
5
+ # This program is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Affero General Public License as
7
+ # published by the Free Software Foundation, either version 3 of the
8
+ # License, or (at your option) any later version.
9
+ #
10
+ # This program is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Affero General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Affero General Public License
16
+ # along with this program. If not, see <http://www.gnu.org/licenses/>.
17
+ #
18
+ module LS4
19
+
20
+
21
+ CS_DEFAULT_PORT = 18700
22
+ DS_DEFAULT_PORT = 18900
23
+ GW_DEFAULT_PORT = 18800
24
+
25
+
26
+ end
@@ -0,0 +1,220 @@
1
+ #
2
+ # CCLog
3
+ # Copyright (c) 2010 FURUHASHI Sadayuki
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+
24
+ class CCLog
25
+ module TTYColor
26
+ RESET = "\033]R"
27
+ CRE = "\033[K"
28
+ CLEAR = "\033c"
29
+ NORMAL = "\033[0;39m"
30
+ RED = "\033[1;31m"
31
+ GREEN = "\033[1;32m"
32
+ YELLOW = "\033[1;33m"
33
+ BLUE = "\033[1;34m"
34
+ MAGENTA = "\033[1;35m"
35
+ CYAN = "\033[1;36m"
36
+ WHITE = "\033[1;37m"
37
+ end
38
+
39
+ LEVEL_TRACE = 0
40
+ LEVEL_DEBUG = 1
41
+ LEVEL_INFO = 2
42
+ LEVEL_WARN = 3
43
+ LEVEL_ERROR = 4
44
+ LEVEL_FATAL = 5
45
+
46
+ def initialize(level = LEVEL_TRACE, out = $stdout)
47
+ if out.tty?
48
+ enable_color
49
+ else
50
+ disable_color
51
+ end
52
+ @level = level
53
+ @out = out
54
+ end
55
+
56
+ def enable_color
57
+ @color_trace = TTYColor::BLUE
58
+ @color_debug = TTYColor::WHITE
59
+ @color_info = TTYColor::GREEN
60
+ @color_warn = TTYColor::YELLOW
61
+ @color_error = TTYColor::MAGENTA
62
+ @color_fatal = TTYColor::RED
63
+ @color_reset = TTYColor::NORMAL
64
+ end
65
+
66
+ def disable_color
67
+ @color_trace = ''
68
+ @color_debug = ''
69
+ @color_info = ''
70
+ @color_warn = ''
71
+ @color_error = ''
72
+ @color_fatal = ''
73
+ @color_reset = ''
74
+ end
75
+
76
+ attr_accessor :out
77
+ attr_accessor :level
78
+
79
+ def on_trace(&block)
80
+ return if @level > LEVEL_TRACE
81
+ block.call if block
82
+ end
83
+
84
+ def trace(*args, &block)
85
+ return if @level > LEVEL_TRACE
86
+ args << block.call if block
87
+ msg = args.join
88
+ puts "#{@color_trace}#{caller_line(1,true)}: #{msg}#{@color_reset}"
89
+ end
90
+ alias TRACE trace
91
+
92
+ def on_debug(&block)
93
+ return if @level > LEVEL_DEBUG
94
+ block.call if block
95
+ end
96
+
97
+ def debug(*args, &block)
98
+ return if @level > LEVEL_DEBUG
99
+ args << block.call if block
100
+ msg = args.join
101
+ puts "#{@color_debug}#{caller_line(1,true)}: #{msg}#{@color_reset}"
102
+ end
103
+ alias DEBUG debug
104
+
105
+ def debug_backtrace(backtrace=$!.backtrace)
106
+ return if @level > LEVEL_DEBUG
107
+ backtrace.each {|msg|
108
+ puts "#{@color_debug}#{caller_line(4,true)}: #{msg}#{@color_reset}"
109
+ }
110
+ nil
111
+ end
112
+
113
+ def on_info(&block)
114
+ return if @level > LEVEL_INFO
115
+ block.call if block
116
+ end
117
+
118
+ def info(*args, &block)
119
+ return if @level > LEVEL_INFO
120
+ args << block.call if block
121
+ msg = args.join
122
+ puts "#{@color_info}#{caller_line(1,true)}: #{msg}#{@color_reset}"
123
+ end
124
+ alias INFO info
125
+
126
+ def info_backtrace(backtrace=$!.backtrace)
127
+ return if @level > LEVEL_INFO
128
+ backtrace.each {|msg|
129
+ puts "#{@color_info}#{caller_line(4,true)}: #{msg}#{@color_reset}"
130
+ }
131
+ nil
132
+ end
133
+
134
+ def on_warn(&block)
135
+ return if @level > LEVEL_WARN
136
+ block.call if block
137
+ end
138
+
139
+ def warn(*args, &block)
140
+ return if @level > LEVEL_WARN
141
+ args << block.call if block
142
+ msg = args.join
143
+ puts "#{@color_warn}#{caller_line(1)}: #{msg}#{@color_reset}"
144
+ end
145
+ alias WARN warn
146
+
147
+ def warn_backtrace(backtrace=$!.backtrace)
148
+ return if @level > LEVEL_WARN
149
+ backtrace.each {|msg|
150
+ puts "#{@color_warn}#{caller_line(4)}: #{msg}#{@color_reset}"
151
+ }
152
+ nil
153
+ end
154
+
155
+ def on_error(&block)
156
+ return if @level > LEVEL_ERROR
157
+ block.call if block
158
+ end
159
+
160
+ def error(*args, &block)
161
+ return if @level > LEVEL_ERROR
162
+ args << block.call if block
163
+ msg = args.join
164
+ puts "#{@color_error}#{caller_line(1)}: #{msg}#{@color_reset}"
165
+ end
166
+ alias ERROR error
167
+
168
+ def error_backtrace(backtrace=$!.backtrace)
169
+ return if @level > LEVEL_ERROR
170
+ backtrace.each {|msg|
171
+ puts "#{@color_error}#{caller_line(4)}: #{msg}#{@color_reset}"
172
+ }
173
+ nil
174
+ end
175
+
176
+ def on_fatal(&block)
177
+ return if @level > LEVEL_FATAL
178
+ block.call if block
179
+ end
180
+
181
+ def fatal(*args, &block)
182
+ return if @level > LEVEL_FATAL
183
+ args << block.call if block
184
+ msg = args.join
185
+ puts "#{@color_fatal}#{caller_line(1)}: #{msg}#{@color_reset}"
186
+ end
187
+ alias FATAL fatal
188
+
189
+ def fatal_backtrace(backtrace=$!.backtrace)
190
+ return if @level > LEVEL_FATAL
191
+ backtrace.each {|msg|
192
+ puts "#{@color_fatal}#{caller_line(4)}: #{msg}#{@color_reset}"
193
+ }
194
+ nil
195
+ end
196
+
197
+ def puts(msg)
198
+ @out.puts(msg)
199
+ @out.flush
200
+ msg
201
+ rescue
202
+ # FIXME
203
+ nil
204
+ end
205
+
206
+ private
207
+ def caller_line(level, debug = false)
208
+ line = caller(level+1)[0]
209
+ if match = /^(.+?):(\d+)(?::in `(.*)')?/.match(line)
210
+ if debug
211
+ "#{match[1]}:#{match[2]}:#{match[3]}"
212
+ else
213
+ "#{match[1]}:#{match[2]}"
214
+ end
215
+ else
216
+ ""
217
+ end
218
+ end
219
+ end
220
+
@@ -0,0 +1,553 @@
1
+ #
2
+ # EventBus
3
+ # Copyright (c) 2010 FURUHASHI Sadayuki
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ # of this software and associated documentation files (the "Software"), to deal
7
+ # in the Software without restriction, including without limitation the rights
8
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ # copies of the Software, and to permit persons to whom the Software is
10
+ # furnished to do so, subject to the following conditions:
11
+ #
12
+ # The above copyright notice and this permission notice shall be included in
13
+ # all copies or substantial portions of the Software.
14
+ #
15
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ # THE SOFTWARE.
22
+ #
23
+ require 'forwardable'
24
+ require 'singleton'
25
+
26
+ class EventBus
27
+ def self.bus(&block)
28
+ Class.new(Bus, &block)
29
+ end
30
+
31
+ class SlotError < NameError
32
+ end
33
+
34
+ class Slot
35
+ end
36
+
37
+ class CallSlot < Slot
38
+ def initialize(bus, name)
39
+ @bus = bus
40
+ @name = name
41
+ @method = nil
42
+ end
43
+
44
+ attr_reader :method
45
+ attr_reader :name
46
+
47
+ def connect(method=nil, &block)
48
+ if @method
49
+ raise ::EventBus::SlotError.new("slot already connected", @name)
50
+ end
51
+ method ||= block
52
+ @method = method
53
+ @bus
54
+ end
55
+
56
+ def disconnect!
57
+ @method = nil
58
+ @bus
59
+ end
60
+
61
+ def call(*args, &block)
62
+ unless @method
63
+ raise ::EventBus::SlotError.new("slot not connected", @name)
64
+ end
65
+ @bus.ebus_call_log(@method, args, &block)
66
+ @method.call(*args, &block)
67
+ end
68
+
69
+ alias signal call
70
+
71
+ def to_s
72
+ m = @method.inspect[/\#\<[^\:]*\:\s?(.+)\>/, 1]
73
+ unless m
74
+ m = m.to_s
75
+ end
76
+ "#<slot :#{@name} => #{m}>"
77
+ end
78
+ end
79
+
80
+ class SignalSlot < Slot
81
+ def initialize(bus, name)
82
+ @bus = bus
83
+ @name = name
84
+ @methods = []
85
+ end
86
+
87
+ attr_reader :methods
88
+ attr_reader :name
89
+
90
+ def connect(method=nil, &block)
91
+ method ||= block
92
+ unless @methods.include?(method)
93
+ @methods << method
94
+ end
95
+ @bus
96
+ end
97
+
98
+ def disconnect!
99
+ @methods.clear
100
+ @bus
101
+ end
102
+
103
+ def call(*args, &block)
104
+ @bus.ebus_signal_log(methods, args, &block)
105
+ methods.each {|block|
106
+ begin
107
+ block.call(*args, &block)
108
+ rescue => err
109
+ @bus.ebus_signal_error(err)
110
+ end
111
+ }
112
+ nil
113
+ end
114
+
115
+ alias signal call
116
+
117
+ def to_s
118
+ methods = @methods.map {|m|
119
+ if s = m.inspect[/\#\<[^\:]*\:\s?(.+)\>/, 1]
120
+ s
121
+ else
122
+ m.to_s
123
+ end
124
+ }
125
+ "#<slot :#{@name} => [#{methods.join(',')}]>"
126
+ end
127
+ end
128
+
129
+ def self.method2const(mname)
130
+ mname = mname.to_s
131
+ mname = mname.gsub(/\?$/, '__p')
132
+ mname = mname.gsub(/\!$/, '__bang')
133
+ mname = mname.gsub(/\=$/, '__eq')
134
+ mname = mname.gsub(/^\[\]/, '__at')
135
+ mname
136
+ end
137
+
138
+ module DeclarerBase
139
+ def call_slot(*slots)
140
+ slots.each {|slot|
141
+ slot = slot.to_sym
142
+ s = CallSlot.new(self, slot)
143
+ c = ::EventBus.method2const(slot)
144
+ const = :"EBUS_SLOT_#{c}"
145
+ ebus_def_slot_delegators(const, s)
146
+ }
147
+ self
148
+ end
149
+
150
+ def signal_slot(*slots)
151
+ slots.each {|slot|
152
+ slot = slot.to_sym
153
+ s = SignalSlot.new(self, slot)
154
+ c = ::EventBus.method2const(slot)
155
+ const = :"EBUS_SLOT_#{c}"
156
+ ebus_def_slot_delegators(const, s)
157
+ }
158
+ self
159
+ end
160
+
161
+ module Methods
162
+ def connect(slot, method)
163
+ slot = slot.to_sym
164
+ __send__("connect_#{slot}", method)
165
+ end
166
+
167
+ def ebus_call_log(method, args, &block)
168
+ end
169
+
170
+ def ebus_signal_log(methods, args, &block)
171
+ end
172
+
173
+ def ebus_signal_error(err)
174
+ end
175
+
176
+ def ebus_all_slots
177
+ slots = []
178
+ (class<<self;self;end).module_eval do
179
+ constants.each {|const|
180
+ if const.to_s =~ /^EBUS_SLOT_.*/
181
+ slots << const_get(const)
182
+ end
183
+ }
184
+ end
185
+ slots
186
+ end
187
+
188
+ def ebus_call_slots
189
+ ebus_all_slots.select {|s|
190
+ s.is_a?(CallSlot)
191
+ }
192
+ end
193
+
194
+ def ebus_signal_slots
195
+ ebus_all_slots.select {|s|
196
+ s.is_a?(SignalSlot)
197
+ }
198
+ end
199
+ end
200
+ end
201
+
202
+ module BusMixin
203
+ include DeclarerBase
204
+ include DeclarerBase::Methods
205
+ include ::SingleForwardable
206
+
207
+ def ebus_all_slots
208
+ slots = []
209
+ constants.each {|const|
210
+ if const.to_s =~ /^EBUS_SLOT_.*/
211
+ slots << const_get(const)
212
+ end
213
+ }
214
+ slots
215
+ end
216
+
217
+ def ebus_disconnect!
218
+ constants.each {|const|
219
+ if const.to_s =~ /^EBUS_SLOT_.*/
220
+ slot = const_get(const)
221
+ slot.disconnect!
222
+ end
223
+ }
224
+ nil
225
+ end
226
+
227
+ private
228
+ def ebus_def_slot_delegators(const, s)
229
+ const_set(const, s)
230
+ def_delegator("self::#{const}", :call, s.name)
231
+ def_delegator("self::#{const}", :connect, "connect_#{s.name}")
232
+ end
233
+ end
234
+
235
+ class Bus
236
+ extend BusMixin
237
+ end
238
+
239
+
240
+ module ObjectMixin
241
+ include ::Forwardable
242
+
243
+ include DeclarerBase
244
+
245
+ def self.extended(mod)
246
+ methods = DeclarerBase::Methods
247
+ mod.instance_eval do
248
+ include methods
249
+ end
250
+ end
251
+
252
+ private
253
+ def ebus_def_slot_delegators(const, s)
254
+ const_set(const, s)
255
+ def_delegator(const, :call, s.name)
256
+ def_delegator(const, :connect, "connect_#{s.name}")
257
+ end
258
+ end
259
+
260
+ class Object
261
+ extend ObjectMixin
262
+ end
263
+
264
+
265
+ module SingletonMixin
266
+ include BusMixin
267
+
268
+ def self.extended(mod)
269
+ mod.instance_eval do
270
+ include ::Singleton
271
+ end
272
+ end
273
+
274
+ class ConnectEntry
275
+ def initialize(bus, slot, mname)
276
+ @bus = bus
277
+ @slot = slot
278
+ @mname = mname
279
+ end
280
+ attr_reader :bus
281
+ attr_reader :slot
282
+ attr_reader :mname
283
+ end
284
+
285
+ def ebus_connect(bus, *slots)
286
+ slots.each {|slot|
287
+ case slot
288
+ when Symbol
289
+ ebus_connect_const_set(bus, slot, slot)
290
+ when String
291
+ ebus_connect_const_set(bus, slot.to_sym, slot.to_sym)
292
+ when Hash
293
+ slot.each_pair {|k,v|
294
+ ebus_connect_const_set(bus, k.to_sym, v.to_sym)
295
+ }
296
+ else
297
+ raise "slot name must be a Symbol: #{slot.inspect}"
298
+ end
299
+ }
300
+ end
301
+
302
+ alias connect ebus_connect
303
+
304
+ def ebus_bind!
305
+ constants.each {|const|
306
+ if const.to_s =~ /^EBUS_CONNECT_.*/
307
+ e = const_get(const)
308
+ if e.bus.is_a?(Symbol)
309
+ bus = eval("#{e.bus}")
310
+ else
311
+ bus = e.bus
312
+ end
313
+ bus.__send__("connect_#{e.slot}", instance.method(e.mname))
314
+ end
315
+ }
316
+ self
317
+ end
318
+
319
+ alias bind! ebus_bind!
320
+
321
+ private
322
+ def ebus_connect_const_set(bus, slot, mname)
323
+ e = ConnectEntry.new(bus, slot, mname)
324
+ c = ::EventBus.method2const(slot)
325
+ const_set(:"EBUS_CONNECT_#{c.object_id}_#{c}", e)
326
+ end
327
+ end
328
+
329
+ class Singleton
330
+ extend SingletonMixin
331
+ end
332
+ end
333
+
334
+
335
+ if $0 == __FILE__
336
+ def assert(boolean)
337
+ unless boolean
338
+ raise "test failed"
339
+ end
340
+ end
341
+
342
+ def dump_slots(bus)
343
+ if bus.is_a?(Class)
344
+ puts bus.name
345
+ else
346
+ puts bus.class.name
347
+ end
348
+ bus.ebus_all_slots.each {|s|
349
+ puts " #{s}"
350
+ }
351
+ end
352
+
353
+ module Test01
354
+ Users = EventBus.bus do
355
+ call_slot :add
356
+ call_slot :get
357
+ call_slot :added?
358
+ signal_slot :user_added
359
+ end
360
+
361
+ class UserService < EventBus::Singleton
362
+ def initialize
363
+ @db = {}
364
+ end
365
+
366
+ def add(uid, name)
367
+ @db[uid] = name
368
+ Users.user_added(uid)
369
+ name
370
+ end
371
+
372
+ def get(uid)
373
+ @db[uid]
374
+ end
375
+
376
+ def added?(uid)
377
+ @db.has_key?(uid)
378
+ end
379
+
380
+ connect Users, :add, :get, :added?
381
+ end
382
+
383
+ class UserCounter < EventBus::Singleton
384
+ def initialize
385
+ @count = 0
386
+ end
387
+
388
+ def on_add_user(uid)
389
+ @count += 1
390
+ end
391
+
392
+ attr_reader :count
393
+
394
+ connect Users, :user_added => :on_add_user
395
+
396
+ call_slot :get_count
397
+ connect self, :get_count => :count
398
+ end
399
+
400
+ UserService.bind!
401
+ UserCounter.bind!
402
+
403
+ dump_slots(Users)
404
+ dump_slots(UserCounter)
405
+
406
+ Users.add(0, "frsyuki")
407
+ Users.add(1, "viver")
408
+ assert Users.get(0) == "frsyuki"
409
+ assert Users.get(1) == "viver"
410
+ assert Users.added?(0) == true
411
+ assert Users.added?(1) == true
412
+ assert UserCounter.instance.count == 2
413
+ assert UserCounter.get_count == 2
414
+ end
415
+
416
+
417
+ module Test02
418
+ class Users < EventBus::Bus
419
+ call_slot :add
420
+ call_slot :get
421
+ call_slot :added?
422
+ signal_slot :user_added
423
+ end
424
+
425
+ class UserService
426
+ extend EventBus::SingletonMixin
427
+
428
+ def initialize
429
+ @db = {}
430
+ end
431
+
432
+ def add(uid, name)
433
+ @db[uid] = name
434
+ Users.user_added(uid)
435
+ name
436
+ end
437
+
438
+ def get(uid)
439
+ @db[uid]
440
+ end
441
+
442
+ def added?(uid)
443
+ @db.has_key?(uid)
444
+ end
445
+
446
+ connect Users, :add, :get, :added?
447
+ end
448
+
449
+ class UserCounter
450
+ extend EventBus::BusMixin
451
+
452
+ def initialize
453
+ @count = 0
454
+ end
455
+
456
+ def on_add_user(uid)
457
+ @count += 1
458
+ end
459
+
460
+ attr_reader :count
461
+ end
462
+
463
+ ucouter = UserCounter.new
464
+
465
+ UserService.bind!
466
+ Users.connect(:user_added, ucouter.method(:on_add_user))
467
+
468
+ dump_slots(Users)
469
+
470
+ Users.add(0, "frsyuki")
471
+ Users.add(1, "viver")
472
+ assert Users.get(0) == "frsyuki"
473
+ assert Users.get(1) == "viver"
474
+ assert Users.added?(0) == true
475
+ assert Users.added?(1) == true
476
+ assert ucouter.count == 2
477
+ end
478
+
479
+
480
+ module Test03
481
+ class Button < EventBus::Object
482
+ def press
483
+ on_press
484
+ end
485
+
486
+ call_slot :on_press
487
+ end
488
+
489
+ class App
490
+ def initialize
491
+ @pressed = false
492
+ end
493
+
494
+ def draw
495
+ a = Button.new
496
+ a.connect(:on_press, method(:on_press))
497
+ dump_slots(a)
498
+ a
499
+ end
500
+
501
+ def on_press
502
+ @pressed = true
503
+ end
504
+
505
+ attr_reader :pressed
506
+ end
507
+
508
+ app = App.new
509
+ b = app.draw
510
+ b.on_press
511
+
512
+ assert app.pressed == true
513
+ end
514
+
515
+
516
+ module Test04
517
+ class Button
518
+ extend EventBus::ObjectMixin
519
+
520
+ def press
521
+ on_press
522
+ end
523
+
524
+ call_slot :on_press
525
+ end
526
+
527
+ class App
528
+ def initialize
529
+ @pressed = false
530
+ end
531
+
532
+ def draw
533
+ a = Button.new
534
+ a.connect(:on_press, method(:on_press))
535
+ dump_slots(a)
536
+ a
537
+ end
538
+
539
+ def on_press
540
+ @pressed = true
541
+ end
542
+
543
+ attr_reader :pressed
544
+ end
545
+
546
+ app = App.new
547
+ b = app.draw
548
+ b.on_press
549
+
550
+ assert app.pressed == true
551
+ end
552
+ end
553
+