ls4 0.9.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.
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
+