rserve-client 0.1.5 → 0.1.6

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.
Files changed (46) hide show
  1. data.tar.gz.sig +1 -2
  2. data/.gitignore +1 -0
  3. data/History.txt +15 -2
  4. data/Manifest.txt +8 -0
  5. data/README.txt +41 -19
  6. data/lib/rserve.rb +1 -1
  7. data/lib/rserve/connection.rb +152 -69
  8. data/lib/rserve/engine.rb +9 -9
  9. data/lib/rserve/packet.rb +2 -2
  10. data/lib/rserve/protocol.rb +51 -46
  11. data/lib/rserve/protocol/rexpfactory.rb +659 -366
  12. data/lib/rserve/rexp.rb +175 -156
  13. data/lib/rserve/rexp/double.rb +45 -38
  14. data/lib/rserve/rexp/environment.rb +40 -0
  15. data/lib/rserve/rexp/expressionvector.rb +9 -0
  16. data/lib/rserve/rexp/genericvector.rb +5 -3
  17. data/lib/rserve/rexp/integer.rb +38 -38
  18. data/lib/rserve/rexp/language.rb +2 -2
  19. data/lib/rserve/rexp/list.rb +3 -0
  20. data/lib/rserve/rexp/logical.rb +17 -4
  21. data/lib/rserve/rexp/null.rb +20 -14
  22. data/lib/rserve/rexp/raw.rb +19 -0
  23. data/lib/rserve/rexp/reference.rb +42 -0
  24. data/lib/rserve/rexp/s4.rb +10 -0
  25. data/lib/rserve/rexp/string.rb +5 -3
  26. data/lib/rserve/rexp/symbol.rb +3 -0
  27. data/lib/rserve/rexp/vector.rb +30 -15
  28. data/lib/rserve/rexp/wrapper.rb +58 -0
  29. data/lib/rserve/rfactor.rb +10 -10
  30. data/lib/rserve/rlist.rb +129 -100
  31. data/lib/rserve/talk.rb +61 -61
  32. data/spec/rserve_connection_spec.rb +99 -33
  33. data/spec/rserve_double_spec.rb +28 -15
  34. data/spec/rserve_integer_spec.rb +24 -15
  35. data/spec/rserve_logical_spec.rb +21 -12
  36. data/spec/rserve_protocol_spec.rb +7 -7
  37. data/spec/rserve_rexp_spec.rb +3 -3
  38. data/spec/rserve_rexp_wrapper_spec.rb +36 -0
  39. data/spec/rserve_rexpfactory_spec.rb +86 -20
  40. data/spec/rserve_rfactor_spec.rb +2 -2
  41. data/spec/rserve_rlist_spec.rb +53 -0
  42. data/spec/rserve_spec.rb +8 -5
  43. data/spec/rserve_talk_spec.rb +7 -7
  44. data/spec/spec_helper.rb +1 -0
  45. metadata +13 -3
  46. metadata.gz.sig +0 -0
data.tar.gz.sig CHANGED
@@ -1,2 +1 @@
1
- A.���CTzEc��-�ˣmt��r�I���Y���>w��������:��_ܭA�Z��y�a >�e����xX���_A8�}��כ���5~~��C�,�p��r>��n� _���˂�P���t��`F��Ʉ'���'���f��# ��M/��t�|�*�}F��U��\�{�� ������а�
2
- �| �5`[2�W���ڀl����!o�E!�s�O5�G�nB�x<Y̬�\5w 蛩�ɨ��
1
+ `�~�i��N �hDNr�ZJ)C�-*ؔtt�|��ŽkR�����OHn�B��uy%@��O�=o��u���I�������� #Ͱp�����f�O����{���l)j?c�%{p}ް�s���T3Ww��(*�@����^:kx�]yꋭ�EXvb/%��{������w%[�� �^�e���"��s#����q�A����A]�4F���2�{q�%��#�%oݤJ>�b{o�%b���t ��
data/.gitignore CHANGED
@@ -1,3 +1,4 @@
1
+ coverage.info
1
2
  *~
2
3
  doc
3
4
  pkg
@@ -1,11 +1,24 @@
1
+ === 0.1.6 / 2010-05-27
2
+ * Assign complete for all commons REXPs
3
+ * Added Connection#shutdown
4
+ * Added arch dependent for Double NA
5
+ * Bug fix: list with booleans and NA raise an error
6
+ * Added support for all types of REXP.
7
+ * REXP::Wrapper provides a method to convert ruby types to R types.
8
+ * Added spec for Rlist and REXP::Wrapper
9
+ * Added generic to_ruby method. Ex.: Rlist#to_ruby returns an array
10
+ * README.txt updated
11
+
12
+
1
13
  === 0.1.5 / 2010-05-24
2
14
  * Bug fix: Incorrect NA for Logical, String and Double Vector
3
15
  * Factors implemented
16
+ * Correct Manifest.txt
4
17
 
5
18
  === 0.1.3 / 2010-05-24
6
19
  * Better README.txt
7
- * Implemented hash of options on Connection.new
8
- * Better implementation of errors on connections
20
+ * Implemented options hash on Connection.new
21
+ * Better implementation of errors on connection
9
22
  * REXP::Double#as_strings returns values as floats, not Rationals
10
23
  * Bug fix on REXP#as_double_matrix.
11
24
  * Added REXP#as_matrix, which return a standard library matrix from a R matrix
@@ -12,6 +12,8 @@ lib/rserve/protocol.rb
12
12
  lib/rserve/protocol/rexpfactory.rb
13
13
  lib/rserve/rexp.rb
14
14
  lib/rserve/rexp/double.rb
15
+ lib/rserve/rexp/environment.rb
16
+ lib/rserve/rexp/expressionvector.rb
15
17
  lib/rserve/rexp/factor.rb
16
18
  lib/rserve/rexp/genericvector.rb
17
19
  lib/rserve/rexp/integer.rb
@@ -19,10 +21,14 @@ lib/rserve/rexp/language.rb
19
21
  lib/rserve/rexp/list.rb
20
22
  lib/rserve/rexp/logical.rb
21
23
  lib/rserve/rexp/null.rb
24
+ lib/rserve/rexp/raw.rb
25
+ lib/rserve/rexp/reference.rb
26
+ lib/rserve/rexp/s4.rb
22
27
  lib/rserve/rexp/string.rb
23
28
  lib/rserve/rexp/symbol.rb
24
29
  lib/rserve/rexp/unknown.rb
25
30
  lib/rserve/rexp/vector.rb
31
+ lib/rserve/rexp/wrapper.rb
26
32
  lib/rserve/rfactor.rb
27
33
  lib/rserve/rlist.rb
28
34
  lib/rserve/talk.rb
@@ -33,8 +39,10 @@ spec/rserve_logical_spec.rb
33
39
  spec/rserve_packet_spec.rb
34
40
  spec/rserve_protocol_spec.rb
35
41
  spec/rserve_rexp_spec.rb
42
+ spec/rserve_rexp_wrapper_spec.rb
36
43
  spec/rserve_rexpfactory_spec.rb
37
44
  spec/rserve_rfactor_spec.rb
45
+ spec/rserve_rlist_spec.rb
38
46
  spec/rserve_spec.rb
39
47
  spec/rserve_talk_spec.rb
40
48
  spec/spec.opts
data/README.txt CHANGED
@@ -15,13 +15,17 @@ Follows closely the new Java client API, but maintains all Ruby conventions when
15
15
  * Uses TCP/IP sockets to interchange data and commands
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
- * Work with Ruby 1.8, 1.9 and JRuby 1.5
18
+ * Work with Ruby 1.8, 1.9 and JRuby 1.5.
19
+ * Should work on Windows (not tested yet)
19
20
  * Implements almost completely R's datatypes: integer, doubles, chars, logical vectors, lists and raw data.
20
- * Follows closely the Java API, so any change on the server could be adopted without much problem
21
+ * Follows closely the Java API, so any change on the server API could be adopted without much problem
21
22
  * Fast
23
+ * Easy management of differences between R and Ruby, or "You can have your cake and eat it, too!"
24
+ * 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
+ * Between R and Ruby: Every REXP object implements methods to convert to specific Ruby type: as_integers, as_doubles, as_strings
26
+ * From Ruby side: Every REXP objects has a <tt>to_ruby</tt> method, which automagicly converts every R type on equivalent Ruby type. So, a vector of size 1 is converted to an integer or double, a vector of size>1 returns an array, a named list returns a hash and so on. If you need to create a complex expression, you could always use method <tt>eval</tt> without problem
22
27
  Cons:
23
28
  * Requires Rserve
24
- * No seamless integration with Ruby. You obtain data with an interface closer to R than Ruby.
25
29
 
26
30
  == RELATED LIBRARIES (Ruby / R)
27
31
 
@@ -51,13 +55,6 @@ Cons:
51
55
 
52
56
  Implements
53
57
 
54
- * REXPs
55
- * Enviroment
56
- * ExpressionVector
57
- * Raw
58
- * Reference
59
- * S4
60
- * Wrapper
61
58
  * Sessions
62
59
  * Authentification
63
60
  * Original test
@@ -70,16 +67,41 @@ Spec
70
67
 
71
68
  == SYNOPSIS:
72
69
 
73
- require 'rserve'
74
- con=Rserve::Connection.new
75
- con.eval("x<-rnorm(1)")
76
- => #<Rserve::REXP::Double:0x000000011a13c8
77
- @payload=[(5339785585931699/2251799813685248)],
78
- @attr=nil>
79
- con.eval("list(name='Fred')").as_list
80
-
81
- => #<Rserve::Rlist:0x00000001bf82a8 @names=["name"], @data=[#<Rserve::REXP::String:0x00000001bf8548 @payload=["Fred"], @attr=nil>]>
70
+ require 'rserve'
71
+ con=Rserve::Connection.new
72
+
73
+ # Evaluation retrieves a <tt>Rserve::REXP</tt> object
74
+
75
+ x=con.eval('x<-rnorm(1)')
76
+ => #<Rserve::REXP::Double:0x000000010a81f0 @payload=[(4807469545488851/9007199254740992)], @attr=nil>
82
77
 
78
+ # You could use specific methods to retrieve ruby objects
79
+ x.as_doubles => [0.533736337958596]
80
+ x.as_strings => ["0.533736337958596"]
81
+
82
+ # Every Rserve::REXP could be converted to Ruby objects using
83
+ # method <tt>to_ruby</tt>
84
+ x.to_ruby => (4807469545488851/9007199254740992)
85
+
86
+ # The API could manage complex recursive list
87
+
88
+ x=con.eval('list(l1=list(c(2,3)),l2=c(1,2,3))').to_ruby
89
+ => {"l1"=>[[(2/1), (3/1)]], "l2"=>[(1/1), (2/1), (3/1)]}
90
+
91
+ # You could assign a REXP to R variables
92
+
93
+ con.assign("x", Rserve::REXP::Double.new([1.5,2.3,5]))
94
+ => #<Rserve::Packet:0x0000000136b068 @cmd=65537, @cont=nil>
95
+ con.eval("x")
96
+ => #<Rserve::REXP::Double:0x0000000134e770 @payload=[(3/2), (2589569785738035/1125899906842624), (5/1)], @attr=nil>
97
+
98
+ # Rserve::REXP::Wrapper.wrap allows you to transform Ruby object to
99
+ # REXP, could be assigned to R variables
100
+
101
+ Rserve::REXP::Wrapper.wrap(["a","b",["c","d"]])
102
+
103
+ => #<Rserve::REXP::GenericVector:0x000000010c81d0 @attr=nil, @payload=#<Rserve::Rlist:0x000000010c8278 @names=nil, @data=[#<Rserve::REXP::String:0x000000010c86d8 @payload=["a"], @attr=nil>, #<Rserve::REXP::String:0x000000010c85c0 @payload=["b"], @attr=nil>, #<Rserve::REXP::String:0x000000010c82e8 @payload=["c", "d"], @attr=nil>]>>
104
+
83
105
  == REQUIREMENTS:
84
106
 
85
107
  * R
@@ -1,7 +1,7 @@
1
1
  require 'socket'
2
2
 
3
3
  module Rserve
4
- VERSION = '0.1.5'
4
+ VERSION = '0.1.6'
5
5
  end
6
6
 
7
7
 
@@ -1,7 +1,7 @@
1
1
  module Rserve
2
2
  class Connection < Rserve::Engine
3
3
  include Rserve::Protocol
4
-
4
+
5
5
  # :section: Exceptions
6
6
  RserveNotStarted=Class.new(Exception)
7
7
  ServerNotAvailable=Class.new(Exception)
@@ -18,7 +18,7 @@ module Rserve
18
18
  end
19
19
  attr_reader :hostname
20
20
  attr_reader :port_number
21
- attr_reader :protocol
21
+ attr_reader :protocol
22
22
  attr_reader :last_error
23
23
  attr_reader :connected
24
24
  attr_reader :auth_req
@@ -29,9 +29,10 @@ module Rserve
29
29
  attr_reader :port
30
30
  attr_writer :transfer_charset
31
31
  attr_reader :rsrv_version
32
+ attr_writer :persistent
32
33
  AT_plain=0
33
34
  AT_crypt=1
34
-
35
+
35
36
  def initialize(opts=Hash.new)
36
37
  @auth_req = opts.delete(:auth_req) || false
37
38
  @transfer_charset = opts.delete(:transfer_charset) || "UTF-8"
@@ -39,52 +40,53 @@ module Rserve
39
40
  @hostname = opts.delete(:hostname) || "127.0.0.1"
40
41
  @port_number = opts.delete(:port_number) || 6311
41
42
  @max_tries = opts.delete(:max_tries) || 5
42
-
43
43
  @tries = 0
44
44
  @connected=false
45
-
46
-
47
- begin
45
+
46
+
47
+ begin
48
48
  #puts "Tryin to connect..."
49
49
  connect
50
50
  rescue Errno::ECONNREFUSED
51
51
  if @tries<@max_tries
52
- @tries+=1
53
- # Rserve is available?
54
- if system "killall -s 0 Rserve"
55
- # Rserve is available. Incorrect host and/or portname
56
- raise ServerNotAvailable, "Rserve started, but not available on #{hostname}:#{port_number}"
57
- # Rserve not available. We should instanciate it first
58
- else
59
- if system "R CMD Rserve"
60
- #puts "Ok"
61
- retry
62
- else
63
- raise RserveNotStarted, "Can't start Rserve"
64
- end
65
- end
52
+ @tries+=1
53
+ # Rserve is available?
54
+ if system "killall -s 0 Rserve"
55
+ # Rserve is available. Incorrect host and/or portname
56
+ raise ServerNotAvailable, "Rserve started, but not available on #{hostname}:#{port_number}"
57
+ # Rserve not available. We should instanciate it first
58
+ else
59
+ if system "R CMD Rserve"
60
+ # Wait a moment please
61
+ sleep(0.25)
62
+ retry
63
+ else
64
+ raise RserveNotStarted, "Can't start Rserve"
65
+ end
66
+ end
66
67
  #puts "Init RServe"
67
-
68
+
68
69
  else
69
70
  raise
70
71
  end
71
72
  end
72
73
  end
73
74
  def connect
74
- close if @connected
75
- @s = TCPSocket::new(@hostname, @port_number)
76
- @rt=Rserve::Talk.new(@s)
77
- #puts "Connected"
78
- # Accept first input
79
- input=@s.recv(32).unpack("a4a4a4a20")
80
- raise IncorrectServer,"Handshake failed: Rsrv signature expected, but received [#{input[0]}]" unless input[0]=="Rsrv"
81
- @rsrv_version=input[1].to_i
82
- raise IncorrectServerVersion, "Handshake failed: The server uses more recent protocol than this client." if @rsrv_version>103
83
- @protocol=input[2]
84
- raise IncorrectProtocol, "Handshake failed: unsupported transfer protocol #{@protocol}, I talk only QAP1." if @protocol!="QAP1"
85
- @extra=input[4]
86
- @connected=true
87
- @last_error="OK"
75
+
76
+ close if @connected
77
+ @s = TCPSocket::new(@hostname, @port_number)
78
+ @rt=Rserve::Talk.new(@s)
79
+ #puts "Connected"
80
+ # Accept first input
81
+ input=@s.recv(32).unpack("a4a4a4a20")
82
+ raise IncorrectServer,"Handshake failed: Rsrv signature expected, but received [#{input[0]}]" unless input[0]=="Rsrv"
83
+ @rsrv_version=input[1].to_i
84
+ raise IncorrectServerVersion, "Handshake failed: The server uses more recent protocol than this client." if @rsrv_version>103
85
+ @protocol=input[2]
86
+ raise IncorrectProtocol, "Handshake failed: unsupported transfer protocol #{@protocol}, I talk only QAP1." if @protocol!="QAP1"
87
+ @extra=input[4]
88
+ @connected=true
89
+ @last_error="OK"
88
90
 
89
91
  end
90
92
  def connected?
@@ -102,10 +104,10 @@ module Rserve
102
104
  def get_server_version
103
105
  @rsrv_version
104
106
  end
105
-
107
+
106
108
  # evaluates the given command, but does not fetch the result (useful for assignment operations)
107
109
  # * @param cmd command/expression string */
108
- def void_eval(cmd)
110
+ def void_eval(cmd)
109
111
  raise NotConnected if !connected? or rt.nil?
110
112
  rp=rt.request(:cmd=>Rserve::Protocol::CMD_voidEval, :cont=>cmd+"\n")
111
113
  if !rp.nil? and rp.ok?
@@ -113,43 +115,124 @@ module Rserve
113
115
  else
114
116
  raise EvalError.new(rp), "voidEval failed: #{rp.to_s}"
115
117
  end
116
-
117
- end
118
-
119
-
120
- # evaluates the given command and retrieves the result
121
- # * @param cmd command/expression string
122
- # * @return R-xpression or <code>null</code> if an error occured */
123
- def eval(cmd)
124
- raise NotConnected if !connected? or rt.nil?
125
- rp=rt.request(:cmd=>Rserve::Protocol::CMD_eval, :cont=>cmd+"\n")
126
- if !rp.nil? and rp.ok?
127
- parse_eval_response(rp)
128
- else
129
- raise EvalError.new(rp), "voidEval failed: #{rp.to_s}"
118
+
130
119
  end
131
- end
132
- def parse_eval_response(rp)
133
- rxo=0
134
- pc=rp.cont
135
- if (rsrv_version>100) # /* since 0101 eval responds correctly by using DT_SEXP type/len header which is 4 bytes long */
136
- rxo=4
137
- # we should check parameter type (should be DT_SEXP) and fail if it's not
138
- if (pc[0]!=Rserve::Protocol::DT_SEXP && pc[0]!=(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
139
- raise "Error while processing eval output: SEXP (type "+Rserve::Protocol::DT_SEXP+") expected but found result type "+pc[0].to_s+"."
140
- end
141
- if (pc[0]==(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
142
- rxo=8; # large data need skip of 8 bytes
120
+
121
+
122
+ # evaluates the given command and retrieves the result
123
+ # * @param cmd command/expression string
124
+ # * @return R-xpression or <code>null</code> if an error occured */
125
+ def eval(cmd)
126
+ raise NotConnected if !connected? or rt.nil?
127
+ rp=rt.request(:cmd=>Rserve::Protocol::CMD_eval, :cont=>cmd+"\n")
128
+ if !rp.nil? and rp.ok?
129
+ parse_eval_response(rp)
130
+ else
131
+ raise EvalError.new(rp), "voidEval failed: #{rp.to_s}"
143
132
  end
144
- # warning: we are not checking or using the length - we assume that only the one SEXP is returned. This is true for the current CMD_eval implementation, but may not be in the future. */
145
133
  end
146
- if pc.length>rxo
134
+
135
+ # NOT TESTED
136
+ def parse_eval_response(rp)
137
+ rxo=0
138
+ pc=rp.cont
139
+ if (rsrv_version>100) # /* since 0101 eval responds correctly by using DT_SEXP type/len header which is 4 bytes long */
140
+ rxo=4
141
+ # we should check parameter type (should be DT_SEXP) and fail if it's not
142
+ if (pc[0]!=Rserve::Protocol::DT_SEXP && pc[0]!=(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
143
+ raise "Error while processing eval output: SEXP (type "+Rserve::Protocol::DT_SEXP+") expected but found result type "+pc[0].to_s+"."
144
+ end
145
+ if (pc[0]==(Rserve::Protocol::DT_SEXP|Rserve::Protocol::DT_LARGE))
146
+ rxo=8; # large data need skip of 8 bytes
147
+ end
148
+ # warning: we are not checking or using the length - we assume that only the one SEXP is returned. This is true for the current CMD_eval implementation, but may not be in the future. */
149
+ end
150
+ if pc.length>rxo
147
151
  rx=REXPFactory.new;
148
- rx.parse_REXP(pc, rxo);
149
- return rx.get_REXP();
152
+ rx.parse_REXP(pc, rxo);
153
+ return rx.get_REXP();
150
154
  else
151
155
  return nil
156
+ end
157
+ end
158
+
159
+ #assign a string value to a symbol in R. The symbol is created if it doesn't exist already.
160
+ # @param sym symbol name. Currently assign uses CMD_setSEXP command of Rserve, i.e. the symbol value is NOT parsed. It is the responsibility of the user to make sure that the symbol name is valid in R (recall the difference between a symbol and an expression!). In fact R will always create the symbol, but it may not be accessible (examples: "bar\nfoo" or "bar$foo").
161
+ # @param ct contents
162
+ def assign(sym, ct)
163
+ raise NotConnected if !connected? or rt.nil?
164
+ case ct
165
+ when String
166
+ assign_string(sym,ct)
167
+ when REXP
168
+ assign_rexp(sym,ct)
169
+ else
170
+ raise "Should be String or REXP"
171
+ end
172
+ end
173
+ def assign_string(sym,ct)
174
+ symn = sym.unpack("C*")
175
+ ctn = ct.unpack("C*")
176
+ sl=symn.length+1
177
+ cl=ctn.length+1
178
+ sl=(sl&0xfffffc)+4 if ((sl&3)>0) # make sure the symbol length is divisible by 4
179
+ cl=(cl&0xfffffc)+4 if ((cl&3)>0) # make sure the content length is divisible by 4
180
+ rq=Array.new(sl+4+cl+4)
181
+ symn.length.times {|i| rq[i+4]=symn[i]}
182
+ ic=symn.length
183
+ while (ic<sl)
184
+ rq[ic+4]=0
185
+ ic+=1
186
+ end
187
+ ctn.length.times {|i| rq[i+sl+8]=ctn[i]}
188
+ ic=ctn.length
189
+ while (ic<cl)
190
+ rq[ic+sl+8]=0
191
+ ic+=1
192
+ end
193
+ set_hdr(Rserve::Protocol::DT_STRING,sl,rq,0)
194
+ set_hdr(Rserve::Protocol::DT_STRING,cl,rq,sl+4)
195
+ rp=rt.request(:cmd=>Rserve::Protocol::CMD_setSEXP,:cont=>rq)
196
+ if (!rp.nil? and rp.ok?)
197
+ rp
198
+ else
199
+ raise "Assign Failed"
200
+ end
201
+ end
202
+ def assign_rexp(sym, rexp)
203
+ r = REXPFactory.new(rexp);
204
+ rl=r.get_binary_length();
205
+ symn=sym.unpack("C*");
206
+ sl=symn.length+1;
207
+ sl=(sl&0xfffffc)+4 if ((sl&3)>0) # make sure the symbol length is divisible by 4
208
+ rq=Array.new(sl+rl+((rl>0xfffff0) ? 12 : 8));
209
+ symn.length.times {|i| rq[i+4]=symn[i]}
210
+ ic=symn.length
211
+ while(ic<sl)
212
+ rq[ic+4]=0;
213
+ ic+=1;
214
+ end # pad with 0
215
+
216
+ set_hdr(Rserve::Protocol::DT_STRING,sl,rq,0)
217
+ set_hdr(Rserve::Protocol::DT_SEXP,rl,rq,sl+4);
218
+ r.get_binary_representation(rq, sl+((rl>0xfffff0) ? 12 : 8));
219
+ # puts "ASSIGN RQ: #{rq}" if $DEBUG
220
+ rp=rt.request(:cmd=>Rserve::Protocol::CMD_setSEXP, :cont=>rq)
221
+ if (!rp.nil? and rp.ok?)
222
+ rp
223
+ else
224
+ raise "Assign Failed"
225
+ end
226
+ end
227
+ def shutdown
228
+ raise NotConnected if !connected? or rt.nil?
229
+ rp=rt.request(:cmd=>Rserve::Protocol::CMD_shutdown)
230
+ if !rp.nil? and rp.ok?
231
+ true
232
+ else
233
+ raise "Shutdown failed"
234
+ end
152
235
  end
236
+
153
237
  end
154
238
  end
155
- end