rserve-client 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
+