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.
@@ -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