em-rserve 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -0,0 +1,5 @@
1
+ module EM
2
+ module Rserve
3
+ VERSION = "0.1.0"
4
+ end
5
+ end
data/lib/em-rserve.rb ADDED
@@ -0,0 +1,11 @@
1
+ require 'eventmachine'
2
+ require "em-rserve/version"
3
+ require "em-rserve/connection"
4
+ require "em-rserve/r/r_to_ruby/translator"
5
+ require "em-rserve/r/ruby_to_r/translator"
6
+
7
+ module EM
8
+ module Rserve
9
+ # Your code goes here...
10
+ end
11
+ end
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