rserve-client 0.1.5 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data.tar.gz.sig +1 -2
- data/.gitignore +1 -0
- data/History.txt +15 -2
- data/Manifest.txt +8 -0
- data/README.txt +41 -19
- data/lib/rserve.rb +1 -1
- data/lib/rserve/connection.rb +152 -69
- data/lib/rserve/engine.rb +9 -9
- data/lib/rserve/packet.rb +2 -2
- data/lib/rserve/protocol.rb +51 -46
- data/lib/rserve/protocol/rexpfactory.rb +659 -366
- data/lib/rserve/rexp.rb +175 -156
- data/lib/rserve/rexp/double.rb +45 -38
- data/lib/rserve/rexp/environment.rb +40 -0
- data/lib/rserve/rexp/expressionvector.rb +9 -0
- data/lib/rserve/rexp/genericvector.rb +5 -3
- data/lib/rserve/rexp/integer.rb +38 -38
- data/lib/rserve/rexp/language.rb +2 -2
- data/lib/rserve/rexp/list.rb +3 -0
- data/lib/rserve/rexp/logical.rb +17 -4
- data/lib/rserve/rexp/null.rb +20 -14
- data/lib/rserve/rexp/raw.rb +19 -0
- data/lib/rserve/rexp/reference.rb +42 -0
- data/lib/rserve/rexp/s4.rb +10 -0
- data/lib/rserve/rexp/string.rb +5 -3
- data/lib/rserve/rexp/symbol.rb +3 -0
- data/lib/rserve/rexp/vector.rb +30 -15
- data/lib/rserve/rexp/wrapper.rb +58 -0
- data/lib/rserve/rfactor.rb +10 -10
- data/lib/rserve/rlist.rb +129 -100
- data/lib/rserve/talk.rb +61 -61
- data/spec/rserve_connection_spec.rb +99 -33
- data/spec/rserve_double_spec.rb +28 -15
- data/spec/rserve_integer_spec.rb +24 -15
- data/spec/rserve_logical_spec.rb +21 -12
- data/spec/rserve_protocol_spec.rb +7 -7
- data/spec/rserve_rexp_spec.rb +3 -3
- data/spec/rserve_rexp_wrapper_spec.rb +36 -0
- data/spec/rserve_rexpfactory_spec.rb +86 -20
- data/spec/rserve_rfactor_spec.rb +2 -2
- data/spec/rserve_rlist_spec.rb +53 -0
- data/spec/rserve_spec.rb +8 -5
- data/spec/rserve_talk_spec.rb +7 -7
- data/spec/spec_helper.rb +1 -0
- metadata +13 -3
- metadata.gz.sig +0 -0
@@ -0,0 +1,40 @@
|
|
1
|
+
module Rserve
|
2
|
+
class REXP
|
3
|
+
# REXPEnvironment represents an environment in R. Very much like {@link org.rosuda.REngine.REXPReference} this is a proxy object to the actual object on the R side. It provides methods for accessing the content of the environment. The actual implementation may vary by the back-end used and not all engines support environments. Check {@link org.rosuda.REngine.REngine.supportsEnvironments()} for the given engine. Environments are specific for a given engine, they cannot be passed across engines
|
4
|
+
class Environment < REXP
|
5
|
+
attr_reader :eng
|
6
|
+
attr_reader :handle
|
7
|
+
# create a new environemnt reference - this constructor should never be used directly, use {@link REngine.newEnvironment()} instead.
|
8
|
+
# * @param eng engine responsible for this environment
|
9
|
+
# * @param handle handle used by the engine to identify this environment
|
10
|
+
def initialize(e,h)
|
11
|
+
super();
|
12
|
+
@eng = e;
|
13
|
+
@handle = h;
|
14
|
+
end
|
15
|
+
def environment?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
19
|
+
# get a value from this environment
|
20
|
+
# * @param name name of the value
|
21
|
+
# * @param resolve if <code>false</code> returns a reference to the object, if <code>false</code> the reference is resolved
|
22
|
+
# * @return value corresponding to the symbol name or possibly <code>null</code> if the value is unbound (the latter is currently engine-specific)
|
23
|
+
def get(name, resolve=true)
|
24
|
+
@eng.get(name,self,resolve)
|
25
|
+
end
|
26
|
+
# assigns a value to a given symbol name
|
27
|
+
# @param name symbol name
|
28
|
+
# @param value value */
|
29
|
+
def assign(name, value)
|
30
|
+
@eng.assign(name, value, self)
|
31
|
+
end
|
32
|
+
def parent(resolve=true)
|
33
|
+
@eng.get_parent_environment(self,resolve)
|
34
|
+
end
|
35
|
+
def to_ruby
|
36
|
+
raise "No idea how to transform #{self.class}"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -2,14 +2,13 @@ module Rserve
|
|
2
2
|
class REXP
|
3
3
|
class GenericVector < REXP::Vector
|
4
4
|
attr_reader :payload
|
5
|
-
def initialize(list,attr=nil)
|
5
|
+
def initialize(list, attr=nil)
|
6
6
|
super(attr)
|
7
7
|
@payload=list.nil? ? Rlist.new() : list
|
8
|
-
|
9
8
|
if (payload.named?)
|
10
9
|
@attr = REXP::List.new(
|
11
10
|
Rlist.new([REXP::String.new(payload.keys())],
|
12
|
-
|
11
|
+
["names"]));
|
13
12
|
end
|
14
13
|
end
|
15
14
|
def length
|
@@ -24,6 +23,9 @@ module Rserve
|
|
24
23
|
def as_list
|
25
24
|
@payload
|
26
25
|
end
|
26
|
+
def to_ruby
|
27
|
+
@payload.to_ruby
|
28
|
+
end
|
27
29
|
end
|
28
30
|
end
|
29
31
|
end
|
data/lib/rserve/rexp/integer.rb
CHANGED
@@ -6,44 +6,44 @@ module Rserve
|
|
6
6
|
NA = -2147483648;
|
7
7
|
def initialize(data, attrs=nil)
|
8
8
|
@payload=case data
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
end
|
9
|
+
when Integer
|
10
|
+
[data]
|
11
|
+
when Numeric
|
12
|
+
[data.to_i]
|
13
|
+
when Array
|
14
|
+
data
|
15
|
+
else
|
16
|
+
raise ArgumentError, "Should be Numeric or Array"
|
17
|
+
end
|
18
|
+
super(attrs)
|
19
|
+
end
|
20
|
+
def length
|
21
|
+
payload.length
|
22
|
+
end
|
23
|
+
def integer?
|
24
|
+
true
|
25
|
+
end
|
26
|
+
def numeric?
|
27
|
+
true
|
28
|
+
end
|
29
|
+
def as_integers
|
30
|
+
@payload
|
31
|
+
end
|
32
|
+
def as_doubles
|
33
|
+
@payload.map(&:to_f)
|
34
|
+
end
|
35
|
+
def as_strings
|
36
|
+
@payload.map(&:to_s)
|
37
|
+
end
|
38
|
+
|
39
|
+
def na?(value=nil)
|
40
|
+
return value == NA unless value.nil?
|
41
|
+
@payload.map {|v| v==NA}
|
42
|
+
end
|
43
|
+
def to_debug_string
|
44
|
+
t=super
|
45
|
+
t << "{" << @payload.map(&:to_s).join(",") << "}"
|
47
46
|
end
|
48
47
|
end
|
49
48
|
end
|
49
|
+
end
|
data/lib/rserve/rexp/language.rb
CHANGED
data/lib/rserve/rexp/list.rb
CHANGED
data/lib/rserve/rexp/logical.rb
CHANGED
@@ -17,7 +17,7 @@ module Rserve
|
|
17
17
|
def initialize(l,attr=nil)
|
18
18
|
super(attr)
|
19
19
|
if l.is_a? Array
|
20
|
-
@payload= l
|
20
|
+
@payload= l
|
21
21
|
else
|
22
22
|
@payload = [ l==NA ? NA : (l==1 ? TRUE : FALSE) ]
|
23
23
|
end
|
@@ -31,14 +31,27 @@ module Rserve
|
|
31
31
|
def as_bytes
|
32
32
|
@payload
|
33
33
|
end
|
34
|
+
|
35
|
+
# Retrieves values as Ruby array of true and false values
|
36
|
+
# NA will be replaced with nils
|
37
|
+
def to_a
|
38
|
+
@payload.map {|v|
|
39
|
+
case v
|
40
|
+
when NA then nil
|
41
|
+
when TRUE then true
|
42
|
+
when FALSE then false
|
43
|
+
end
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
34
47
|
def as_integers
|
35
|
-
@payload.map {|v| v==NA ? REXP::Integer::NA : ( v == FALSE ? 0 : 1 )}
|
48
|
+
@payload.map {|v| v==NA ? REXP::Integer::NA : ( v == FALSE ? 0 : 1 )}
|
36
49
|
end
|
37
50
|
def as_doubles
|
38
|
-
@payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? 0.0 : 1.0 )}
|
51
|
+
@payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? 0.0 : 1.0 )}
|
39
52
|
end
|
40
53
|
def as_strings
|
41
|
-
@payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? "FALSE" : "TRUE" )}
|
54
|
+
@payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? "FALSE" : "TRUE" )}
|
42
55
|
end
|
43
56
|
def true?
|
44
57
|
@payload.map {|v| v==TRUE}
|
data/lib/rserve/rexp/null.rb
CHANGED
@@ -1,17 +1,23 @@
|
|
1
1
|
module Rserve
|
2
2
|
class REXP
|
3
|
-
# represents a NULL object in R.
|
4
|
-
# Note: there is a slight asymmetry - in R NULL is represented by a zero-length pairlist. For this reason <code>REXPNull</code> returns <code>true</code> for {@link #isList()} and {@link #asList()} will return an empty list. Nonetheless <code>REXPList</code> of the length 0 will NOT return <code>true</code> in {@link #isNull()} (currently), becasue it is considered a different object in Java. These nuances are still subject to change, because it's not clear how it should be treated. At any rate use <code>REXPNull</code> instead of empty <code>REXPList</code> if NULL is the intended value.
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
3
|
+
# represents a NULL object in R.
|
4
|
+
# Note: there is a slight asymmetry - in R NULL is represented by a zero-length pairlist. For this reason <code>REXPNull</code> returns <code>true</code> for {@link #isList()} and {@link #asList()} will return an empty list. Nonetheless <code>REXPList</code> of the length 0 will NOT return <code>true</code> in {@link #isNull()} (currently), becasue it is considered a different object in Java. These nuances are still subject to change, because it's not clear how it should be treated. At any rate use <code>REXPNull</code> instead of empty <code>REXPList</code> if NULL is the intended value.
|
5
|
+
class Null < REXP
|
6
|
+
def null?
|
7
|
+
true
|
8
|
+
end
|
9
|
+
def ==(v)
|
10
|
+
v.is_a? self.class
|
11
|
+
end
|
12
|
+
def list?
|
13
|
+
true
|
14
|
+
end
|
15
|
+
def as_list
|
16
|
+
Rlist.new
|
17
|
+
end
|
18
|
+
def to_ruby
|
19
|
+
nil
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
17
23
|
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Rserve
|
2
|
+
class REXP
|
3
|
+
class Raw < REXP::Vector
|
4
|
+
def initialize(l,attr=nil)
|
5
|
+
super(attr);
|
6
|
+
@payload=(l.nil?) ? Array.new() : l;
|
7
|
+
end
|
8
|
+
def length
|
9
|
+
@payload.length
|
10
|
+
end
|
11
|
+
def raw?
|
12
|
+
true
|
13
|
+
end
|
14
|
+
def as_bytes
|
15
|
+
@payload
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
module Rserve
|
3
|
+
class REXP
|
4
|
+
class Reference < REXP
|
5
|
+
extend Forwardable
|
6
|
+
attr_reader :eng
|
7
|
+
attr_reader :handle
|
8
|
+
attr_reader :resolved_value
|
9
|
+
|
10
|
+
def initialize(e,h)
|
11
|
+
super()
|
12
|
+
@eng=e
|
13
|
+
@handle=h
|
14
|
+
@resolved_value=nil
|
15
|
+
end
|
16
|
+
|
17
|
+
# check type methods
|
18
|
+
def_delegators :@resolved_value, :string?, :numeric?, :integer?, :null?, :factor?, :list?, :logical?, :environment? , :language?, :symbol?, :vector?, :raw?, :complex?, :recursive?
|
19
|
+
# convertion methods
|
20
|
+
def_delegators :@resolved_value, :as_strings, :as_integers, :as_floats, :as_list, :as_factor
|
21
|
+
# other methods
|
22
|
+
def_delegators :@resolved_value, :attr, :length
|
23
|
+
|
24
|
+
def reference?
|
25
|
+
true
|
26
|
+
end
|
27
|
+
def resolve
|
28
|
+
@resolved_value||= @eng.resolve_reference(self)
|
29
|
+
end
|
30
|
+
def invalidate
|
31
|
+
@resolved_value=nil
|
32
|
+
end
|
33
|
+
def finalize
|
34
|
+
begin
|
35
|
+
@eng.finalize_reference(self)
|
36
|
+
ensure
|
37
|
+
super.finalize()
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/rserve/rexp/string.rb
CHANGED
@@ -2,13 +2,14 @@ module Rserve
|
|
2
2
|
class REXP
|
3
3
|
class String < REXP::Vector
|
4
4
|
attr_reader :payload
|
5
|
+
NA="NA"
|
5
6
|
def initialize(data, attrs=nil)
|
6
7
|
@payload=case data
|
7
8
|
when Array
|
8
9
|
data.map {|v| v.to_s}
|
9
|
-
|
10
|
-
|
11
|
-
|
10
|
+
else
|
11
|
+
[data.to_s]
|
12
|
+
end
|
12
13
|
super(attrs)
|
13
14
|
end
|
14
15
|
def length
|
@@ -28,6 +29,7 @@ module Rserve
|
|
28
29
|
t=super
|
29
30
|
t << "{" << @payload.map(&:to_s).join(",") << "}"
|
30
31
|
end
|
32
|
+
|
31
33
|
end
|
32
34
|
end
|
33
35
|
end
|
data/lib/rserve/rexp/symbol.rb
CHANGED
data/lib/rserve/rexp/vector.rb
CHANGED
@@ -1,23 +1,38 @@
|
|
1
1
|
module Rserve
|
2
2
|
class REXP
|
3
3
|
class Vector < REXP
|
4
|
+
attr_reader :payload
|
5
|
+
def ==(o)
|
6
|
+
#p "Comparing #{self.inspect} with #{o.inspect} gives #{self.payload==o.payload and self.attr==o.attr}"
|
7
|
+
self.class==o.class and self.payload==o.payload and self.attr==o.attr
|
8
|
+
end
|
9
|
+
|
4
10
|
# returns the length of the vector (i.e. the number of elements)
|
5
|
-
# @return length of the vector
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
11
|
+
# @return length of the vector
|
12
|
+
def length;
|
13
|
+
end;
|
14
|
+
def vector?;
|
15
|
+
true;
|
16
|
+
end
|
17
|
+
# 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
|
18
|
+
# @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 */
|
19
|
+
def na?
|
20
|
+
end
|
21
|
+
|
22
|
+
# Retrieves values as Ruby array
|
23
|
+
# NA will be replaced with nils
|
24
|
+
def to_a
|
25
|
+
@payload.map {|v| na?(v) ? nil : v }
|
26
|
+
end
|
27
|
+
def to_ruby
|
28
|
+
if @payload.nil? or @payload.size==0
|
29
|
+
nil
|
30
|
+
elsif @payload.size==1
|
31
|
+
@payload[0]
|
32
|
+
else
|
33
|
+
@payload.map {|v| na?(v) ? nil : v}
|
20
34
|
end
|
35
|
+
end
|
21
36
|
end
|
22
37
|
end
|
23
38
|
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module Rserve
|
2
|
+
class REXP
|
3
|
+
#
|
4
|
+
# Utility module to wrap an Ruby Object into a REXP object.
|
5
|
+
#
|
6
|
+
# This facilitates wrapping native ruby objects and arrays
|
7
|
+
# into REXP objects that can be pushed to R
|
8
|
+
#
|
9
|
+
# @author Romain Francois <francoisromain@free.fr>
|
10
|
+
#
|
11
|
+
module Wrapper
|
12
|
+
def self.wrap(o)
|
13
|
+
return o if o.is_a? REXP
|
14
|
+
case o
|
15
|
+
when TrueClass
|
16
|
+
REXP::Logical.new(1)
|
17
|
+
when FalseClass
|
18
|
+
REXP::Logical.new(0)
|
19
|
+
when NilClass
|
20
|
+
REXP::Null.new()
|
21
|
+
when ::String
|
22
|
+
REXP::String.new(o)
|
23
|
+
when Integer
|
24
|
+
REXP::Integer.new(o)
|
25
|
+
when Fixnum
|
26
|
+
REXP::Integer.new(o)
|
27
|
+
when Float
|
28
|
+
REXP::Double.new(o)
|
29
|
+
when Array
|
30
|
+
find_type_of_array(o)
|
31
|
+
else
|
32
|
+
puts "Clase:#{o.class}"
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
end
|
36
|
+
def self.find_type_of_array(o)
|
37
|
+
if o.all? {|v| v.nil?}
|
38
|
+
REXP::Integer.new([REXP::Integer::NA]*o.size)
|
39
|
+
elsif o.all? {|v| v.is_a? Integer or v.is_a? Fixnum or v.nil?}
|
40
|
+
REXP::Integer.new(o.map {|v| v.nil? ? REXP::Integer::NA : v})
|
41
|
+
elsif o.all? {|v| v.is_a? Numeric or v.nil?}
|
42
|
+
REXP::Double.new(o.map {|v| v.nil? ? REXP::Double::NA : v.to_f})
|
43
|
+
elsif o.all? {|v| v.is_a? ::String or v.nil?}
|
44
|
+
REXP::String.new(o.map {|v| v.nil? ? REXP::String::NA : v})
|
45
|
+
elsif o.all? {|v| v.is_a? TrueClass or v.is_a? FalseClass or v.nil?}
|
46
|
+
REXP::Logical.new(o.map{|v| v.nil? ? REXP::Logical::NA : (v ? 1 : 0)})
|
47
|
+
# mixed values. We must return a LIST!
|
48
|
+
else
|
49
|
+
REXP::GenericVector.new(
|
50
|
+
Rlist.new(
|
51
|
+
o.map{|v| wrap(v)}
|
52
|
+
)
|
53
|
+
)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|