rserve-client 0.1.6 → 0.1.7
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +0 -0
- data/Examples.txt +48 -0
- data/History.txt +8 -0
- data/Manifest.txt +6 -0
- data/Rakefile +1 -0
- data/examples/hello_world.rb +8 -0
- data/examples/lowless.rb +10 -0
- data/lib/rserve.rb +6 -1
- data/lib/rserve/protocol/rexpfactory.rb +3 -4
- data/lib/rserve/rexp.rb +38 -35
- data/lib/rserve/rlist.rb +31 -126
- data/lib/rserve/withattributes.rb +5 -0
- data/lib/rserve/withnames.rb +109 -0
- data/spec/rserve_rlist_spec.rb +8 -8
- data/spec/rserve_withnames_spec.rb +73 -0
- metadata +11 -3
- metadata.gz.sig +0 -0
data.tar.gz.sig
CHANGED
Binary file
|
data/Examples.txt
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= Examples for Rserve
|
2
|
+
|
3
|
+
<em>Based on original Java version [http://www.rforge.net/Rserve/example.html]</em>
|
4
|
+
|
5
|
+
Rserve itself is provided as a regular R package and can be installed as such. The actual use is not performed by the library command, but by starting the Rserve executable (Windows) or typing R CMD Rserve on the command line (all others). By default Rserve runs in local mode with no enforced authentication. Once the Rserve is running any applications can use its services.
|
6
|
+
|
7
|
+
We will show examples using the Ruby client for Rserve. The principles are identical when using other Rserve clients. Before plunging into real examples, let us consider the minimal ``hello world'' example:
|
8
|
+
|
9
|
+
require 'rserve'
|
10
|
+
include Rserve
|
11
|
+
c = Connection.new
|
12
|
+
x = c.eval("R.version.string");
|
13
|
+
puts x.as_string
|
14
|
+
|
15
|
+
The code has the same effect as typing R.version.string in R. In the first line a connection to the local Rserve is established. Then the R command is evaluated and the result stored in a special object of the class REXP. This class encapsulates any objects received or sent to Rserve. If the type of the returned objects is known in advance, accessor methods can be called to obtain the Ruby object corresponding to the R value, in our case a regular String. Finally this string is printed on the standard output.
|
16
|
+
|
17
|
+
The following code fragment illustrates the use of slightly more complex native Ruby types:
|
18
|
+
|
19
|
+
d = c.eval("rnorm(100)").as_doubles
|
20
|
+
|
21
|
+
|
22
|
+
The single line in Ruby provides an array of 100 doubles representing random numbers from the standard normal distribution. The numeric vector in R is automatically converted into an array of floats. In cases where no native Ruby type exists, Rserve Ruby client defines its own classes such as Rlist or Logical (Ruby's boolean type has no support for NA missing values, therefore it cannot be used to directly represent logical type in R). This approach makes the use of Rserve very easy. As a first more practical example we want to calculate a Lowess smoother through a given set of points. The Ruby application lets the user specify the data allowing interactive changes of the points, displays a regular scatter plot and needs coordinates of the smoother to be obtained from R. One way of obtaining such a result would be to construct a long string command of the form lowes(c(0.2,0.4,...), c(2.5,4.8,...)) and using the eval method to obtain the result. This is somewhat clumsy, because the points usually already exist in an array in the Ruby application and the command string must be constructed from these. An alternative involves constructing objects in R directly. The following code shows the full Lowess example:
|
23
|
+
|
24
|
+
require 'rserve'
|
25
|
+
|
26
|
+
data_x=Rserve::REXP::Wrapper.wrap(10.times.map{|i| rand(i)})
|
27
|
+
data_y=Rserve::REXP::Wrapper.wrap(10.times.map{|i| rand(i)})
|
28
|
+
c = Rserve::Connection.new();
|
29
|
+
c.assign("x", data_x);
|
30
|
+
c.assign("y", data_y);
|
31
|
+
l = c.eval("lowess(x,y)").as_list
|
32
|
+
lx = l.at("x").as_floats
|
33
|
+
ly = l.at("y").as_floats
|
34
|
+
|
35
|
+
First the Ruby application defines the arrays for the data points data_x and data_y. The application is responsible for filling these arrays with the desired content (in this case, random data). Then we assign the contents of these arrays to R variables x and y. The assign command transfers the contents in binary form to Rserve and assigns this content to the specified symbol. This is far more efficient than constructing a string representation of the content.
|
36
|
+
|
37
|
+
Once the variables are set in R we are ready to use the lowess function. It returns a list consisting of two vectors x and y which contain the smoother points. The Rlist object provides the method at for extraction of named entries of a list. Since lists may contain entries of different types, the object returned by the at method is of the class REXP whose content can be cast into floats in our case. The result can now be used by the Ruby application.
|
38
|
+
|
39
|
+
More complex computations can be performed even without transmission of resulting objects. This is useful when defining functions or constructing complex models. Model objects are usually large, because they contain original data points, residuals and other meta data. Although they can be transferred to the client, it is more efficient to retain such objects in R and extract relevant information only. This can be done by using the void_eval method which does not transfer the result of the evaluation back to the client:
|
40
|
+
|
41
|
+
c.assign(y, ...) ...
|
42
|
+
c.void_eval("m<-lm(y~a+b+c)");
|
43
|
+
coeff = c.eval("coefficients(m)").as_floats
|
44
|
+
|
45
|
+
In the above example a linear model is fitted, but its content is not passed back to the client. It is stored in an object in R for later use. Finally the coefficients are extracted from the model and passed back to the Ruby application.
|
46
|
+
|
47
|
+
So far we used Rserve in local mode only. Extension to remote Rserve connections is possible without code changes, except for additional parameters to the Rserve::Connection constructor, specifying the remote computer running the \Rs. For details about the use of remote authentication, error handling and file transfer, consult the source code documentation.
|
48
|
+
|
data/History.txt
CHANGED
@@ -1,3 +1,11 @@
|
|
1
|
+
=== 0.1.7 / 2010-05-28
|
2
|
+
|
3
|
+
* Reimplement Rlist as an Array with module WithNames included
|
4
|
+
* Added modules WithAttributes and WithNames
|
5
|
+
* Added examples of use
|
6
|
+
|
7
|
+
|
8
|
+
|
1
9
|
=== 0.1.6 / 2010-05-27
|
2
10
|
* Assign complete for all commons REXPs
|
3
11
|
* Added Connection#shutdown
|
data/Manifest.txt
CHANGED
@@ -1,9 +1,12 @@
|
|
1
1
|
.autotest
|
2
2
|
.gitignore
|
3
|
+
Examples.txt
|
3
4
|
History.txt
|
4
5
|
Manifest.txt
|
5
6
|
README.txt
|
6
7
|
Rakefile
|
8
|
+
examples/hello_world.rb
|
9
|
+
examples/lowless.rb
|
7
10
|
lib/rserve.rb
|
8
11
|
lib/rserve/connection.rb
|
9
12
|
lib/rserve/engine.rb
|
@@ -32,6 +35,8 @@ lib/rserve/rexp/wrapper.rb
|
|
32
35
|
lib/rserve/rfactor.rb
|
33
36
|
lib/rserve/rlist.rb
|
34
37
|
lib/rserve/talk.rb
|
38
|
+
lib/rserve/withattributes.rb
|
39
|
+
lib/rserve/withnames.rb
|
35
40
|
spec/rserve_connection_spec.rb
|
36
41
|
spec/rserve_double_spec.rb
|
37
42
|
spec/rserve_integer_spec.rb
|
@@ -45,5 +50,6 @@ spec/rserve_rfactor_spec.rb
|
|
45
50
|
spec/rserve_rlist_spec.rb
|
46
51
|
spec/rserve_spec.rb
|
47
52
|
spec/rserve_talk_spec.rb
|
53
|
+
spec/rserve_withnames_spec.rb
|
48
54
|
spec/spec.opts
|
49
55
|
spec/spec_helper.rb
|
data/Rakefile
CHANGED
@@ -9,6 +9,7 @@ Hoe.spec 'rserve-client' do
|
|
9
9
|
self.test_globs="spec/*_spec.rb"
|
10
10
|
self.version=Rserve::VERSION
|
11
11
|
self.rubyforge_name = 'ruby-statsample' # if different than 'rserve'
|
12
|
+
self.remote_rdoc_dir = "rserve-client"
|
12
13
|
self.developer('Claudio Bustos', 'clbustos_AT_gmail.com')
|
13
14
|
end
|
14
15
|
|
data/examples/lowless.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'rserve'
|
2
|
+
|
3
|
+
data_x=Rserve::REXP::Wrapper.wrap(10.times.map{|i| rand(i)})
|
4
|
+
data_y=Rserve::REXP::Wrapper.wrap(10.times.map{|i| rand(i)})
|
5
|
+
c = Rserve::Connection.new();
|
6
|
+
c.assign("x", data_x);
|
7
|
+
c.assign("y", data_y);
|
8
|
+
l = c.eval("lowess(x,y)").as_list
|
9
|
+
lx = l.at("x").as_floats
|
10
|
+
ly = l.at("y").as_floats
|
data/lib/rserve.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
1
|
require 'socket'
|
2
2
|
|
3
3
|
module Rserve
|
4
|
-
VERSION = '0.1.
|
4
|
+
VERSION = '0.1.7'
|
5
5
|
end
|
6
6
|
|
7
7
|
|
8
|
+
require 'rserve/withnames'
|
9
|
+
require 'rserve/withattributes'
|
10
|
+
|
11
|
+
|
8
12
|
require 'rserve/protocol'
|
9
13
|
require 'rserve/packet'
|
10
14
|
require 'rserve/talk'
|
@@ -14,3 +18,4 @@ require 'rserve/connection'
|
|
14
18
|
require 'rserve/rlist'
|
15
19
|
require 'rserve/rfactor'
|
16
20
|
|
21
|
+
|
@@ -236,8 +236,8 @@ module Rserve
|
|
236
236
|
|
237
237
|
# hack for factors
|
238
238
|
if (!get_attr.nil?)
|
239
|
-
ca = get_attr().as_list
|
240
|
-
ls = get_attr().as_list
|
239
|
+
ca = get_attr().as_list["class"]
|
240
|
+
ls = get_attr().as_list["levels"]
|
241
241
|
if (!ca.nil? and !ls.nil? and ca.as_string=="factor")
|
242
242
|
# R uses 1-based index, Java (and Ruby) uses 0-based one
|
243
243
|
@cont = REXP::Factor.new(d, ls.as_strings(), get_attr)
|
@@ -275,8 +275,7 @@ module Rserve
|
|
275
275
|
name=nf.cont.as_string if(nf.cont.symbol? or nf.cont.string?)
|
276
276
|
end
|
277
277
|
if name.nil?
|
278
|
-
|
279
|
-
l.add(lc.cont)
|
278
|
+
l.push(lc.cont)
|
280
279
|
else
|
281
280
|
l.put(name,lc.cont)
|
282
281
|
end
|
data/lib/rserve/rexp.rb
CHANGED
@@ -81,7 +81,9 @@ module Rserve
|
|
81
81
|
def as_doubles; raise MismatchException,"double";end;
|
82
82
|
|
83
83
|
# On Ruby, Float are stored in double precision
|
84
|
-
|
84
|
+
def as_floats
|
85
|
+
as_doubles
|
86
|
+
end
|
85
87
|
|
86
88
|
# returns the contents as an array of bytes (if supported by the represented object)
|
87
89
|
def as_bytes; raise MismatchException , "byte";end;
|
@@ -115,8 +117,9 @@ module Rserve
|
|
115
117
|
def as_double
|
116
118
|
as_doubles[0]
|
117
119
|
end
|
118
|
-
|
119
|
-
|
120
|
+
def as_float
|
121
|
+
as_double
|
122
|
+
end
|
120
123
|
# convenience method corresponding to <code>asStrings()[0]</code>
|
121
124
|
# @return first entry returned by {@link #asStrings}
|
122
125
|
def as_string
|
@@ -147,8 +150,8 @@ module Rserve
|
|
147
150
|
# @return an array of integers with corresponding dimensions or <code>null</code> if the object has no dimension attribute
|
148
151
|
def dim
|
149
152
|
begin
|
150
|
-
|
151
|
-
|
153
|
+
return has_attribute?("dim") ? @attr.as_list['dim'].as_integers : nil;
|
154
|
+
rescue MismatchException
|
152
155
|
# nothing to do
|
153
156
|
end
|
154
157
|
nil
|
@@ -158,7 +161,7 @@ module Rserve
|
|
158
161
|
# @param klass class name
|
159
162
|
# @return <code>true</code> if this object is of the class <code>klass</code>, <code>false</code> otherwise
|
160
163
|
def inherits?(klass)
|
161
|
-
|
164
|
+
return false if (!has_attribute? "class")
|
162
165
|
begin
|
163
166
|
c = get_attribute("class").as_strings;
|
164
167
|
if (!c.nil?)
|
@@ -227,35 +230,35 @@ module Rserve
|
|
227
230
|
def to_ruby
|
228
231
|
raise "You should implement this!"
|
229
232
|
end
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
require 'rserve/rexp/environment'
|
235
|
-
require 'rserve/rexp/null'
|
236
|
-
require 'rserve/rexp/unknown'
|
237
|
-
|
238
|
-
|
239
|
-
require 'rserve/rexp/vector'
|
240
|
-
|
241
|
-
require 'rserve/rexp/raw'
|
242
|
-
require 'rserve/rexp/symbol'
|
243
|
-
require 'rserve/rexp/string'
|
244
|
-
require 'rserve/rexp/double'
|
245
|
-
require 'rserve/rexp/integer'
|
246
|
-
require 'rserve/rexp/logical'
|
247
|
-
|
248
|
-
require 'rserve/rexp/factor'
|
233
|
+
end
|
234
|
+
end
|
249
235
|
|
250
|
-
require 'rserve/rexp/genericvector'
|
251
|
-
require 'rserve/rexp/expressionvector'
|
252
236
|
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
237
|
+
require 'rserve/rexp/environment'
|
238
|
+
require 'rserve/rexp/null'
|
239
|
+
require 'rserve/rexp/unknown'
|
240
|
+
|
241
|
+
|
242
|
+
require 'rserve/rexp/vector'
|
243
|
+
|
244
|
+
require 'rserve/rexp/raw'
|
245
|
+
require 'rserve/rexp/symbol'
|
246
|
+
require 'rserve/rexp/string'
|
247
|
+
require 'rserve/rexp/double'
|
248
|
+
require 'rserve/rexp/integer'
|
249
|
+
require 'rserve/rexp/logical'
|
250
|
+
|
251
|
+
require 'rserve/rexp/factor'
|
252
|
+
|
253
|
+
require 'rserve/rexp/genericvector'
|
254
|
+
require 'rserve/rexp/expressionvector'
|
255
|
+
|
256
|
+
|
257
|
+
require 'rserve/rexp/list'
|
258
|
+
require 'rserve/rexp/language'
|
259
|
+
require 'rserve/rexp/s4'
|
260
|
+
|
261
|
+
require 'rserve/rexp/reference'
|
262
|
+
|
263
|
+
require 'rserve/rexp/wrapper'
|
261
264
|
|
data/lib/rserve/rlist.rb
CHANGED
@@ -1,150 +1,55 @@
|
|
1
1
|
module Rserve
|
2
|
-
class Rlist
|
3
|
-
include
|
4
|
-
attr_reader :names
|
2
|
+
class Rlist < Array
|
3
|
+
include WithNames
|
5
4
|
attr_reader :data
|
6
|
-
def initialize(data=nil,n=nil)
|
5
|
+
def initialize(data=nil, n=nil)
|
7
6
|
@names=nil
|
8
|
-
|
9
|
-
|
10
|
-
@data=case data
|
11
|
-
when Array
|
12
|
-
data
|
13
|
-
when Numeric
|
14
|
-
Array.new(data)
|
7
|
+
if data.nil?
|
8
|
+
super()
|
15
9
|
else
|
16
|
-
|
10
|
+
case data
|
11
|
+
when Array
|
12
|
+
super(data)
|
13
|
+
when Numeric
|
14
|
+
super([data])
|
15
|
+
else
|
16
|
+
raise ArgumentError
|
17
|
+
end
|
17
18
|
end
|
18
|
-
|
19
|
+
|
19
20
|
if n
|
20
|
-
@names=Array.new(
|
21
|
+
@names=Array.new(size)
|
21
22
|
n.each_index {|i| @names[i]=n[i]} if n.respond_to? :each_index
|
22
23
|
end
|
23
24
|
end
|
24
|
-
def named?
|
25
|
-
!@names.nil?
|
26
|
-
end
|
27
|
-
def ==(o)
|
28
|
-
#p "Comparing #{self.inspect} with #{o.inspect} gives #{o.is_a? Rlist and self.data==o.data and self.names==o.names}"
|
29
|
-
o.is_a? Rlist and self.data==o.data and self.names==o.names
|
30
|
-
end
|
31
|
-
# Return element with name x or 0-index x
|
32
|
-
def [](v)
|
33
|
-
if v.is_a? String
|
34
|
-
return nil if @names.nil? or v==""
|
35
|
-
i=@names.index(v)
|
36
|
-
return i.nil? ? nil : @data[i]
|
37
|
-
elsif v.is_a? Integer
|
38
|
-
return @data[v]
|
39
|
-
else
|
40
|
-
raise ArgumentError,"Should be String or Integer"
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def at(v)
|
45
|
-
self.[](v)
|
46
|
-
end
|
47
|
-
|
48
|
-
def key_at(v)
|
49
|
-
return nil if @names.nil?
|
50
|
-
@names[v]
|
51
|
-
end
|
52
|
-
def size
|
53
|
-
@data.size
|
54
|
-
end
|
55
|
-
|
56
|
-
def each
|
57
|
-
@data.each do |v|
|
58
|
-
yield v
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
def set_key_at(i,value)
|
63
|
-
if @names.nil?
|
64
|
-
@names=Array.new
|
65
|
-
end
|
66
|
-
if @names.size<size
|
67
|
-
(size-@names.size).times {@names.push(nil)}
|
68
|
-
end
|
69
|
-
|
70
|
-
@names[i]=value if i < size
|
71
|
-
|
72
|
-
end
|
73
|
-
|
74
25
|
def keys
|
75
26
|
@names
|
76
27
|
end
|
77
|
-
|
78
|
-
def
|
79
|
-
|
80
|
-
if key.nil?
|
81
|
-
add(value)
|
82
|
-
return nil
|
83
|
-
end
|
84
|
-
if !@names.nil?
|
85
|
-
p=names.index(key)
|
86
|
-
if !p.nil?
|
87
|
-
return @names[p]=value
|
88
|
-
end
|
89
|
-
end
|
90
|
-
puts "add key and value" if $DEBUG
|
91
|
-
i=size
|
92
|
-
@names=Array.new(i) if(@names.nil?)
|
93
|
-
@data.push(value)
|
94
|
-
@names.push(key)
|
95
|
-
|
96
|
-
end
|
97
|
-
def add(a,b=nil)
|
98
|
-
if b.nil?
|
99
|
-
@data.push(a)
|
100
|
-
@names=Array.new(@data.size-1) if @names.nil?
|
101
|
-
@names.push(nil)
|
102
|
-
else
|
103
|
-
@data.insert(a,b)
|
104
|
-
@names.insert(a,nil)
|
105
|
-
end
|
106
|
-
end
|
107
|
-
def clear
|
108
|
-
@data.clear
|
109
|
-
@names=nil
|
28
|
+
# Returns the data without names, as Ruby objects
|
29
|
+
def to_a
|
30
|
+
self.map {|d| d.to_ruby}
|
110
31
|
end
|
111
|
-
|
112
|
-
|
32
|
+
# Returns the data, as REXP
|
33
|
+
def data
|
34
|
+
self.map {|d| d}
|
113
35
|
end
|
114
|
-
def
|
115
|
-
|
116
|
-
|
117
|
-
elsif elem.is_a? Integer
|
118
|
-
i=elem
|
119
|
-
end
|
120
|
-
return false if i.nil?
|
121
|
-
@data.delete_at(i)
|
122
|
-
@names.delete_at(i) unless @names.nil?
|
123
|
-
@names=nil if size==0
|
124
|
-
end
|
125
|
-
# Returns data with appropiate ruby representation
|
126
|
-
def to_a
|
127
|
-
@data.map {|d|
|
128
|
-
d.to_ruby
|
129
|
-
}
|
36
|
+
def ==(o)
|
37
|
+
#p "Comparing #{self.inspect} with #{o.inspect} gives #{o.is_a? Rlist and self.data==o.data and self.names==o.names}"
|
38
|
+
o.is_a? Rlist and self.data==o.data and self.names==o.names
|
130
39
|
end
|
131
|
-
|
40
|
+
|
41
|
+
|
42
|
+
# Returns an Array with module WithNames included
|
132
43
|
# * Unnamed list: returns an Array
|
133
44
|
# * Named List: returns a Hash. Every element without explicit name receive
|
134
45
|
# as key the number of element, 1-based
|
135
46
|
#
|
136
47
|
|
137
48
|
def to_ruby
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
names.each_with_index {|name,i|
|
143
|
-
key= (name=="" or name.nil?) ? i+1 : name
|
144
|
-
h[key]=@data[i].to_ruby
|
145
|
-
}
|
146
|
-
h
|
147
|
-
end
|
49
|
+
data=to_a
|
50
|
+
data.extend WithNames
|
51
|
+
data.names=@names
|
52
|
+
data
|
148
53
|
end
|
149
54
|
end
|
150
55
|
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module Rserve
|
2
|
+
# Provides names to elements on an Array
|
3
|
+
module WithNames
|
4
|
+
attr_reader :names
|
5
|
+
def names=(v)
|
6
|
+
raise ArgumentError, "#size should be equal to object size" if !v.nil? and v.size!=self.size
|
7
|
+
raise ArgumentError, "element must be String or nil" unless v.nil? or v.all? {|v1| v1.nil? or v1.is_a? String}
|
8
|
+
@names=v
|
9
|
+
end
|
10
|
+
def push(v,name=nil)
|
11
|
+
@names||=Array.new(self.size)
|
12
|
+
(@names.size-self.size).times { @names.push(nil)}
|
13
|
+
@names.push(name)
|
14
|
+
super(v)
|
15
|
+
end
|
16
|
+
def inspect
|
17
|
+
"#<#{self.class}:#{self.object_id} #{super} names:#{@names.inspect}>"
|
18
|
+
end
|
19
|
+
def clear
|
20
|
+
@names=nil
|
21
|
+
super()
|
22
|
+
end
|
23
|
+
def delete_at(i)
|
24
|
+
unless @names.nil?
|
25
|
+
@names.delete_at(i)
|
26
|
+
end
|
27
|
+
super(i)
|
28
|
+
end
|
29
|
+
def pop
|
30
|
+
unless @names.nil?
|
31
|
+
@names.pop
|
32
|
+
end
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
def reverse!
|
37
|
+
unless @names.nil?
|
38
|
+
@names.reverse!
|
39
|
+
end
|
40
|
+
super
|
41
|
+
end
|
42
|
+
def shift
|
43
|
+
unless @names.nil?
|
44
|
+
@names.shift
|
45
|
+
end
|
46
|
+
super
|
47
|
+
end
|
48
|
+
def slice(*args)
|
49
|
+
sliced=super(*args)
|
50
|
+
unless @names.nil?
|
51
|
+
sliced.extend Rserve::WithNames
|
52
|
+
sliced.names=@names.slice(*args)
|
53
|
+
end
|
54
|
+
sliced
|
55
|
+
end
|
56
|
+
def named?
|
57
|
+
!@names.nil?
|
58
|
+
end
|
59
|
+
def to_a
|
60
|
+
Array.new(self)
|
61
|
+
end
|
62
|
+
def key_at(v)
|
63
|
+
@names.nil? ? nil : @names[v]
|
64
|
+
end
|
65
|
+
# Put a value on specific key
|
66
|
+
# If key exists, replaces element of apropiate index
|
67
|
+
# If key doesn't exists, works as push(value,key)
|
68
|
+
def put(key,value)
|
69
|
+
if key.nil?
|
70
|
+
add(value)
|
71
|
+
return nil
|
72
|
+
end
|
73
|
+
|
74
|
+
if !@names.nil?
|
75
|
+
pos=@names.index(key)
|
76
|
+
if !pos.nil?
|
77
|
+
return @names[pos]=value
|
78
|
+
end
|
79
|
+
end
|
80
|
+
push(value,key)
|
81
|
+
end
|
82
|
+
def __add(a,b=nil)
|
83
|
+
if b.nil?
|
84
|
+
@data.push(a)
|
85
|
+
@names=Array.new(@data.size-1) if @names.nil?
|
86
|
+
@names.push(nil)
|
87
|
+
else
|
88
|
+
@data.insert(a,b)
|
89
|
+
@names.insert(a,nil)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
def [](v)
|
93
|
+
case v
|
94
|
+
when Integer
|
95
|
+
at(v)
|
96
|
+
when Array
|
97
|
+
raise "You must use something like v[[1]]" if v.size!=1 or !v[0].is_a? Integer
|
98
|
+
at(v[0]-1)
|
99
|
+
when String
|
100
|
+
if !@names.nil?
|
101
|
+
i=@names.index(v)
|
102
|
+
i.nil? ? nil : at(i)
|
103
|
+
else
|
104
|
+
nil
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
data/spec/rserve_rlist_spec.rb
CHANGED
@@ -32,21 +32,21 @@ describe Rserve::Rlist do
|
|
32
32
|
it "method to_a return an array with best ruby representation of data" do
|
33
33
|
@l.to_a.should==['Fred',30,10,20,[1,2,3]]
|
34
34
|
end
|
35
|
-
it "method to_ruby returns a
|
35
|
+
it "method to_ruby returns a named array when all names are set" do
|
36
36
|
list=@r.eval("list(name='Fred', age=30)")
|
37
|
-
|
37
|
+
a=['Fred',30]
|
38
|
+
a.extend Rserve::WithNames
|
39
|
+
a.names=['name','age']
|
40
|
+
list.to_ruby.should==a
|
38
41
|
end
|
39
|
-
it "method to_ruby returns a
|
40
|
-
list=@r.eval("list(name='Fred', age=30,'aaaa')")
|
41
|
-
list.to_ruby.should=={'name'=>'Fred','age'=>30,3=>'aaaa'}
|
42
|
-
end
|
43
|
-
it "method to_ruby returns an array when no names are set" do
|
42
|
+
it "method to_ruby returns a simple array when no names are set" do
|
44
43
|
list=@r.eval("list(10,20,30)")
|
45
44
|
list.to_ruby.should==[10,20,30]
|
46
45
|
end
|
47
46
|
it "should allow recursive list" do
|
48
47
|
list=@r.eval("list(l1=list(l11=1,l22=2),l2=list(3,4))").as_list
|
49
|
-
list
|
48
|
+
list.names.should==['l1','l2']
|
49
|
+
list['l1'].to_ruby.should==[1,2]
|
50
50
|
list['l2'].to_ruby.should==[3,4]
|
51
51
|
|
52
52
|
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
require File.dirname(__FILE__)+"/spec_helper.rb"
|
2
|
+
|
3
|
+
describe Rserve::WithNames do
|
4
|
+
before do
|
5
|
+
@a=[1,2,3,4]
|
6
|
+
@a.extend Rserve::WithNames
|
7
|
+
end
|
8
|
+
it "should return nil without names" do
|
9
|
+
@a.names.should be_nil
|
10
|
+
end
|
11
|
+
describe "with incorrect naming" do
|
12
|
+
it "should raise an error with names array of another size" do
|
13
|
+
lambda {@a.names=["1","2"]}.should raise_exception
|
14
|
+
end
|
15
|
+
it "should raise an error with names array !(String or nil) " do
|
16
|
+
lambda {@a.names=[1,"a","b","c"]}.should raise_exception
|
17
|
+
lambda {@a.names=[nil,"a","b","c"]}.should_not raise_exception
|
18
|
+
end
|
19
|
+
end
|
20
|
+
describe "correct naming" do
|
21
|
+
before do
|
22
|
+
@a.names=['a','b','c',nil]
|
23
|
+
end
|
24
|
+
it "should set names and return them without problems" do
|
25
|
+
@a.names.should==['a','b','c',nil]
|
26
|
+
end
|
27
|
+
it "should return correct values with 0-index([x])" do
|
28
|
+
@a[0].should==1
|
29
|
+
@a[3].should==4
|
30
|
+
end
|
31
|
+
it "should return correct values with 1-index syntactic sugar ([[x]])" do
|
32
|
+
@a[[1]].should==1
|
33
|
+
@a[[4]].should==4
|
34
|
+
end
|
35
|
+
it "should return with names(['x'])" do
|
36
|
+
@a['a'].should==1
|
37
|
+
@a['b'].should==2
|
38
|
+
end
|
39
|
+
it "should push with or without name" do
|
40
|
+
@a.push(5)
|
41
|
+
@a.names.should==['a','b','c',nil,nil]
|
42
|
+
@a.push(6,'f')
|
43
|
+
@a.names.should==['a','b','c',nil,nil,'f']
|
44
|
+
end
|
45
|
+
it "method clear should delete names" do
|
46
|
+
@a.clear
|
47
|
+
@a.names.should be_nil
|
48
|
+
end
|
49
|
+
it "should delete_at names" do
|
50
|
+
@a.delete_at(0)
|
51
|
+
@a.should==[2,3,4]
|
52
|
+
@a.names.should==["b","c",nil]
|
53
|
+
end
|
54
|
+
it "should pop names" do
|
55
|
+
@a.pop
|
56
|
+
@a.names.should==['a','b','c']
|
57
|
+
end
|
58
|
+
it "should shift names" do
|
59
|
+
@a.shift
|
60
|
+
@a.names.should==['b','c',nil]
|
61
|
+
end
|
62
|
+
it "should reverse! names" do
|
63
|
+
@a.reverse!
|
64
|
+
@a.names.should==[nil,'c','b','a']
|
65
|
+
end
|
66
|
+
it "should slice names" do
|
67
|
+
b=@a.slice(1,2)
|
68
|
+
b.should==[2,3]
|
69
|
+
b.names.should==['b','c']
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
metadata
CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
segments:
|
6
6
|
- 0
|
7
7
|
- 1
|
8
|
-
-
|
9
|
-
version: 0.1.
|
8
|
+
- 7
|
9
|
+
version: 0.1.7
|
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-05-
|
38
|
+
date: 2010-05-28 00:00:00 -04:00
|
39
39
|
default_executable:
|
40
40
|
dependencies:
|
41
41
|
- !ruby/object:Gem::Dependency
|
@@ -77,16 +77,20 @@ executables: []
|
|
77
77
|
extensions: []
|
78
78
|
|
79
79
|
extra_rdoc_files:
|
80
|
+
- Examples.txt
|
80
81
|
- History.txt
|
81
82
|
- Manifest.txt
|
82
83
|
- README.txt
|
83
84
|
files:
|
84
85
|
- .autotest
|
85
86
|
- .gitignore
|
87
|
+
- Examples.txt
|
86
88
|
- History.txt
|
87
89
|
- Manifest.txt
|
88
90
|
- README.txt
|
89
91
|
- Rakefile
|
92
|
+
- examples/hello_world.rb
|
93
|
+
- examples/lowless.rb
|
90
94
|
- lib/rserve.rb
|
91
95
|
- lib/rserve/connection.rb
|
92
96
|
- lib/rserve/engine.rb
|
@@ -115,6 +119,8 @@ files:
|
|
115
119
|
- lib/rserve/rfactor.rb
|
116
120
|
- lib/rserve/rlist.rb
|
117
121
|
- lib/rserve/talk.rb
|
122
|
+
- lib/rserve/withattributes.rb
|
123
|
+
- lib/rserve/withnames.rb
|
118
124
|
- spec/rserve_connection_spec.rb
|
119
125
|
- spec/rserve_double_spec.rb
|
120
126
|
- spec/rserve_integer_spec.rb
|
@@ -128,6 +134,7 @@ files:
|
|
128
134
|
- spec/rserve_rlist_spec.rb
|
129
135
|
- spec/rserve_spec.rb
|
130
136
|
- spec/rserve_talk_spec.rb
|
137
|
+
- spec/rserve_withnames_spec.rb
|
131
138
|
- spec/spec.opts
|
132
139
|
- spec/spec_helper.rb
|
133
140
|
has_rdoc: true
|
@@ -167,6 +174,7 @@ test_files:
|
|
167
174
|
- spec/rserve_rfactor_spec.rb
|
168
175
|
- spec/rserve_connection_spec.rb
|
169
176
|
- spec/rserve_double_spec.rb
|
177
|
+
- spec/rserve_withnames_spec.rb
|
170
178
|
- spec/rserve_packet_spec.rb
|
171
179
|
- spec/rserve_rexpfactory_spec.rb
|
172
180
|
- spec/rserve_rexp_spec.rb
|
metadata.gz.sig
CHANGED
Binary file
|