em-rserve 0.1.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/.gitignore +4 -0
- data/Gemfile +4 -0
- data/README +26 -0
- data/Rakefile +1 -0
- data/TODO +14 -0
- data/em-rserve.gemspec +20 -0
- data/lib/em-rserve/connection.rb +84 -0
- data/lib/em-rserve/fibered_connection.rb +66 -0
- data/lib/em-rserve/pooler.rb +76 -0
- data/lib/em-rserve/protocol/connector.rb +89 -0
- data/lib/em-rserve/protocol/id.rb +14 -0
- data/lib/em-rserve/protocol/parser.rb +93 -0
- data/lib/em-rserve/protocol/request.rb +22 -0
- data/lib/em-rserve/qap1/constants.rb +111 -0
- data/lib/em-rserve/qap1/header.rb +45 -0
- data/lib/em-rserve/qap1/message.rb +26 -0
- data/lib/em-rserve/qap1/rpack.rb +127 -0
- data/lib/em-rserve/r/r_to_ruby/translator.rb +152 -0
- data/lib/em-rserve/r/ruby_to_r/translator.rb +131 -0
- data/lib/em-rserve/r/sexp.rb +421 -0
- data/lib/em-rserve/version.rb +5 -0
- data/lib/em-rserve.rb +11 -0
- data/samples/assign.rb +211 -0
- data/samples/detach_attach.rb +70 -0
- data/samples/fibers.rb +32 -0
- data/samples/run.rb +66 -0
- data/samples/sql.rb +167 -0
- data/samples/views/plot.erb +6 -0
- data/samples/webplot.rb +37 -0
- data/specs/id_parser_spec.rb +45 -0
- data/specs/message_parser_spec.rb +70 -0
- data/specs/parser_spec.rb +80 -0
- data/specs/ruby_to_r_translator_spec.rb +88 -0
- data/specs/spec_helper.rb +3 -0
- metadata +101 -0
@@ -0,0 +1,421 @@
|
|
1
|
+
|
2
|
+
require 'em-rserve/qap1/constants'
|
3
|
+
|
4
|
+
module EM::Rserve
|
5
|
+
module R
|
6
|
+
class Sexp
|
7
|
+
include QAP1::Constants
|
8
|
+
|
9
|
+
XT_NULL = 0
|
10
|
+
XT_INT = 1
|
11
|
+
XT_DOUBLE = 2
|
12
|
+
XT_STR = 3
|
13
|
+
XT_LANG = 4
|
14
|
+
XT_SYM = 5
|
15
|
+
XT_BOOL = 6
|
16
|
+
XT_S4 = 7
|
17
|
+
|
18
|
+
XT_VECTOR = 16
|
19
|
+
XT_LIST = 17
|
20
|
+
XT_CLOS = 18
|
21
|
+
XT_SYMNAME = 19
|
22
|
+
XT_LIST_NOTAG = 20
|
23
|
+
XT_LIST_TAG = 21
|
24
|
+
XT_LANG_NOTAG = 22
|
25
|
+
XT_LANG_TAG = 23
|
26
|
+
XT_VECTOR_EXP = 26
|
27
|
+
XT_VECTOR_STR = 27
|
28
|
+
|
29
|
+
XT_ARRAY_INT = 32
|
30
|
+
XT_ARRAY_DOUBLE = 33
|
31
|
+
|
32
|
+
XT_ARRAY_STR = 34
|
33
|
+
XT_ARRAY_BOOL_UA = 35
|
34
|
+
XT_ARRAY_BOOL = 36
|
35
|
+
XT_RAW = 37
|
36
|
+
XT_ARRAY_CPLX = 38
|
37
|
+
XT_UNKNOWN = 48
|
38
|
+
|
39
|
+
class Node
|
40
|
+
attr_accessor :attribute
|
41
|
+
attr_accessor :children
|
42
|
+
|
43
|
+
def initialize
|
44
|
+
@children = []
|
45
|
+
@attribute = nil
|
46
|
+
yield self if block_given?
|
47
|
+
end
|
48
|
+
|
49
|
+
def descent(depth=0, &blk)
|
50
|
+
if block_given?
|
51
|
+
blk.call(self, depth)
|
52
|
+
@children.each do |c|
|
53
|
+
c.descent(depth + 1, &blk)
|
54
|
+
end
|
55
|
+
else
|
56
|
+
Enumerator.new(self, :descent)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def dump_sexp
|
61
|
+
body = dumped_value_with_attribute
|
62
|
+
children_data = children.map do |n|
|
63
|
+
n.dump_sexp
|
64
|
+
end.join('')
|
65
|
+
size = body.size + children_data.size
|
66
|
+
flags = {:large => false, :attr => attribute && true}
|
67
|
+
head = self.class.parameter_head(self.class.code, flags, size)
|
68
|
+
[head, body + children_data].pack('Va*')
|
69
|
+
end
|
70
|
+
|
71
|
+
def dumped_value_with_attribute
|
72
|
+
if attribute
|
73
|
+
attribute.dump_sexp + dumped_value
|
74
|
+
else
|
75
|
+
dumped_value
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def dumped_value
|
80
|
+
''
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.parameter_head(type, flags, len)
|
84
|
+
head_bits = type & 0x3f #high bits are for flags
|
85
|
+
len_bits = (len & 0xffffff) << 8
|
86
|
+
flags_bits = 0
|
87
|
+
flags_bits |= 0x40 if flags[:large]
|
88
|
+
flags_bits |= 0x80 if flags[:attr]
|
89
|
+
ret = head_bits | len_bits | flags_bits
|
90
|
+
ret
|
91
|
+
end
|
92
|
+
|
93
|
+
class << self
|
94
|
+
def inherited(klass)
|
95
|
+
klass.instance_variable_set(:@code, nil)
|
96
|
+
end
|
97
|
+
|
98
|
+
def code(val=nil)
|
99
|
+
if val
|
100
|
+
@code = val
|
101
|
+
end
|
102
|
+
@code
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def self.build_map!
|
107
|
+
all_nodes = ObjectSpace.each_object(Class).select{|k| k.ancestors.include?(self)} - [self]
|
108
|
+
true_nodes = all_nodes.select(&:code)
|
109
|
+
pairs = true_nodes.map{|n| [n.code, n]}
|
110
|
+
@@map = Hash[*pairs.flatten]
|
111
|
+
end
|
112
|
+
|
113
|
+
def self.map
|
114
|
+
@@map ||= build_map!
|
115
|
+
end
|
116
|
+
|
117
|
+
def self.class_for_type(type)
|
118
|
+
map[type]
|
119
|
+
end
|
120
|
+
|
121
|
+
attr_accessor :rb_raw
|
122
|
+
alias :rb_val :rb_raw
|
123
|
+
alias :interpret :rb_raw=
|
124
|
+
|
125
|
+
def int2bool(i)
|
126
|
+
if i == 1
|
127
|
+
true
|
128
|
+
elsif i == 0
|
129
|
+
false
|
130
|
+
elsif i == 2
|
131
|
+
nil
|
132
|
+
else
|
133
|
+
raise "unknown bool int: #{i}"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
def bool2int(b)
|
138
|
+
if b == true
|
139
|
+
1
|
140
|
+
elsif b == false
|
141
|
+
0
|
142
|
+
elsif b.nil?
|
143
|
+
2
|
144
|
+
else
|
145
|
+
raise "unknown bool for int: #{b}"
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
# not leaves
|
150
|
+
class ParentNode < Node
|
151
|
+
def interpret(dat)
|
152
|
+
@children = Sexp.decode_nodes_array(dat)
|
153
|
+
super(children.map(&:rb_raw))
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
class Root < ParentNode
|
158
|
+
def rb_val
|
159
|
+
children.first.rb_val
|
160
|
+
end
|
161
|
+
|
162
|
+
def dump_sexp
|
163
|
+
children.first.dump_sexp
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
class Null < Node
|
168
|
+
code XT_NULL
|
169
|
+
def interpret(dat)
|
170
|
+
super nil
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
class Bool < Node
|
175
|
+
code XT_BOOL
|
176
|
+
def interpret(dat)
|
177
|
+
super int2bool(dat.unpack('i').first)
|
178
|
+
end
|
179
|
+
|
180
|
+
def dumped_value
|
181
|
+
[bool2int(rb_raw)].pack('i')
|
182
|
+
end
|
183
|
+
end
|
184
|
+
|
185
|
+
class Int < Node
|
186
|
+
code XT_INT
|
187
|
+
def interpret(dat)
|
188
|
+
super dat.unpack('i').first
|
189
|
+
end
|
190
|
+
|
191
|
+
def dumped_value
|
192
|
+
[rb_raw].pack('i')
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
class Double < Node
|
197
|
+
code XT_DOUBLE
|
198
|
+
def interpret(dat)
|
199
|
+
super dat.unpack('d').first
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
class NodesArray < Node
|
204
|
+
def rb_val
|
205
|
+
if rb_raw.size > 1
|
206
|
+
rb_raw
|
207
|
+
else
|
208
|
+
rb_raw.first
|
209
|
+
end
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
class String < Node
|
214
|
+
code XT_STR
|
215
|
+
def interpret(dat)
|
216
|
+
val, padding = dat.split("\0", 2)
|
217
|
+
super val
|
218
|
+
end
|
219
|
+
end
|
220
|
+
|
221
|
+
class SymName < String
|
222
|
+
code XT_SYMNAME
|
223
|
+
|
224
|
+
def dumped_value
|
225
|
+
ret = rb_raw + "\0"
|
226
|
+
ret << "\0" * (ret.size % 4)
|
227
|
+
ret
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
class ArrayString < NodesArray
|
232
|
+
code XT_ARRAY_STR
|
233
|
+
def interpret(dat)
|
234
|
+
ary = dat.split("\0")
|
235
|
+
return(super(ary)) if ary.empty?
|
236
|
+
ary.pop if ary.last.tr("\1",'').empty?
|
237
|
+
super ary
|
238
|
+
end
|
239
|
+
|
240
|
+
def dumped_value
|
241
|
+
str = (rb_raw + ['']).join("\0")
|
242
|
+
str << "\1" * (str.size % 4)
|
243
|
+
str
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
class ArrayInt < NodesArray
|
248
|
+
code XT_ARRAY_INT
|
249
|
+
def interpret(dat)
|
250
|
+
super dat.unpack('i'*(dat.size/4))
|
251
|
+
end
|
252
|
+
|
253
|
+
def dumped_value
|
254
|
+
rb_raw.pack('i*')
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class ArrayDouble < NodesArray
|
259
|
+
code XT_ARRAY_DOUBLE
|
260
|
+
def interpret(dat)
|
261
|
+
super dat.unpack('d'*(dat.size/8))
|
262
|
+
end
|
263
|
+
|
264
|
+
def dumped_value
|
265
|
+
rb_raw.pack('d*')
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
269
|
+
class ArrayBool < NodesArray
|
270
|
+
code XT_ARRAY_BOOL
|
271
|
+
|
272
|
+
def interpret(dat)
|
273
|
+
cnt, dat = dat.unpack('ia*')
|
274
|
+
super dat.unpack('c'*cnt).map{|i| int2bool(i)}
|
275
|
+
end
|
276
|
+
|
277
|
+
def dumped_value
|
278
|
+
([rb_raw.size] + rb_raw.map{|v| bool2int(v)}).pack('ic*')
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
class ArrayComplex < NodesArray
|
283
|
+
code XT_ARRAY_CPLX
|
284
|
+
def interpret(dat)
|
285
|
+
ary = dat.unpack('d'*(dat.size/8)).each_slice(2).map do |real,imag|
|
286
|
+
Complex(real, imag)
|
287
|
+
end
|
288
|
+
super ary
|
289
|
+
end
|
290
|
+
|
291
|
+
def dumped_value
|
292
|
+
rb_raw.map{|cpx| [cpx.real, cpx.imag]}.flatten.pack('d*')
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
class NodesList < ParentNode
|
297
|
+
end
|
298
|
+
|
299
|
+
class ListTag < NodesList
|
300
|
+
code XT_LIST_TAG
|
301
|
+
|
302
|
+
def rb_val
|
303
|
+
ary = children.map(&:rb_val)
|
304
|
+
hash = Hash.new
|
305
|
+
ary.each_slice(2){|v,k| hash[k] = v}
|
306
|
+
hash
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
class ListNoTag < NodesList
|
311
|
+
code XT_LIST_NOTAG
|
312
|
+
end
|
313
|
+
|
314
|
+
class NodesLang < ParentNode
|
315
|
+
end
|
316
|
+
|
317
|
+
class LangTag < NodesLang
|
318
|
+
code XT_LANG_TAG
|
319
|
+
end
|
320
|
+
|
321
|
+
class LangNoTag < NodesLang
|
322
|
+
code XT_LANG_NOTAG
|
323
|
+
end
|
324
|
+
|
325
|
+
class Vector < ParentNode
|
326
|
+
code XT_VECTOR
|
327
|
+
end
|
328
|
+
|
329
|
+
class Raw < Node
|
330
|
+
code XT_RAW
|
331
|
+
def interpret(dat)
|
332
|
+
cnt,dat=dat.unpack('ia*')
|
333
|
+
super dat.slice(0,cnt)
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
class Unknown < Node
|
338
|
+
code XT_UNKNOWN
|
339
|
+
end
|
340
|
+
|
341
|
+
class Closure < ParentNode
|
342
|
+
code XT_CLOS
|
343
|
+
end
|
344
|
+
|
345
|
+
class S4 < ParentNode
|
346
|
+
code XT_S4
|
347
|
+
end
|
348
|
+
end
|
349
|
+
|
350
|
+
def self.parse(dat)
|
351
|
+
node = Node::Root.new
|
352
|
+
node.interpret(dat)
|
353
|
+
node
|
354
|
+
end
|
355
|
+
|
356
|
+
def self.head_parameter(head)
|
357
|
+
type = head & 0x3f #high bits are for flags
|
358
|
+
large_flag = !(head & 0x40 == 0) # i.e. 1 << 6 (64)
|
359
|
+
attr_flag = !(head & 0x80 == 0) # i.e. 1 << 7 (128)
|
360
|
+
len = (head & ~0xff) >> 8
|
361
|
+
flags = {large: large_flag, attr: attr_flag}
|
362
|
+
[type, flags, len]
|
363
|
+
end
|
364
|
+
|
365
|
+
# debugging function
|
366
|
+
def self.xt_type_sym(type)
|
367
|
+
self.constants.find{|c| self.const_get(c) == type}
|
368
|
+
end
|
369
|
+
|
370
|
+
# debugging function
|
371
|
+
def self.announce(str)
|
372
|
+
# puts "A:#{str}"
|
373
|
+
end
|
374
|
+
|
375
|
+
# Decodes a buffer given a type of node
|
376
|
+
def self.decode_node(type, buffer)
|
377
|
+
announce [xt_type_sym(type), "0x%02x" % type, buffer.size, buffer].inspect
|
378
|
+
klass = Node.class_for_type(type)
|
379
|
+
if klass
|
380
|
+
node = klass.new
|
381
|
+
node.interpret(buffer)
|
382
|
+
node
|
383
|
+
else
|
384
|
+
raise RuntimeError, "no Node to decode type #{type}"
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
388
|
+
# Decodes a buffer starting with a header
|
389
|
+
# returns an array of two elements:
|
390
|
+
# - the new, interpreted Node
|
391
|
+
# - the remainder of the buffer
|
392
|
+
def self.decode_nodes(buffer)
|
393
|
+
head, buffer = buffer.unpack('Va*')
|
394
|
+
type, flags, len = head_parameter(head)
|
395
|
+
|
396
|
+
# Cuts the buffer at the correct length and give away the remainder
|
397
|
+
buffer, remainder = buffer.unpack("a#{len}a*")
|
398
|
+
|
399
|
+
attrs = nil
|
400
|
+
if flags[:attr]
|
401
|
+
attrs, buffer = decode_nodes(buffer)
|
402
|
+
end
|
403
|
+
|
404
|
+
node = decode_node(type, buffer)
|
405
|
+
|
406
|
+
node.attribute = attrs if attrs
|
407
|
+
|
408
|
+
[node, remainder]
|
409
|
+
end
|
410
|
+
|
411
|
+
def self.decode_nodes_array(buffer)
|
412
|
+
ary = []
|
413
|
+
until buffer.empty?
|
414
|
+
val, buffer = decode_nodes(buffer)
|
415
|
+
ary << val
|
416
|
+
end
|
417
|
+
ary
|
418
|
+
end
|
419
|
+
end
|
420
|
+
end
|
421
|
+
end
|
data/lib/em-rserve.rb
ADDED
data/samples/assign.rb
ADDED
@@ -0,0 +1,211 @@
|
|
1
|
+
#example which shows how various R objects are dumped and translated in Ruby
|
2
|
+
$LOAD_PATH << './lib'
|
3
|
+
|
4
|
+
require 'em-rserve'
|
5
|
+
require 'pp'
|
6
|
+
|
7
|
+
class DevelConnection < EM::Rserve::Connection
|
8
|
+
attr_reader :request_queue
|
9
|
+
|
10
|
+
def dump_sexp(msg)
|
11
|
+
raise unless msg.parameters.size == 1
|
12
|
+
root = msg.parameters.first
|
13
|
+
pp root
|
14
|
+
val = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(root)
|
15
|
+
p val
|
16
|
+
end
|
17
|
+
|
18
|
+
def dump_r_val(str)
|
19
|
+
r_eval(str) do |req|
|
20
|
+
req.callback do |msg|
|
21
|
+
dump_sexp msg
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def assign_and_debug_node(sym, node)
|
27
|
+
assign(sym, node) do |req|
|
28
|
+
req.errback do |err|
|
29
|
+
puts 'could not assign'
|
30
|
+
end
|
31
|
+
req.callback do |msg|
|
32
|
+
puts 'assigned'
|
33
|
+
dump_r_val sym.to_s
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def loop_parse_r_val(str)
|
39
|
+
r_eval(str) do |req|
|
40
|
+
req.callback do |msg|
|
41
|
+
raise unless msg.parameters.size == 1
|
42
|
+
root = msg.parameters.first
|
43
|
+
new_root = EM::Rserve::R::Sexp.parse(root.dump_sexp)
|
44
|
+
val1 = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(root)
|
45
|
+
val2 = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(new_root)
|
46
|
+
if val1 == val2
|
47
|
+
p "ok: #{str}"
|
48
|
+
else
|
49
|
+
p "ko: #{str}"
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def do_int
|
56
|
+
do_array_int([1])
|
57
|
+
end
|
58
|
+
|
59
|
+
def do_array_int(ints=[1,2,3,4,5])
|
60
|
+
root = EM::Rserve::R::Sexp::Node::Root.new
|
61
|
+
array = EM::Rserve::R::Sexp::Node::ArrayInt.new
|
62
|
+
array.rb_raw = ints
|
63
|
+
root.children << array
|
64
|
+
assign_and_debug_node :lol, root
|
65
|
+
end
|
66
|
+
|
67
|
+
def do_double
|
68
|
+
do_array_double [3.14]
|
69
|
+
end
|
70
|
+
|
71
|
+
def do_array_double(doubles=[1,2,3,4.2])
|
72
|
+
root = EM::Rserve::R::Sexp::Node::Root.new
|
73
|
+
array = EM::Rserve::R::Sexp::Node::ArrayDouble.new
|
74
|
+
array.rb_raw = doubles
|
75
|
+
root.children << array
|
76
|
+
assign_and_debug_node :lol, root
|
77
|
+
end
|
78
|
+
|
79
|
+
def do_array_bool(bools=[true, false, nil])
|
80
|
+
root = EM::Rserve::R::Sexp::Node::Root.new
|
81
|
+
array = EM::Rserve::R::Sexp::Node::ArrayBool.new
|
82
|
+
array.rb_raw = bools
|
83
|
+
root.children << array
|
84
|
+
assign_and_debug_node :lol, root
|
85
|
+
end
|
86
|
+
|
87
|
+
def do_true
|
88
|
+
do_array_bool [true]
|
89
|
+
end
|
90
|
+
|
91
|
+
def do_false
|
92
|
+
do_array_bool [false]
|
93
|
+
end
|
94
|
+
|
95
|
+
def do_nil
|
96
|
+
do_array_bool [nil]
|
97
|
+
end
|
98
|
+
|
99
|
+
def do_string
|
100
|
+
do_array_string ["lulzor"]
|
101
|
+
end
|
102
|
+
|
103
|
+
def do_array_string(strs=['for', 'great', 'justice'])
|
104
|
+
root = EM::Rserve::R::Sexp::Node::Root.new
|
105
|
+
array = EM::Rserve::R::Sexp::Node::ArrayString.new
|
106
|
+
array.rb_raw = strs
|
107
|
+
root.children << array
|
108
|
+
assign_and_debug_node :lol, root
|
109
|
+
end
|
110
|
+
|
111
|
+
def do_table_for_ints
|
112
|
+
root = EM::Rserve::R::Sexp::Node::Root.new do |root|
|
113
|
+
root.children << EM::Rserve::R::Sexp::Node::ArrayInt.new do |node|
|
114
|
+
node.rb_raw = [1,3,1]
|
115
|
+
node.attribute = EM::Rserve::R::Sexp::Node::ListTag.new do |attr|
|
116
|
+
attr.children << EM::Rserve::R::Sexp::Node::ArrayInt.new do |val|
|
117
|
+
val.rb_raw = [3]
|
118
|
+
end
|
119
|
+
attr.children << EM::Rserve::R::Sexp::Node::SymName.new do |val|
|
120
|
+
val.rb_raw = "dim"
|
121
|
+
end
|
122
|
+
attr.children << EM::Rserve::R::Sexp::Node::Vector.new do |vector|
|
123
|
+
vector.attribute = EM::Rserve::R::Sexp::Node::ListTag.new do |tags|
|
124
|
+
tags.rb_raw = [[''], "names"] #XXX should not be necessary to correct dump
|
125
|
+
tags.children << EM::Rserve::R::Sexp::Node::ArrayString.new do |strings|
|
126
|
+
strings.rb_raw = ['']
|
127
|
+
end
|
128
|
+
tags.children << EM::Rserve::R::Sexp::Node::SymName.new do |val|
|
129
|
+
val.rb_raw = 'names'
|
130
|
+
end
|
131
|
+
end
|
132
|
+
vector.children << EM::Rserve::R::Sexp::Node::ArrayString.new do |strings|
|
133
|
+
strings.rb_raw = ['1', '2', '3']
|
134
|
+
end
|
135
|
+
vector.rb_raw = [['1', '2', '3']] #XXX should not be needed
|
136
|
+
end
|
137
|
+
attr.children << EM::Rserve::R::Sexp::Node::SymName.new do |val|
|
138
|
+
val.rb_raw = "dimnames"
|
139
|
+
end
|
140
|
+
attr.children << EM::Rserve::R::Sexp::Node::ArrayString.new do |val|
|
141
|
+
val.rb_raw = ["table"]
|
142
|
+
end
|
143
|
+
attr.children << EM::Rserve::R::Sexp::Node::SymName.new do |val|
|
144
|
+
val.rb_raw = "class"
|
145
|
+
end
|
146
|
+
attr.rb_raw = [[3], "dim", [["1", "2", "3"]], "dimnames", ["table"], "class"] #XXX should not be needed
|
147
|
+
end
|
148
|
+
root.rb_raw = [[1, 3, 1]]
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
assign_and_debug_node :lol, root
|
153
|
+
end
|
154
|
+
|
155
|
+
def ready
|
156
|
+
puts "ready"
|
157
|
+
|
158
|
+
loop_parse_r_val '1+1i'
|
159
|
+
loop_parse_r_val 'c(1:1000)'
|
160
|
+
loop_parse_r_val 'c(1:10000000)'
|
161
|
+
|
162
|
+
return
|
163
|
+
|
164
|
+
root = EM::Rserve::R::RubytoR::Translator.ruby_to_r ['hello', 'world']
|
165
|
+
assign_and_debug_node :lol, root
|
166
|
+
|
167
|
+
root = EM::Rserve::R::RubytoR::Translator.ruby_to_r [400, 30, 12]
|
168
|
+
assign_and_debug_node :lol, root
|
169
|
+
|
170
|
+
root = EM::Rserve::R::RubytoR::Translator.ruby_to_r(:foo => [1,2,3],
|
171
|
+
:bar => ['a', 'b', 'c'])
|
172
|
+
assign_and_debug_node :lol, root
|
173
|
+
|
174
|
+
return
|
175
|
+
|
176
|
+
loop_parse_r_val 'c(1:5)'
|
177
|
+
loop_parse_r_val 'table(c(1,2,3,2,2))'
|
178
|
+
loop_parse_r_val "data.frame(foo=c(1:8), bar=seq(100,800,100))"
|
179
|
+
loop_parse_r_val "data.frame(foo=c(1,2,3), bar=c(NA,FALSE,TRUE), row.names=c('foo','bar','baz'))"
|
180
|
+
|
181
|
+
#do_int
|
182
|
+
#do_double
|
183
|
+
#do_true
|
184
|
+
#do_false
|
185
|
+
#do_nil
|
186
|
+
#do_string
|
187
|
+
|
188
|
+
#do_array_int
|
189
|
+
#do_array_double
|
190
|
+
#do_array_bool
|
191
|
+
#do_array_string
|
192
|
+
|
193
|
+
#do_table_for_ints
|
194
|
+
|
195
|
+
#r_eval 'table(c(1,2,3,2,2))'
|
196
|
+
#table:
|
197
|
+
# root
|
198
|
+
# ArrayInt
|
199
|
+
#
|
200
|
+
|
201
|
+
return
|
202
|
+
r_eval 'function(a,b=2){a+b}'
|
203
|
+
r_eval 'ls'
|
204
|
+
r_eval 'print'
|
205
|
+
end
|
206
|
+
|
207
|
+
end
|
208
|
+
|
209
|
+
EM.run do
|
210
|
+
DevelConnection.start
|
211
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
#this sample will detach a session and reattach a session in a new connection
|
2
|
+
$LOAD_PATH << './lib'
|
3
|
+
|
4
|
+
require 'em-rserve'
|
5
|
+
|
6
|
+
$KEYPORT = false
|
7
|
+
|
8
|
+
class DevelConnection < EM::Rserve::Connection
|
9
|
+
attr_reader :request_queue
|
10
|
+
|
11
|
+
def post_init
|
12
|
+
super
|
13
|
+
if $KEYPORT
|
14
|
+
replace_parser! EM::Rserve::Protocol::MessageParser
|
15
|
+
key = $KEYPORT.last
|
16
|
+
attach key do |req|
|
17
|
+
req.callback do |msg|
|
18
|
+
p "attached"
|
19
|
+
shutdown!
|
20
|
+
end
|
21
|
+
req.errback do |err|
|
22
|
+
p "not attached"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
r_eval "ls()" do |req|
|
26
|
+
req.callback do |msg|
|
27
|
+
p msg
|
28
|
+
end
|
29
|
+
req.errback do |err|
|
30
|
+
p err
|
31
|
+
end
|
32
|
+
end
|
33
|
+
#shutdown!
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def ready
|
38
|
+
p "ready"
|
39
|
+
if $KEYPORT
|
40
|
+
key = $KEYPORT.last
|
41
|
+
else
|
42
|
+
r_eval "a <- c(1:10)"
|
43
|
+
detach do |d|
|
44
|
+
d.callback do |msg|
|
45
|
+
puts "detached"
|
46
|
+
$KEYPORT = msg.parameters
|
47
|
+
port = $KEYPORT.first
|
48
|
+
puts "connecting: #{port}"
|
49
|
+
EM::next_tick do
|
50
|
+
DevelConnection.start('127.0.0.1', port)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def detach
|
58
|
+
puts "detaching"
|
59
|
+
super
|
60
|
+
end
|
61
|
+
|
62
|
+
def attach(key, &blk)
|
63
|
+
puts "attaching"
|
64
|
+
super
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
EM.run do
|
69
|
+
DevelConnection.start
|
70
|
+
end
|