rserve-client 0.1.0

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.
@@ -0,0 +1,46 @@
1
+ module Rserve
2
+ class REXP
3
+ class Double < REXP::Vector
4
+ attr_reader :payload
5
+ NA = 0x7ff00000000007a2;
6
+ def initialize(data, attrs=nil)
7
+ @payload=case data
8
+ when Numeric
9
+ [data.to_f]
10
+ when Array
11
+ data
12
+ else
13
+ raise ArgumentError, "Should be Numeric or Array"
14
+ end
15
+ super(attrs)
16
+ end
17
+ def length
18
+ payload.length
19
+ end
20
+ def integer?
21
+ true
22
+ end
23
+ def numeric?
24
+ true
25
+ end
26
+ def as_integers
27
+ @payload.map(&:to_i)
28
+ end
29
+ def as_doubles
30
+ @payload
31
+ end
32
+ def as_strings
33
+ @payload.map(&:to_s)
34
+ end
35
+
36
+ def na?(value=nil)
37
+ return value == NA unless value.nil?
38
+ @payload.map {|v| v==NA}
39
+ end
40
+ def to_debug_string
41
+ t=super
42
+ t << "{" << @payload.map(&:to_s).join(",") << "}"
43
+ end
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,29 @@
1
+ module Rserve
2
+ class REXP
3
+ class GenericVector < REXP::Vector
4
+ attr_reader :payload
5
+ def initialize(list,attr=nil)
6
+ super(attr)
7
+ @payload=list.nil? ? Rlist.new() : list
8
+
9
+ if (payload.named?)
10
+ @attr = REXP::List.new(
11
+ Rlist.new([REXP::String.new(payload.keys())],
12
+ ["names"]));
13
+ end
14
+ end
15
+ def length
16
+ @payload.size
17
+ end
18
+ def list?
19
+ true
20
+ end
21
+ def recursive?
22
+ true
23
+ end
24
+ def as_list
25
+ @payload
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,49 @@
1
+ module Rserve
2
+ class REXP
3
+ class Integer < REXP::Vector
4
+ public_class_method :new
5
+ attr_reader :payload
6
+ NA = -2147483648;
7
+ def initialize(data, attrs=nil)
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
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,33 @@
1
+ module Rserve
2
+ class REXP
3
+ class List < REXP::Vector
4
+ attr_reader :payload
5
+ def initialize(list, attrs=nil)
6
+ @payload=list.nil? ? RList.new : list
7
+ super(attrs)
8
+ end
9
+ def length
10
+ payload.size
11
+ end
12
+ def list?
13
+ true
14
+ end
15
+ def pair_list?
16
+ true
17
+ end
18
+ def recursive?
19
+ true
20
+ end
21
+ def as_list
22
+ @payload
23
+ end
24
+ def to_s
25
+ super+(as_list.named? ? "named":"")
26
+ end
27
+ def to_debug_string
28
+ t=super
29
+ t << "{" << @payload.map {|k,v| "#{k}=#{v}"}.join(",\n") << "}"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,48 @@
1
+ module Rserve
2
+ class REXP
3
+ class Logical < REXP::Vector
4
+ attr_reader :payload
5
+ NA_internal = -2147483648;
6
+ NA=-128
7
+ TRUE=1
8
+ FALSE=0
9
+ def na?(value=nil)
10
+ if value
11
+ value==NA
12
+ else
13
+ @payload.map {|v| v==NA}
14
+ end
15
+ end
16
+ def initialize(l,attr=nil)
17
+ super(attr)
18
+ if l.is_a? Array
19
+ @payload=l.map {|l| l==1 ? TRUE : FALSE}
20
+ else
21
+ @payload = [ l==1 ? TRUE : FALSE ]
22
+ end
23
+ end
24
+ def length
25
+ @payload.length
26
+ end
27
+ def logical?
28
+ true
29
+ end
30
+ def as_integers
31
+ @payload.map {|v| v==NA ? REXP::Integer::NA : ( v == FALSE ? 0 : 1 )}
32
+ end
33
+ def as_doubles
34
+ @payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? 0.0 : 1.0 )}
35
+ end
36
+ def as_strings
37
+ @payload.map {|v| v==NA ? REXP::Double::NA : ( v == FALSE ? "FALSE" : "TRUE" )}
38
+ end
39
+ def true?
40
+ @payload.map {|v| v==TRUE}
41
+ end
42
+ def false?
43
+ @payload.map {|v| v==FALSE}
44
+
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,33 @@
1
+ module Rserve
2
+ class REXP
3
+ class String < REXP::Vector
4
+ attr_reader :payload
5
+ def initialize(data, attrs=nil)
6
+ @payload=case data
7
+ when Array
8
+ data.map {|v| v.to_s}
9
+ else
10
+ [data.to_s]
11
+ end
12
+ super(attrs)
13
+ end
14
+ def length
15
+ payload.length
16
+ end
17
+ def string?
18
+ true
19
+ end
20
+ def as_strings
21
+ @payload
22
+ end
23
+
24
+ def na?
25
+ @payload.map {|v| v.nil}
26
+ end
27
+ def to_debug_string
28
+ t=super
29
+ t << "{" << @payload.map(&:to_s).join(",") << "}"
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,26 @@
1
+ module Rserve
2
+ class REXP
3
+ class Symbol < REXP::Vector
4
+ attr_reader :name
5
+ def initialize(name)
6
+ super()
7
+ @name== name.nil? ? "":name
8
+ end
9
+ def symbol?
10
+ true
11
+ end
12
+ def as_string
13
+ @name
14
+ end
15
+ def as_strings
16
+ [@name]
17
+ end
18
+ def to_s
19
+ super+"["+name+"]"
20
+ end
21
+ def to_debug_string
22
+ super+"["+name+"]"
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,23 @@
1
+ module Rserve
2
+ class REXP
3
+ class Vector < REXP
4
+ # 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}]"
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,124 @@
1
+ module Rserve
2
+ class Rlist
3
+ include Enumerable
4
+ attr_reader :names
5
+ attr_reader :data
6
+ def initialize(data=nil,n=nil)
7
+ @names=nil
8
+ @data=[]
9
+ if data
10
+ @data=case data
11
+ when Array
12
+ data
13
+ when Numeric
14
+ Array.new(data)
15
+ else
16
+ raise ArgumentError
17
+ end
18
+ end
19
+ if n
20
+ @names=Array.new(@data.size)
21
+ n.each_index {|i| @names[i]=n[i]} if n.respond_to? :each_index
22
+ end
23
+ end
24
+ def named?
25
+ !@names.nil?
26
+ end
27
+ def [](v)
28
+ if v.is_a? String
29
+ return nil if @names.nil?
30
+ i=@names.index(v)
31
+ return i.nil? ? nil : @data[i]
32
+ elsif v.is_a? Integer
33
+ return @data[i]
34
+ else
35
+ raise ArgumentError,"Should be String or Integer"
36
+ end
37
+ end
38
+
39
+ def at(v)
40
+ @data[v]
41
+ end
42
+
43
+ def key_at(v)
44
+ return nil if @names.nil?
45
+ @names[v]
46
+ end
47
+ def size
48
+ @data.size
49
+ end
50
+
51
+ def each
52
+ @data.each do |v|
53
+ yield v
54
+ end
55
+ end
56
+
57
+ def set_key_at(i,value)
58
+ if @names.nil?
59
+ @names=Array.new
60
+ end
61
+ if @names.size<size
62
+ (size-@names.size).times {@names.push(nil)}
63
+ end
64
+
65
+ @names[i]=value if i < size
66
+
67
+ end
68
+
69
+ def keys
70
+ @names
71
+ end
72
+
73
+ def put(key,value)
74
+ if key.nil?
75
+ add(value)
76
+ return nil
77
+ end
78
+ if !names.nil?
79
+ p=names.index(key)
80
+ if !p.nil?
81
+ return @names[p]=value
82
+ end
83
+ end
84
+ i=size
85
+ add(value)
86
+ if(@names.nil?)
87
+ @names=Array.new(i+1)
88
+ while(@names.size<i) do
89
+ @names.push(nil)
90
+ end
91
+ @names.push(key)
92
+ end
93
+
94
+ end
95
+ def add(a,b=nil)
96
+ if b.nil?
97
+ @data.push(a)
98
+ @names=Array.new(@data.size-1) if @names.nil?
99
+ @names.push(nil)
100
+ else
101
+ @data.insert(a,b)
102
+ @names.insert(a,nil)
103
+ end
104
+ end
105
+ def clear
106
+ @data.clear
107
+ @names=nil
108
+ end
109
+ def clone
110
+ RList.new(@data,@names)
111
+ end
112
+ def remove(elem)
113
+ if elem.is_a? String
114
+ i=@data.index(elem)
115
+ elsif elem.is_a? Integer
116
+ i=elem
117
+ end
118
+ return false if i.nil?
119
+ @data.delete_at(i)
120
+ @names.delete_at(i) unless @names.nil?
121
+ @names=nil if size==0
122
+ end
123
+ end
124
+ end
@@ -0,0 +1,123 @@
1
+ module Rserve
2
+ # Class which 'talk' to the server.
3
+ #
4
+ # I separated the 'abstract' aspect of the protocol on
5
+ # Protocol module, for better testing
6
+ #
7
+ class Talk
8
+ include Rserve::Protocol
9
+ attr_reader :io
10
+ def initialize(io)
11
+ @io=io
12
+ end
13
+ # sends a request with attached prefix and parameters.
14
+ # All parameters should be enter on Hash
15
+ # Both :prefix and :cont can be <code>nil</code>. Effectively <code>request(:cmd=>a,:prefix=>b,:cont=>nil)</code> and <code>request(:cmd=>a,:prefix=>nil,:cont=>b)</code> are equivalent.
16
+ # @param :cmd command - a special command of -1 prevents request from sending anything
17
+ # @param :prefix - this content is sent *before* cont. It is provided to save memory copy operations where a small header precedes a large data chunk (usually prefix conatins the parameter header and cont contains the actual data).
18
+ # @param :cont contents
19
+ # @param :offset offset in cont where to start sending (if <0 then 0 is assumed, if >cont.length then no cont is sent)
20
+ # @param :len number of bytes in cont to send (it is clipped to the length of cont if necessary)
21
+ # @return returned packet or <code>null</code> if something went wrong */
22
+ def request(params=Hash.new)
23
+
24
+ cmd = params.delete :cmd
25
+ prefix = params.delete :prefix
26
+ cont = params.delete :cont
27
+ offset = params.delete :offset
28
+ len = params.delete :len
29
+
30
+ if cont.is_a? String
31
+ cont=request_string(cont)
32
+ elsif cont.is_a? Integer
33
+ cont=request_int(cont)
34
+ end
35
+ raise ArgumentError, ":cont should be an Enumerable" if !cont.nil? and !cont.is_a? Enumerable
36
+
37
+ if len.nil?
38
+ len=(cont.nil?) ? 0 : cont.length
39
+ end
40
+
41
+ offset||=0
42
+
43
+
44
+ if (!cont.nil?)
45
+ if (offset>=cont.length)
46
+ cont=nil;len=0
47
+ elsif (len>cont.length-offset)
48
+ len=cont.length-offset
49
+ end
50
+ end
51
+ offset=0 if offset<0
52
+ len=0 if len<0
53
+ contlen=(cont.nil?) ? 0 : len
54
+ contlen+=prefix.length if (!prefix.nil? and prefix.length>0)
55
+
56
+ hdr=Array.new(16)
57
+ set_int(cmd,hdr,0)
58
+ set_int(contlen,hdr,4);
59
+ 8.upto(15) {|i| hdr[i]=0}
60
+ if (cmd!=-1)
61
+ io.write(hdr.pack("C*"))
62
+ if (!prefix.nil? && prefix.length>0)
63
+ io.write(prefix.pack("C*"))
64
+ puts "SEND PREFIX #{prefix}" if $DEBUG
65
+ end
66
+ if (!cont.nil? && cont.length>0)
67
+ io.write(cont.slice(offset, len).pack("C*"))
68
+ puts "SEND CONTENT '#{cont.slice(offset, len).pack("C*")}'" if $DEBUG
69
+ end
70
+ end
71
+
72
+ ih=io.recv(16).unpack("C*")
73
+
74
+ return nil if (ih.length!=16)
75
+
76
+ puts "Answer: #{ih.to_s}" if $DEBUG
77
+
78
+ rep=get_int(ih,0);
79
+
80
+ rl =get_int(ih,4);
81
+
82
+ if $DEBUG
83
+ puts "rep: #{rep} #{rep.class} #{rep & 0x00FFFFFF}"
84
+ puts "rl: #{rl} #{rl.class}"
85
+ end
86
+
87
+ if (rl>0)
88
+ ct=Array.new();
89
+ n=0;
90
+ while (n<rl) do
91
+ data=io.recv(rl-n).unpack("C*")
92
+ ct+=data
93
+ rd=data.length
94
+ n+=rd;
95
+ end
96
+
97
+ return Packet.new(rep,ct);
98
+ end
99
+
100
+ return Packet.new(rep,nil);
101
+ end
102
+ def request_string(s)
103
+ b=s.unpack("C*")
104
+ sl=b.length+1;
105
+ sl=(sl&0xfffffc)+4 if ((sl&3)>0) # make sure the length is divisible by 4
106
+ rq=Array.new(sl+5)
107
+
108
+ b.length.times {|i| rq[i+4]=b[i]}
109
+ ((b.length)..sl).each {|i|
110
+ rq[i+4]=0
111
+ }
112
+ set_hdr(DT_STRING,sl,rq,0)
113
+ rq
114
+ end
115
+ def request_int(par)
116
+ rq=Array.new(8)
117
+ set_int(par,rq,4)
118
+ set_hdr(DT_INT,4,rq,0)
119
+ rq
120
+ end
121
+ end
122
+ end
123
+