rserve-client 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/History.txt +3 -0
- data/Manifest.txt +31 -0
- data/README.txt +50 -0
- data/Rakefile +14 -0
- data/lib/rserve.rb +14 -0
- data/lib/rserve/connection.rb +138 -0
- data/lib/rserve/engine.rb +40 -0
- data/lib/rserve/packet.rb +31 -0
- data/lib/rserve/protocol.rb +183 -0
- data/lib/rserve/protocol/rexpfactory.rb +360 -0
- data/lib/rserve/rexp.rb +234 -0
- data/lib/rserve/rexp/double.rb +46 -0
- data/lib/rserve/rexp/genericvector.rb +29 -0
- data/lib/rserve/rexp/integer.rb +49 -0
- data/lib/rserve/rexp/list.rb +33 -0
- data/lib/rserve/rexp/logical.rb +48 -0
- data/lib/rserve/rexp/string.rb +33 -0
- data/lib/rserve/rexp/symbol.rb +26 -0
- data/lib/rserve/rexp/vector.rb +23 -0
- data/lib/rserve/rlist.rb +124 -0
- data/lib/rserve/talk.rb +123 -0
- data/spec/rserve_connection_spec.rb +43 -0
- data/spec/rserve_double_spec.rb +55 -0
- data/spec/rserve_integer_spec.rb +55 -0
- data/spec/rserve_packet_spec.rb +19 -0
- data/spec/rserve_protocol_spec.rb +75 -0
- data/spec/rserve_rexpfactory_spec.rb +44 -0
- data/spec/rserve_spec.rb +18 -0
- data/spec/rserve_talk_spec.rb +73 -0
- data/spec/spec.opts +3 -0
- data/spec/spec_helper.rb +4 -0
- metadata +149 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,360 @@
|
|
1
|
+
module Rserve
|
2
|
+
module Protocol
|
3
|
+
# representation of R-eXpressions in Ruby
|
4
|
+
class REXPFactory
|
5
|
+
include Rserve::Protocol
|
6
|
+
# xpression type: NULL
|
7
|
+
XT_NULL=0;
|
8
|
+
# xpression type: integer
|
9
|
+
XT_INT=1;
|
10
|
+
# xpression type: double
|
11
|
+
XT_DOUBLE=2;
|
12
|
+
# xpression type: String
|
13
|
+
XT_STR=3;
|
14
|
+
# xpression type: language construct (currently content is same as list)
|
15
|
+
XT_LANG=4;
|
16
|
+
# xpression type: symbol (content is symbol name: String)
|
17
|
+
XT_SYM=5;
|
18
|
+
# xpression type: RBool
|
19
|
+
XT_BOOL=6;
|
20
|
+
# xpression type: S4 object
|
21
|
+
#@since Rserve 0.5
|
22
|
+
XT_S4=7;
|
23
|
+
# xpression type: generic vector (RList)
|
24
|
+
XT_VECTOR=16;
|
25
|
+
# xpression type: dotted-pair list (RList)
|
26
|
+
XT_LIST=17;
|
27
|
+
# xpression type: closure (there is no java class for that type (yet?). currently the body of the closure is stored in the content part of the REXP. Please note that this may change in the future!)
|
28
|
+
XT_CLOS=18;
|
29
|
+
# xpression type: symbol name
|
30
|
+
# @since Rserve 0.5
|
31
|
+
XT_SYMNAME=19;
|
32
|
+
# xpression type: dotted-pair list (w/o tags)
|
33
|
+
# @since Rserve 0.5
|
34
|
+
XT_LIST_NOTAG=20;
|
35
|
+
# xpression type: dotted-pair list (w tags)
|
36
|
+
# @since Rserve 0.5
|
37
|
+
XT_LIST_TAG=21;
|
38
|
+
# xpression type: language list (w/o tags)
|
39
|
+
# @since Rserve 0.5
|
40
|
+
XT_LANG_NOTAG=22;
|
41
|
+
# xpression type: language list (w tags)
|
42
|
+
# @since Rserve 0.5
|
43
|
+
XT_LANG_TAG=23;
|
44
|
+
# xpression type: expression vector
|
45
|
+
XT_VECTOR_EXP=26;
|
46
|
+
# xpression type: string vector
|
47
|
+
XT_VECTOR_STR=27;
|
48
|
+
# xpression type: int[]
|
49
|
+
XT_ARRAY_INT=32;
|
50
|
+
# xpression type: double[]
|
51
|
+
XT_ARRAY_DOUBLE=33;
|
52
|
+
# xpression type: String[] (currently not used, Vector is used instead)
|
53
|
+
XT_ARRAY_STR=34;
|
54
|
+
# internal use only! this constant should never appear in a REXP
|
55
|
+
XT_ARRAY_BOOL_UA=35;
|
56
|
+
# xpression type: RBool[]
|
57
|
+
XT_ARRAY_BOOL=36;
|
58
|
+
# xpression type: raw (byte[])
|
59
|
+
# @since Rserve 0.4-?
|
60
|
+
XT_RAW=37;
|
61
|
+
# xpression type: Complex[]
|
62
|
+
# @since Rserve 0.5
|
63
|
+
XT_ARRAY_CPLX=38;
|
64
|
+
# xpression type: unknown; no assumptions can be made about the content
|
65
|
+
XT_UNKNOWN=48;
|
66
|
+
# xpression type: RFactor; this XT is internally generated (ergo is does not come from Rsrv.h) to support RFactor class which is built from XT_ARRAY_INT
|
67
|
+
XT_FACTOR=127;
|
68
|
+
# used for transport only - has attribute
|
69
|
+
XT_HAS_ATTR=128;
|
70
|
+
|
71
|
+
attr_reader :type, :attr, :cont, :root_list
|
72
|
+
def get_REXP
|
73
|
+
@cont
|
74
|
+
end
|
75
|
+
def get_attr
|
76
|
+
attr.nil? ? nil : attr.cont
|
77
|
+
end
|
78
|
+
def initialize(*args)
|
79
|
+
if args.size==0
|
80
|
+
|
81
|
+
elsif
|
82
|
+
r=args[0]
|
83
|
+
r=Rserve::REXP::Null if r.nil?
|
84
|
+
a=r.attr
|
85
|
+
@attr=Factory.new(a) if !a.nil?
|
86
|
+
if r.is_a? REXP::Null
|
87
|
+
@type=XT_NULL
|
88
|
+
elsif r.is_a? REXP::List
|
89
|
+
l=r.as_list
|
90
|
+
@type=l.named? ? XT_LIST_TAG : XT_LIST_NOTAG
|
91
|
+
if r.is_a? REXPLanguage
|
92
|
+
@type = (@type==XT_LIST_TAG) ? XT_LANG_TAG : XT_LANG_NOTAG;
|
93
|
+
end
|
94
|
+
elsif r.is_a? REXP::GenericVector
|
95
|
+
@type = XT_VECTOR; # FIXME: may have to adjust names attr
|
96
|
+
elsif r.is_a? REXP::S4
|
97
|
+
@type = XT_S4
|
98
|
+
elsif r.is_a? REXP::Integer
|
99
|
+
@type = XT_ARRAY_INT
|
100
|
+
elsif r.is_a? REXP::Double
|
101
|
+
@type = XT_ARRAY_DOUBLE
|
102
|
+
elsif r.is_a? REXP::String
|
103
|
+
@type = XT_ARRAY_STRING
|
104
|
+
elsif r.is_a? REXP::Symbol
|
105
|
+
@type = XT_SYMNAME
|
106
|
+
elsif r.is_a? REXP::Raw
|
107
|
+
@type = XT_RAW
|
108
|
+
elsif r.is_a? REXP::Logical
|
109
|
+
@type = XT_ARRAY_BOOL
|
110
|
+
else
|
111
|
+
raise ArgumentError("***REXPFactory unable to interpret #{r}")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
115
|
+
def parse_REXP(buf,o)
|
116
|
+
xl=get_len(buf,o)
|
117
|
+
#p "buffer:#{buf.to_s}"
|
118
|
+
has_at = (buf[o]&128)!=0
|
119
|
+
is_long = (buf[o]&64 )!=0
|
120
|
+
xt = buf[o]&63
|
121
|
+
o+=4 if is_long
|
122
|
+
o+=4
|
123
|
+
eox=o+xl
|
124
|
+
@type=xt
|
125
|
+
|
126
|
+
@attr=REXPFactory.new()
|
127
|
+
@cont=nil
|
128
|
+
|
129
|
+
o=attr.parse_REXP(buf,o) if has_at
|
130
|
+
|
131
|
+
if xt==XT_NULL
|
132
|
+
@cont=REXP::Null(get_attr)
|
133
|
+
return o
|
134
|
+
end
|
135
|
+
if xt==XT_DOUBLE
|
136
|
+
lr=get_long(buf,o)
|
137
|
+
d=[longBitsToDouble(lr)]
|
138
|
+
o+=8
|
139
|
+
if(o!=eox)
|
140
|
+
$STDERR.puts("Warning: double SEXP size mismatch\n");
|
141
|
+
o=eox
|
142
|
+
end
|
143
|
+
@cont=REXP::Double.new(d,get_attr)
|
144
|
+
return o
|
145
|
+
end
|
146
|
+
if xt==XT_ARRAY_DOUBLE
|
147
|
+
as=(eox-o).quo(8)
|
148
|
+
i=0
|
149
|
+
d=Array.new(as)
|
150
|
+
while(o<eox)
|
151
|
+
d[i]=longBitsToDouble(get_long(buf,o))
|
152
|
+
o+=8
|
153
|
+
i+=1
|
154
|
+
end
|
155
|
+
if(o!=eox)
|
156
|
+
$STDERR.puts("Warning: double SEXP size mismatch\n");
|
157
|
+
o=eox
|
158
|
+
end
|
159
|
+
@cont=REXP::Double.new(d,get_attr)
|
160
|
+
return o
|
161
|
+
end
|
162
|
+
if xt==XT_BOOL
|
163
|
+
b=[buf[o]]
|
164
|
+
if (b[0]!=0 && b[0]!=1)
|
165
|
+
b[0]=REXP::Logical::NA
|
166
|
+
end
|
167
|
+
@cont=REXP::Logical.new(b,get_attr)
|
168
|
+
o+=1
|
169
|
+
return o
|
170
|
+
end
|
171
|
+
if xt==XT_ARRAY_BOOL_UA
|
172
|
+
as=(eox-o)
|
173
|
+
i=0
|
174
|
+
d=Array.new(as)
|
175
|
+
(eox-i).times {|i| d[i]=buf[o+i]}
|
176
|
+
o=eox
|
177
|
+
d.length.each {|j|
|
178
|
+
if d[j]!=0 && d[j]!=1
|
179
|
+
d[j]==REXP::Logical::NA
|
180
|
+
end
|
181
|
+
}
|
182
|
+
@cont=REXP::Logical.new(d,get_attr)
|
183
|
+
return o
|
184
|
+
end
|
185
|
+
if xt==XT_ARRAY_BOOL
|
186
|
+
as=get_int(buf, o)
|
187
|
+
o+=4
|
188
|
+
d=Array.new(as)
|
189
|
+
as.times {|i| d[i]=buf[o+i]}
|
190
|
+
d.length.times {|j|
|
191
|
+
if d[j]!=0 && d[j]!=1
|
192
|
+
d[j]==REXP::Logical::NA
|
193
|
+
end
|
194
|
+
}
|
195
|
+
o=eox
|
196
|
+
@cont=REXP::Logical.new(d,get_attr)
|
197
|
+
return o
|
198
|
+
end
|
199
|
+
if xt==XT_INT
|
200
|
+
i=Array.new(get_int(buf,o))
|
201
|
+
@cont=REXP::Integer.new(i,get_attr)
|
202
|
+
o+=4
|
203
|
+
if o!=eox
|
204
|
+
$STDERR.puts "int SEXP size mismatch"
|
205
|
+
o=eox
|
206
|
+
end
|
207
|
+
return o
|
208
|
+
end
|
209
|
+
|
210
|
+
if xt==XT_ARRAY_INT
|
211
|
+
as=(eox-o).quo(4)
|
212
|
+
i=0
|
213
|
+
d=Array.new(as)
|
214
|
+
while(o<eox)
|
215
|
+
d[i]=get_int(buf,o)
|
216
|
+
o+=4
|
217
|
+
i+=1
|
218
|
+
end
|
219
|
+
if o!=eox
|
220
|
+
$STDERR.puts "int SEXP size mismatch"
|
221
|
+
o=eox
|
222
|
+
end
|
223
|
+
# hack for list. Not implemented yet!
|
224
|
+
@cont=nil
|
225
|
+
@cont=REXP::Integer(d,get_attr)
|
226
|
+
return o
|
227
|
+
end
|
228
|
+
|
229
|
+
# RAW not implemented yet
|
230
|
+
if xt==XT_LIST_NOTAG or xt==XT_LIST_TAG or xt==XT_LANG_NOTAG or xt==XT_LANG_TAG
|
231
|
+
lc=REXPFactory.new
|
232
|
+
nf=REXPFactory.new
|
233
|
+
l=Rlist.new
|
234
|
+
while(o<eox)
|
235
|
+
name=nil
|
236
|
+
o=lc.parse_REXP(buf,o)
|
237
|
+
if(xt==XT_LIST_TAG or xt==XT_LANG_TAG)
|
238
|
+
o=nf.parse_REXP(buf,o)
|
239
|
+
name=nf.cont.as_strings if(nf.cont.symbol? or nf.cont.string?)
|
240
|
+
end
|
241
|
+
if name.nil?
|
242
|
+
l.add(lc.cont)
|
243
|
+
else
|
244
|
+
l.put(name,lc.cont)
|
245
|
+
end
|
246
|
+
end
|
247
|
+
|
248
|
+
@cont=(xt==XT_LANG_NOTAG or xt==XT_LANG_TAG) ?
|
249
|
+
REXP::Language.new(l,get_attr) : REXP::List.new(l, get_attr)
|
250
|
+
|
251
|
+
if(o!=eox)
|
252
|
+
$STDERR.puts "Mismatch"
|
253
|
+
o=eox
|
254
|
+
end
|
255
|
+
|
256
|
+
return o
|
257
|
+
|
258
|
+
end
|
259
|
+
|
260
|
+
|
261
|
+
# XT_LIST and XT_LANG not implemented yet
|
262
|
+
|
263
|
+
if xt==XT_VECTOR or xt==XT_VECTOR_EXP
|
264
|
+
v=Array.new
|
265
|
+
while(o<eox)
|
266
|
+
xx=REXPFactory.new()
|
267
|
+
o = xx.parse_REXP(buf,o);
|
268
|
+
v.push(xx.cont);
|
269
|
+
end
|
270
|
+
if (o!=eox)
|
271
|
+
$STDERR.puts("Warning: int vector SEXP size mismatch\n");
|
272
|
+
o=eox;
|
273
|
+
end
|
274
|
+
# fixup for lists since they're stored as attributes of vectors
|
275
|
+
if !get_attr.nil? and !get_attr.as_list['names'].nil?
|
276
|
+
nam=get_attr.as_list['names']
|
277
|
+
names=nil
|
278
|
+
if nam.string?
|
279
|
+
names=nam.as_strings
|
280
|
+
elsif nam.vector?
|
281
|
+
l=nam.to_a
|
282
|
+
names=Array.new(aa.length)
|
283
|
+
aa.length.times {|i| names[i]=aa[i].as_string}
|
284
|
+
end
|
285
|
+
l=RList.new(v,names)
|
286
|
+
@cont=(xt==XT_VECTOR_EXP) ? REXP::ExpressionVector.new(l,get_attr) : REXP::GenericVector.new(l,get_attr)
|
287
|
+
else
|
288
|
+
|
289
|
+
@cont=(xt==XT_VECTOR_EXP) ? REXP::ExpressionVector.new(Rlist.new(v), get_attr) : REXP::GenericVector.new(Rlist.new(v), get_attr)
|
290
|
+
end
|
291
|
+
return o
|
292
|
+
end
|
293
|
+
if xt==XT_ARRAY_STR
|
294
|
+
c=0
|
295
|
+
i=o
|
296
|
+
while(i<eox)
|
297
|
+
c+=1 if buf[i]==0
|
298
|
+
i+=1
|
299
|
+
end
|
300
|
+
s=Array.new(c)
|
301
|
+
if c>0
|
302
|
+
c=0; i=o;
|
303
|
+
while(o < eox)
|
304
|
+
if buf[o]==0
|
305
|
+
begin
|
306
|
+
s[c]=buf[i,o-i].pack("C*")
|
307
|
+
rescue
|
308
|
+
s[c]=""
|
309
|
+
end
|
310
|
+
c+=1
|
311
|
+
i=o+1
|
312
|
+
end
|
313
|
+
o+=1
|
314
|
+
end
|
315
|
+
|
316
|
+
end
|
317
|
+
@cont=REXP::String.new(s, get_attr)
|
318
|
+
return o
|
319
|
+
end
|
320
|
+
if xt==XT_VECTOR_STR
|
321
|
+
v=Array.new
|
322
|
+
while(o<eox)
|
323
|
+
xx=REXP::Factory.new
|
324
|
+
o=xx.parse_REXP(buf,o)
|
325
|
+
v.push(xx.cont.as_string)
|
326
|
+
end
|
327
|
+
sa=Array.new(v.size)
|
328
|
+
i=0
|
329
|
+
while(i<sa.length)
|
330
|
+
sa[i]=v.get(i)
|
331
|
+
i+=1
|
332
|
+
end
|
333
|
+
@cont=REXP::String.new(sa,get_attr)
|
334
|
+
return o
|
335
|
+
end
|
336
|
+
|
337
|
+
if (xt==XT_STR||xt==XT_SYMNAME)
|
338
|
+
i = o;
|
339
|
+
while (buf[i]!=0 && i<eox) do
|
340
|
+
i+=1
|
341
|
+
end
|
342
|
+
if (xt==XT_STR)
|
343
|
+
@cont = REXP::String.new(buf[o,i-o].pack("C*"), get_attr);
|
344
|
+
else
|
345
|
+
@cont = REXP::Symbol.new(buf[o,i-o].pack("C*"))
|
346
|
+
end
|
347
|
+
|
348
|
+
o = eox;
|
349
|
+
return o;
|
350
|
+
end
|
351
|
+
|
352
|
+
#not implemented XT_SYM, XT_CLOSS, XT_UNKNOWN, XT_S4
|
353
|
+
@cont=nil
|
354
|
+
o=eox
|
355
|
+
raise "Unhandled type:#{xt}"
|
356
|
+
return o
|
357
|
+
end # def
|
358
|
+
end # Factory
|
359
|
+
end # end Protocol
|
360
|
+
end # end Rserve
|
data/lib/rserve/rexp.rb
ADDED
@@ -0,0 +1,234 @@
|
|
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.
|
5
|
+
#
|
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
|
+
#
|
8
|
+
class REXP
|
9
|
+
MismatchException= Class.new(Exception)
|
10
|
+
attr_reader :attr
|
11
|
+
def initialize(attr=nil)
|
12
|
+
@attr=attr
|
13
|
+
end
|
14
|
+
# specifies how many items of a vector or list will be displayed in {@link #toDebugString} */
|
15
|
+
MaxDebugItems = 32
|
16
|
+
# :section: type checks
|
17
|
+
# check whether the <code>REXP</code> object is a character vector (string)
|
18
|
+
# @return <code>true</code> if the receiver is a character vector, <code>false</code> otherwise */
|
19
|
+
|
20
|
+
def string?;return false;end
|
21
|
+
|
22
|
+
# # check whether the <code>REXP</code> object is a numeric vector
|
23
|
+
# @return <code>true</code> if the receiver is a numeric vector, <code>false</code> otherwise */
|
24
|
+
|
25
|
+
def numeric?;false;end
|
26
|
+
# check whether the <code>REXP</code> object is an integer vector
|
27
|
+
# @return <code>true</code> if the receiver is an integer vector, <code>false</code> otherwise */
|
28
|
+
def integer?;false;end
|
29
|
+
# check whether the <code>REXP</code> object is NULL
|
30
|
+
# @return <code>true</code> if the receiver is NULL, <code>false</code> otherwise */
|
31
|
+
def null?;false;end
|
32
|
+
# check whether the <code>REXP</code> object is a factor
|
33
|
+
# @return <code>true</code> if the receiver is a factor, <code>false</code> otherwise */
|
34
|
+
def factor?;false;end
|
35
|
+
# check whether the <code>REXP</code> object is a list (either generic vector or a pairlist - i.e. {@link #asList()} will succeed)
|
36
|
+
# @return <code>true</code> if the receiver is a generic vector or a pair-list, <code>false</code> otherwise */
|
37
|
+
def list?;false;end
|
38
|
+
# check whether the <code>REXP</code> object is a pair-list
|
39
|
+
# @return <code>true</code> if the receiver is a pair-list, <code>false</code> otherwise */
|
40
|
+
def pair_list?;false;end
|
41
|
+
# check whether the <code>REXP</code> object is a logical vector
|
42
|
+
# @return <code>true</code> if the receiver is a logical vector, <code>false</code> otherwise */
|
43
|
+
def logical?;false;end
|
44
|
+
# check whether the <code>REXP</code> object is an environment
|
45
|
+
# @return <code>true</code> if the receiver is an environment, <code>false</code> otherwise */
|
46
|
+
def environment?;false;end
|
47
|
+
# check whether the <code>REXP</code> object is a language object
|
48
|
+
# @return <code>true</code> if the receiver is a language object, <code>false</code> otherwise */
|
49
|
+
def language?;false;end
|
50
|
+
# check whether the <code>REXP</code> object is an expression vector
|
51
|
+
# @return <code>true</code> if the receiver is an expression vector, <code>false</code> otherwise */
|
52
|
+
def expression?;false;end
|
53
|
+
# check whether the <code>REXP</code> object is a symbol
|
54
|
+
# @return <code>true</code> if the receiver is a symbol, <code>false</code> otherwise */
|
55
|
+
def symbol?;false;end
|
56
|
+
# check whether the <code>REXP</code> object is a vector
|
57
|
+
# @return <code>true</code> if the receiver is a vector, <code>false</code> otherwise */
|
58
|
+
def vector?;false;end
|
59
|
+
# check whether the <code>REXP</code> object is a raw vector
|
60
|
+
# @return <code>true</code> if the receiver is a raw vector, <code>false</code> otherwise */
|
61
|
+
def raw?;false;end
|
62
|
+
# check whether the <code>REXP</code> object is a complex vector
|
63
|
+
# @return <code>true</code> if the receiver is a complex vector, <code>false</code> otherwise */
|
64
|
+
def complex?;false;end
|
65
|
+
# check whether the <code>REXP</code> object is a recursive obejct
|
66
|
+
# @return <code>true</code> if the receiver is a recursive object, <code>false</code> otherwise */
|
67
|
+
def recursive?;false;end
|
68
|
+
# check whether the <code>REXP</code> object is a reference to an R object
|
69
|
+
# @return <code>true</code> if the receiver is a reference, <code>false</code> otherwise */
|
70
|
+
def reference?;false;end
|
71
|
+
|
72
|
+
# :section: basic accessor methods
|
73
|
+
# returns the contents as an array of Strings (if supported by the represented object)
|
74
|
+
def as_strings;raise MismatchException, "String";end
|
75
|
+
# returns the contents as an array of integers (if supported by the represented object) */
|
76
|
+
|
77
|
+
def as_integers; raise MismatchException, "int";end;
|
78
|
+
# returns the contents as an array of doubles (if supported by the represented object) */
|
79
|
+
def as_doubles; raise MismatchException,"double";end;
|
80
|
+
# returns the contents as an array of bytes (if supported by the represented object) */
|
81
|
+
def as_bytes; raise MismatchException , "byte";end;
|
82
|
+
# returns the contents as a (named) list (if supported by the represented object) */
|
83
|
+
def as_list; raise MismatchException,"list";end;
|
84
|
+
# returns the contents as a factor (if supported by the represented object) */
|
85
|
+
def as_factor; raise MismatchException,"factor";end;
|
86
|
+
|
87
|
+
# 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 {@link #dim} for retrieving matrix and multidimentional-array dimensions).
|
88
|
+
# * @return length (number of elements) in a vector object
|
89
|
+
# * @throws MismatchException if this is not a vector object */
|
90
|
+
def length()
|
91
|
+
raise MismatchException, "vector";
|
92
|
+
end
|
93
|
+
|
94
|
+
# 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
|
95
|
+
# * @return 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
|
96
|
+
# * @throws MismatchException if this is not a vector object */
|
97
|
+
def na?
|
98
|
+
raise MismatchException, "vector"
|
99
|
+
end
|
100
|
+
|
101
|
+
# :section: convenience accessor methods
|
102
|
+
# convenience method corresponding to <code>as_integer()[0]</code>
|
103
|
+
# @return first entry returned by {@link #as_integer} */
|
104
|
+
def as_integer
|
105
|
+
as_integers[0]
|
106
|
+
end
|
107
|
+
# convenience method corresponding to <code>asDoubles()[0]</code>
|
108
|
+
# @return first entry returned by {@link #asDoubles} */
|
109
|
+
def as_double
|
110
|
+
as_doubles[0]
|
111
|
+
end
|
112
|
+
# convenience method corresponding to <code>asStrings()[0]</code>
|
113
|
+
# @return first entry returned by {@link #asStrings} */
|
114
|
+
def as_string
|
115
|
+
as_strings[0]
|
116
|
+
end
|
117
|
+
# // methods common to all REXPs
|
118
|
+
|
119
|
+
# retrieve an attribute of the given name from this object
|
120
|
+
# * @param name attribute name
|
121
|
+
# * @return attribute value or <code>null</code> if the attribute does not exist */
|
122
|
+
|
123
|
+
def get_attribute(name)
|
124
|
+
nil if @attr.nil? or !@attr.is_list?
|
125
|
+
@attr.as_list[name]
|
126
|
+
end
|
127
|
+
|
128
|
+
# checks whether this obejct has a given attribute
|
129
|
+
# * @param name attribute name
|
130
|
+
# * @return <code>true</code> if the attribute exists, <code>false</code> otherwise */
|
131
|
+
def has_attribute? (name)
|
132
|
+
return (!@attr.nil? and @attr.is_list and !@attr.as_list[name].nil?);
|
133
|
+
end
|
134
|
+
|
135
|
+
|
136
|
+
# :section: helper methods common to all REXPs
|
137
|
+
|
138
|
+
# returns dimensions of the object (as determined by the "<code>dim</code>" attribute)
|
139
|
+
# @return an array of integers with corresponding dimensions or <code>null</code> if the object has no dimension attribute */
|
140
|
+
def dim
|
141
|
+
begin
|
142
|
+
return has_attribute?("dim") ? @attr.as_list['dim'].as_integers : nil;
|
143
|
+
rescue MismatchException
|
144
|
+
# nothing to do
|
145
|
+
end
|
146
|
+
nil
|
147
|
+
end
|
148
|
+
|
149
|
+
# 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)
|
150
|
+
# @param klass class name
|
151
|
+
# @return <code>true</code> if this object is of the class <code>klass</code>, <code>false</code> otherwise */
|
152
|
+
def inherits?(klass)
|
153
|
+
return false if (!has_attribute? "class")
|
154
|
+
begin
|
155
|
+
c = get_attribute("class").as_strings;
|
156
|
+
if (!c.nil?)
|
157
|
+
return c.any? {|v| v.equals klass}
|
158
|
+
end
|
159
|
+
rescue MismatchException
|
160
|
+
end
|
161
|
+
return false;
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
|
166
|
+
# returns a string description of the object
|
167
|
+
# @return string describing the object - it can be of an arbitrary form and used only for debugging (do not confuse with {@link #asString()} for accessing string REXPs) */
|
168
|
+
#def to_s
|
169
|
+
#return super+((!@attr.nil?) ? "+" : "");
|
170
|
+
# end
|
171
|
+
|
172
|
+
# returns representation that it useful for debugging (e.g. it includes attributes and may include vector values -- see {@link #maxDebugItems})
|
173
|
+
# @return extended description of the obejct -- it may include vector values
|
174
|
+
#def inspect {
|
175
|
+
# (!@attr.nil?) ? (("<"+@attr.inspect()+">")+to_s()) : to_s;
|
176
|
+
#}
|
177
|
+
|
178
|
+
#//======= complex convenience methods
|
179
|
+
# 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
|
180
|
+
# a ruby dfeault library matrix.
|
181
|
+
# Matrix(c.eval("matrix(c(1,2,3,4,5,6),2,3)").asDoubleMatrix());</code>
|
182
|
+
# @return 2D array of doubles in the form double[rows][cols] or <code>null</code> if the contents is no 2-dimensional matrix of doubles */
|
183
|
+
def as_double_matrix()
|
184
|
+
ct = as_doubles()
|
185
|
+
dim =get_attribute "dim"
|
186
|
+
raise MismatchException, "matrix (dim attribute missing)" if dim.nil?
|
187
|
+
ds = dim.as_integers
|
188
|
+
raise MismatchException, "matrix (wrong dimensionality)" if (ds.length!=2)
|
189
|
+
m = ds[0], n = ds[1]
|
190
|
+
# R stores matrices as matrix(c(1,2,3,4),2,2) = col1:(1,2), col2:(3,4)
|
191
|
+
# we need to copy everything, since we create 2d array from 1d array
|
192
|
+
r=m.times.map {|i| n.times.map {|j| ct[j*n+i]}}
|
193
|
+
end
|
194
|
+
def to_s
|
195
|
+
(@attr.nil? ? "" : "+")
|
196
|
+
end
|
197
|
+
def to_debug_string
|
198
|
+
(@attr.nil? ? "" : "<"+@attr.to_debug_string+">")
|
199
|
+
end
|
200
|
+
|
201
|
+
# :section: tools
|
202
|
+
|
203
|
+
# creates a data frame object from a list object using integer row names
|
204
|
+
# * @param l a (named) list of vectors ({@link REXPVector} subclasses), each element corresponds to a column and all elements must have the same length
|
205
|
+
# * @return a data frame object
|
206
|
+
# * @throws MismatchException if the list is empty or any of the elements is not a vector */
|
207
|
+
def create_data_frame(l)
|
208
|
+
raise(MismatchException, "data frame (must have dim>0)") if l.nil? or l.size<1
|
209
|
+
raise MismatchException, "data frame (contents must be vectors)" if (!(l[0].is_a? REXP::Vector))
|
210
|
+
fe = l[0]
|
211
|
+
return REXP::GenericVector.new(l,
|
212
|
+
REXP::List.new(
|
213
|
+
RList.new(
|
214
|
+
[
|
215
|
+
REXP::String.new("data.frame"),
|
216
|
+
REXP::String.new(l.keys()),
|
217
|
+
REXP::Integer.new([REXP::Integer.NA, -fe.length()])
|
218
|
+
],
|
219
|
+
["class", "names", "row.names" ])
|
220
|
+
)
|
221
|
+
)
|
222
|
+
end
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
require 'rserve/rexp/vector'
|
227
|
+
require 'rserve/rexp/genericvector'
|
228
|
+
require 'rserve/rexp/integer'
|
229
|
+
require 'rserve/rexp/double'
|
230
|
+
require 'rserve/rexp/list'
|
231
|
+
require 'rserve/rexp/logical'
|
232
|
+
require 'rserve/rexp/string'
|
233
|
+
require 'rserve/rexp/symbol'
|
234
|
+
|