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.
- data/AUTHORS +1 -0
- data/COPYING +661 -0
- data/ChangeLog +9 -0
- data/NOTICE +8 -0
- data/README.rdoc +61 -0
- data/bin/ls4-cs +3 -0
- data/bin/ls4-ds +3 -0
- data/bin/ls4-gw +3 -0
- data/bin/ls4-standalone +3 -0
- data/bin/ls4cmd +3 -0
- data/bin/ls4ctl +3 -0
- data/bin/ls4rpc +3 -0
- data/bin/ls4stat +3 -0
- data/bin/ls4top +3 -0
- data/lib/ls4/command/cmd.rb +241 -0
- data/lib/ls4/command/cs.rb +190 -0
- data/lib/ls4/command/ctl.rb +278 -0
- data/lib/ls4/command/ds.rb +335 -0
- data/lib/ls4/command/gw.rb +256 -0
- data/lib/ls4/command/rpc.rb +172 -0
- data/lib/ls4/command/standalone.rb +318 -0
- data/lib/ls4/command/stat.rb +244 -0
- data/lib/ls4/command/top.rb +291 -0
- data/lib/ls4/default.rb +26 -0
- data/lib/ls4/lib/cclog.rb +220 -0
- data/lib/ls4/lib/ebus.rb +553 -0
- data/lib/ls4/lib/vbcode.rb +228 -0
- data/lib/ls4/logic/fault_detector.rb +212 -0
- data/lib/ls4/logic/membership.rb +253 -0
- data/lib/ls4/logic/node.rb +66 -0
- data/lib/ls4/logic/okey.rb +45 -0
- data/lib/ls4/logic/tsv_data.rb +81 -0
- data/lib/ls4/logic/weight.rb +166 -0
- data/lib/ls4/service/balance.rb +62 -0
- data/lib/ls4/service/base.rb +29 -0
- data/lib/ls4/service/bus.rb +37 -0
- data/lib/ls4/service/config.rb +63 -0
- data/lib/ls4/service/config_cs.rb +33 -0
- data/lib/ls4/service/config_ds.rb +56 -0
- data/lib/ls4/service/config_gw.rb +42 -0
- data/lib/ls4/service/data_client.rb +122 -0
- data/lib/ls4/service/data_server.rb +168 -0
- data/lib/ls4/service/data_server_url.rb +83 -0
- data/lib/ls4/service/gateway.rb +375 -0
- data/lib/ls4/service/gateway_ro.rb +91 -0
- data/lib/ls4/service/gw_http.rb +821 -0
- data/lib/ls4/service/heartbeat.rb +182 -0
- data/lib/ls4/service/log.rb +81 -0
- data/lib/ls4/service/master_select.rb +148 -0
- data/lib/ls4/service/mds.rb +292 -0
- data/lib/ls4/service/mds_cache.rb +294 -0
- data/lib/ls4/service/mds_cache_mem.rb +63 -0
- data/lib/ls4/service/mds_cache_memcached.rb +65 -0
- data/lib/ls4/service/mds_ha.rb +176 -0
- data/lib/ls4/service/mds_memcache.rb +209 -0
- data/lib/ls4/service/mds_tc.rb +508 -0
- data/lib/ls4/service/mds_tt.rb +472 -0
- data/lib/ls4/service/membership.rb +331 -0
- data/lib/ls4/service/process.rb +90 -0
- data/lib/ls4/service/rpc.rb +50 -0
- data/lib/ls4/service/rpc_cs.rb +101 -0
- data/lib/ls4/service/rpc_ds.rb +96 -0
- data/lib/ls4/service/rpc_gw.rb +255 -0
- data/lib/ls4/service/rts.rb +94 -0
- data/lib/ls4/service/rts_file.rb +76 -0
- data/lib/ls4/service/rts_memory.rb +55 -0
- data/lib/ls4/service/slave.rb +132 -0
- data/lib/ls4/service/stat.rb +91 -0
- data/lib/ls4/service/stat_cs.rb +25 -0
- data/lib/ls4/service/stat_ds.rb +40 -0
- data/lib/ls4/service/stat_gw.rb +25 -0
- data/lib/ls4/service/storage.rb +116 -0
- data/lib/ls4/service/storage_dir.rb +201 -0
- data/lib/ls4/service/sync.rb +206 -0
- data/lib/ls4/service/time_check.rb +80 -0
- data/lib/ls4/service/ulog.rb +159 -0
- data/lib/ls4/service/ulog_file.rb +398 -0
- data/lib/ls4/service/ulog_memory.rb +53 -0
- data/lib/ls4/service/weight.rb +134 -0
- data/lib/ls4/version.rb +5 -0
- data/test/01_add_get_remove.rt +84 -0
- data/test/02_read.rt +61 -0
- data/test/03_getd_readd.rt +69 -0
- data/test/04_version_time.rt +170 -0
- data/test/05_version_name.rt +161 -0
- data/test/06_http_get_set_remove_1.rt +119 -0
- data/test/07_http_get_set_remove_2.rt +116 -0
- data/test/08_read_only_time.rt +177 -0
- data/test/09_read_only_name.rt +173 -0
- data/test/10_http_get_set_remove_3.rt +73 -0
- data/test/11_mds_cache_memcached.rt +88 -0
- data/test/12_mds_cache_local_memory.rt +86 -0
- data/test/13_memcache_mds.rt +84 -0
- data/test/14_delete.rt +63 -0
- data/test/15_standalone.rt +71 -0
- data/test/chukan.rb +516 -0
- data/test/common.rb +250 -0
- data/test/load_test.rb +79 -0
- data/test/load_test_offload.rb +86 -0
- metadata +295 -0
data/lib/ls4/default.rb
ADDED
@@ -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
|
+
|
data/lib/ls4/lib/ebus.rb
ADDED
@@ -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
|
+
|