R4rb 1.0.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.
- checksums.yaml +7 -0
- data/R4rb.gemspec +32 -0
- data/Rakefile +114 -0
- data/ext/R4rb/MANIFEST +0 -0
- data/ext/R4rb/R4rb.c +595 -0
- data/ext/R4rb/extconf.rb +133 -0
- data/lib/R2rb.rb +5 -0
- data/lib/R4rb.rb +59 -0
- data/lib/R4rb/R2rb_eval.rb +116 -0
- data/lib/R4rb/R2rb_init.rb +109 -0
- data/lib/R4rb/R4rb.rb +164 -0
- data/lib/R4rb/Rserve.rb +208 -0
- data/lib/R4rb/converter.rb +69 -0
- data/lib/R4rb/init.rb +127 -0
- data/lib/R4rb/robj.rb +46 -0
- data/lib/Rserve.rb +8 -0
- data/script/README +5 -0
- data/script/Rserv +39 -0
- data/script/install_Rserv +8 -0
- data/test/R4rbRserve.rb +30 -0
- data/test/compR4rbRserve.rb +2 -0
- data/test/test.rb +89 -0
- data/test/testArray.rb +27 -0
- data/test/testBuffer.rb +12 -0
- data/test/testConsole.rb +5 -0
- data/test/testR4rb.rb +42 -0
- data/test/testRVect.rb +18 -0
- data/test/testRserve.rb +90 -0
- data/test/test_error.rb +32 -0
- metadata +74 -0
data/lib/R4rb/Rserve.rb
ADDED
@@ -0,0 +1,208 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
### IMPORTANT, no use of R4rb tools! R2rb or Rserve mode only!
|
3
|
+
|
4
|
+
module Rserve
|
5
|
+
|
6
|
+
## server side
|
7
|
+
def Rserve.pid
|
8
|
+
`ps -C Rserve -o pid=`.strip
|
9
|
+
end
|
10
|
+
|
11
|
+
def Rserve.running?
|
12
|
+
!Rserve.pid.empty?
|
13
|
+
end
|
14
|
+
|
15
|
+
def Rserve.start(rserve=File.expand_path("~/bin/Rserv"))
|
16
|
+
`R CMD #{rserve}` unless Rserve.running?
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def Rserve.stop
|
21
|
+
pid=Rserve.pid
|
22
|
+
`kill #{pid}` unless pid.empty?
|
23
|
+
sleep(2)
|
24
|
+
if Rserve.running?
|
25
|
+
puts "Sorry! but the Rserver is still running!"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
## client side
|
30
|
+
@@clients,@@cli=nil,nil
|
31
|
+
|
32
|
+
def Rserve.init
|
33
|
+
#puts "Rserve.init"
|
34
|
+
Array.initR
|
35
|
+
#puts "Rserve.init2"
|
36
|
+
"require(Rserve)".R2rb
|
37
|
+
#puts "Rserve.init3"
|
38
|
+
@@clients,@@cli=[],nil
|
39
|
+
@@out=[]
|
40
|
+
@@out.rb2R=R2rb
|
41
|
+
#puts "Rserve.init4"
|
42
|
+
end
|
43
|
+
|
44
|
+
#####################################################
|
45
|
+
# the two following methods to be possibly redefined
|
46
|
+
# in particular inside Dyndoc to automatically
|
47
|
+
# allocate the R session related to the user!
|
48
|
+
def Rserve.cli
|
49
|
+
@@cli
|
50
|
+
end
|
51
|
+
#
|
52
|
+
def Rserve.cli=(cli)
|
53
|
+
@@cli=cli
|
54
|
+
end
|
55
|
+
#####################################################
|
56
|
+
|
57
|
+
|
58
|
+
def Rserve.client(cli=nil)
|
59
|
+
## automate the init process!
|
60
|
+
#Rserve.init unless @@clients
|
61
|
+
|
62
|
+
##return current client!
|
63
|
+
unless cli
|
64
|
+
return Rserve.cli
|
65
|
+
## create a new client
|
66
|
+
else
|
67
|
+
Rserve.open(cli)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
## change the current client!
|
72
|
+
def Rserve.client=(cli=nil)
|
73
|
+
return nil unless @@clients.include? cli
|
74
|
+
Rserve.cli=cli
|
75
|
+
end
|
76
|
+
|
77
|
+
def Rserve.open(cli)
|
78
|
+
"#{cli.to_s} <- RSconnect()".R2rb
|
79
|
+
@@clients << cli
|
80
|
+
Rserve.cli=cli
|
81
|
+
end
|
82
|
+
|
83
|
+
def Rserve.close(cli=nil)
|
84
|
+
cli=Rserve.cli unless cli
|
85
|
+
return unless @@clients.include? cli
|
86
|
+
"RSclose(#{cli.to_s})".R2rb
|
87
|
+
@@clients.delete(cli)
|
88
|
+
end
|
89
|
+
|
90
|
+
def Rserve.ls
|
91
|
+
@@clients
|
92
|
+
end
|
93
|
+
|
94
|
+
#####################################################
|
95
|
+
## interface
|
96
|
+
def Rserve.complete_code!(code)
|
97
|
+
code.gsub!("\\","\\\\")
|
98
|
+
code.gsub!("\"","\\\"")
|
99
|
+
code.replace("RSeval(#{cli},\"capture.output({"+code+"})\")")
|
100
|
+
end
|
101
|
+
|
102
|
+
|
103
|
+
def Rserve.completed_code(code,capture=true)
|
104
|
+
open,close= (capture ? ["capture.output({","})"] : ["",""])
|
105
|
+
"RSeval(#{cli},\""+open+code.gsub("\\","\\\\").gsub("\"","\\\"")+close+"\")"
|
106
|
+
end
|
107
|
+
|
108
|
+
def Rserve.eval(code,cli=nil)
|
109
|
+
cli=Rserve.cli unless cli
|
110
|
+
return nil unless cli
|
111
|
+
## check parsing locally (without RSeval)
|
112
|
+
status=R2rb.parse code
|
113
|
+
if status!=1
|
114
|
+
R2rb.parse code,true
|
115
|
+
return false
|
116
|
+
end
|
117
|
+
## RSeval completed in code!
|
118
|
+
Rserve.complete_code!(code)
|
119
|
+
#puts "Rserve.eval:";p code
|
120
|
+
R2rb.eval code
|
121
|
+
#@@out < code ##@@out.inR2rb code # since @@out < code but for R2rb
|
122
|
+
end
|
123
|
+
|
124
|
+
def Rserve.try_eval(code,cli=nil)
|
125
|
+
cli=Rserve.cli unless cli
|
126
|
+
try_code=".result_try_code<-try({\n"+code+"\n},silent=TRUE)\n"
|
127
|
+
puts Rserve.output(try_code,cli).join("\n")
|
128
|
+
puts R2rb.output(Rserve.completed_code(".result_try_code",false)) if "inherits(.result_try_code,'try-error')".to_R
|
129
|
+
end
|
130
|
+
|
131
|
+
def Rserve.<<(code)
|
132
|
+
Rserve.eval(code)
|
133
|
+
end
|
134
|
+
|
135
|
+
def Rserve.output(code,cli=nil)
|
136
|
+
#puts "Rserve.output:";p code
|
137
|
+
cli=Rserve.cli unless cli
|
138
|
+
return nil unless cli
|
139
|
+
## RSeval completed in code!
|
140
|
+
Rserve.complete_code!(code)
|
141
|
+
@@out < code ##@@out.inR2rb rcode.to_s
|
142
|
+
return (@@out.length<=1 ? @@out[0] : @@out)
|
143
|
+
end
|
144
|
+
|
145
|
+
def Rserve.<(code)
|
146
|
+
Rserve.output(code)
|
147
|
+
end
|
148
|
+
|
149
|
+
def Rserve.assign(code,var=nil,cli=nil)
|
150
|
+
code+=",quote(#{var})" if var
|
151
|
+
cli=Rserve.cli unless cli
|
152
|
+
code="RSassign(#{cli},#{code})"
|
153
|
+
#p code
|
154
|
+
#R2rb << code ###????
|
155
|
+
Rserve << code
|
156
|
+
end
|
157
|
+
|
158
|
+
class RVector < R2rb::RVector
|
159
|
+
|
160
|
+
def RVector.assign(var,ary,cli=nil)
|
161
|
+
super(var,ary)
|
162
|
+
Rserve.assign(var,var,cli)
|
163
|
+
end
|
164
|
+
|
165
|
+
attr_accessor :cli
|
166
|
+
|
167
|
+
## The goal is to connect a ruby Array to a Rserve Vector
|
168
|
+
def initialize(name,cli=nil)
|
169
|
+
@cli=(cli ? cli : Rserve.cli)
|
170
|
+
puts "WARNING: Rserve::RVector.initialize: @cli is null!" unless @cli
|
171
|
+
@name_orig=name
|
172
|
+
super(name!)
|
173
|
+
@type="expr"
|
174
|
+
end
|
175
|
+
|
176
|
+
def name! #name from cli and name_orig
|
177
|
+
##puts "name!";p @name_orig
|
178
|
+
##deb,fin="quote(",")" #(@name_orig=~/^evalq\(/ ? ["quote(",")"] : ["\"","\""])
|
179
|
+
"RSeval(#{@cli},quote(#{@name_orig}))"
|
180
|
+
end
|
181
|
+
|
182
|
+
def <<(name)
|
183
|
+
## no "var" in this context! transform it in String if necessary
|
184
|
+
@name_orig=name.to_s
|
185
|
+
super(name!)
|
186
|
+
return self
|
187
|
+
end
|
188
|
+
|
189
|
+
## no need to make aby change for ">"
|
190
|
+
|
191
|
+
def <(ary)
|
192
|
+
ary.R2rb(".rubyExport") #transition
|
193
|
+
Rserve.assign(".rubyExport",@name_orig,@cli)
|
194
|
+
end
|
195
|
+
|
196
|
+
alias value= <
|
197
|
+
|
198
|
+
def set_with_arg(ary)
|
199
|
+
ary=[ary] unless ary.is_a? Array
|
200
|
+
ary.R2rb(".rubyExport") #transition
|
201
|
+
#p @name_orig+@arg
|
202
|
+
Rserve.assign(".rubyExport",@name_orig+@arg,@cli)
|
203
|
+
end
|
204
|
+
|
205
|
+
alias value_with_arg= set_with_arg
|
206
|
+
|
207
|
+
end
|
208
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
class String
|
3
|
+
|
4
|
+
def to_aRy(sep=",")
|
5
|
+
self.split(sep).map{|str|
|
6
|
+
R2rb.multilang_parser(str)
|
7
|
+
}.flatten
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
module R2rb
|
13
|
+
|
14
|
+
@@pair=["<<",">>"]
|
15
|
+
|
16
|
+
def R2rb.pair
|
17
|
+
@@pair
|
18
|
+
end
|
19
|
+
|
20
|
+
def R2rb.pair=(pair)
|
21
|
+
if pair.is_a? String
|
22
|
+
pairs={"{"=>"}","("=>")","<"=>">","["=>"]"}
|
23
|
+
pair2=pair.reverse.gsub(/[#{Regexp.escape(pairs.keys.join)}]/) {|e| Regexp.escape(pairs[e])}
|
24
|
+
pair=[pair,pair2]
|
25
|
+
end
|
26
|
+
#p "ICI";p pair
|
27
|
+
if (pair.is_a? Array) and pair.length==2
|
28
|
+
@@pair=pair
|
29
|
+
end
|
30
|
+
#p @@pair
|
31
|
+
end
|
32
|
+
|
33
|
+
def R2rb.multilang_parser(str)
|
34
|
+
#p @@pair
|
35
|
+
lang="r|R|rb|Rb"
|
36
|
+
s=str
|
37
|
+
if @@pair[0].empty?
|
38
|
+
mask = /((?:#{lang}).*)/
|
39
|
+
else
|
40
|
+
mask = /#{Regexp.escape(@@pair[0])}((?:#{lang})[^#{Regexp.escape(@@pair[0])}]*)#{Regexp.escape(@@pair[1])}/
|
41
|
+
end
|
42
|
+
str=str.split(mask,-1)
|
43
|
+
return s if str.length<=1
|
44
|
+
vals=[]
|
45
|
+
res=[]
|
46
|
+
inds=0..(str.length / 2 - 1)
|
47
|
+
".tmp<-NULL".to_R
|
48
|
+
inds.each {|i|
|
49
|
+
res << str[2*i]
|
50
|
+
if str[2*i+1] =~ /^(?:r|R):(.*)/
|
51
|
+
(".tmp<-cbind(.tmp,"+$1+")").to_R
|
52
|
+
end
|
53
|
+
if str[2*i+1] =~ /^(?:rb|Rb):(.*)/
|
54
|
+
a=eval($1)
|
55
|
+
a=[a] unless a.is_a? Array
|
56
|
+
a > :tmp
|
57
|
+
(".tmp<-cbind(.tmp,tmp)").to_R
|
58
|
+
end
|
59
|
+
}
|
60
|
+
res << str[-1]
|
61
|
+
#p res
|
62
|
+
cmd="apply(.tmp,1,function(e) paste("
|
63
|
+
inds.each{|i| cmd += "'"+res[i]+"',e["+i.to_s+"+1]," }
|
64
|
+
cmd += "'"+res[-1]+"',sep=''))"
|
65
|
+
#"print(.tmp)".to_R
|
66
|
+
#p cmd
|
67
|
+
cmd.to_R
|
68
|
+
end
|
69
|
+
end
|
data/lib/R4rb/init.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
## Attention "...\n..." have to be replaced by "...\\n..."
|
2
|
+
## example : 'cat("toto\n")' fails but not 'cat("toto\\n")'
|
3
|
+
## more surprisingly, this fails even in comment '# cat("toto\n")'
|
4
|
+
|
5
|
+
module R2rb
|
6
|
+
|
7
|
+
def R2rb.init(args=["--save","--slave","--quiet"])
|
8
|
+
@@initR=R2rb.initR(args) unless R2rb.alive?
|
9
|
+
end
|
10
|
+
|
11
|
+
def R2rb.alive?
|
12
|
+
defined? @@initR
|
13
|
+
end
|
14
|
+
|
15
|
+
class RBuffer
|
16
|
+
def initialize
|
17
|
+
@s=String.new
|
18
|
+
end
|
19
|
+
|
20
|
+
def init
|
21
|
+
R2rb.init
|
22
|
+
end
|
23
|
+
|
24
|
+
def clear
|
25
|
+
@s=""
|
26
|
+
end
|
27
|
+
|
28
|
+
def +(s=nil)
|
29
|
+
if s
|
30
|
+
s=s.to_s unless s.is_a? String
|
31
|
+
@s += "\n"+s
|
32
|
+
else
|
33
|
+
clear
|
34
|
+
end
|
35
|
+
return self
|
36
|
+
end
|
37
|
+
|
38
|
+
def exec(aff=nil)
|
39
|
+
R2rb.eval @s,aff
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
=begin
|
44
|
+
class RVector
|
45
|
+
def <<(name)
|
46
|
+
if name.is_a? Symbol
|
47
|
+
@name=name.to_s
|
48
|
+
@type="var"
|
49
|
+
else
|
50
|
+
@name=name
|
51
|
+
@type="expr"
|
52
|
+
end
|
53
|
+
return self
|
54
|
+
end
|
55
|
+
|
56
|
+
def >(arr)
|
57
|
+
arr.replace(self.get)
|
58
|
+
return self
|
59
|
+
end
|
60
|
+
end
|
61
|
+
=end
|
62
|
+
|
63
|
+
class RConsole
|
64
|
+
def initialize
|
65
|
+
require "readline"
|
66
|
+
end
|
67
|
+
|
68
|
+
def init args
|
69
|
+
R2rb.init args
|
70
|
+
end
|
71
|
+
|
72
|
+
def exec
|
73
|
+
#todo : continuation
|
74
|
+
toggle=true
|
75
|
+
fin=false
|
76
|
+
words=[]
|
77
|
+
rvect=R2rb::RVector.new("")
|
78
|
+
Readline.completion_proc=Proc.new {|e|
|
79
|
+
cpt=0
|
80
|
+
begin
|
81
|
+
begin
|
82
|
+
cpt += 1
|
83
|
+
toggle = !toggle
|
84
|
+
rvect << (toggle ? "apropos(" : "ls(pat=")+"'^"+e+"')" > words
|
85
|
+
res=words.map{|w| w[Regexp.new("^"+e+".*")]}-[nil]
|
86
|
+
end while res.empty? and cpt<3
|
87
|
+
res
|
88
|
+
rescue
|
89
|
+
warn("\r"+e+" not suitable for completion!!!")
|
90
|
+
[]
|
91
|
+
end
|
92
|
+
}
|
93
|
+
Readline.completion_append_character=""
|
94
|
+
begin
|
95
|
+
line = Readline.readline("R> ", true)
|
96
|
+
if !(fin = line=="quit")
|
97
|
+
R2rb.eval line,true
|
98
|
+
toggle=true
|
99
|
+
end
|
100
|
+
end until fin
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def find_installed_R
|
106
|
+
|
107
|
+
if RUBY_PLATFORM=~/mingw32/
|
108
|
+
ENV["R_HOME"]=`R RHOME`
|
109
|
+
elsif RUBY_PLATFORM=~/darwin/
|
110
|
+
ENV["R_HOME"]=`R RHOME`.strip
|
111
|
+
else
|
112
|
+
dirs=["/usr/lib/R","/usr/local/lib/R","/usr/lib64/R","/usr/local/lib64/R"]
|
113
|
+
|
114
|
+
dirs.each do |dir|
|
115
|
+
if FileTest.exists?(dir)
|
116
|
+
return dir
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
raise RuntimeError, "couldn't find R Home : R seems to be uninstalled!!"
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
ENV["R_HOME"]=`R RHOME`.strip.split("\n").select{|l| l=~/^\//}[0] unless `R RHOME`.empty?
|
126
|
+
|
127
|
+
ENV["R_HOME"]=find_installed_R unless ENV["R_HOME"]
|
data/lib/R4rb/robj.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module RObj
|
3
|
+
|
4
|
+
def RObj.<(rcode)
|
5
|
+
return (R2rb < rcode)
|
6
|
+
end
|
7
|
+
|
8
|
+
def RObj.class(rname)
|
9
|
+
RObj < "class(#{rname})"
|
10
|
+
end
|
11
|
+
|
12
|
+
def RObj.mode(rcode)
|
13
|
+
RObj < "mode(#{rcode})"
|
14
|
+
end
|
15
|
+
|
16
|
+
# temporary R object saved in ruby object!
|
17
|
+
def RObj.make(rcode,first=true)
|
18
|
+
mode=RObj.mode(rcode)
|
19
|
+
RObj < ".tmpRObj<-(#{rcode})" if first
|
20
|
+
code=(first ? ".tmpRObj" : rcode.dup)
|
21
|
+
if ['numeric','logical','complex','character'].include?(mode)
|
22
|
+
#if RObj.class(code)=="matrix"
|
23
|
+
return (RObj< rcode)
|
24
|
+
elsif mode=="list"
|
25
|
+
robj={}
|
26
|
+
tmpNames=RObj < "names(#{rcode})"
|
27
|
+
tmpNames.each_with_index do |nam,i|
|
28
|
+
key=(nam.empty? ? i : nam)
|
29
|
+
rkey=(nam.empty? ? i : "\""+nam+"\"")
|
30
|
+
robj[key]=RObj.make("#{rcode}[[#{rkey}]]",false)
|
31
|
+
end
|
32
|
+
return robj
|
33
|
+
else
|
34
|
+
return nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def RObj.<<(rcode)
|
39
|
+
RObj.make(rcode)
|
40
|
+
end
|
41
|
+
|
42
|
+
def RObj.exist?(rname)
|
43
|
+
RObj < "exists(\"#{rname}\")"
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|