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
data/samples/fibers.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
$LOAD_PATH << './lib'
|
2
|
+
require 'em-rserve'
|
3
|
+
require 'em-rserve/pooler'
|
4
|
+
|
5
|
+
class MyConnection < EM::Rserve::FiberedConnection
|
6
|
+
def ready
|
7
|
+
p 'ready'
|
8
|
+
super
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
pool = EM::Rserve::Pooler.new(3, MyConnection)
|
13
|
+
|
14
|
+
EM::run do
|
15
|
+
pool.fill
|
16
|
+
|
17
|
+
EM.next_tick do
|
18
|
+
EM::Rserve::Pooler::r do |r|
|
19
|
+
x = (0 .. 5).map{|v| Math.sin(v)}
|
20
|
+
y = x.map{|i| i**2 + 0.4*rand()}
|
21
|
+
r[:dat] = {x: x, y: y}
|
22
|
+
p r.call('cor(dat$x, dat$y)')
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
EM.add_periodic_timer(1) do
|
27
|
+
pool.r do |r|
|
28
|
+
r[:dat] = 'hello world'
|
29
|
+
p r[:dat]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/samples/run.rb
ADDED
@@ -0,0 +1,66 @@
|
|
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 receive_message(msg)
|
11
|
+
super
|
12
|
+
dump_sexp(msg)
|
13
|
+
end
|
14
|
+
|
15
|
+
def dump_sexp(msg)
|
16
|
+
raise unless msg.parameters.size == 1
|
17
|
+
root = msg.parameters.first
|
18
|
+
catch :cannot_translate do
|
19
|
+
val = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(root)
|
20
|
+
puts "translated"
|
21
|
+
puts val.inspect
|
22
|
+
end
|
23
|
+
node = root.children.first
|
24
|
+
pp node
|
25
|
+
end
|
26
|
+
|
27
|
+
def unbind
|
28
|
+
super
|
29
|
+
p "closing"
|
30
|
+
end
|
31
|
+
|
32
|
+
def ready
|
33
|
+
puts "ready"
|
34
|
+
|
35
|
+
r_eval 'as.Date("2/3/2004", "%m/%d/%Y")'
|
36
|
+
return
|
37
|
+
r_eval 'ts(1:8)'
|
38
|
+
r_eval 'as.formula(y~x1+x2+x3)'
|
39
|
+
r_eval 'raw(8)'
|
40
|
+
r_eval 'c(NaN, Inf)'
|
41
|
+
r_eval 'quote(c(1:3))'
|
42
|
+
r_eval 'as.factor(c("a", "a", "b", "c"))'
|
43
|
+
r_eval "data.frame(foo=c(1:8), bar=seq(100,800,100))"
|
44
|
+
r_eval 'table(c(1,2,3,2,2))'
|
45
|
+
r_eval 'list(name="Fred", wife="Mary", no.children=3, child.ages=c(4,7,9))'
|
46
|
+
r_eval 'c(1:5)'
|
47
|
+
r_eval 'TRUE'
|
48
|
+
r_eval 'FALSE'
|
49
|
+
r_eval 'NA'
|
50
|
+
r_eval "data(Cars93, package='MASS')"
|
51
|
+
r_eval "cor(c(1:100), runif(1:100))"
|
52
|
+
r_eval "cor(c(1:100), c(1:100))"
|
53
|
+
r_eval 'table(c("a", "b", "c", "a", "b"))'
|
54
|
+
r_eval "data.frame(foo=c(1:8))"
|
55
|
+
r_eval "data.frame(foo=c(1,2,3), bar=c(NA,FALSE,TRUE), row.names=c('foo','bar','baz'))"
|
56
|
+
# r_eval 'function(a,b=2){a+b}'
|
57
|
+
# r_eval 'ls'
|
58
|
+
# r_eval 'print'
|
59
|
+
r_eval 't.test(c(1,2,3,1),c(1,6,7,8))'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
EM.run do
|
65
|
+
DevelConnection.start
|
66
|
+
end
|
data/samples/sql.rb
ADDED
@@ -0,0 +1,167 @@
|
|
1
|
+
# this example requires
|
2
|
+
# rubygems: sequel and the sqlite3 adapter
|
3
|
+
# R: RSQLite package
|
4
|
+
# first run this script with 'create' argument to generate a simple table
|
5
|
+
require 'sequel'
|
6
|
+
|
7
|
+
DB = Sequel.sqlite('dat.sqlite')
|
8
|
+
items = DB[:items]
|
9
|
+
|
10
|
+
if ARGV.include?('create')
|
11
|
+
DB.create_table :items do
|
12
|
+
primary_key :id
|
13
|
+
String :name
|
14
|
+
Float :price
|
15
|
+
Float :sells
|
16
|
+
end
|
17
|
+
|
18
|
+
100.times do |t|
|
19
|
+
price = rand(t)*100
|
20
|
+
sells = rand(Math.sqrt(price))
|
21
|
+
items.insert(:name => 'abc',
|
22
|
+
:price => price,
|
23
|
+
:sells => sells)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
$code = items.filter(:name => 'abc').sql
|
28
|
+
p $code
|
29
|
+
|
30
|
+
DB.disconnect
|
31
|
+
|
32
|
+
$LOAD_PATH << './lib'
|
33
|
+
|
34
|
+
require 'em-rserve'
|
35
|
+
require 'em-rserve/qap1'
|
36
|
+
|
37
|
+
class DevelConnection < EM::Rserve::Connection
|
38
|
+
attr_reader :request_queue
|
39
|
+
|
40
|
+
def dump_sexp(msg)
|
41
|
+
raise unless msg.parameters.size == 1
|
42
|
+
root = msg.parameters.first
|
43
|
+
node = root.children.first
|
44
|
+
catch :cannot_translate do
|
45
|
+
val = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(root)
|
46
|
+
p val
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def ready
|
51
|
+
puts "ready"
|
52
|
+
r_eval "library(DBI)", true do |q|
|
53
|
+
q.errback do |err|
|
54
|
+
p "error loading DBI"
|
55
|
+
end
|
56
|
+
q.callback do |msg|
|
57
|
+
p "DBI loaded"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
r_eval "library(RSQLite)", true do |q|
|
61
|
+
q.errback do |err|
|
62
|
+
p "error loading RSQLite"
|
63
|
+
end
|
64
|
+
q.callback do |msg|
|
65
|
+
p "RSQLite loaded"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
r_eval "driver <- dbDriver('SQLite')", true do |q|
|
69
|
+
q.errback do |err|
|
70
|
+
p "error driving RSQLite"
|
71
|
+
end
|
72
|
+
q.callback do |msg|
|
73
|
+
p "RSQLite driver"
|
74
|
+
end
|
75
|
+
end
|
76
|
+
code = "con <- dbConnect(driver, \"#{File.expand_path('dat.sqlite')}\")"
|
77
|
+
puts code
|
78
|
+
r_eval(code, true) do |q|
|
79
|
+
q.errback do |err|
|
80
|
+
p "error connecting RSQLite"
|
81
|
+
end
|
82
|
+
q.callback do |msg|
|
83
|
+
p "RSQLite connected"
|
84
|
+
end
|
85
|
+
end
|
86
|
+
code = "query <- dbSendQuery(con, statement = \"#{$code}\")"
|
87
|
+
puts code
|
88
|
+
r_eval(code, true) do |q|
|
89
|
+
q.errback do |err|
|
90
|
+
p "error querying RSQLite"
|
91
|
+
end
|
92
|
+
q.callback do |msg|
|
93
|
+
p "RSQLite queried"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
r_eval "dat <- fetch(query)", true do |q|
|
97
|
+
q.errback do |err|
|
98
|
+
p "error fecthing query"
|
99
|
+
end
|
100
|
+
q.callback do |msg|
|
101
|
+
p "query fetched"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
r_eval "sqliteCloseResult(query)", true do |q|
|
105
|
+
q.errback do |err|
|
106
|
+
p "error closing query"
|
107
|
+
end
|
108
|
+
q.callback do |msg|
|
109
|
+
p "query closed"
|
110
|
+
end
|
111
|
+
end
|
112
|
+
r_eval "sqliteCloseConnection(con)", true do |q|
|
113
|
+
q.errback do |err|
|
114
|
+
p "error closing connection"
|
115
|
+
end
|
116
|
+
q.callback do |msg|
|
117
|
+
p "connection closed"
|
118
|
+
end
|
119
|
+
end
|
120
|
+
r_eval "sqliteCloseDriver(driver)", true do |q|
|
121
|
+
q.errback do |err|
|
122
|
+
p "error closing driver"
|
123
|
+
end
|
124
|
+
q.callback do |msg|
|
125
|
+
p "driver closed"
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
# dataframes are mapped to subclasses of Hashes which respond_to :each_struct
|
130
|
+
r_eval "dat" do |q|
|
131
|
+
q.errback do |err|
|
132
|
+
p "error getting dat"
|
133
|
+
end
|
134
|
+
q.callback do |msg|
|
135
|
+
p "got dat"
|
136
|
+
root = msg.parameters.first
|
137
|
+
node = root.children.first
|
138
|
+
catch :cannot_translate do
|
139
|
+
val = EM::Rserve::R::RtoRuby::Translator.r_to_ruby(root)
|
140
|
+
val.each_struct do |st|
|
141
|
+
p st
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
# vectors of doubles with a single item are mapped to a single double
|
148
|
+
r_eval "cor(dat$sells, dat$price)" do |q|
|
149
|
+
q.errback do |err|
|
150
|
+
p "error getting correlation"
|
151
|
+
end
|
152
|
+
q.callback do |msg|
|
153
|
+
p "got correlation"
|
154
|
+
dump_sexp(msg)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
r_eval "c(1:10)"
|
158
|
+
end
|
159
|
+
|
160
|
+
end
|
161
|
+
|
162
|
+
EM.run do
|
163
|
+
# EM::Rserve::Connection.start
|
164
|
+
DevelConnection.start
|
165
|
+
end
|
166
|
+
|
167
|
+
|
data/samples/webplot.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
|
2
|
+
$LOAD_PATH << './lib'
|
3
|
+
require 'sinatra'
|
4
|
+
require 'em-rserve'
|
5
|
+
require 'em-rserve/pooler'
|
6
|
+
require 'fileutils'
|
7
|
+
|
8
|
+
FileUtils.mkdir_p 'plots'
|
9
|
+
|
10
|
+
get '/' do
|
11
|
+
redirect :plot
|
12
|
+
end
|
13
|
+
|
14
|
+
helpers do
|
15
|
+
def pool
|
16
|
+
@@pool ||= EM::Rserve::Pooler.new 10
|
17
|
+
end
|
18
|
+
|
19
|
+
def plot(template, system=:erb)
|
20
|
+
pool.r do |r|
|
21
|
+
@path = File.join(Dir.pwd, "plots", "plot-#{request.object_id}.png")
|
22
|
+
r[:color] = 'blue' #sets color variable in R context (used in the template)
|
23
|
+
script = send system, template
|
24
|
+
r.call(script, true)
|
25
|
+
ctype = content_type || 'image/png'
|
26
|
+
File.open(@path,'r') do |ret|
|
27
|
+
env["async.callback"].call [200, {'Content-Type' => ctype}, ret]
|
28
|
+
end
|
29
|
+
FileUtils.rm @path
|
30
|
+
end
|
31
|
+
throw :async
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
get '/plot' do
|
36
|
+
plot :plot, :erb
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
require 'em-rserve/protocol/parser'
|
3
|
+
|
4
|
+
describe EM::Rserve::Protocol::IDParser do
|
5
|
+
before :each do
|
6
|
+
@receiver = Class.new do
|
7
|
+
attr_accessor :test_block
|
8
|
+
def receive_id(id)
|
9
|
+
test_block.call(id)
|
10
|
+
end
|
11
|
+
end.new
|
12
|
+
|
13
|
+
@parser = EM::Rserve::Protocol::IDParser.new(@receiver)
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should slice stuff in IDs of 4 bytes" do
|
17
|
+
idx = 0
|
18
|
+
count = 3
|
19
|
+
@receiver.test_block = lambda do |id|
|
20
|
+
idx += 1
|
21
|
+
id.should be_a(EM::Rserve::Protocol::ID)
|
22
|
+
id.string.should eql('1234')
|
23
|
+
end
|
24
|
+
@parser << ("1234"*count)
|
25
|
+
idx.should eql(3)
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should not bother about chunked input" do
|
29
|
+
idx = 0
|
30
|
+
count = 3
|
31
|
+
@receiver.test_block = lambda do |id|
|
32
|
+
idx += 1
|
33
|
+
id.should be_a(EM::Rserve::Protocol::ID)
|
34
|
+
id.string.should eql('1234')
|
35
|
+
end
|
36
|
+
count.times do |t|
|
37
|
+
@parser << "1"
|
38
|
+
@parser << "23"
|
39
|
+
idx.should eql(t)
|
40
|
+
@parser << "4"
|
41
|
+
end
|
42
|
+
idx.should eql(3)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
|
2
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
3
|
+
require 'em-rserve/protocol/parser'
|
4
|
+
|
5
|
+
describe EM::Rserve::Protocol::MessageParser do
|
6
|
+
before :each do
|
7
|
+
@receiver = Class.new do
|
8
|
+
attr_accessor :h_test_block
|
9
|
+
attr_accessor :m_test_block
|
10
|
+
def receive_message_header(h)
|
11
|
+
h_test_block.call(h)
|
12
|
+
end
|
13
|
+
def receive_message(m)
|
14
|
+
m_test_block.call(m)
|
15
|
+
end
|
16
|
+
end.new
|
17
|
+
|
18
|
+
@parser = EM::Rserve::Protocol::MessageParser.new(@receiver)
|
19
|
+
end
|
20
|
+
|
21
|
+
it "should read a header after 16bytes" do
|
22
|
+
idx = 0
|
23
|
+
@receiver.h_test_block = lambda do |h|
|
24
|
+
idx += 1
|
25
|
+
h.should be_a(EM::Rserve::QAP1::Header)
|
26
|
+
end
|
27
|
+
@parser << ("\0" * 16)
|
28
|
+
idx.should eql(1)
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should read a header after 16bytes, even if data is chunked" do
|
32
|
+
idx = 0
|
33
|
+
@receiver.h_test_block = lambda do |h|
|
34
|
+
idx += 1
|
35
|
+
h.should be_a(EM::Rserve::QAP1::Header)
|
36
|
+
end
|
37
|
+
16.times { @parser << "\0" }
|
38
|
+
idx.should eql(1)
|
39
|
+
end
|
40
|
+
|
41
|
+
|
42
|
+
it "should read a message whose length is specified in the header and data is sliced" do
|
43
|
+
hack = Module.new do
|
44
|
+
attr_accessor :message_length
|
45
|
+
end
|
46
|
+
#XXX this is actual, valid data, we should split the slicing and parsing
|
47
|
+
message = "0a 0c 00 00 21 08 00 00 00 00 00 00 00 00 f0 3f".split.
|
48
|
+
pack('H2'*16)
|
49
|
+
|
50
|
+
@receiver.h_test_block = lambda do |m|
|
51
|
+
m.should be_a(EM::Rserve::QAP1::Header)
|
52
|
+
# Here we overwrite the header to not care about header's content in this spec
|
53
|
+
m.extend hack
|
54
|
+
m.message_length = message.length
|
55
|
+
end
|
56
|
+
|
57
|
+
idx = 0
|
58
|
+
@receiver.m_test_block = lambda do |m|
|
59
|
+
idx += 1
|
60
|
+
m.should be_a(EM::Rserve::QAP1::Message)
|
61
|
+
end
|
62
|
+
|
63
|
+
stream = ("\0" * 16) + message
|
64
|
+
stream.split('').each do |char|
|
65
|
+
idx.should eql(0)
|
66
|
+
@parser << char
|
67
|
+
end
|
68
|
+
idx.should eql(1)
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
require 'em-rserve/protocol/parser'
|
3
|
+
|
4
|
+
describe EM::Rserve::Protocol::Parser, 'initialized' do
|
5
|
+
before :each do
|
6
|
+
@parser = EM::Rserve::Protocol::Parser.new(:foobar)
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should have an empty buffer" do
|
10
|
+
@parser.buffer.should be_empty
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should remember the handler" do
|
14
|
+
@parser.handler.should eql(:foobar)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe EM::Rserve::Protocol::Parser, 'replacement' do
|
19
|
+
before :each do
|
20
|
+
@parser = EM::Rserve::Protocol::Parser.new(:foo)
|
21
|
+
@new_parser = EM::Rserve::Protocol::Parser.new(:bar)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should replace the buffer but not the handler" do
|
25
|
+
@parser.buffer << "foobar" #XXX we directly manipulate the buffer here
|
26
|
+
@new_parser.replace(@parser)
|
27
|
+
@new_parser.handler.should eql(:bar)
|
28
|
+
@new_parser.buffer.should eql("foobar")
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe EM::Rserve::Protocol::Parser, 'loop guard for topklass' do
|
33
|
+
before :each do
|
34
|
+
@parser = EM::Rserve::Protocol::Parser.new(:foo)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should ask for subclassing" do
|
38
|
+
lambda {
|
39
|
+
@parser << "lulz"
|
40
|
+
}.should raise_error(NotImplementedError)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
describe EM::Rserve::Protocol::Parser, 'loop mechanics for subklasses' do
|
45
|
+
before :each do
|
46
|
+
m = Module.new do
|
47
|
+
attr_accessor :test_proc
|
48
|
+
def parse!
|
49
|
+
test_proc.call
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
@parser = EM::Rserve::Protocol::Parser.new(:foo)
|
54
|
+
@parser.extend m
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should loop until we throw :stop when we call the loop" do
|
58
|
+
idx = 0
|
59
|
+
limit = 123
|
60
|
+
@parser.test_proc = lambda do
|
61
|
+
idx += 1
|
62
|
+
throw :stop if idx == limit
|
63
|
+
end
|
64
|
+
|
65
|
+
@parser.parse_loop!
|
66
|
+
idx.should eql(limit)
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should call the loop when we add data" do
|
70
|
+
idx = 0
|
71
|
+
limit = 123
|
72
|
+
@parser.test_proc = lambda do
|
73
|
+
idx += 1
|
74
|
+
throw :stop if idx == limit
|
75
|
+
end
|
76
|
+
|
77
|
+
@parser << "for great justice"
|
78
|
+
idx.should eql(limit)
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
require 'em-rserve/r/ruby_to_r/translator'
|
3
|
+
require 'em-rserve/r/sexp'
|
4
|
+
|
5
|
+
describe EM::Rserve::R::RubytoR::Translator do
|
6
|
+
include EM::Rserve::R::RubytoR
|
7
|
+
|
8
|
+
it "should remember the object" do
|
9
|
+
tr = Translator.new(:foobar)
|
10
|
+
tr.obj.should eql(:foobar)
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should throw :cannot_translate when cannot translate" do
|
14
|
+
thrown=true
|
15
|
+
catch :cannot_translate do
|
16
|
+
Translator.new.translate
|
17
|
+
thrown=false
|
18
|
+
end
|
19
|
+
thrown.should be_true
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should translate simple arrays" do
|
23
|
+
thrown=true
|
24
|
+
catch :cannot_translate do
|
25
|
+
Translator.ruby_to_r([1, 2, 3])
|
26
|
+
Translator.ruby_to_r([1, 2.2, 3.2])
|
27
|
+
Translator.ruby_to_r([true, false, nil])
|
28
|
+
Translator.ruby_to_r(["we", "miss", "you", "_why"])
|
29
|
+
thrown=false
|
30
|
+
end
|
31
|
+
thrown.should be_false
|
32
|
+
end
|
33
|
+
|
34
|
+
it "should translate simple values" do
|
35
|
+
thrown=true
|
36
|
+
catch :cannot_translate do
|
37
|
+
Translator.ruby_to_r(1)
|
38
|
+
Translator.ruby_to_r(1.0)
|
39
|
+
Translator.ruby_to_r(false)
|
40
|
+
Translator.ruby_to_r(nil)
|
41
|
+
Translator.ruby_to_r(true)
|
42
|
+
Translator.ruby_to_r("hello world")
|
43
|
+
thrown=false
|
44
|
+
end
|
45
|
+
thrown.should be_false
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should translate simple hashes" do
|
49
|
+
thrown=true
|
50
|
+
catch :cannot_translate do
|
51
|
+
Translator.ruby_to_r({'foo' => [1,2,3,4], 'bar' => ['a', 'b', 'c', 'd']})
|
52
|
+
thrown=false
|
53
|
+
end
|
54
|
+
thrown.should be_false
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
describe EM::Rserve::R::RubytoR::Translator::ArrayTranslator do
|
59
|
+
include EM::Rserve::R
|
60
|
+
|
61
|
+
def translator(obj)
|
62
|
+
EM::Rserve::R::RubytoR::Translator::ArrayTranslator.new obj
|
63
|
+
end
|
64
|
+
|
65
|
+
def node_class_for(obj)
|
66
|
+
translator(obj).array_node_class
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should propose arrays of bools" do
|
70
|
+
node_class_for([true, true, false, nil]).should eql(Sexp::Node::ArrayBool)
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should propose arrays of ints" do
|
74
|
+
node_class_for([1, 2, 3]).should eql(Sexp::Node::ArrayInt)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should propose arrays of doubles" do
|
78
|
+
node_class_for([1.2, 2.0, Math::PI]).should eql(Sexp::Node::ArrayDouble)
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should propose arrays of strings" do
|
82
|
+
node_class_for(["chunky", "bacon"]).should eql(Sexp::Node::ArrayString)
|
83
|
+
end
|
84
|
+
|
85
|
+
it "should propose arrays of doubles for mixes of floats and fixnums" do
|
86
|
+
node_class_for([1.5, 3]).should eql(Sexp::Node::ArrayDouble)
|
87
|
+
end
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: em-rserve
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- crapooze
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-10-10 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Do evented stats with EventMachine and RServe
|
23
|
+
email:
|
24
|
+
- crapooze@gmail.com
|
25
|
+
executables: []
|
26
|
+
|
27
|
+
extensions: []
|
28
|
+
|
29
|
+
extra_rdoc_files: []
|
30
|
+
|
31
|
+
files:
|
32
|
+
- .gitignore
|
33
|
+
- Gemfile
|
34
|
+
- README
|
35
|
+
- Rakefile
|
36
|
+
- TODO
|
37
|
+
- em-rserve.gemspec
|
38
|
+
- lib/em-rserve.rb
|
39
|
+
- lib/em-rserve/connection.rb
|
40
|
+
- lib/em-rserve/fibered_connection.rb
|
41
|
+
- lib/em-rserve/pooler.rb
|
42
|
+
- lib/em-rserve/protocol/connector.rb
|
43
|
+
- lib/em-rserve/protocol/id.rb
|
44
|
+
- lib/em-rserve/protocol/parser.rb
|
45
|
+
- lib/em-rserve/protocol/request.rb
|
46
|
+
- lib/em-rserve/qap1/constants.rb
|
47
|
+
- lib/em-rserve/qap1/header.rb
|
48
|
+
- lib/em-rserve/qap1/message.rb
|
49
|
+
- lib/em-rserve/qap1/rpack.rb
|
50
|
+
- lib/em-rserve/r/r_to_ruby/translator.rb
|
51
|
+
- lib/em-rserve/r/ruby_to_r/translator.rb
|
52
|
+
- lib/em-rserve/r/sexp.rb
|
53
|
+
- lib/em-rserve/version.rb
|
54
|
+
- samples/assign.rb
|
55
|
+
- samples/detach_attach.rb
|
56
|
+
- samples/fibers.rb
|
57
|
+
- samples/run.rb
|
58
|
+
- samples/sql.rb
|
59
|
+
- samples/views/plot.erb
|
60
|
+
- samples/webplot.rb
|
61
|
+
- specs/id_parser_spec.rb
|
62
|
+
- specs/message_parser_spec.rb
|
63
|
+
- specs/parser_spec.rb
|
64
|
+
- specs/ruby_to_r_translator_spec.rb
|
65
|
+
- specs/spec_helper.rb
|
66
|
+
has_rdoc: true
|
67
|
+
homepage: ""
|
68
|
+
licenses: []
|
69
|
+
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
|
73
|
+
require_paths:
|
74
|
+
- lib
|
75
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
76
|
+
none: false
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
hash: 3
|
81
|
+
segments:
|
82
|
+
- 0
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
hash: 3
|
90
|
+
segments:
|
91
|
+
- 0
|
92
|
+
version: "0"
|
93
|
+
requirements: []
|
94
|
+
|
95
|
+
rubyforge_project: em-rserve
|
96
|
+
rubygems_version: 1.3.7
|
97
|
+
signing_key:
|
98
|
+
specification_version: 3
|
99
|
+
summary: An EventMachine client for RServe
|
100
|
+
test_files: []
|
101
|
+
|