erlectricity 0.1.0 → 0.2.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/CONTRIBUTORS +2 -0
- data/History.txt +1 -0
- data/Manifest.txt +5 -1
- data/Rakefile +1 -1
- data/examples/gruff/gruff_provider.rb +11 -11
- data/examples/tinderl/tinderl.erl +4 -0
- data/examples/tinderl/tinderl.rb +10 -6
- data/ext/decoder.c +389 -0
- data/ext/extconf.rb +11 -0
- data/lib/erlectricity.rb +11 -2
- data/lib/erlectricity/condition.rb +24 -21
- data/lib/erlectricity/conditions/hash.rb +2 -3
- data/lib/erlectricity/conditions/static.rb +2 -6
- data/lib/erlectricity/conditions/type.rb +3 -5
- data/lib/erlectricity/encoder.rb +1 -1
- data/lib/erlectricity/matcher.rb +6 -28
- data/lib/erlectricity/receiver.rb +9 -4
- data/lib/erlectricity/types/list.rb +1 -0
- data/lib/erlectricity/version.rb +1 -1
- data/test/condition_spec.rb +11 -16
- data/test/decode_spec.rb +1 -11
- data/test/encode_spec.rb +7 -0
- data/test/matcher_spec.rb +0 -4
- data/test/receiver_spec.rb +23 -23
- data/test/test_helper.rb +6 -1
- metadata +16 -8
- data/lib/erlectricity/match_context.rb +0 -20
data/CONTRIBUTORS
ADDED
data/History.txt
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
|
data/Manifest.txt
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
CONTRIBUTORS
|
2
|
+
History.txt
|
1
3
|
Manifest.txt
|
2
4
|
README.txt
|
3
5
|
Rakefile
|
@@ -8,6 +10,8 @@ examples/gruff/stat_run.erl
|
|
8
10
|
examples/gruff/stat_writer.erl
|
9
11
|
examples/tinderl/tinderl.erl
|
10
12
|
examples/tinderl/tinderl.rb
|
13
|
+
ext/decoder.c
|
14
|
+
ext/extconf.rb
|
11
15
|
lib/erlectricity.rb
|
12
16
|
lib/erlectricity/condition.rb
|
13
17
|
lib/erlectricity/conditions/hash.rb
|
@@ -19,11 +23,11 @@ lib/erlectricity/encoder.rb
|
|
19
23
|
lib/erlectricity/errors/decode_error.rb
|
20
24
|
lib/erlectricity/errors/encode_error.rb
|
21
25
|
lib/erlectricity/errors/erlectricity_error.rb
|
22
|
-
lib/erlectricity/match_context.rb
|
23
26
|
lib/erlectricity/matcher.rb
|
24
27
|
lib/erlectricity/port.rb
|
25
28
|
lib/erlectricity/receiver.rb
|
26
29
|
lib/erlectricity/types/function.rb
|
30
|
+
lib/erlectricity/types/list.rb
|
27
31
|
lib/erlectricity/types/new_function.rb
|
28
32
|
lib/erlectricity/types/new_reference.rb
|
29
33
|
lib/erlectricity/types/pid.rb
|
data/Rakefile
CHANGED
@@ -49,7 +49,7 @@ hoe = Hoe.new(GEM_NAME, VERS) do |p|
|
|
49
49
|
|
50
50
|
# == Optional
|
51
51
|
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
|
52
|
-
|
52
|
+
p.extra_deps = [ ] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
|
53
53
|
#p.spec_extras = {} # A hash of extra values to set in the gemspec.
|
54
54
|
end
|
55
55
|
|
@@ -1,36 +1,36 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + "/../../lib/")
|
2
|
-
require 'rubygems'
|
3
2
|
require 'erlectricity'
|
3
|
+
require 'rubygems'
|
4
4
|
require 'gruff'
|
5
5
|
|
6
|
-
receive do
|
6
|
+
receive do |f|
|
7
7
|
|
8
8
|
|
9
9
|
|
10
|
-
|
10
|
+
f.when(:plot, String, Symbol, String) do |name, style, font|
|
11
11
|
graph = Gruff.const_get(style).new
|
12
12
|
graph.title = name
|
13
13
|
graph.font = font
|
14
14
|
graph.legend_font_size = 10
|
15
15
|
|
16
16
|
|
17
|
-
receive do
|
18
|
-
|
17
|
+
f.receive do |g|
|
18
|
+
g.when(:data, Symbol, Array) do |name, points|
|
19
19
|
graph.data name, points
|
20
|
-
receive_loop
|
20
|
+
g.receive_loop
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
g.when(:labels, Erl.hash) do |label_data|
|
24
24
|
graph.labels = label_data
|
25
|
-
receive_loop
|
25
|
+
g.receive_loop
|
26
26
|
end
|
27
27
|
|
28
|
-
|
28
|
+
g.when(:end){ :ok }
|
29
29
|
end
|
30
30
|
|
31
31
|
|
32
|
-
send! :result, graph.to_blob
|
33
|
-
receive_loop
|
32
|
+
f.send! :result, graph.to_blob
|
33
|
+
f.receive_loop
|
34
34
|
end
|
35
35
|
|
36
36
|
end
|
@@ -12,7 +12,11 @@ start(Domain, Email, Password, Room) ->
|
|
12
12
|
|
13
13
|
stop() -> tinderl ! stop.
|
14
14
|
|
15
|
+
|
16
|
+
speak(String) when is_list(String) -> speak(list_to_binary(String));
|
15
17
|
speak(String) when is_binary(String) -> tinderl ! {speak, self(), String}.
|
18
|
+
|
19
|
+
paste(String) when is_list(String) -> speak(list_to_binary(String));
|
16
20
|
paste(String) when is_binary(String) -> tinderl ! {paste, self(), String}.
|
17
21
|
|
18
22
|
port_loop(Port) ->
|
data/examples/tinderl/tinderl.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + "/../../lib/")
|
2
|
-
require 'rubygems'
|
3
2
|
require 'erlectricity'
|
3
|
+
require 'rubygems'
|
4
4
|
require 'tinder'
|
5
5
|
|
6
6
|
domain, email, password, room_name = *ARGV
|
@@ -8,15 +8,19 @@ campfire = Tinder::Campfire.new domain
|
|
8
8
|
campfire.login email, password
|
9
9
|
room = campfire.find_room_by_name room_name
|
10
10
|
|
11
|
-
receive do
|
12
|
-
|
11
|
+
receive do |f|
|
12
|
+
f.when(:speak, Any) do |comment|
|
13
13
|
room.speak comment
|
14
|
-
receive_loop
|
14
|
+
f.receive_loop
|
15
15
|
end
|
16
16
|
|
17
|
-
|
17
|
+
f.when(:paste, Any) do |comment|
|
18
18
|
room.paste comment
|
19
|
-
receive_loop
|
19
|
+
f.receive_loop
|
20
|
+
end
|
21
|
+
|
22
|
+
f.when(Any) do |obj|
|
23
|
+
STDERR.write obj.inspect
|
20
24
|
end
|
21
25
|
end
|
22
26
|
|
data/ext/decoder.c
ADDED
@@ -0,0 +1,389 @@
|
|
1
|
+
#include "ruby.h"
|
2
|
+
#include <string.h>
|
3
|
+
|
4
|
+
#define ERL_VERSION 131
|
5
|
+
#define ERL_SMALL_INT 97
|
6
|
+
#define ERL_INT 98
|
7
|
+
#define ERL_SMALL_BIGNUM 110
|
8
|
+
#define ERL_LARGE_BIGNUM 111
|
9
|
+
#define ERL_FLOAT 99
|
10
|
+
#define ERL_ATOM 100
|
11
|
+
#define ERL_REF 101
|
12
|
+
#define ERL_NEW_REF 114
|
13
|
+
#define ERL_PORT 102
|
14
|
+
#define ERL_PID 103
|
15
|
+
#define ERL_SMALL_TUPLE 104
|
16
|
+
#define ERL_LARGE_TUPLE 105
|
17
|
+
#define ERL_NIL 106
|
18
|
+
#define ERL_STRING 107
|
19
|
+
#define ERL_LIST 108
|
20
|
+
#define ERL_BIN 109
|
21
|
+
#define ERL_FUN 117
|
22
|
+
#define ERL_NEW_FUN 112
|
23
|
+
|
24
|
+
static VALUE mErlectricity;
|
25
|
+
static VALUE cDecoder;
|
26
|
+
void Init_decoder();
|
27
|
+
|
28
|
+
VALUE method_read_any_from(VALUE klass, VALUE rString);
|
29
|
+
|
30
|
+
VALUE read_any_raw(unsigned char **pData);
|
31
|
+
|
32
|
+
// checkers
|
33
|
+
|
34
|
+
void check_int(int num) {
|
35
|
+
char buf[17];
|
36
|
+
sprintf(buf, "%u", num);
|
37
|
+
rb_raise(rb_eStandardError, buf);
|
38
|
+
}
|
39
|
+
|
40
|
+
void check_str(char *str) {
|
41
|
+
rb_raise(rb_eStandardError, str);
|
42
|
+
}
|
43
|
+
|
44
|
+
// string peekers/readers
|
45
|
+
|
46
|
+
unsigned int peek_1(unsigned char **pData) {
|
47
|
+
return (unsigned int) **pData;
|
48
|
+
}
|
49
|
+
|
50
|
+
unsigned int peek_2(unsigned char **pData) {
|
51
|
+
return (unsigned int) ((**pData << 8) + *(*pData + 1));
|
52
|
+
}
|
53
|
+
|
54
|
+
unsigned int peek_4(unsigned char **pData) {
|
55
|
+
return (unsigned int) ((**pData << 24) + (*(*pData + 1) << 16) + (*(*pData + 2) << 8) + *(*pData + 3));
|
56
|
+
}
|
57
|
+
|
58
|
+
unsigned int read_1(unsigned char **pData) {
|
59
|
+
unsigned int val = peek_1(pData);
|
60
|
+
*pData += 1;
|
61
|
+
return val;
|
62
|
+
}
|
63
|
+
|
64
|
+
unsigned int read_2(unsigned char **pData) {
|
65
|
+
unsigned int val = peek_2(pData);
|
66
|
+
*pData += 2;
|
67
|
+
return val;
|
68
|
+
}
|
69
|
+
|
70
|
+
unsigned int read_4(unsigned char **pData) {
|
71
|
+
unsigned int val = peek_4(pData);
|
72
|
+
*pData += 4;
|
73
|
+
return val;
|
74
|
+
}
|
75
|
+
|
76
|
+
// tuples, lists
|
77
|
+
|
78
|
+
VALUE read_small_tuple(unsigned char **pData) {
|
79
|
+
if(read_1(pData) != ERL_SMALL_TUPLE) {
|
80
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a small tuple");
|
81
|
+
}
|
82
|
+
|
83
|
+
int arity = read_1(pData);
|
84
|
+
|
85
|
+
VALUE array = rb_ary_new2(arity);
|
86
|
+
|
87
|
+
int i;
|
88
|
+
for(i = 0; i < arity; ++i) {
|
89
|
+
rb_ary_store(array, i, read_any_raw(pData));
|
90
|
+
}
|
91
|
+
|
92
|
+
return array;
|
93
|
+
}
|
94
|
+
|
95
|
+
VALUE read_large_tuple(unsigned char **pData) {
|
96
|
+
if(read_1(pData) != ERL_LARGE_TUPLE) {
|
97
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a large tuple");
|
98
|
+
}
|
99
|
+
|
100
|
+
int arity = read_4(pData);
|
101
|
+
|
102
|
+
VALUE array = rb_ary_new2(arity);
|
103
|
+
|
104
|
+
int i;
|
105
|
+
for(i = 0; i < arity; ++i) {
|
106
|
+
rb_ary_store(array, i, read_any_raw(pData));
|
107
|
+
}
|
108
|
+
|
109
|
+
return array;
|
110
|
+
}
|
111
|
+
|
112
|
+
VALUE read_list(unsigned char **pData) {
|
113
|
+
if(read_1(pData) != ERL_LIST) {
|
114
|
+
rb_raise(rb_eStandardError, "Invalid Type, not an erlang list");
|
115
|
+
}
|
116
|
+
|
117
|
+
int size = read_4(pData);
|
118
|
+
|
119
|
+
VALUE array = rb_ary_new2(size);
|
120
|
+
|
121
|
+
int i;
|
122
|
+
for(i = 0; i < size; ++i) {
|
123
|
+
rb_ary_store(array, i, read_any_raw(pData));
|
124
|
+
}
|
125
|
+
|
126
|
+
return array;
|
127
|
+
}
|
128
|
+
|
129
|
+
// primitives
|
130
|
+
|
131
|
+
void read_string_raw(unsigned char *dest, unsigned char **pData, int length) {
|
132
|
+
memcpy((char *) dest, (char *) *pData, length);
|
133
|
+
*(dest + length) = (unsigned char) 0;
|
134
|
+
*pData += length;
|
135
|
+
}
|
136
|
+
|
137
|
+
VALUE read_bin(unsigned char **pData) {
|
138
|
+
if(read_1(pData) != ERL_BIN) {
|
139
|
+
rb_raise(rb_eStandardError, "Invalid Type, not an erlang binary");
|
140
|
+
}
|
141
|
+
|
142
|
+
int length = read_4(pData);
|
143
|
+
|
144
|
+
unsigned char buf[length + 1];
|
145
|
+
read_string_raw(buf, pData, length);
|
146
|
+
|
147
|
+
return rb_str_new2((char *) buf);
|
148
|
+
}
|
149
|
+
|
150
|
+
VALUE read_string(unsigned char **pData) {
|
151
|
+
if(read_1(pData) != ERL_STRING) {
|
152
|
+
rb_raise(rb_eStandardError, "Invalid Type, not an erlang string");
|
153
|
+
}
|
154
|
+
|
155
|
+
int length = read_2(pData);
|
156
|
+
|
157
|
+
unsigned char buf[length + 1];
|
158
|
+
read_string_raw(buf, pData, length);
|
159
|
+
|
160
|
+
VALUE array = rb_ary_new2(length);
|
161
|
+
|
162
|
+
int i = 0;
|
163
|
+
for(i; i < length; ++i) {
|
164
|
+
rb_ary_store(array, i, INT2NUM(*(buf + i)));
|
165
|
+
}
|
166
|
+
|
167
|
+
return array;
|
168
|
+
}
|
169
|
+
|
170
|
+
VALUE read_atom(unsigned char **pData) {
|
171
|
+
if(read_1(pData) != ERL_ATOM) {
|
172
|
+
rb_raise(rb_eStandardError, "Invalid Type, not an atom");
|
173
|
+
}
|
174
|
+
|
175
|
+
int length = read_2(pData);
|
176
|
+
|
177
|
+
unsigned char buf[length + 1];
|
178
|
+
read_string_raw(buf, pData, length);
|
179
|
+
|
180
|
+
return ID2SYM(rb_intern((char *) buf));
|
181
|
+
}
|
182
|
+
|
183
|
+
VALUE read_small_int(unsigned char **pData) {
|
184
|
+
if(read_1(pData) != ERL_SMALL_INT) {
|
185
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a small int");
|
186
|
+
}
|
187
|
+
|
188
|
+
int value = read_1(pData);
|
189
|
+
|
190
|
+
return INT2FIX(value);
|
191
|
+
}
|
192
|
+
|
193
|
+
VALUE read_int(unsigned char **pData) {
|
194
|
+
if(read_1(pData) != ERL_INT) {
|
195
|
+
rb_raise(rb_eStandardError, "Invalid Type, not an int");
|
196
|
+
}
|
197
|
+
|
198
|
+
long long value = read_4(pData);
|
199
|
+
|
200
|
+
long long negative = ((value >> 31) & 0x1 == 1);
|
201
|
+
|
202
|
+
if(negative) {
|
203
|
+
value = (value - ((long long) 1 << 32));
|
204
|
+
}
|
205
|
+
|
206
|
+
return INT2FIX(value);
|
207
|
+
}
|
208
|
+
|
209
|
+
VALUE read_small_bignum(unsigned char **pData) {
|
210
|
+
if(read_1(pData) != ERL_SMALL_BIGNUM) {
|
211
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a small bignum");
|
212
|
+
}
|
213
|
+
|
214
|
+
unsigned int size = read_1(pData);
|
215
|
+
unsigned int sign = read_1(pData);
|
216
|
+
|
217
|
+
VALUE num = INT2NUM(0);
|
218
|
+
VALUE tmp;
|
219
|
+
|
220
|
+
unsigned char buf[size + 1];
|
221
|
+
read_string_raw(buf, pData, size);
|
222
|
+
|
223
|
+
int i;
|
224
|
+
for(i = 0; i < size; ++i) {
|
225
|
+
tmp = INT2FIX(*(buf + i));
|
226
|
+
tmp = rb_funcall(tmp, rb_intern("<<"), 1, INT2NUM(i * 8));
|
227
|
+
num = rb_funcall(num, rb_intern("+"), 1, tmp);
|
228
|
+
}
|
229
|
+
|
230
|
+
if(sign) {
|
231
|
+
num = rb_funcall(num, rb_intern("*"), 1, INT2NUM(-1));
|
232
|
+
}
|
233
|
+
|
234
|
+
return num;
|
235
|
+
}
|
236
|
+
|
237
|
+
VALUE read_large_bignum(unsigned char **pData) {
|
238
|
+
if(read_1(pData) != ERL_LARGE_BIGNUM) {
|
239
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a small bignum");
|
240
|
+
}
|
241
|
+
|
242
|
+
unsigned int size = read_4(pData);
|
243
|
+
unsigned int sign = read_1(pData);
|
244
|
+
|
245
|
+
VALUE num = INT2NUM(0);
|
246
|
+
VALUE tmp;
|
247
|
+
|
248
|
+
unsigned char buf[size + 1];
|
249
|
+
read_string_raw(buf, pData, size);
|
250
|
+
|
251
|
+
int i;
|
252
|
+
for(i = 0; i < size; ++i) {
|
253
|
+
tmp = INT2FIX(*(buf + i));
|
254
|
+
tmp = rb_funcall(tmp, rb_intern("<<"), 1, INT2NUM(i * 8));
|
255
|
+
|
256
|
+
num = rb_funcall(num, rb_intern("+"), 1, tmp);
|
257
|
+
}
|
258
|
+
|
259
|
+
if(sign) {
|
260
|
+
num = rb_funcall(num, rb_intern("*"), 1, INT2NUM(-1));
|
261
|
+
}
|
262
|
+
|
263
|
+
return num;
|
264
|
+
}
|
265
|
+
|
266
|
+
VALUE read_float(unsigned char **pData) {
|
267
|
+
if(read_1(pData) != ERL_FLOAT) {
|
268
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a float");
|
269
|
+
}
|
270
|
+
|
271
|
+
unsigned char buf[32];
|
272
|
+
read_string_raw(buf, pData, 31);
|
273
|
+
|
274
|
+
VALUE rString = rb_str_new2((char *) buf);
|
275
|
+
|
276
|
+
return rb_funcall(rString, rb_intern("to_f"), 0);
|
277
|
+
}
|
278
|
+
|
279
|
+
VALUE read_nil(unsigned char **pData) {
|
280
|
+
if(read_1(pData) != ERL_NIL) {
|
281
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a nil list");
|
282
|
+
}
|
283
|
+
|
284
|
+
return rb_ary_new2(0);
|
285
|
+
}
|
286
|
+
|
287
|
+
// specials
|
288
|
+
|
289
|
+
VALUE read_pid(unsigned char **pData) {
|
290
|
+
if(read_1(pData) != ERL_PID) {
|
291
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a pid");
|
292
|
+
}
|
293
|
+
|
294
|
+
VALUE node = read_atom(pData);
|
295
|
+
VALUE id = INT2NUM(read_4(pData));
|
296
|
+
VALUE serial = INT2NUM(read_4(pData));
|
297
|
+
VALUE creation = INT2FIX(read_1(pData));
|
298
|
+
|
299
|
+
VALUE pid_class = rb_const_get(mErlectricity, rb_intern("Pid"));
|
300
|
+
return rb_funcall(pid_class, rb_intern("new"), 4, node, id, serial, creation);
|
301
|
+
}
|
302
|
+
|
303
|
+
VALUE read_new_reference(unsigned char **pData) {
|
304
|
+
if(read_1(pData) != ERL_NEW_REF) {
|
305
|
+
rb_raise(rb_eStandardError, "Invalid Type, not a new-style reference");
|
306
|
+
}
|
307
|
+
|
308
|
+
int size = read_2(pData);
|
309
|
+
VALUE node = read_atom(pData);
|
310
|
+
VALUE creation = INT2FIX(read_1(pData));
|
311
|
+
|
312
|
+
VALUE id = rb_ary_new2(size);
|
313
|
+
int i;
|
314
|
+
for(i = 0; i < size; ++i) {
|
315
|
+
rb_ary_store(id, i, INT2NUM(read_4(pData)));
|
316
|
+
}
|
317
|
+
|
318
|
+
VALUE newref_class = rb_const_get(mErlectricity, rb_intern("NewReference"));
|
319
|
+
return rb_funcall(newref_class, rb_intern("new"), 3, node, creation, id);
|
320
|
+
}
|
321
|
+
|
322
|
+
// read_any_raw
|
323
|
+
|
324
|
+
VALUE read_any_raw(unsigned char **pData) {
|
325
|
+
switch(peek_1(pData)) {
|
326
|
+
case ERL_SMALL_INT:
|
327
|
+
return read_small_int(pData);
|
328
|
+
break;
|
329
|
+
case ERL_INT:
|
330
|
+
return read_int(pData);
|
331
|
+
break;
|
332
|
+
case ERL_FLOAT:
|
333
|
+
return read_float(pData);
|
334
|
+
break;
|
335
|
+
case ERL_ATOM:
|
336
|
+
return read_atom(pData);
|
337
|
+
break;
|
338
|
+
case ERL_PID:
|
339
|
+
return read_pid(pData);
|
340
|
+
break;
|
341
|
+
case ERL_SMALL_TUPLE:
|
342
|
+
return read_small_tuple(pData);
|
343
|
+
break;
|
344
|
+
case ERL_LARGE_TUPLE:
|
345
|
+
return read_large_tuple(pData);
|
346
|
+
break;
|
347
|
+
case ERL_NIL:
|
348
|
+
return read_nil(pData);
|
349
|
+
break;
|
350
|
+
case ERL_STRING:
|
351
|
+
return read_string(pData);
|
352
|
+
break;
|
353
|
+
case ERL_LIST:
|
354
|
+
return read_list(pData);
|
355
|
+
break;
|
356
|
+
case ERL_BIN:
|
357
|
+
return read_bin(pData);
|
358
|
+
break;
|
359
|
+
case ERL_SMALL_BIGNUM:
|
360
|
+
return read_small_bignum(pData);
|
361
|
+
break;
|
362
|
+
case ERL_LARGE_BIGNUM:
|
363
|
+
return read_large_bignum(pData);
|
364
|
+
break;
|
365
|
+
case ERL_NEW_REF:
|
366
|
+
return read_new_reference(pData);
|
367
|
+
break;
|
368
|
+
}
|
369
|
+
return Qnil;
|
370
|
+
}
|
371
|
+
|
372
|
+
VALUE method_read_any_from(VALUE klass, VALUE rString) {
|
373
|
+
unsigned char *data = (unsigned char *) StringValuePtr(rString);
|
374
|
+
|
375
|
+
unsigned char **pData = &data;
|
376
|
+
|
377
|
+
// check protocol version
|
378
|
+
if(read_1(pData) != ERL_VERSION) {
|
379
|
+
rb_raise(rb_eStandardError, "Bad Magic");
|
380
|
+
}
|
381
|
+
|
382
|
+
return read_any_raw(pData);
|
383
|
+
}
|
384
|
+
|
385
|
+
void Init_decoder() {
|
386
|
+
mErlectricity = rb_const_get(rb_cObject, rb_intern("Erlectricity"));
|
387
|
+
cDecoder = rb_define_class_under(mErlectricity, "Decoder", rb_cObject);
|
388
|
+
rb_define_singleton_method(cDecoder, "read_any_from", method_read_any_from, 1);
|
389
|
+
}
|
data/ext/extconf.rb
ADDED
data/lib/erlectricity.rb
CHANGED
@@ -3,13 +3,20 @@ require 'erlectricity/constants'
|
|
3
3
|
require 'erlectricity/types/new_reference'
|
4
4
|
require 'erlectricity/types/pid'
|
5
5
|
require 'erlectricity/types/function'
|
6
|
+
require 'erlectricity/types/list'
|
7
|
+
|
8
|
+
begin
|
9
|
+
#try to load the decoder C extension
|
10
|
+
require 'decoder'
|
11
|
+
rescue LoadError
|
12
|
+
#load the pure ruby instead
|
13
|
+
require 'erlectricity/decoder'
|
14
|
+
end
|
6
15
|
|
7
|
-
require 'erlectricity/decoder'
|
8
16
|
require 'erlectricity/encoder'
|
9
17
|
|
10
18
|
require 'erlectricity/port'
|
11
19
|
require 'erlectricity/matcher'
|
12
|
-
require 'erlectricity/match_context'
|
13
20
|
|
14
21
|
require 'erlectricity/condition'
|
15
22
|
require 'erlectricity/conditions/hash'
|
@@ -21,3 +28,5 @@ require 'erlectricity/receiver'
|
|
21
28
|
require 'erlectricity/errors/erlectricity_error'
|
22
29
|
require 'erlectricity/errors/decode_error'
|
23
30
|
require 'erlectricity/errors/encode_error'
|
31
|
+
|
32
|
+
Erl = Erlectricity
|
@@ -1,48 +1,51 @@
|
|
1
1
|
module Erlectricity
|
2
2
|
class Condition
|
3
|
-
attr_accessor :binding_name
|
4
3
|
|
5
|
-
def initialize
|
6
|
-
self.binding_name = binding_name
|
4
|
+
def initialize
|
7
5
|
end
|
8
6
|
|
9
|
-
def
|
10
|
-
|
7
|
+
def binding_for(arg)
|
8
|
+
nil
|
11
9
|
end
|
12
10
|
|
13
11
|
def satisfies?(arg)
|
14
12
|
false
|
15
13
|
end
|
16
|
-
|
14
|
+
|
15
|
+
alias === satisfies?
|
17
16
|
end
|
18
17
|
|
19
18
|
module Conditions
|
20
|
-
def atom(
|
21
|
-
TypeCondition.new(Symbol
|
19
|
+
def atom()
|
20
|
+
TypeCondition.new(Symbol)
|
22
21
|
end
|
23
22
|
|
24
|
-
def any(
|
25
|
-
TypeCondition.new(Object
|
23
|
+
def any()
|
24
|
+
TypeCondition.new(Object)
|
26
25
|
end
|
27
26
|
|
28
|
-
def number(
|
29
|
-
TypeCondition.new(Fixnum
|
27
|
+
def number()
|
28
|
+
TypeCondition.new(Fixnum)
|
30
29
|
end
|
31
30
|
|
32
|
-
def pid(
|
33
|
-
TypeCondition.new(Erlectricity::Pid
|
31
|
+
def pid()
|
32
|
+
TypeCondition.new(Erlectricity::Pid)
|
34
33
|
end
|
35
34
|
|
36
|
-
def string(
|
37
|
-
TypeCondition.new(String
|
35
|
+
def string()
|
36
|
+
TypeCondition.new(String)
|
38
37
|
end
|
39
38
|
|
40
|
-
def list(
|
41
|
-
TypeCondition.new(Array
|
39
|
+
def list()
|
40
|
+
TypeCondition.new(Array)
|
42
41
|
end
|
43
42
|
|
44
|
-
def hash(
|
45
|
-
HashCondition.new(
|
43
|
+
def hash()
|
44
|
+
HashCondition.new()
|
46
45
|
end
|
47
46
|
end
|
48
|
-
|
47
|
+
|
48
|
+
extend Conditions
|
49
|
+
end
|
50
|
+
|
51
|
+
Any = Object
|
@@ -6,10 +6,9 @@ class HashCondition < Condition
|
|
6
6
|
arg.all?{|x| x.class == Array && x.length == 2}
|
7
7
|
end
|
8
8
|
|
9
|
-
def
|
10
|
-
return {} unless self.binding_name
|
9
|
+
def binding_for(arg)
|
11
10
|
flattened = arg.inject([]){|memo, kv| memo + kv}
|
12
|
-
|
11
|
+
Hash[*flattened]
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end
|
@@ -1,17 +1,13 @@
|
|
1
1
|
module Erlectricity
|
2
2
|
class StaticCondition < Condition
|
3
3
|
attr_accessor :value
|
4
|
-
def initialize(value
|
4
|
+
def initialize(value)
|
5
5
|
self.value = value
|
6
|
-
super(name)
|
7
6
|
end
|
8
7
|
|
9
8
|
def satisfies?(arg)
|
10
9
|
arg.eql? value
|
11
10
|
end
|
12
|
-
|
13
|
-
def bindings_for(arg)
|
14
|
-
{}
|
15
|
-
end
|
11
|
+
|
16
12
|
end
|
17
13
|
end
|
@@ -2,18 +2,16 @@ module Erlectricity
|
|
2
2
|
class TypeCondition < Condition
|
3
3
|
attr_accessor :type
|
4
4
|
|
5
|
-
def initialize(type
|
5
|
+
def initialize(type)
|
6
6
|
self.type = type
|
7
|
-
super(name)
|
8
7
|
end
|
9
8
|
|
10
9
|
def satisfies?(arg)
|
11
10
|
arg.is_a? self.type
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
15
|
-
|
16
|
-
{self.binding_name => arg}
|
13
|
+
def binding_for(arg)
|
14
|
+
arg
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
data/lib/erlectricity/encoder.rb
CHANGED
@@ -19,6 +19,7 @@ class Encoder
|
|
19
19
|
when Float then write_float(obj)
|
20
20
|
when Erlectricity::NewReference then write_new_reference(obj)
|
21
21
|
when Erlectricity::Pid then write_pid(obj)
|
22
|
+
when Erlectricity::List then write_list(obj)
|
22
23
|
when Array then write_tuple(obj)
|
23
24
|
when String then write_binary(obj)
|
24
25
|
else
|
@@ -106,7 +107,6 @@ class Encoder
|
|
106
107
|
fail(data) unless data.is_a? Array
|
107
108
|
write_1 NIL and return if data.empty?
|
108
109
|
|
109
|
-
#NOTE: we do not ever encode as the string format.
|
110
110
|
write_1 LIST
|
111
111
|
write_4 data.length
|
112
112
|
data.each{|e| write_any_raw e }
|
data/lib/erlectricity/matcher.rb
CHANGED
@@ -10,10 +10,8 @@ class Matcher
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def run(arg)
|
13
|
-
|
14
|
-
|
15
|
-
populate_context context, arg
|
16
|
-
context.instance_eval &block
|
13
|
+
args = get_bound arg
|
14
|
+
block.call *args
|
17
15
|
end
|
18
16
|
|
19
17
|
def matches?(arg)
|
@@ -28,33 +26,13 @@ class Matcher
|
|
28
26
|
|
29
27
|
|
30
28
|
private
|
31
|
-
|
29
|
+
|
30
|
+
def get_bound(arg)
|
32
31
|
if @condition.is_a?(Array) && arg.is_a?(Array)
|
33
|
-
@condition.zip(arg).
|
32
|
+
@condition.zip(arg).map{|l,r| l.binding_for r}.compact
|
34
33
|
else
|
35
|
-
|
34
|
+
@condition.binding_for(arg)
|
36
35
|
end
|
37
36
|
end
|
38
|
-
|
39
|
-
def set_binding(context, condition, arg)
|
40
|
-
condition.bindings_for(arg).each do |k, v|
|
41
|
-
add_to_context(context, k, v)
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
def add_to_context(context, name, value)
|
46
|
-
return if name.nil?
|
47
|
-
|
48
|
-
context.instance_eval <<-EOS
|
49
|
-
def #{name}
|
50
|
-
@#{name}
|
51
|
-
end
|
52
|
-
def #{name}= (value)
|
53
|
-
@#{name} = value
|
54
|
-
end
|
55
|
-
EOS
|
56
|
-
|
57
|
-
context.send(:"#{name}=", value)
|
58
|
-
end
|
59
37
|
end
|
60
38
|
end
|
@@ -1,6 +1,5 @@
|
|
1
1
|
module Erlectricity
|
2
2
|
class Receiver
|
3
|
-
include Conditions
|
4
3
|
|
5
4
|
attr_accessor :port
|
6
5
|
attr_accessor :parent
|
@@ -13,7 +12,7 @@ class Receiver
|
|
13
12
|
@port = port
|
14
13
|
@parent = parent
|
15
14
|
@matchers = []
|
16
|
-
|
15
|
+
block.call self if block
|
17
16
|
end
|
18
17
|
|
19
18
|
def process(arg)
|
@@ -27,8 +26,14 @@ class Receiver
|
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
def
|
31
|
-
args = args.map
|
29
|
+
def when(*args, &block)
|
30
|
+
args = args.map do |a|
|
31
|
+
case a
|
32
|
+
when Condition then a
|
33
|
+
when Class then TypeCondition.new(a)
|
34
|
+
else StaticCondition.new(a)
|
35
|
+
end
|
36
|
+
end
|
32
37
|
|
33
38
|
args = args.first if args.length == 1
|
34
39
|
@matchers << Matcher.new(self, args, block)
|
@@ -0,0 +1 @@
|
|
1
|
+
class Erlectricity::List < Array ; end
|
data/lib/erlectricity/version.rb
CHANGED
data/test/condition_spec.rb
CHANGED
@@ -7,16 +7,16 @@ context "Erlectricity::StaticConditions" do
|
|
7
7
|
Erlectricity::StaticCondition.new(3).satisfies?(3).should == true
|
8
8
|
end
|
9
9
|
|
10
|
-
specify "should not satisfy on
|
10
|
+
specify "should not satisfy on different values" do
|
11
11
|
Erlectricity::StaticCondition.new(:foo).satisfies?("foo").should == false
|
12
12
|
Erlectricity::StaticCondition.new([:foo]).satisfies?(:foo).should == false
|
13
13
|
Erlectricity::StaticCondition.new(Object.new).satisfies?(Object.new).should == false
|
14
14
|
Erlectricity::StaticCondition.new(3).satisfies?(3.0).should == false
|
15
15
|
end
|
16
16
|
|
17
|
-
specify "should not produce any bindings
|
18
|
-
s = Erlectricity::StaticCondition.new(:foo
|
19
|
-
s.
|
17
|
+
specify "should not produce any bindings" do
|
18
|
+
s = Erlectricity::StaticCondition.new(:foo)
|
19
|
+
s.binding_for(:foo).should == nil
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -42,17 +42,12 @@ context "Erlectricity::TypeConditions" do
|
|
42
42
|
Erlectricity::TypeCondition.new(Fixnum).satisfies?(3.0).should == false
|
43
43
|
end
|
44
44
|
|
45
|
-
specify "should bind the arg
|
46
|
-
s = Erlectricity::TypeCondition.new(Symbol, :bound_name)
|
47
|
-
s.bindings_for(:foo).should == {:bound_name => :foo}
|
48
|
-
s.bindings_for(:bar).should == {:bound_name => :bar}
|
49
|
-
end
|
50
|
-
|
51
|
-
specify "should not bind anything if no binding name is specified" do
|
52
|
-
|
45
|
+
specify "should bind the arg with no transormations" do
|
53
46
|
s = Erlectricity::TypeCondition.new(Symbol)
|
54
|
-
s.
|
47
|
+
s.binding_for(:foo).should == :foo
|
48
|
+
s.binding_for(:bar).should == :bar
|
55
49
|
end
|
50
|
+
|
56
51
|
end
|
57
52
|
|
58
53
|
context "Erlectricity::HashConditions" do
|
@@ -71,8 +66,8 @@ context "Erlectricity::HashConditions" do
|
|
71
66
|
Erlectricity::HashCondition.new.satisfies?(3.0).should == false
|
72
67
|
end
|
73
68
|
|
74
|
-
specify "should
|
75
|
-
s = Erlectricity::HashCondition.new(
|
76
|
-
s.
|
69
|
+
specify "should bind to a Hash" do
|
70
|
+
s = Erlectricity::HashCondition.new()
|
71
|
+
s.binding_for([[:foo, 3], [:bar, [3,4,5]]]).should == {:foo => 3, :bar => [3,4,5] }
|
77
72
|
end
|
78
73
|
end
|
data/test/decode_spec.rb
CHANGED
@@ -1,16 +1,7 @@
|
|
1
1
|
require File.dirname(__FILE__) + '/test_helper.rb'
|
2
2
|
|
3
|
-
context "The byte reader attached to decoder" do
|
4
|
-
specify "should not advance the stream when peeking unless there arent enough bytes available" do
|
5
|
-
@decoder = Erlectricity::Decoder.new(StringIO.new('abcdefghijklmnopqrstuvwxyz'))
|
6
|
-
100.times{ @decoder.peek_1.should == 'a'[0] }
|
7
|
-
100.times{ @decoder.peek_2.should == 'ab'.unpack("n").first }
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
3
|
context "When unpacking from a binary stream" do
|
12
4
|
setup do
|
13
|
-
@decoder = Erlectricity::Decoder.new(nil)
|
14
5
|
end
|
15
6
|
|
16
7
|
specify "an erlang atom should decode to a ruby symbol" do
|
@@ -127,7 +118,6 @@ context "When unpacking from a binary stream" do
|
|
127
118
|
|
128
119
|
def get(str)
|
129
120
|
bin = run_erl("term_to_binary(#{str})")
|
130
|
-
|
131
|
-
@decoder.read_any
|
121
|
+
Erlectricity::Decoder.read_any_from(bin)
|
132
122
|
end
|
133
123
|
end
|
data/test/encode_spec.rb
CHANGED
@@ -88,6 +88,13 @@ context "When packing to a binary stream" do
|
|
88
88
|
write_any([3] * 512).should == get_erl_with_magic("{#{([3] * 512).join(',')}}")
|
89
89
|
end
|
90
90
|
|
91
|
+
specify "An Erlectricity::List should by default be written as a list" do
|
92
|
+
write_any(Erl::List.new([1,2,300])).should == get_erl_with_magic("[1,2,300]")
|
93
|
+
write_any(Erl::List.new([300] * 255)).should == get_erl_with_magic("[#{([300] * 255).join(',')}]")
|
94
|
+
write_any(Erl::List.new([300] * 256)).should == get_erl_with_magic("[#{([300] * 256).join(',')}]")
|
95
|
+
write_any(Erl::List.new([300] * 512)).should == get_erl_with_magic("[#{([300] * 512).join(',')}]")
|
96
|
+
end
|
97
|
+
|
91
98
|
specify "An array written with write_list should encode as erlang would a list" do
|
92
99
|
get{@encoder.write_list [1,2,300]}.should == get_erl("[1,2,300]")
|
93
100
|
get{@encoder.write_list [300] * 255}.should == get_erl("[#{([300] * 255).join(',')}]")
|
data/test/matcher_spec.rb
CHANGED
data/test/receiver_spec.rb
CHANGED
@@ -5,8 +5,8 @@ def simple_receiver_and_port(*terms, &block)
|
|
5
5
|
receiver = if block
|
6
6
|
Erlectricity::Receiver.new(port, &block)
|
7
7
|
else
|
8
|
-
Erlectricity::Receiver.new(port) do
|
9
|
-
|
8
|
+
Erlectricity::Receiver.new(port) do |f|
|
9
|
+
f.when Erl.any do
|
10
10
|
:matched
|
11
11
|
end
|
12
12
|
end
|
@@ -17,12 +17,12 @@ end
|
|
17
17
|
context "When a receiver is passed a message that matches two match blocks it" do
|
18
18
|
setup do
|
19
19
|
@port = FakePort.new([:foo, :foo])
|
20
|
-
@receiver = Erlectricity::Receiver.new(@port) do
|
21
|
-
|
20
|
+
@receiver = Erlectricity::Receiver.new(@port) do |f|
|
21
|
+
f.when(:foo, :foo) do
|
22
22
|
:first
|
23
23
|
end
|
24
24
|
|
25
|
-
|
25
|
+
f.when(:foo, Erl.any) do
|
26
26
|
:second
|
27
27
|
end
|
28
28
|
end
|
@@ -41,9 +41,9 @@ context "A receiver" do
|
|
41
41
|
end
|
42
42
|
|
43
43
|
specify "should process another message if the matched block returns the results of receive_loop" do
|
44
|
-
recv = simple_receiver_and_port(:foo, :bar, :baz) do
|
45
|
-
|
46
|
-
|
44
|
+
recv = simple_receiver_and_port(:foo, :bar, :baz) do |f|
|
45
|
+
f.when(:bar) { }
|
46
|
+
f.when(Erl.any) { f.receive_loop }
|
47
47
|
end
|
48
48
|
|
49
49
|
recv.run
|
@@ -52,15 +52,15 @@ context "A receiver" do
|
|
52
52
|
|
53
53
|
specify "should properly nest" do
|
54
54
|
@port = FakePort.new(:foo, :bar, :baz)
|
55
|
-
@receiver = Erlectricity::Receiver.new(@port) do
|
56
|
-
|
57
|
-
receive do
|
58
|
-
|
55
|
+
@receiver = Erlectricity::Receiver.new(@port) do |f|
|
56
|
+
f.when(:foo) do
|
57
|
+
f.receive do |g|
|
58
|
+
g.when(:bar){ :ok }
|
59
59
|
end
|
60
|
-
receive_loop
|
60
|
+
f.receive_loop
|
61
61
|
end
|
62
62
|
|
63
|
-
|
63
|
+
f.when(:baz) do
|
64
64
|
:done
|
65
65
|
end
|
66
66
|
end
|
@@ -71,15 +71,15 @@ context "A receiver" do
|
|
71
71
|
|
72
72
|
specify "should queue up skipped results and restore them when a match happens" do
|
73
73
|
@port = FakePort.new(:foo, :baz, :bar)
|
74
|
-
@receiver = Erlectricity::Receiver.new(@port) do
|
75
|
-
|
76
|
-
receive do
|
77
|
-
|
74
|
+
@receiver = Erlectricity::Receiver.new(@port) do |f|
|
75
|
+
f.when(:foo) do
|
76
|
+
f.receive do |g|
|
77
|
+
g.when(:bar){ :ok }
|
78
78
|
end
|
79
|
-
receive_loop
|
79
|
+
f.receive_loop
|
80
80
|
end
|
81
81
|
|
82
|
-
|
82
|
+
f.when(:baz) do
|
83
83
|
:done
|
84
84
|
end
|
85
85
|
end
|
@@ -91,10 +91,10 @@ context "A receiver" do
|
|
91
91
|
specify "should expose bindings to the matched block" do
|
92
92
|
@port = FakePort.new(:foo, :bar, :baz)
|
93
93
|
results = []
|
94
|
-
@receiver = Erlectricity::Receiver.new(@port) do
|
95
|
-
|
94
|
+
@receiver = Erlectricity::Receiver.new(@port) do |f|
|
95
|
+
f.when(Erl.atom) do |bindinated|
|
96
96
|
results << bindinated
|
97
|
-
receive_loop
|
97
|
+
f.receive_loop
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
data/test/test_helper.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
2
|
+
require 'erlectricity'
|
2
3
|
require 'rubygems'
|
3
4
|
require 'test/unit'
|
4
5
|
require 'test/spec'
|
5
|
-
require 'erlectricity'
|
6
6
|
|
7
7
|
class Test::Unit::TestCase
|
8
8
|
|
@@ -10,6 +10,11 @@ class Test::Unit::TestCase
|
|
10
10
|
`erl -noshell -eval 'A = #{code.split.join(' ')}, io:put_chars(A).' -s erlang halt`
|
11
11
|
end
|
12
12
|
|
13
|
+
def encode_packet(code)
|
14
|
+
bin = run_erl("term_to_binary(#{code})")
|
15
|
+
[bin.length, bin].pack("Na#{bin.length}")
|
16
|
+
end
|
17
|
+
|
13
18
|
def word_length
|
14
19
|
(1.size * 8) - 2
|
15
20
|
end
|
metadata
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
|
-
rubygems_version: 0.9.
|
2
|
+
rubygems_version: 0.9.4
|
3
3
|
specification_version: 1
|
4
4
|
name: erlectricity
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2007-
|
6
|
+
version: 0.2.0
|
7
|
+
date: 2007-10-29 00:00:00 -07:00
|
8
8
|
summary: A library to interface erlang and ruby through the erlang port system
|
9
9
|
require_paths:
|
10
10
|
- lib
|
11
|
+
- ext
|
11
12
|
email: nullstyle@gmail.com
|
12
13
|
homepage: http://erlectricity.rubyforge.org
|
13
14
|
rubyforge_project: erlectricity
|
@@ -29,6 +30,8 @@ post_install_message:
|
|
29
30
|
authors:
|
30
31
|
- Scott Fleckenstein
|
31
32
|
files:
|
33
|
+
- CONTRIBUTORS
|
34
|
+
- History.txt
|
32
35
|
- Manifest.txt
|
33
36
|
- README.txt
|
34
37
|
- Rakefile
|
@@ -39,6 +42,8 @@ files:
|
|
39
42
|
- examples/gruff/stat_writer.erl
|
40
43
|
- examples/tinderl/tinderl.erl
|
41
44
|
- examples/tinderl/tinderl.rb
|
45
|
+
- ext/decoder.c
|
46
|
+
- ext/extconf.rb
|
42
47
|
- lib/erlectricity.rb
|
43
48
|
- lib/erlectricity/condition.rb
|
44
49
|
- lib/erlectricity/conditions/hash.rb
|
@@ -50,11 +55,11 @@ files:
|
|
50
55
|
- lib/erlectricity/errors/decode_error.rb
|
51
56
|
- lib/erlectricity/errors/encode_error.rb
|
52
57
|
- lib/erlectricity/errors/erlectricity_error.rb
|
53
|
-
- lib/erlectricity/match_context.rb
|
54
58
|
- lib/erlectricity/matcher.rb
|
55
59
|
- lib/erlectricity/port.rb
|
56
60
|
- lib/erlectricity/receiver.rb
|
57
61
|
- lib/erlectricity/types/function.rb
|
62
|
+
- lib/erlectricity/types/list.rb
|
58
63
|
- lib/erlectricity/types/new_function.rb
|
59
64
|
- lib/erlectricity/types/new_reference.rb
|
60
65
|
- lib/erlectricity/types/pid.rb
|
@@ -73,10 +78,13 @@ files:
|
|
73
78
|
test_files:
|
74
79
|
- test/test_erlectricity.rb
|
75
80
|
- test/test_helper.rb
|
76
|
-
rdoc_options:
|
77
|
-
|
78
|
-
|
79
|
-
|
81
|
+
rdoc_options:
|
82
|
+
- --main
|
83
|
+
- README.txt
|
84
|
+
extra_rdoc_files:
|
85
|
+
- History.txt
|
86
|
+
- Manifest.txt
|
87
|
+
- README.txt
|
80
88
|
executables: []
|
81
89
|
|
82
90
|
extensions: []
|
@@ -1,20 +0,0 @@
|
|
1
|
-
module Erlectricity
|
2
|
-
class MatchContext
|
3
|
-
attr_accessor :receiver
|
4
|
-
def initialize(receiver)
|
5
|
-
self.receiver = receiver
|
6
|
-
end
|
7
|
-
|
8
|
-
def receive(&block)
|
9
|
-
receiver.receive(&block)
|
10
|
-
end
|
11
|
-
|
12
|
-
def receive_loop
|
13
|
-
receiver.receive_loop
|
14
|
-
end
|
15
|
-
|
16
|
-
def send!(*term)
|
17
|
-
receiver.send!(*term)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|