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.
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
@@ -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
@@ -0,0 +1,9 @@
1
+ module Rserve
2
+ class REXP
3
+ class ExpressionVector < REXP::GenericVector
4
+ def expression?
5
+ true
6
+ end
7
+ end
8
+ end
9
+ 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
- ["names"]));
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
@@ -6,44 +6,44 @@ module Rserve
6
6
  NA = -2147483648;
7
7
  def initialize(data, attrs=nil)
8
8
  @payload=case data
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(",") << "}"
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
@@ -1,9 +1,9 @@
1
1
  module Rserve
2
2
  class REXP
3
- class Language < REXP::List
3
+ class Language < REXP::List
4
4
  def initialize(list, attr=nil)
5
5
  super(list,attr)
6
-
6
+
7
7
  end
8
8
  def language?
9
9
  true
@@ -33,6 +33,9 @@ module Rserve
33
33
  end
34
34
  t+inner
35
35
  end
36
+ def to_ruby
37
+ as_list.to_ruby
38
+ end
36
39
  end
37
40
  end
38
41
  end
@@ -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}
@@ -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
- class Null < REXP
6
- def null?
7
- true
8
- end
9
- def list?
10
- true
11
- end
12
- def as_list
13
- Rlist.new
14
- end
15
- end
16
- end
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
@@ -0,0 +1,10 @@
1
+ module Rserve
2
+ class REXP
3
+ # S4 REXP is a completely vanilla REXP
4
+ class S4 < REXP
5
+ def initialize(attr=nil)
6
+ super(attr)
7
+ end
8
+ end
9
+ end
10
+ end
@@ -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
- else
10
- [data.to_s]
11
- end
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
@@ -21,6 +21,9 @@ module Rserve
21
21
  def to_debug_string
22
22
  super+"["+name+"]"
23
23
  end
24
+ def to_ruby
25
+ @name
26
+ end
24
27
  end
25
28
  end
26
29
  end
@@ -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
- def length;
7
- end;
8
- def vector?;
9
- true;
10
- end
11
- # 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
12
- # @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 */
13
- def na?
14
- end
15
- def to_s
16
- super+"[#{length}]"
17
- end
18
- def to_debug_string
19
- super+"[#{length}]"
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