rserve-client 0.1.9 → 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.tar.gz.sig +0 -0
- data/History.txt +9 -1
- data/Manifest.txt +7 -0
- data/README.txt +8 -7
- data/benchmark/benchmark.rb +113 -0
- data/benchmark/comparison_2010_06_07.xls +0 -0
- data/benchmark/comparison_2010_06_07_using_pack.xls +0 -0
- data/benchmark/plot.rb +69 -0
- data/examples/hello_world.rb +1 -1
- data/lib/rserve.rb +2 -1
- data/lib/rserve/connection.rb +75 -14
- data/lib/rserve/protocol.rb +22 -1
- data/lib/rserve/rexp.rb +138 -74
- data/lib/rserve/rexp/double.rb +9 -2
- data/lib/rserve/session.rb +29 -0
- data/spec/rserve_connection_on_unix_spec.rb +37 -0
- data/spec/rserve_connection_spec.rb +22 -16
- data/spec/rserve_protocol_spec.rb +5 -0
- data/spec/rserve_rexp_to_ruby_spec.rb +3 -0
- data/spec/rserve_rexpfactory_spec.rb +4 -1
- data/spec/rserve_rlist_spec.rb +3 -0
- data/spec/rserve_session_spec.rb +27 -0
- data/spec/rserve_spec.rb +3 -0
- metadata +15 -6
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/History.txt
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
-
=== 0.
|
1
|
+
=== 0.2.0 / 2010-06-15
|
2
|
+
* Session implemented.
|
3
|
+
* Retrieve auth information from server first responde. TODO: Implement authentification
|
4
|
+
* Rserve::Protocol get_int and get_long uses pack. Spec for test compatibility for old method
|
5
|
+
* Added benchmark, comparing Rserve with RinRuby and RsRuby
|
6
|
+
* Windows Support:
|
7
|
+
* On windows, any new connection closes the previous. Rserve on Windows can't process parallel connections
|
8
|
+
* All Specification works on Windows
|
2
9
|
|
10
|
+
=== 0.1.9 / 2010-06-04
|
3
11
|
* Documentation:
|
4
12
|
* Added commentaries on examples/regression.txt
|
5
13
|
* Examples.txt on main directory renamed to Introduction.txt
|
data/Manifest.txt
CHANGED
@@ -4,6 +4,10 @@ Introduction.txt
|
|
4
4
|
Manifest.txt
|
5
5
|
README.txt
|
6
6
|
Rakefile
|
7
|
+
benchmark/benchmark.rb
|
8
|
+
benchmark/comparison_2010_06_07.xls
|
9
|
+
benchmark/comparison_2010_06_07_using_pack.xls
|
10
|
+
benchmark/plot.rb
|
7
11
|
data/gettysburg.txt
|
8
12
|
examples/gettysburg.rb
|
9
13
|
examples/hello_world.rb
|
@@ -36,9 +40,11 @@ lib/rserve/rexp/vector.rb
|
|
36
40
|
lib/rserve/rexp/wrapper.rb
|
37
41
|
lib/rserve/rfactor.rb
|
38
42
|
lib/rserve/rlist.rb
|
43
|
+
lib/rserve/session.rb
|
39
44
|
lib/rserve/talk.rb
|
40
45
|
lib/rserve/withattributes.rb
|
41
46
|
lib/rserve/withnames.rb
|
47
|
+
spec/rserve_connection_on_unix_spec.rb
|
42
48
|
spec/rserve_connection_spec.rb
|
43
49
|
spec/rserve_double_spec.rb
|
44
50
|
spec/rserve_genericvector_spec.rb
|
@@ -52,6 +58,7 @@ spec/rserve_rexp_wrapper_spec.rb
|
|
52
58
|
spec/rserve_rexpfactory_spec.rb
|
53
59
|
spec/rserve_rfactor_spec.rb
|
54
60
|
spec/rserve_rlist_spec.rb
|
61
|
+
spec/rserve_session_spec.rb
|
55
62
|
spec/rserve_spec.rb
|
56
63
|
spec/rserve_talk_spec.rb
|
57
64
|
spec/rserve_withnames_spec.rb
|
data/README.txt
CHANGED
@@ -16,10 +16,11 @@ Follows closely the new Java client API, but maintains all Ruby conventions when
|
|
16
16
|
* Requires Rserve installed on the server machine. On debian / ubuntu, you should use <tt>sudo apt-get install r-cran-rserve</tt>
|
17
17
|
Pros:
|
18
18
|
* Work with Ruby 1.8, 1.9 and JRuby 1.5.
|
19
|
-
*
|
20
|
-
*
|
21
|
-
*
|
22
|
-
*
|
19
|
+
* Work on Windows. Rserve limitations on that plataform applies (single connection, crash on parse errors)
|
20
|
+
* Retrieve and assign various R's datatypes: integer, doubles, chars, logical vectors, lists and raw data.
|
21
|
+
* Session allows to process data asynchronously. You start a command, detach the process and retrieve result later. You can marshall the session, store on file or database and use it when you need it.
|
22
|
+
* Ruby API follows closely the Java API, so any change on the server API could be adopted without much problem
|
23
|
+
* Fast: 5-10 times faster than RinRuby.
|
23
24
|
* Easy management of differences between R and Ruby, or "You can have your cake and eat it, too!"
|
24
25
|
* From R side: The evaluation of expression retrieves REXP object, with a lot of information from original variables on R. You can construct your REXP objects and <tt>assign</tt> them to variables on R fast using binary TCP/IP port or send complex expression without lost of time using <tt>void_eval</tt>
|
25
26
|
* Between R and Ruby: Every REXP object implements methods to convert to specific Ruby type: as_integers, as_doubles, as_strings
|
@@ -38,16 +39,17 @@ Cons:
|
|
38
39
|
* Work with Ruby 1.8, 1.9 and JRuby 1.5
|
39
40
|
* All API tested
|
40
41
|
* Cons:
|
41
|
-
* VERY SLOW
|
42
|
+
* VERY SLOW on assignation
|
42
43
|
* Very limited datatypes: Only vector and Matrix
|
43
44
|
* RSRuby
|
44
45
|
* C Extension for Ruby, linked to R's shared library
|
45
46
|
* Pros:
|
46
|
-
*
|
47
|
+
* Blazing speed! 5-10 times faster than Rserve and 100-1000 than RinRuby.
|
47
48
|
* Seamless integration with ruby. Every method and object is treated like a Ruby one
|
48
49
|
* Cons:
|
49
50
|
* Transformation between R and Ruby types aren't trivial
|
50
51
|
* Dependent on operating system, Ruby implementation and R version
|
52
|
+
* Ocassionaly crash
|
51
53
|
* Not available for alternative implementations of Ruby (JRuby, IronRuby and Rubinius)
|
52
54
|
|
53
55
|
|
@@ -55,7 +57,6 @@ Cons:
|
|
55
57
|
|
56
58
|
Implements
|
57
59
|
|
58
|
-
* Sessions
|
59
60
|
* Authentification
|
60
61
|
* Original test
|
61
62
|
|
@@ -0,0 +1,113 @@
|
|
1
|
+
# Compares rserve, rinruby and rsruby
|
2
|
+
# in retrieval and assign of information
|
3
|
+
$:.unshift(File.dirname(__FILE__)+"/../lib")
|
4
|
+
|
5
|
+
require 'rubygems'
|
6
|
+
require 'rserve'
|
7
|
+
require 'rinruby'
|
8
|
+
begin
|
9
|
+
require 'rsruby'
|
10
|
+
rs=RSRuby.instance
|
11
|
+
rescue LoadError
|
12
|
+
rs=nil
|
13
|
+
end
|
14
|
+
require 'benchmark'
|
15
|
+
data_size=30000
|
16
|
+
tries=50
|
17
|
+
con=Rserve::Connection.new
|
18
|
+
R.eval("1",false)
|
19
|
+
data=data_size.times.map {rand()}
|
20
|
+
data_integer=data_size.times.map {rand(100)}
|
21
|
+
Benchmark.bm(30) do |x|
|
22
|
+
x.report("assign '1' rinruby") {
|
23
|
+
tries.times {
|
24
|
+
R.a=1
|
25
|
+
}
|
26
|
+
}
|
27
|
+
x.report("assign '1' rserve") {
|
28
|
+
con.assign("a", 1)
|
29
|
+
}
|
30
|
+
if rs
|
31
|
+
x.report("assign '1' rsruby") {
|
32
|
+
rs.assign('a',1)
|
33
|
+
}
|
34
|
+
end
|
35
|
+
x.report("assign double(#{data_size}) rinruby") {
|
36
|
+
tries.times {
|
37
|
+
R.a=data
|
38
|
+
}
|
39
|
+
}
|
40
|
+
x.report("assign double(#{data_size}) rserve") {
|
41
|
+
con.assign("a", data)
|
42
|
+
}
|
43
|
+
if rs
|
44
|
+
x.report("assign double(#{data_size}) rsruby") {
|
45
|
+
rs.assign("a", data)
|
46
|
+
}
|
47
|
+
end
|
48
|
+
x.report("void_eval rinruby") {
|
49
|
+
tries.times {
|
50
|
+
R.eval("1",false)
|
51
|
+
}
|
52
|
+
}
|
53
|
+
x.report("void_eval rserve") {
|
54
|
+
tries.times {
|
55
|
+
con.void_eval("1")
|
56
|
+
}
|
57
|
+
}
|
58
|
+
if rs
|
59
|
+
x.report("void_eval rsruby") {
|
60
|
+
tries.times {
|
61
|
+
rs.eval("1")
|
62
|
+
}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
# Assign data
|
66
|
+
R.a=1
|
67
|
+
con.assign('a',1)
|
68
|
+
if rs
|
69
|
+
rs.assign('a',1)
|
70
|
+
end
|
71
|
+
x.report("get '1' rinruby") {
|
72
|
+
tries.times {
|
73
|
+
R.pull('a')
|
74
|
+
}
|
75
|
+
}
|
76
|
+
x.report("get '1' rserve") {
|
77
|
+
tries.times {
|
78
|
+
con.eval('a').to_ruby
|
79
|
+
}
|
80
|
+
}
|
81
|
+
if rs
|
82
|
+
x.report("get '1' rsruby") {
|
83
|
+
tries.times {
|
84
|
+
rs.a
|
85
|
+
}
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
R.a=data
|
90
|
+
con.assign('a',data)
|
91
|
+
if rs
|
92
|
+
rs.assign('a',data)
|
93
|
+
end
|
94
|
+
x.report("get double(#{data_size}) rinruby") {
|
95
|
+
tries.times {
|
96
|
+
R.pull('a')
|
97
|
+
}
|
98
|
+
}
|
99
|
+
x.report("get double(#{data_size}) rserve") {
|
100
|
+
tries.times {
|
101
|
+
con.eval('a').to_ruby
|
102
|
+
}
|
103
|
+
}
|
104
|
+
|
105
|
+
if rs
|
106
|
+
x.report("get double(#{data_size}) rsruby") {
|
107
|
+
tries.times {
|
108
|
+
rs.a
|
109
|
+
}
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
Binary file
|
Binary file
|
data/benchmark/plot.rb
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
# Creates a graph with multiple size assignment and retrieval
|
2
|
+
|
3
|
+
require 'rubygems'
|
4
|
+
require 'rserve'
|
5
|
+
require 'rinruby'
|
6
|
+
require 'benchmark'
|
7
|
+
require 'statsample'
|
8
|
+
require 'rsruby'
|
9
|
+
|
10
|
+
max=45
|
11
|
+
R.eval("1")
|
12
|
+
rs=RSRuby.instance
|
13
|
+
con=Rserve::Connection.new
|
14
|
+
rserve_assign = []
|
15
|
+
rserve_retrieve = []
|
16
|
+
rinruby_assign = []
|
17
|
+
rinruby_retrieve = []
|
18
|
+
rs_assign=[]
|
19
|
+
rs_retrieve=[]
|
20
|
+
|
21
|
+
max.times.map {|x|
|
22
|
+
puts "Rserve #{x}"
|
23
|
+
start=Time.new.to_f
|
24
|
+
con.assign('a',(x*100+1).times.map {rand})
|
25
|
+
a=Time.new.to_f-start
|
26
|
+
|
27
|
+
start=Time.new.to_f
|
28
|
+
|
29
|
+
con.eval('a').to_f
|
30
|
+
|
31
|
+
b=Time.new.to_f-start
|
32
|
+
|
33
|
+
rserve_assign.push(a)
|
34
|
+
rserve_retrieve.push(b)
|
35
|
+
}
|
36
|
+
max.times.map {|x|
|
37
|
+
|
38
|
+
puts "Rinruby #{x}"
|
39
|
+
start=Time.new.to_f
|
40
|
+
R.assign("a", (x*100+1).times.map {rand})
|
41
|
+
a=Time.new.to_f-start
|
42
|
+
start=Time.new.to_f
|
43
|
+
R.pull('a')
|
44
|
+
b=Time.new.to_f-start
|
45
|
+
rinruby_assign.push(a)
|
46
|
+
rinruby_retrieve.push(b)
|
47
|
+
}
|
48
|
+
|
49
|
+
|
50
|
+
max.times.map {|x|
|
51
|
+
puts "RsRuby #{x}"
|
52
|
+
start=Time.new.to_f
|
53
|
+
rs.assign('a',(x*100+1).times.map {rand})
|
54
|
+
a=Time.new.to_f-start
|
55
|
+
|
56
|
+
start=Time.new.to_f
|
57
|
+
|
58
|
+
rs.a.to_f
|
59
|
+
|
60
|
+
b=Time.new.to_f-start
|
61
|
+
|
62
|
+
rs_assign.push(a)
|
63
|
+
rs_retrieve.push(b)
|
64
|
+
}
|
65
|
+
|
66
|
+
|
67
|
+
ds_assign={'times'=>(1..max).map {|v| v*100+1}.to_scale,'rserve assign'=> rserve_assign.to_scale, 'rserve retrieve'=>rserve_retrieve.to_scale, 'rinruby assign'=>rinruby_assign.to_scale, 'rinruby retrieve'=>rinruby_retrieve.to_scale, 'rs_assign'=>rs_assign.to_scale, 'rs_retrieve'=>rs_retrieve.to_scale}.to_dataset
|
68
|
+
ds_assign.fields=['times','rs_assign','rserve_assign','rinruby_assign','rs_retrieve','rserve_retrieve','rinruby_retrieve']
|
69
|
+
Statsample::Excel.write(ds_assign,'comparison.xls')
|
data/examples/hello_world.rb
CHANGED
data/lib/rserve.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
3
|
module Rserve
|
4
|
-
VERSION = '0.
|
4
|
+
VERSION = '0.2.0'
|
5
5
|
end
|
6
6
|
|
7
7
|
|
@@ -14,6 +14,7 @@ require 'rserve/packet'
|
|
14
14
|
require 'rserve/talk'
|
15
15
|
require 'rserve/rexp'
|
16
16
|
require 'rserve/engine'
|
17
|
+
require 'rserve/session'
|
17
18
|
require 'rserve/connection'
|
18
19
|
require 'rserve/rlist'
|
19
20
|
require 'rserve/rfactor'
|
data/lib/rserve/connection.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
|
+
require 'rbconfig'
|
1
2
|
module Rserve
|
2
3
|
class Connection < Rserve::Engine
|
4
|
+
@@connected_object=nil
|
3
5
|
include Rserve::Protocol
|
4
6
|
|
5
7
|
# :section: Exceptions
|
@@ -27,6 +29,7 @@ module Rserve
|
|
27
29
|
attr_reader :rt
|
28
30
|
attr_reader :s
|
29
31
|
attr_reader :port
|
32
|
+
attr_reader :session
|
30
33
|
attr_writer :transfer_charset
|
31
34
|
attr_reader :rsrv_version
|
32
35
|
attr_writer :persistent
|
@@ -40,10 +43,13 @@ module Rserve
|
|
40
43
|
@hostname = opts.delete(:hostname) || "127.0.0.1"
|
41
44
|
@port_number = opts.delete(:port_number) || 6311
|
42
45
|
@max_tries = opts.delete(:max_tries) || 5
|
46
|
+
@session = opts.delete(:session) || nil
|
43
47
|
@tries = 0
|
44
48
|
@connected=false
|
45
|
-
|
46
|
-
|
49
|
+
if (!@session.nil?)
|
50
|
+
@hostname=@session.host
|
51
|
+
@port_number=@session.port
|
52
|
+
end
|
47
53
|
begin
|
48
54
|
#puts "Tryin to connect..."
|
49
55
|
connect
|
@@ -72,22 +78,49 @@ module Rserve
|
|
72
78
|
end
|
73
79
|
end
|
74
80
|
def connect
|
75
|
-
|
81
|
+
# On windows, Rserve doesn't allows concurrent connections.
|
82
|
+
# So, we must close the last open connection first
|
83
|
+
if RbConfig::CONFIG['arch']=~/mswin/ and !@@connected_object.nil?
|
84
|
+
@@connected_object.close
|
85
|
+
end
|
86
|
+
|
76
87
|
close if @connected
|
88
|
+
|
77
89
|
@s = TCPSocket::new(@hostname, @port_number)
|
78
90
|
@rt=Rserve::Talk.new(@s)
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
91
|
+
if @session.nil?
|
92
|
+
#puts "Connected"
|
93
|
+
# Accept first input
|
94
|
+
input=@s.recv(32).unpack("a4a4a4a4a4a4a4a4")
|
95
|
+
raise IncorrectServer,"Handshake failed: Rsrv signature expected, but received [#{input[0]}]" unless input[0]=="Rsrv"
|
96
|
+
@rsrv_version=input[1].to_i
|
97
|
+
raise IncorrectServerVersion, "Handshake failed: The server uses more recent protocol than this client." if @rsrv_version>103
|
98
|
+
@protocol=input[2]
|
99
|
+
raise IncorrectProtocol, "Handshake failed: unsupported transfer protocol #{@protocol}, I talk only QAP1." if @protocol!="QAP1"
|
100
|
+
(3..7).each do |i|
|
101
|
+
attr=input[i]
|
102
|
+
if (attr=="ARpt")
|
103
|
+
if (!auth_req) # this method is only fallback when no other was specified
|
104
|
+
auth_req=true
|
105
|
+
auth_type=AT_plain
|
106
|
+
end
|
107
|
+
end
|
108
|
+
if (attr=="ARuc")
|
109
|
+
auth_req=true
|
110
|
+
authType=AT_crypt
|
111
|
+
end
|
112
|
+
if (attr[0]=='K')
|
113
|
+
key=attr[1,3]
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
else # we have a session to take care of
|
118
|
+
@s.write(@session.key.pack("C*"))
|
119
|
+
@rsrv_version=session.rsrv_version
|
120
|
+
end
|
88
121
|
@connected=true
|
122
|
+
@@connected_object=self
|
89
123
|
@last_error="OK"
|
90
|
-
|
91
124
|
end
|
92
125
|
def connected?
|
93
126
|
@connected
|
@@ -99,6 +132,7 @@ module Rserve
|
|
99
132
|
end
|
100
133
|
raise "Can't close socket" unless @s.closed?
|
101
134
|
@connected=false
|
135
|
+
@@connected_object=nil
|
102
136
|
true
|
103
137
|
end
|
104
138
|
def get_server_version
|
@@ -119,6 +153,20 @@ module Rserve
|
|
119
153
|
end
|
120
154
|
|
121
155
|
|
156
|
+
def void_eval_detach(cmd)
|
157
|
+
raise NotConnected if !connected? or rt.nil?
|
158
|
+
rp=rt.request(:cmd=>Rserve::Protocol::CMD_detachedVoidEval,:cont=>cmd+"\n")
|
159
|
+
if rp.nil? or !rp.ok?
|
160
|
+
raise EvalError.new(rp), "detached void eval failed : #{rp.to_s}"
|
161
|
+
else
|
162
|
+
s=Rserve::Session.new(self,rp)
|
163
|
+
close
|
164
|
+
s
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
122
170
|
# evaluates the given command and retrieves the result
|
123
171
|
# * @param cmd command/expression string
|
124
172
|
# * @return R-xpression or <code>null</code> if an error occured */
|
@@ -233,6 +281,19 @@ module Rserve
|
|
233
281
|
raise "Shutdown failed"
|
234
282
|
end
|
235
283
|
end
|
236
|
-
|
284
|
+
# detaches the session and closes the connection (requires Rserve 0.4+).
|
285
|
+
# The session can be only resumed by calling RSession.attach
|
286
|
+
|
287
|
+
def detach
|
288
|
+
raise NotConnected if !connected? or rt.nil?
|
289
|
+
rp=rt.request(:cmd=>Rserve::Protocol::CMD_detachSession)
|
290
|
+
if !rp.nil? and rp.ok?
|
291
|
+
s=Rserve::Session.new(self,rp)
|
292
|
+
close
|
293
|
+
s
|
294
|
+
else
|
295
|
+
raise "Cannot detach"
|
296
|
+
end
|
297
|
+
end
|
237
298
|
end
|
238
299
|
end
|
data/lib/rserve/protocol.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
require 'rbconfig'
|
1
2
|
module Rserve
|
2
3
|
#
|
3
4
|
# This module encapsulates methods and constants related to QAP1 protocol used by Rserv. Follows almost exactly the interface on RTalk class
|
@@ -7,6 +8,15 @@ module Rserve
|
|
7
8
|
# Policy: No other class should know about the internal of protocol!
|
8
9
|
# See Rtalk class on Java version.
|
9
10
|
module Protocol
|
11
|
+
# Arch dependent Long Nil value
|
12
|
+
case Config::CONFIG['arch']
|
13
|
+
when 'i686-linux'
|
14
|
+
LONG_NA=9221120237041092514 # :nodoc:
|
15
|
+
when /mswin/
|
16
|
+
LONG_NA=9221120237041092514 # :nodoc:
|
17
|
+
else
|
18
|
+
LONG_NA=9218868437227407266 # :nodoc:
|
19
|
+
end
|
10
20
|
# Defines from Rsrv.h
|
11
21
|
CMD_RESP=0x010000 # all responses have this flag set
|
12
22
|
RESP_OK=(CMD_RESP|0x0001) # command succeeded; returned parameters depend on the command issued
|
@@ -162,7 +172,9 @@ module Rserve
|
|
162
172
|
# make sure that the buffer is big enough
|
163
173
|
|
164
174
|
def get_int(buf, o)
|
165
|
-
|
175
|
+
buf[o,4].pack("C*").unpack("l")[0]
|
176
|
+
end
|
177
|
+
def get_int_original(buf,o) # :nodoc:
|
166
178
|
v=((buf[o]&255)|((buf[o+1]&255)<<8)|((buf[o+2]&255)<<16)|((buf[o+3]&255)<<24))
|
167
179
|
v >= MAX_LONG_SIGNED ? v-MAX_LONG_UNSIGNED : v
|
168
180
|
end
|
@@ -187,12 +199,20 @@ module Rserve
|
|
187
199
|
# @param o offset (8 bytes will be used)
|
188
200
|
# @return long value */
|
189
201
|
def get_long(buf, o)
|
202
|
+
buf[o,8].pack("CCCCCCCC").unpack("Q")[0]
|
203
|
+
end
|
204
|
+
def get_long_original(buf,o) #:nodoc:
|
190
205
|
low=(get_int(buf,o))&0xffffffff;
|
191
206
|
hi=(get_int(buf,o+4))&0xffffffff;
|
192
207
|
hi<<=32; hi|=low;
|
193
208
|
hi
|
194
209
|
end
|
210
|
+
|
195
211
|
def longBitsToDouble(bits)
|
212
|
+
(bits==LONG_NA) ? Rserve::REXP::Double::NA : [bits].pack("Q").unpack("d")[0]
|
213
|
+
end
|
214
|
+
# Complete version of longBitsToDouble, as Java documentation established
|
215
|
+
def longBitsToDouble_old(bits) # :nodoc:
|
196
216
|
s = ((bits >> 63) == 0) ? 1 : -1;
|
197
217
|
e = ((bits >> 52) & 0x7ff)
|
198
218
|
m = (e == 0) ?
|
@@ -200,6 +220,7 @@ module Rserve
|
|
200
220
|
(bits & 0xfffffffffffff) | 0x10000000000000;
|
201
221
|
s*m*2**(e-1075)
|
202
222
|
end
|
223
|
+
|
203
224
|
def doubleToRawLongBits(double)
|
204
225
|
[double].pack("d").unpack("Q")[0]
|
205
226
|
end
|
data/lib/rserve/rexp.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module Rserve
|
2
|
-
# Basic class representing an object of any type in R. Each type in R in represented by a specific subclass.
|
3
|
-
#
|
4
|
-
# This class defines basic accessor methods (<tt>as</tt><i>XXX</i>), type check methods (<tt>is</tt><i>XXX</i>), gives access to attributes ({@link #getAttribute}, {@link #hasAttribute}) as well as several convenience methods. If a given method is not applicable to a particular type, it will throw the {@link MismatchException} exception.
|
2
|
+
# Basic class representing an object of any type in R. Each type in R in represented by a specific subclass.
|
5
3
|
#
|
4
|
+
# This class defines basic accessor methods (<tt>as</tt>_<i>xxx</i>), type check methods (<i>XXX</i><tt>?</tt>), gives access to attributes (REXP.get_attribute, REXP.has_attribute?) as well as several convenience methods. If a given method is not applicable to a particular type, it will throw the MismatchException exception.
|
5
|
+
#
|
6
6
|
# This root class will throw on any accessor call and returns <code>false</code> for all type methods. This allows subclasses to override accessor and type methods selectively.
|
7
7
|
#
|
8
8
|
class REXP
|
@@ -16,181 +16,232 @@ module Rserve
|
|
16
16
|
# specifies how many items of a vector or list will be displayed in {@link #toDebugString}
|
17
17
|
MaxDebugItems = 32
|
18
18
|
# :section: type checks
|
19
|
-
|
20
|
-
#
|
21
|
-
|
19
|
+
|
20
|
+
# check whether the <code>REXP</code> object is a character vector (string).
|
21
|
+
#
|
22
|
+
# @return [boolean] <code>true</code> if the receiver is a character vector, <code>false</code> otherwise
|
22
23
|
def string?
|
23
24
|
false
|
24
25
|
end
|
25
26
|
|
26
|
-
|
27
|
-
|
27
|
+
# check whether the <code>REXP</code> object is a numeric vector.
|
28
|
+
#
|
29
|
+
# @return [boolean] <code>true</code> if the receiver is a numeric vector, <code>false</code> otherwise
|
28
30
|
|
29
31
|
def numeric?
|
30
32
|
false
|
31
33
|
end
|
32
|
-
# check whether the <code>REXP</code> object is an integer vector
|
33
|
-
#
|
34
|
+
# check whether the <code>REXP</code> object is an integer vector.
|
35
|
+
#
|
36
|
+
# @return [boolean] <code>true</code> if the receiver is an integer vector, <code>false</code> otherwise
|
34
37
|
def integer?
|
35
38
|
false
|
36
39
|
end
|
37
|
-
# check whether the <code>REXP</code> object is NULL
|
38
|
-
#
|
40
|
+
# check whether the <code>REXP</code> object is NULL.
|
41
|
+
#
|
42
|
+
# @return [boolean] <code>true</code> if the receiver is NULL, <code>false</code> otherwise
|
39
43
|
def null?
|
40
44
|
false
|
41
45
|
end
|
42
|
-
|
43
|
-
#
|
46
|
+
|
47
|
+
# check whether the <code>REXP</code> object is a factor.
|
48
|
+
#
|
49
|
+
# @return [boolean] <code>true</code> if the receiver is a factor, <code>false</code> otherwise
|
44
50
|
def factor?
|
45
51
|
false
|
46
52
|
end
|
47
|
-
|
48
|
-
#
|
53
|
+
|
54
|
+
# check whether the <code>REXP</code> object is a list (either generic vector or a pairlist - i.e. REXP.asList() will succeed).
|
55
|
+
#
|
56
|
+
# @return [boolean] <code>true</code> if the receiver is a generic vector or a pair-list, <code>false</code> otherwise
|
49
57
|
def list?
|
50
58
|
false
|
51
59
|
end
|
52
|
-
# check whether the <code>REXP</code> object is a pair-list
|
53
|
-
#
|
60
|
+
# check whether the <code>REXP</code> object is a pair-list.
|
61
|
+
#
|
62
|
+
# @return [boolean] <code>true</code> if the receiver is a pair-list, <code>false</code> otherwise
|
54
63
|
def pair_list?
|
55
64
|
false
|
56
65
|
end
|
57
|
-
# check whether the <code>REXP</code> object is a logical vector
|
58
|
-
#
|
66
|
+
# check whether the <code>REXP</code> object is a logical vector.
|
67
|
+
#
|
68
|
+
# @return [boolean] <code>true</code> if the receiver is a logical vector, <code>false</code> otherwise */
|
59
69
|
def logical?
|
60
70
|
false
|
61
71
|
end
|
62
|
-
#
|
63
|
-
#
|
72
|
+
# check whether the <code>REXP</code> object is an environment.
|
73
|
+
#
|
74
|
+
# @return [boolean] <code>true</code> if the receiver is an environment, <code>false</code> otherwise
|
64
75
|
def environment?
|
65
76
|
false
|
66
77
|
end
|
67
|
-
# check whether the <code>REXP</code> object is a language object
|
68
|
-
#
|
78
|
+
# check whether the <code>REXP</code> object is a language object.
|
79
|
+
#
|
80
|
+
# @return [boolean] <code>true</code> if the receiver is a language object, <code>false</code> otherwise
|
69
81
|
def language?
|
70
82
|
false
|
71
83
|
end
|
72
|
-
# check whether the <code>REXP</code> object is an expression vector
|
73
|
-
#
|
84
|
+
# check whether the <code>REXP</code> object is an expression vector.
|
85
|
+
#
|
86
|
+
# @return [boolean] <code>true</code> if the receiver is an expression vector, <code>false</code> otherwise
|
74
87
|
def expression?
|
75
88
|
false
|
76
89
|
end
|
77
|
-
# check whether the <code>REXP</code> object is a symbol
|
78
|
-
#
|
90
|
+
# check whether the <code>REXP</code> object is a symbol.
|
91
|
+
#
|
92
|
+
# @return [boolean] <code>true</code> if the receiver is a symbol, <code>false</code> otherwise
|
79
93
|
def symbol?
|
80
94
|
false
|
81
95
|
end
|
82
|
-
# check whether the <code>REXP</code> object is a vector
|
83
|
-
#
|
96
|
+
# check whether the <code>REXP</code> object is a vector.
|
97
|
+
#
|
98
|
+
# @return [boolean] <code>true</code> if the receiver is a vector, <code>false</code> otherwise
|
84
99
|
def vector?
|
85
100
|
false
|
86
101
|
end
|
87
102
|
# check whether the <code>REXP</code> object is a raw vector
|
88
|
-
# @return <code>true</code> if the receiver is a raw vector, <code>false</code> otherwise
|
103
|
+
# @return [boolean] <code>true</code> if the receiver is a raw vector, <code>false</code> otherwise
|
89
104
|
def raw?
|
90
105
|
false
|
91
106
|
end
|
92
107
|
# check whether the <code>REXP</code> object is a complex vector
|
93
|
-
# @return <code>true</code> if the receiver is a complex vector, <code>false</code> otherwise
|
108
|
+
# @return [boolean] <code>true</code> if the receiver is a complex vector, <code>false</code> otherwise
|
94
109
|
def complex?
|
95
110
|
false
|
96
111
|
end
|
97
112
|
# check whether the <code>REXP</code> object is a recursive obejct
|
98
|
-
# @return <code>true</code> if the receiver is a recursive object, <code>false</code> otherwise
|
113
|
+
# @return [boolean] <code>true</code> if the receiver is a recursive object, <code>false</code> otherwise
|
99
114
|
def recursive?
|
100
115
|
false
|
101
116
|
end
|
102
117
|
# check whether the <code>REXP</code> object is a reference to an R object
|
103
|
-
# @return <code>true</code> if the receiver is a reference, <code>false</code> otherwise
|
118
|
+
# @return [boolean] <code>true</code> if the receiver is a reference, <code>false</code> otherwise
|
104
119
|
def reference?
|
105
120
|
false
|
106
121
|
end
|
107
122
|
|
108
123
|
# :section: basic accessor methods
|
109
|
-
|
124
|
+
|
125
|
+
# returns the contents as an array of Strings (if supported by the represented object).
|
126
|
+
#
|
127
|
+
# @return [Array]
|
110
128
|
def as_strings
|
111
129
|
raise MismatchException, "String"
|
112
130
|
end
|
113
131
|
# returns the contents as an array of integers (if supported by the represented object)
|
132
|
+
#
|
133
|
+
# @return [Array]
|
114
134
|
|
115
135
|
def as_integers
|
116
136
|
raise MismatchException, "int"
|
117
137
|
end
|
118
138
|
|
119
|
-
# returns the contents as an array of
|
139
|
+
# returns the contents as an array of floats (C double precision) (if supported by the represented object).
|
140
|
+
#
|
141
|
+
# @return [Array]
|
142
|
+
|
120
143
|
def as_doubles
|
121
144
|
raise MismatchException,"double"
|
122
145
|
end
|
123
146
|
|
124
|
-
# On Ruby, Float are stored in double precision
|
147
|
+
# On Ruby, Float are stored in double precision.
|
148
|
+
#
|
149
|
+
# @return [Array]
|
125
150
|
def as_floats
|
126
151
|
as_doubles
|
127
152
|
end
|
128
153
|
|
129
|
-
# returns the contents as an array of bytes (if supported by the represented object)
|
154
|
+
# returns the contents as an array of bytes (if supported by the represented object).
|
155
|
+
#
|
156
|
+
# @return [Array]
|
157
|
+
|
130
158
|
def as_bytes
|
131
159
|
raise MismatchException , "byte"
|
132
160
|
end
|
133
161
|
# returns the contents as a (named) list (if supported by the represented object)
|
162
|
+
#
|
163
|
+
# @return [Array]
|
134
164
|
def as_list
|
135
165
|
raise MismatchException,"list"
|
136
166
|
end
|
137
|
-
# returns the contents as a factor (if supported by the represented object)
|
167
|
+
# returns the contents as a factor (if supported by the represented object).
|
168
|
+
#
|
169
|
+
# @return [RFactor]
|
138
170
|
def as_factor
|
139
171
|
raise MismatchException,"factor"
|
140
172
|
end
|
141
173
|
|
142
|
-
# returns the length of a vector object. Note that we use R semantics here, i.e. a matrix will have a length of <i>m * n</i> since it is represented by a single vector (see
|
143
|
-
#
|
144
|
-
#
|
174
|
+
# returns the length of a vector object. Note that we use R semantics here, i.e. a matrix will have a length of <i>m * n</i> since it is represented by a single vector (see REXP.dim) for retrieving matrix and multidimentional-array dimensions).
|
175
|
+
#
|
176
|
+
# @return [Integer] length (number of elements) in a vector object.
|
145
177
|
def length
|
146
178
|
raise MismatchException, "vector"
|
147
179
|
end
|
148
180
|
|
149
|
-
# returns a boolean vector of the same length as this vector with <code>true</code> for NA values and <code>false</code> for any other values
|
150
|
-
#
|
151
|
-
#
|
181
|
+
# returns a boolean vector of the same length as this vector with <code>true</code> for NA values and <code>false</code> for any other values.
|
182
|
+
#
|
183
|
+
# @return [boolean] a boolean vector of the same length as this vector with <code>true</code> for NA values and <code>false</code> for any other values.
|
184
|
+
#
|
152
185
|
def na?
|
153
186
|
raise MismatchException, "vector"
|
154
187
|
end
|
155
188
|
|
156
189
|
# :section: convenience accessor methods
|
190
|
+
|
191
|
+
|
157
192
|
# convenience method corresponding to <code>as_integer()[0]</code>
|
158
|
-
#
|
193
|
+
#
|
194
|
+
# @return [Integer] first entry returned by as_integers()
|
159
195
|
def as_integer
|
160
196
|
as_integers[0]
|
161
197
|
end
|
198
|
+
# Alias for as_integer().
|
199
|
+
#
|
200
|
+
# @return [Integer]
|
201
|
+
|
162
202
|
def to_i
|
163
203
|
as_integers[0]
|
164
204
|
end
|
165
|
-
# convenience method corresponding to <code>
|
166
|
-
#
|
205
|
+
# convenience method corresponding to <code>as_floats[0]</code>.
|
206
|
+
#
|
207
|
+
# @return [Float] first entry returned by as_doubles()
|
167
208
|
def as_double
|
168
209
|
as_doubles[0]
|
169
210
|
end
|
211
|
+
# Alias for as_double()
|
212
|
+
#
|
213
|
+
# @return [Float]
|
170
214
|
def as_float
|
171
215
|
as_double
|
172
216
|
end
|
217
|
+
# Alias for as_float()
|
218
|
+
#
|
219
|
+
# @return [Float]
|
173
220
|
def to_f
|
174
221
|
as_double
|
175
222
|
end
|
176
|
-
# convenience method corresponding to <code>
|
177
|
-
#
|
223
|
+
# convenience method corresponding to <code>as_strings[0]</code>.
|
224
|
+
#
|
225
|
+
# @return [String] first entry returned by REXP.as_strings
|
178
226
|
def as_string
|
179
227
|
as_strings[0]
|
180
228
|
end
|
181
|
-
# // methods common to all REXPs
|
182
229
|
|
183
|
-
#
|
184
|
-
|
185
|
-
#
|
230
|
+
# :section: methods common to all REXPs
|
231
|
+
|
232
|
+
# Retrieve an attribute of the given name from this object.
|
233
|
+
#
|
234
|
+
# @param [String] attribute name.
|
235
|
+
# @return [Rlist, nil] attribute value or <code>nil</code> if the attribute does not exist
|
186
236
|
|
187
237
|
def get_attribute(name)
|
188
238
|
has_attribute?(name) ? @attr.as_list[name] : nil
|
189
239
|
end
|
190
240
|
|
191
|
-
# checks whether this
|
192
|
-
#
|
193
|
-
#
|
241
|
+
# checks whether this object has a given attribute.
|
242
|
+
#
|
243
|
+
# @param [String] attribute name.
|
244
|
+
# @return [boolean] <code>true</code> if the attribute exists, <code>false</code> otherwise
|
194
245
|
def has_attribute? (name)
|
195
246
|
!@attr.nil? and @attr.list? and !@attr.as_list[name].nil?
|
196
247
|
end
|
@@ -198,8 +249,9 @@ module Rserve
|
|
198
249
|
|
199
250
|
# :section: helper methods common to all REXPs
|
200
251
|
|
201
|
-
#
|
202
|
-
#
|
252
|
+
# Returns dimensions of the object (as determined by the REXP::dim() attribute).
|
253
|
+
#
|
254
|
+
# @return [Array] an array of integers with corresponding dimensions or <code>nil</code> if the object has no dimension attribute
|
203
255
|
def dim
|
204
256
|
begin
|
205
257
|
return has_attribute?("dim") ? @attr.as_list['dim'].as_integers : nil;
|
@@ -209,9 +261,10 @@ module Rserve
|
|
209
261
|
nil
|
210
262
|
end
|
211
263
|
|
212
|
-
# determines whether this object inherits from a given class in the same fashion as the <code>inherits()</code> function in R does (i.e. ignoring S4 inheritance)
|
213
|
-
#
|
214
|
-
# @
|
264
|
+
# determines whether this object inherits from a given class in the same fashion as the <code>inherits()</code> function in R does (i.e. ignoring S4 inheritance).
|
265
|
+
#
|
266
|
+
# @param [String] klass class name.
|
267
|
+
# @return [boolean] <code>true</code> if this object is of the class <code>klass</code>, <code>false</code> otherwise.
|
215
268
|
def inherits?(klass)
|
216
269
|
return false if (!has_attribute? "class")
|
217
270
|
begin
|
@@ -226,20 +279,23 @@ module Rserve
|
|
226
279
|
|
227
280
|
|
228
281
|
|
229
|
-
# returns representation that it useful for debugging (e.g. it includes attributes and may include vector values
|
230
|
-
#
|
282
|
+
# returns representation that it useful for debugging (e.g. it includes attributes and may include vector values)
|
283
|
+
#
|
284
|
+
# @return [String] extended description of the obejct -- it may include vector values
|
231
285
|
def to_debug_string
|
232
286
|
(!@attr.nil?) ? (("<"+@attr.to_debug_string()+">")+to_s()) : to_s
|
233
287
|
end
|
234
288
|
|
235
289
|
|
236
|
-
|
290
|
+
# :section: complex convenience methods
|
291
|
+
|
292
|
+
|
237
293
|
# returns the content of the REXP as a ruby matrix of doubles (2D-array: m[rows][cols]). You could use Matrix.rows(result) to create
|
238
294
|
# a ruby matrix.
|
239
295
|
# Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").as_double_matrix());</code>
|
240
296
|
#
|
241
|
-
# @return 2D array of doubles in the form double[rows][cols] or <code>
|
242
|
-
def as_double_matrix
|
297
|
+
# @return [Array] 2D array of doubles in the form double[rows][cols] or <code>nil</code> if the contents is no 2-dimensional matrix of doubles
|
298
|
+
def as_double_matrix
|
243
299
|
ct = as_doubles()
|
244
300
|
dim = get_attribute "dim"
|
245
301
|
raise MismatchException, "matrix (dim attribute missing)" if dim.nil?
|
@@ -252,12 +308,16 @@ module Rserve
|
|
252
308
|
# we need to copy everything, since we create 2d array from 1d array
|
253
309
|
#r=m.times.map {|i| n.times.map {|j| ct[j*n+i]}}
|
254
310
|
end
|
255
|
-
# Returns a standard library's matrix
|
311
|
+
# Returns a standard library's matrix.
|
312
|
+
#
|
313
|
+
# @return [Matrix]
|
256
314
|
def as_matrix
|
257
315
|
require 'matrix'
|
258
316
|
Matrix.rows(as_double_matrix)
|
259
317
|
end
|
260
318
|
# Returns the content of the REXP as a serie of nested arrays of X dimensions
|
319
|
+
#
|
320
|
+
# @return [Array]
|
261
321
|
def as_nested_array
|
262
322
|
ct=as_doubles
|
263
323
|
dim = get_attribute "dim"
|
@@ -267,7 +327,7 @@ module Rserve
|
|
267
327
|
split_array(ct,ds)
|
268
328
|
end
|
269
329
|
|
270
|
-
def split_array(ar, dims)
|
330
|
+
def split_array(ar, dims) # :nodoc:
|
271
331
|
# puts "#{ar} - #{dims}"
|
272
332
|
if dims.size==1
|
273
333
|
raise "Improper size ar:#{ar} , dims=#{dims[0]}" if ar.size!=dims[0]
|
@@ -296,10 +356,10 @@ module Rserve
|
|
296
356
|
|
297
357
|
# :section: tools
|
298
358
|
|
299
|
-
# creates a data frame object from a list object using integer row names
|
300
|
-
#
|
301
|
-
# * @
|
302
|
-
#
|
359
|
+
# creates a data frame object from a list object using integer row names.
|
360
|
+
#
|
361
|
+
# * @param [Rlist] a (named) list of vectors (REXP::Vector subclasses), each element corresponds to a column and all elements must have the same length.
|
362
|
+
# * @return [GenericVector] a data frame object representation.
|
303
363
|
def self.create_data_frame(l)
|
304
364
|
raise(MismatchException, "data frame (must have dim>0)") if l.nil? or l.size<1
|
305
365
|
raise MismatchException, "data frame (contents must be vectors)" if (!(l[0].is_a? REXP::Vector))
|
@@ -321,7 +381,8 @@ module Rserve
|
|
321
381
|
# If R object has attributes, the Ruby object is extended with Rserve::WithAttributes.
|
322
382
|
# If R object is names, the Ruby object is extended with Rserve::WithNames and
|
323
383
|
# their elements can be accessed with [] using numbers and literals.
|
324
|
-
#
|
384
|
+
#
|
385
|
+
# @return [Object] Ruby object.
|
325
386
|
def to_ruby
|
326
387
|
#pp self
|
327
388
|
v=to_ruby_internal
|
@@ -346,6 +407,9 @@ module Rserve
|
|
346
407
|
|
347
408
|
v
|
348
409
|
end
|
410
|
+
# Return the bare-bone representation of REXP as a Ruby Object.
|
411
|
+
# Called by REXP.to_ruby, so shouldn't be used directly by developers.
|
412
|
+
#
|
349
413
|
def to_ruby_internal
|
350
414
|
raise "You should implement to_ruby_internal for #{self.class}"
|
351
415
|
end
|
data/lib/rserve/rexp/double.rb
CHANGED
@@ -7,6 +7,8 @@ module Rserve
|
|
7
7
|
case Config::CONFIG['arch']
|
8
8
|
when 'i686-linux'
|
9
9
|
NA = 269653970229425383598692395468593241088322026492507901905402939417320933254485890939796955099302180188971623023005661539310855695935759376615857567599472873400528811349204333736152257830107446553333670133666606746438802800063353690283455789426038632208916715592554825644961573453826957827246636338344317943808
|
10
|
+
when /mswin/
|
11
|
+
NA = 269653970229425383598692395468593241088322026492507901905402939417320933254485890939796955099302180188971623023005661539310855695935759376615857567599472873400528811349204333736152257830107446553333670133666606746438802800063353690283455789426038632208916715592554825644961573453826957827246636338344317943808
|
10
12
|
else
|
11
13
|
NA = 0x100000000007a2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
|
12
14
|
end
|
@@ -42,8 +44,13 @@ module Rserve
|
|
42
44
|
end
|
43
45
|
|
44
46
|
def na?(value=nil)
|
45
|
-
|
46
|
-
@payload.map {|v| v
|
47
|
+
#if value.nil?
|
48
|
+
# @payload.map {|v| v.respond_to? :nan and v.nan?}
|
49
|
+
#else
|
50
|
+
# value.respond_to? :nan? and value.nan?
|
51
|
+
#end
|
52
|
+
return value.to_i == NA unless value.nil?
|
53
|
+
@payload.map {|v| v.to_i==NA}
|
47
54
|
end
|
48
55
|
def to_debug_string
|
49
56
|
t=super
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rserve
|
2
|
+
class Session
|
3
|
+
# serial version UID should only change if method signatures change
|
4
|
+
# significantly enough that previous versions cannot be used with
|
5
|
+
# current versions
|
6
|
+
include Rserve::Protocol
|
7
|
+
UID=-7048099825974875604
|
8
|
+
attr_reader :host
|
9
|
+
attr_reader :port
|
10
|
+
attr_reader :key
|
11
|
+
attr_reader :attach_packet
|
12
|
+
attr_reader :rsrv_version
|
13
|
+
def initialize(con,packet)
|
14
|
+
@host=con.hostname
|
15
|
+
@rsrv_version=con.rsrv_version
|
16
|
+
ct=packet.cont
|
17
|
+
if ct.nil? or ct.length!=32+3*4
|
18
|
+
raise "Invalid response to session detach request."
|
19
|
+
end
|
20
|
+
@port=get_int(ct,4)
|
21
|
+
@key=ct[12,32]
|
22
|
+
end
|
23
|
+
def attach
|
24
|
+
c=Rserve::Connection.new(:session=>self)
|
25
|
+
@attach_packet=c.rt.request(:cmd=>-1,:cont=>[])
|
26
|
+
c
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require File.dirname(__FILE__)+"/spec_helper.rb"
|
2
|
+
require 'rbconfig'
|
3
|
+
describe "Rserve::Connection on unix" do
|
4
|
+
before do
|
5
|
+
@r=Rserve::Connection.new
|
6
|
+
end
|
7
|
+
if RbConfig::CONFIG['arch']!~/mswin/
|
8
|
+
it "method eval_void should raise an error with an incorrect expression" do
|
9
|
+
lambda {@r.void_eval("x<-")}.should raise_exception(Rserve::Connection::EvalError) {|e| e.request_packet.stat.should==2}
|
10
|
+
lambda {@r.void_eval("as.stt(c(1))")}.should raise_exception(Rserve::Connection::EvalError) {|e|
|
11
|
+
e.request_packet.stat.should==127}
|
12
|
+
end
|
13
|
+
it "method eval should raise an error with an incorrect expression" do
|
14
|
+
lambda {@r.eval("x<-")}.should raise_exception(Rserve::Connection::EvalError) {|e| e.request_packet.stat.should==2}
|
15
|
+
lambda {@r.eval("as.stt(c(1))")}.should raise_exception(Rserve::Connection::EvalError) {|e|
|
16
|
+
e.request_packet.stat.should==127}
|
17
|
+
end
|
18
|
+
it "should raise ServerNotAvailable if started another instance on another port" do
|
19
|
+
lambda {Rserve::Connection.new(:port_number=>6700)}.should raise_exception(Rserve::Connection::ServerNotAvailable)
|
20
|
+
end
|
21
|
+
it "should create different session on *nix" do
|
22
|
+
s=Rserve::Connection.new
|
23
|
+
@r.assign("a", 1)
|
24
|
+
s.assign("a",2)
|
25
|
+
@r.eval('a').to_i.should==1
|
26
|
+
s.eval('a').to_i.should==2
|
27
|
+
s.close
|
28
|
+
end
|
29
|
+
else
|
30
|
+
it "shouldn't crash server with an incorrect expression as Windows version does"
|
31
|
+
it "shouldn't raise ServerNotAvailable if started another instance on another port as Windows version does"
|
32
|
+
it "shouldn create a different session. On Windows, every new connection closes previously open session"
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
|
@@ -10,9 +10,6 @@ describe Rserve::Connection do
|
|
10
10
|
@r.last_error.should=="OK"
|
11
11
|
@r.rt.should be_instance_of(Rserve::Talk)
|
12
12
|
end
|
13
|
-
it "should raise ServerNotAvailable if started another instance on another port" do
|
14
|
-
lambda {Rserve::Connection.new(:port_number=>6700)}.should raise_exception(Rserve::Connection::ServerNotAvailable)
|
15
|
-
end
|
16
13
|
it "should quit correctly" do
|
17
14
|
@r.should be_connected
|
18
15
|
@r.close.should be_true
|
@@ -35,24 +32,31 @@ describe Rserve::Connection do
|
|
35
32
|
it "method eval_void should return true with correct expression" do
|
36
33
|
@r.void_eval("x<-1").should be_true
|
37
34
|
end
|
38
|
-
|
39
|
-
lambda {@r.void_eval("x<-")}.should raise_exception(Rserve::Connection::EvalError) {|e| e.request_packet.stat.should==2}
|
40
|
-
lambda {@r.void_eval("as.stt(c(1))")}.should raise_exception(Rserve::Connection::EvalError) {|e|
|
41
|
-
e.request_packet.stat.should==127}
|
42
|
-
end
|
43
|
-
|
35
|
+
|
44
36
|
it "method eval should return a simple object" do
|
45
37
|
la=@r.eval("TRUE")
|
46
38
|
la.should be_instance_of(Rserve::REXP::Logical)
|
47
39
|
la.true?.should==[true]
|
48
40
|
end
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
41
|
+
it "should eval_void_detach correctly" do
|
42
|
+
s=@r.void_eval_detach("x<-c(TRUE,FALSE)")
|
43
|
+
@r.should_not be_connected
|
44
|
+
s.should be_instance_of(Rserve::Session)
|
45
|
+
s.host.should==@r.hostname
|
46
|
+
s.key.size.should==32
|
47
|
+
end
|
48
|
+
it "should detach correctly" do
|
49
|
+
x=rand(100)
|
50
|
+
@r.void_eval("x<-#{x}")
|
51
|
+
s=@r.detach
|
52
|
+
@r.should_not be_connected
|
53
|
+
s.should be_instance_of(Rserve::Session)
|
54
|
+
s.host.should==@r.hostname
|
55
|
+
s.key.size.should==32
|
56
|
+
r=s.attach
|
57
|
+
r.eval("x").to_ruby==x
|
54
58
|
end
|
55
|
-
|
59
|
+
|
56
60
|
it "should eval_void and eval correctly" do
|
57
61
|
@r.void_eval("x<-c(TRUE,FALSE)").should be_true
|
58
62
|
la=@r.eval("x")
|
@@ -68,8 +72,10 @@ describe Rserve::Connection do
|
|
68
72
|
describe "assign using REXPs" do
|
69
73
|
before do
|
70
74
|
@r=Rserve::Connection.new
|
71
|
-
|
72
75
|
end
|
76
|
+
after do
|
77
|
+
@r.close
|
78
|
+
end
|
73
79
|
it "should assign double" do
|
74
80
|
rexp=Rserve::REXP::Double.new([1.5,-1.5])
|
75
81
|
@r.assign("x", rexp)
|
@@ -44,6 +44,7 @@ describe Rserve::Protocol do
|
|
44
44
|
buffer=[0xFF,0x78,0x56,0x34,0x12]
|
45
45
|
expected=0x12345678
|
46
46
|
@t.get_int(buffer,1).should==expected
|
47
|
+
@t.get_int(buffer,1).should==@t.get_int_original(buffer,1)
|
47
48
|
|
48
49
|
# Version with errors
|
49
50
|
|
@@ -51,6 +52,9 @@ describe Rserve::Protocol do
|
|
51
52
|
expected=0x12345678
|
52
53
|
@t.get_int(buffer,1).should==expected
|
53
54
|
end
|
55
|
+
|
56
|
+
|
57
|
+
|
54
58
|
it "get_len method should return correct length from a header" do
|
55
59
|
cmd=Rserve::Protocol::CMD_login
|
56
60
|
len=0x12345678
|
@@ -61,6 +65,7 @@ describe Rserve::Protocol do
|
|
61
65
|
buffer=[0xFF,0x78,0x56,0x34,0x12,0x78,0x56,0x34,0x12]
|
62
66
|
expected=0x1234567812345678
|
63
67
|
@t.get_long(buffer,1).should==expected
|
68
|
+
@t.get_long(buffer,1).should==@t.get_long_original(buffer,1)
|
64
69
|
|
65
70
|
end
|
66
71
|
it "set_long method should set correct long(32 bits) for a given buffer" do
|
@@ -7,7 +7,9 @@ describe Rserve::Protocol::REXPFactory do
|
|
7
7
|
before do
|
8
8
|
@r=Rserve::Connection.new
|
9
9
|
end
|
10
|
-
|
10
|
+
after do
|
11
|
+
@r.close
|
12
|
+
end
|
11
13
|
it "should process null" do
|
12
14
|
la=@r.eval("NULL")
|
13
15
|
la.should be_instance_of(Rserve::REXP::Null)
|
@@ -29,6 +31,7 @@ describe Rserve::Protocol::REXPFactory do
|
|
29
31
|
end
|
30
32
|
it "should process logical vectors with NA" do
|
31
33
|
la=@r.eval("c(TRUE,NA)")
|
34
|
+
|
32
35
|
la.should be_instance_of(Rserve::REXP::Logical)
|
33
36
|
la.na?.should==[false,true]
|
34
37
|
end
|
data/spec/rserve_rlist_spec.rb
CHANGED
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.dirname(__FILE__)+"/spec_helper.rb"
|
2
|
+
describe Rserve::Session do
|
3
|
+
before do
|
4
|
+
@r=Rserve::Connection.new
|
5
|
+
end
|
6
|
+
it "should resume an detached session with void_eval_detach" do
|
7
|
+
x2=10+rand(12)
|
8
|
+
s=@r.void_eval_detach("x<-1:#{x2}")
|
9
|
+
r=Rserve::Connection.new
|
10
|
+
r.void_eval("x<-1")
|
11
|
+
r.eval("x").to_ruby.should==1
|
12
|
+
s.should be_instance_of(Rserve::Session)
|
13
|
+
r2=s.attach
|
14
|
+
r2.eval("x").to_ruby.should==(1..x2).to_a
|
15
|
+
end
|
16
|
+
it "should resume an detached session with detach" do
|
17
|
+
x2=10+rand(12)
|
18
|
+
@r.void_eval("x<-1:#{x2}")
|
19
|
+
s=@r.detach
|
20
|
+
r=Rserve::Connection.new
|
21
|
+
r.void_eval("x<-1")
|
22
|
+
r.eval("x").to_ruby.should==1
|
23
|
+
s.should be_instance_of(Rserve::Session)
|
24
|
+
r2=s.attach
|
25
|
+
r2.eval("x").to_ruby.should==(1..x2).to_a
|
26
|
+
end
|
27
|
+
end
|
data/spec/rserve_spec.rb
CHANGED
metadata
CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
|
|
4
4
|
prerelease: false
|
5
5
|
segments:
|
6
6
|
- 0
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: 0.
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: 0.2.0
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Claudio Bustos
|
@@ -35,7 +35,7 @@ cert_chain:
|
|
35
35
|
rpP0jjs0
|
36
36
|
-----END CERTIFICATE-----
|
37
37
|
|
38
|
-
date: 2010-06-
|
38
|
+
date: 2010-06-16 00:00:00 -04:00
|
39
39
|
default_executable:
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
@@ -62,8 +62,8 @@ dependencies:
|
|
62
62
|
segments:
|
63
63
|
- 2
|
64
64
|
- 6
|
65
|
-
-
|
66
|
-
version: 2.6.
|
65
|
+
- 1
|
66
|
+
version: 2.6.1
|
67
67
|
type: :development
|
68
68
|
version_requirements: *id002
|
69
69
|
description: |-
|
@@ -88,6 +88,10 @@ files:
|
|
88
88
|
- Manifest.txt
|
89
89
|
- README.txt
|
90
90
|
- Rakefile
|
91
|
+
- benchmark/benchmark.rb
|
92
|
+
- benchmark/comparison_2010_06_07.xls
|
93
|
+
- benchmark/comparison_2010_06_07_using_pack.xls
|
94
|
+
- benchmark/plot.rb
|
91
95
|
- data/gettysburg.txt
|
92
96
|
- examples/gettysburg.rb
|
93
97
|
- examples/hello_world.rb
|
@@ -120,9 +124,11 @@ files:
|
|
120
124
|
- lib/rserve/rexp/wrapper.rb
|
121
125
|
- lib/rserve/rfactor.rb
|
122
126
|
- lib/rserve/rlist.rb
|
127
|
+
- lib/rserve/session.rb
|
123
128
|
- lib/rserve/talk.rb
|
124
129
|
- lib/rserve/withattributes.rb
|
125
130
|
- lib/rserve/withnames.rb
|
131
|
+
- spec/rserve_connection_on_unix_spec.rb
|
126
132
|
- spec/rserve_connection_spec.rb
|
127
133
|
- spec/rserve_double_spec.rb
|
128
134
|
- spec/rserve_genericvector_spec.rb
|
@@ -136,6 +142,7 @@ files:
|
|
136
142
|
- spec/rserve_rexpfactory_spec.rb
|
137
143
|
- spec/rserve_rfactor_spec.rb
|
138
144
|
- spec/rserve_rlist_spec.rb
|
145
|
+
- spec/rserve_session_spec.rb
|
139
146
|
- spec/rserve_spec.rb
|
140
147
|
- spec/rserve_talk_spec.rb
|
141
148
|
- spec/rserve_withnames_spec.rb
|
@@ -181,11 +188,13 @@ test_files:
|
|
181
188
|
- spec/rserve_double_spec.rb
|
182
189
|
- spec/rserve_withnames_spec.rb
|
183
190
|
- spec/rserve_packet_spec.rb
|
191
|
+
- spec/rserve_connection_on_unix_spec.rb
|
184
192
|
- spec/rserve_rexpfactory_spec.rb
|
185
193
|
- spec/rserve_rexp_spec.rb
|
186
194
|
- spec/rserve_integer_spec.rb
|
187
195
|
- spec/rserve_spec.rb
|
188
196
|
- spec/rserve_protocol_spec.rb
|
189
197
|
- spec/rserve_genericvector_spec.rb
|
198
|
+
- spec/rserve_session_spec.rb
|
190
199
|
- spec/rserve_logical_spec.rb
|
191
200
|
- spec/rserve_talk_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|