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.
- 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
|