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