galaaz 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +32 -0
- data/Rakefile +177 -0
- data/bin/galaaz +8 -0
- data/examples/50Plots_MasterList/scatter_plot.rb +51 -0
- data/examples/baseball.csv +1 -0
- data/examples/baseball.rb +16 -0
- data/examples/ggplot.rb +178 -0
- data/examples/islr/Figure.jpg +0 -0
- data/examples/islr/all.rb +32 -0
- data/examples/islr/ch2.spec.rb +148 -0
- data/examples/islr/ch3.spec.rb +28 -0
- data/examples/islr/ch3_boston.rb +77 -0
- data/examples/islr/ch3_multiple_regression.rb +36 -0
- data/examples/islr/ch6.spec.rb +64 -0
- data/examples/paper/paper.rb +36 -0
- data/examples/sthda_ggplot/README.md +38 -0
- data/examples/sthda_ggplot/all.rb +68 -0
- data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +52 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +61 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +77 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +69 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +69 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +62 -0
- data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +55 -0
- data/examples/sthda_ggplot/one_variable_continuous/stat.rb +62 -0
- data/examples/sthda_ggplot/one_variable_discrete/bar.rb +54 -0
- data/examples/sthda_ggplot/qplots/box_violin_dot.rb +57 -0
- data/examples/sthda_ggplot/qplots/scatter_plots.rb +67 -0
- data/examples/sthda_ggplot/scatter_gg.rb +60 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +49 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +64 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +52 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +65 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +66 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +83 -0
- data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +63 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +85 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +62 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +75 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +74 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +55 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +70 -0
- data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +40 -0
- data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +108 -0
- data/examples/subsetting.rb +372 -0
- data/lib/expression.rb +45 -0
- data/lib/galaaz.rb +27 -0
- data/lib/r.rb +118 -0
- data/lib/r_methods.rb +89 -0
- data/lib/rbinary_operators.rb +226 -0
- data/lib/rclosure.rb +34 -0
- data/lib/rdata_frame.rb +63 -0
- data/lib/renvironment.rb +34 -0
- data/lib/rexpression.rb +34 -0
- data/lib/rindexed_object.rb +68 -0
- data/lib/rlanguage.rb +64 -0
- data/lib/rlist.rb +72 -0
- data/lib/rmatrix.rb +38 -0
- data/lib/rmd_indexed_object.rb +43 -0
- data/lib/robject.rb +297 -0
- data/lib/rpkg.rb +53 -0
- data/lib/rsupport.rb +292 -0
- data/lib/rsupport_scope.rb +77 -0
- data/lib/rsymbol.rb +57 -0
- data/lib/ruby_callback.rb +83 -0
- data/lib/ruby_extensions.rb +74 -0
- data/lib/runary_operators.rb +58 -0
- data/lib/rvector.rb +117 -0
- data/r_requires/ggplot.rb +31 -0
- data/specs/all.rb +45 -0
- data/specs/r_dataframe.spec.rb +181 -0
- data/specs/r_eval.spec.rb +164 -0
- data/specs/r_function.spec.rb +105 -0
- data/specs/r_language.spec.rb +135 -0
- data/specs/r_list.spec.rb +129 -0
- data/specs/r_list_apply.spec.rb +99 -0
- data/specs/r_matrix.spec.rb +83 -0
- data/specs/r_vector_creation.spec.rb +99 -0
- data/specs/r_vector_functions.spec.rb +59 -0
- data/specs/r_vector_object.spec.rb +94 -0
- data/specs/r_vector_operators.spec.rb +174 -0
- data/specs/r_vector_subsetting.spec.rb +136 -0
- data/specs/tmp.rb +134 -0
- data/version.rb +2 -0
- metadata +198 -0
data/lib/robject.rb
ADDED
@@ -0,0 +1,297 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
##########################################################################################
|
4
|
+
# @author Rodrigo Botafogo
|
5
|
+
#
|
6
|
+
# Copyright © 2018 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
|
7
|
+
# and distribute this software and its documentation, without fee and without a signed
|
8
|
+
# licensing agreement, is hereby granted, provided that the above copyright notice, this
|
9
|
+
# paragraph and the following two paragraphs appear in all copies, modifications, and
|
10
|
+
# distributions.
|
11
|
+
#
|
12
|
+
# IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
|
13
|
+
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
|
14
|
+
# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
|
15
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
16
|
+
#
|
17
|
+
# RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
18
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
19
|
+
# SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
|
20
|
+
# RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
21
|
+
# OR MODIFICATIONS.
|
22
|
+
##########################################################################################
|
23
|
+
|
24
|
+
require_relative 'r_methods'
|
25
|
+
|
26
|
+
module R
|
27
|
+
|
28
|
+
#--------------------------------------------------------------------------------------
|
29
|
+
#
|
30
|
+
#--------------------------------------------------------------------------------------
|
31
|
+
|
32
|
+
class Object
|
33
|
+
|
34
|
+
attr_reader :r_interop
|
35
|
+
attr_accessor :statement
|
36
|
+
|
37
|
+
#--------------------------------------------------------------------------------------
|
38
|
+
#
|
39
|
+
#--------------------------------------------------------------------------------------
|
40
|
+
|
41
|
+
def initialize(r_interop)
|
42
|
+
@r_interop = r_interop
|
43
|
+
end
|
44
|
+
|
45
|
+
#--------------------------------------------------------------------------------------
|
46
|
+
#
|
47
|
+
#--------------------------------------------------------------------------------------
|
48
|
+
|
49
|
+
def as__data__frame
|
50
|
+
R.as__data__frame.call(@r_interop)
|
51
|
+
end
|
52
|
+
|
53
|
+
#--------------------------------------------------------------------------------------
|
54
|
+
# @param r_interop [Interop] pointer to an R object
|
55
|
+
# @return the R object wrapped in a Ruby class
|
56
|
+
#--------------------------------------------------------------------------------------
|
57
|
+
|
58
|
+
def self.build(r_interop)
|
59
|
+
|
60
|
+
# if the value is actually not an r_interop, then just return it: native Ruby
|
61
|
+
# object
|
62
|
+
if (!Truffle::Interop.foreign?(r_interop))
|
63
|
+
return r_interop
|
64
|
+
# a matrix is also a vector... test should come before
|
65
|
+
elsif (R::Support.eval("is.matrix").call(r_interop) == true)
|
66
|
+
Matrix.new(r_interop)
|
67
|
+
elsif (R::Support.eval("is.atomic").call(r_interop) == true)
|
68
|
+
Vector.new(r_interop)
|
69
|
+
elsif (R::Support.eval("is.function").call(r_interop) == true)
|
70
|
+
Closure.new(r_interop)
|
71
|
+
elsif (R::Support.eval("is.data.frame").call(r_interop) == true)
|
72
|
+
DataFrame.new(r_interop)
|
73
|
+
elsif (R::Support.eval("is.list").call(r_interop) == true)
|
74
|
+
List.new(r_interop)
|
75
|
+
elsif (R::Support.eval("typeof").call(r_interop) == "language")
|
76
|
+
Language.new(r_interop)
|
77
|
+
elsif (R::Support.eval("typeof").call(r_interop) == "expression")
|
78
|
+
RExpression.new(r_interop)
|
79
|
+
elsif (R::Support.eval("typeof").call(r_interop) == "name")
|
80
|
+
p "i'm of type name"
|
81
|
+
Name.new(r_interop)
|
82
|
+
elsif (R::Support.eval("typeof").call(r_interop) == "symbol")
|
83
|
+
RSymbol.new(r_interop)
|
84
|
+
elsif (R::Support.eval("typeof").call(r_interop) == "environment")
|
85
|
+
Environment.new(r_interop)
|
86
|
+
else # Generic type
|
87
|
+
p "Generic type: #{R::Support.eval("typeof").call(r_interop).to_s}"
|
88
|
+
r_interop
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
#--------------------------------------------------------------------------------------
|
94
|
+
#
|
95
|
+
#--------------------------------------------------------------------------------------
|
96
|
+
|
97
|
+
def method_missing_assign(column_name, arg)
|
98
|
+
return setR_name("`[<-`", R.empty_symbol, column_name, arg)
|
99
|
+
end
|
100
|
+
|
101
|
+
#--------------------------------------------------------------------------------------
|
102
|
+
#
|
103
|
+
#--------------------------------------------------------------------------------------
|
104
|
+
|
105
|
+
def method_missing(symbol, *args, &block)
|
106
|
+
|
107
|
+
name = R::Support.convert_symbol2r(symbol)
|
108
|
+
|
109
|
+
case
|
110
|
+
when block_given?
|
111
|
+
R::Support.new_scope(symbol, self, *args, &block)
|
112
|
+
when name =~ /(.*)=$/
|
113
|
+
method_missing_assign($1, args[0])
|
114
|
+
when name == "eval"
|
115
|
+
# R function 'eval' needs to be called in a special way, since it expects
|
116
|
+
# the second argument to be an environment. If the arguments are packed
|
117
|
+
# into a list, then there is no second argument and the function fails to
|
118
|
+
# use the second argument as environment
|
119
|
+
R::Support.r_evaluate(r_interop, *args)
|
120
|
+
when args.length == 0
|
121
|
+
# no arguments: 2 options: either a named item of the object or apply the function
|
122
|
+
# to the object
|
123
|
+
# if name is a named item of the object, then return the named item
|
124
|
+
named = R::Support.eval("`%in%`").
|
125
|
+
call(name, R::Support.eval("names").call(@r_interop))
|
126
|
+
(false === named || !(true === named || named[0])) ?
|
127
|
+
R::Support.exec_function_name(name, @r_interop) :
|
128
|
+
R::Support.exec_function_name("`[[`", @r_interop, name)
|
129
|
+
else
|
130
|
+
args.unshift(@r_interop)
|
131
|
+
R::Support.exec_function_name(name, *args)
|
132
|
+
end
|
133
|
+
|
134
|
+
end
|
135
|
+
|
136
|
+
#----------------------------------------------------------------------------------------
|
137
|
+
# We use the following notation to access binary R functions such as %in%:
|
138
|
+
# R.vec_ "in", list.
|
139
|
+
# @param args [Array] The first element of the array is an R infix function, the other
|
140
|
+
# arguments are the list of arguments for the function.
|
141
|
+
#----------------------------------------------------------------------------------------
|
142
|
+
|
143
|
+
def _(*args)
|
144
|
+
name = "`%#{args.shift.to_s}%`"
|
145
|
+
args.unshift(@r_interop)
|
146
|
+
R::Support.exec_function_name(name, *args)
|
147
|
+
end
|
148
|
+
|
149
|
+
#--------------------------------------------------------------------------------------
|
150
|
+
# Sets the current object self interop pointer to the returned value of the execution
|
151
|
+
# of the given method with arguments. This method should be called when R will copy
|
152
|
+
# the parameter, but in Ruby we want to hide the copying.
|
153
|
+
# @param [Interop] Interop pointer to R function
|
154
|
+
# @param [Array] Array of arguments
|
155
|
+
#--------------------------------------------------------------------------------------
|
156
|
+
|
157
|
+
def setR(method, *args)
|
158
|
+
@r_interop = R::Support.exec_function_i(method, @r_interop, *args)
|
159
|
+
self
|
160
|
+
end
|
161
|
+
|
162
|
+
#--------------------------------------------------------------------------------------
|
163
|
+
#
|
164
|
+
#--------------------------------------------------------------------------------------
|
165
|
+
|
166
|
+
def setR_name(method_name, *args)
|
167
|
+
method = R::Support.eval(method_name)
|
168
|
+
setR(method, *args)
|
169
|
+
self
|
170
|
+
end
|
171
|
+
|
172
|
+
#--------------------------------------------------------------------------------------
|
173
|
+
# Sets the names attribute of the object
|
174
|
+
# @param [R::Object] names_vector is an RVector with the list of names.
|
175
|
+
#--------------------------------------------------------------------------------------
|
176
|
+
|
177
|
+
def names=(names_vector)
|
178
|
+
setR_name("`names<-`", names_vector)
|
179
|
+
end
|
180
|
+
|
181
|
+
def names(*args)
|
182
|
+
return R::Support.exec_function_name("names", @r_interop) if (args.length == 0)
|
183
|
+
setR_name("`names<-`", *args)
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
#--------------------------------------------------------------------------------------
|
188
|
+
#
|
189
|
+
#--------------------------------------------------------------------------------------
|
190
|
+
|
191
|
+
def rclass=(class_name)
|
192
|
+
setR_name("`class<-`", class_name)
|
193
|
+
end
|
194
|
+
|
195
|
+
def rclass
|
196
|
+
R::Support.exec_function_name("class", @r_interop)
|
197
|
+
end
|
198
|
+
|
199
|
+
#--------------------------------------------------------------------------------------
|
200
|
+
#
|
201
|
+
#--------------------------------------------------------------------------------------
|
202
|
+
|
203
|
+
def comment=(comment_text)
|
204
|
+
setR_name("`comment<-`", comment_text)
|
205
|
+
end
|
206
|
+
|
207
|
+
def comment
|
208
|
+
R::Support.exec_function_name("comment", @r_interop)
|
209
|
+
end
|
210
|
+
|
211
|
+
#--------------------------------------------------------------------------------------
|
212
|
+
#
|
213
|
+
#--------------------------------------------------------------------------------------
|
214
|
+
|
215
|
+
def dim=(numeric_vector)
|
216
|
+
setR_name("`dim<-`", numeric_vector)
|
217
|
+
end
|
218
|
+
|
219
|
+
def dim
|
220
|
+
R::Support.exec_function_name("dim", @r_interop)
|
221
|
+
end
|
222
|
+
|
223
|
+
#--------------------------------------------------------------------------------------
|
224
|
+
#
|
225
|
+
#--------------------------------------------------------------------------------------
|
226
|
+
|
227
|
+
def dimnames=(names_vector)
|
228
|
+
setR_name("`dimnames<-`", names_vector)
|
229
|
+
end
|
230
|
+
|
231
|
+
def dimnames
|
232
|
+
R::Support.exec_function_name("dimnames", @r_interop)
|
233
|
+
end
|
234
|
+
|
235
|
+
#--------------------------------------------------------------------------------------
|
236
|
+
# @bug Needed to create method R.row__names because dispatch is not working properly
|
237
|
+
#--------------------------------------------------------------------------------------
|
238
|
+
|
239
|
+
def row__names
|
240
|
+
R::Support.exec_function(R::Support.get_row_names, @r_interop)
|
241
|
+
end
|
242
|
+
|
243
|
+
# since we need to call a method and the method changes the object, then we need to
|
244
|
+
# change our internal pointer also @r_interop. Ideally, just setting the row.names
|
245
|
+
# should work.
|
246
|
+
def row__names=(names_vector)
|
247
|
+
@r_interop = R::Support.set_row_names.call(@r_interop, names_vector.r_interop)
|
248
|
+
self
|
249
|
+
end
|
250
|
+
|
251
|
+
#--------------------------------------------------------------------------------------
|
252
|
+
#
|
253
|
+
#--------------------------------------------------------------------------------------
|
254
|
+
|
255
|
+
def tsp=(numeric_vector)
|
256
|
+
setR_name("`tsp<-`", numeric_vector)
|
257
|
+
end
|
258
|
+
|
259
|
+
def tsp
|
260
|
+
R::Support.exec_function_name("tsp", @r_interop)
|
261
|
+
end
|
262
|
+
|
263
|
+
#--------------------------------------------------------------------------------------
|
264
|
+
#
|
265
|
+
#--------------------------------------------------------------------------------------
|
266
|
+
|
267
|
+
def attr=(which: w, value: v)
|
268
|
+
value = (R::Support.interop(value) ? value.r_interop : value)
|
269
|
+
# setR(@@set_attr, which, value)
|
270
|
+
setR_name("`attr<-`", which, value)
|
271
|
+
end
|
272
|
+
|
273
|
+
#--------------------------------------------------------------------------------------
|
274
|
+
#
|
275
|
+
#--------------------------------------------------------------------------------------
|
276
|
+
|
277
|
+
def pp
|
278
|
+
R.print(r_interop)
|
279
|
+
end
|
280
|
+
|
281
|
+
#--------------------------------------------------------------------------------------
|
282
|
+
#
|
283
|
+
#--------------------------------------------------------------------------------------
|
284
|
+
|
285
|
+
def to_s
|
286
|
+
cap = R::Support.capture.call(r_interop)
|
287
|
+
str = String.new
|
288
|
+
(0...(cap.size - 1)).each do |i|
|
289
|
+
str << cap[i] << "\n"
|
290
|
+
end
|
291
|
+
str << cap[cap.size - 1] if cap.size >= 1
|
292
|
+
str
|
293
|
+
end
|
294
|
+
|
295
|
+
end
|
296
|
+
|
297
|
+
end
|
data/lib/rpkg.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
##########################################################################################
|
4
|
+
# @author Rodrigo Botafogo
|
5
|
+
#
|
6
|
+
# Copyright © 2018 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
|
7
|
+
# and distribute this software and its documentation, without fee and without a signed
|
8
|
+
# licensing agreement, is hereby granted, provided that the above copyright notice, this
|
9
|
+
# paragraph and the following two paragraphs appear in all copies, modifications, and
|
10
|
+
# distributions.
|
11
|
+
#
|
12
|
+
# IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
|
13
|
+
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
|
14
|
+
# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
|
15
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
16
|
+
#
|
17
|
+
# RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
18
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
19
|
+
# SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
|
20
|
+
# RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
21
|
+
# OR MODIFICATIONS.
|
22
|
+
##########################################################################################
|
23
|
+
|
24
|
+
|
25
|
+
module R
|
26
|
+
|
27
|
+
#----------------------------------------------------------------------------------------
|
28
|
+
#
|
29
|
+
#----------------------------------------------------------------------------------------
|
30
|
+
|
31
|
+
class Pkg
|
32
|
+
|
33
|
+
def initialize(pkg_name)
|
34
|
+
@pkg_name = pkg_name
|
35
|
+
end
|
36
|
+
|
37
|
+
def method_missing(symbol, *args)
|
38
|
+
p "execute #{@pkg_name}.#{symbol}(#{args})"
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
#----------------------------------------------------------------------------------------
|
44
|
+
#
|
45
|
+
#----------------------------------------------------------------------------------------
|
46
|
+
|
47
|
+
def self.const_missing(name)
|
48
|
+
p name
|
49
|
+
Pkg.new(name)
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
data/lib/rsupport.rb
ADDED
@@ -0,0 +1,292 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
|
3
|
+
##########################################################################################
|
4
|
+
# @author Rodrigo Botafogo
|
5
|
+
#
|
6
|
+
# Copyright © 2018 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
|
7
|
+
# and distribute this software and its documentation, without fee and without a signed
|
8
|
+
# licensing agreement, is hereby granted, provided that the above copyright notice, this
|
9
|
+
# paragraph and the following two paragraphs appear in all copies, modifications, and
|
10
|
+
# distributions.
|
11
|
+
#
|
12
|
+
# IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
|
13
|
+
# INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
|
14
|
+
# THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
|
15
|
+
# POSSIBILITY OF SUCH DAMAGE.
|
16
|
+
#
|
17
|
+
# RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
|
18
|
+
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
|
19
|
+
# SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
|
20
|
+
# RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
21
|
+
# OR MODIFICATIONS.
|
22
|
+
##########################################################################################
|
23
|
+
|
24
|
+
|
25
|
+
module R
|
26
|
+
|
27
|
+
#--------------------------------------------------------------------------------------
|
28
|
+
# The empty_symbol is necessary to represent indexing with a missing argument such
|
29
|
+
# as [x, ]. What follows the ',' is an empty_symbol. Whenever we use in Ruby the
|
30
|
+
# :all symbol, it will be converted to an empty_symbol in R.
|
31
|
+
#--------------------------------------------------------------------------------------
|
32
|
+
|
33
|
+
@@empty_symbol = Polyglot.eval("R", <<-R)
|
34
|
+
__missing_arg = quote(f(,0));
|
35
|
+
__missing_arg[[2]]
|
36
|
+
R
|
37
|
+
|
38
|
+
def self.empty_symbol
|
39
|
+
@@empty_symbol
|
40
|
+
end
|
41
|
+
|
42
|
+
# When evaluating to NA, Interop treats it as FALSE. This breaks all expectations
|
43
|
+
# about NA. We need to protect NA from Interop unboxing. Class NotAvailable
|
44
|
+
# puts a list around NA, so that no unboxing occurs.
|
45
|
+
@na = Polyglot.eval("R", <<-R)
|
46
|
+
list(NA)
|
47
|
+
R
|
48
|
+
|
49
|
+
class NotAvailable < R::Object
|
50
|
+
end
|
51
|
+
|
52
|
+
NA = NotAvailable.new(@na)
|
53
|
+
|
54
|
+
#--------------------------------------------------------------------------------------
|
55
|
+
# This is a support module for evaluating R functions
|
56
|
+
#--------------------------------------------------------------------------------------
|
57
|
+
|
58
|
+
module Support
|
59
|
+
|
60
|
+
# Using this method gives us more control over what happens when calling do.call
|
61
|
+
# and allows for debugging. Use it in exec_function when debugging is needed.
|
62
|
+
@@exec_from_ruby = Polyglot.eval("R", <<-R)
|
63
|
+
function(build_method, ...) {
|
64
|
+
# print(build_method);
|
65
|
+
# args = list(...);
|
66
|
+
# print(args);
|
67
|
+
res = do.call(...);
|
68
|
+
# print(res);
|
69
|
+
res2 = build_method(res);
|
70
|
+
# print(res2);
|
71
|
+
res2
|
72
|
+
}
|
73
|
+
R
|
74
|
+
|
75
|
+
#----------------------------------------------------------------------------------------
|
76
|
+
# Evaluates an R code
|
77
|
+
# @param string [String] A string of R code that can be correctly parsed by R
|
78
|
+
#----------------------------------------------------------------------------------------
|
79
|
+
|
80
|
+
def self.eval(string)
|
81
|
+
Polyglot.eval("R", string)
|
82
|
+
end
|
83
|
+
|
84
|
+
#----------------------------------------------------------------------------------------
|
85
|
+
# @param object [Object] Any Ruby object
|
86
|
+
# @return boolean if the object is an interop or not
|
87
|
+
#----------------------------------------------------------------------------------------
|
88
|
+
|
89
|
+
def self.interop(object)
|
90
|
+
Truffle::Interop.foreign?(object)
|
91
|
+
end
|
92
|
+
|
93
|
+
#----------------------------------------------------------------------------------------
|
94
|
+
# @param arg [Object] A Ruby object to be converted to R to be used by an R function, or
|
95
|
+
# whatever needs it
|
96
|
+
# @return Object that can be used in R
|
97
|
+
#----------------------------------------------------------------------------------------
|
98
|
+
|
99
|
+
def self.parse_arg(arg)
|
100
|
+
|
101
|
+
case(arg)
|
102
|
+
when Truffle::Interop
|
103
|
+
arg
|
104
|
+
when R::Object
|
105
|
+
arg.r_interop
|
106
|
+
when NegRange
|
107
|
+
final_value = (arg.exclude_end?)? (arg.last - 1) : arg.last
|
108
|
+
R::Support.eval("seq").call(arg.first, final_value)
|
109
|
+
when Range
|
110
|
+
final_value = (arg.exclude_end?)? (arg.last - 1) : arg.last
|
111
|
+
R::Support.eval("seq").call(arg.first, final_value)
|
112
|
+
when :all
|
113
|
+
R.empty_symbol
|
114
|
+
when Symbol
|
115
|
+
arg = R::Support.eval("as.name").call(arg.to_s)
|
116
|
+
when Proc, Method
|
117
|
+
R::RubyCallback.build(arg)
|
118
|
+
else
|
119
|
+
arg
|
120
|
+
end
|
121
|
+
|
122
|
+
end
|
123
|
+
|
124
|
+
#----------------------------------------------------------------------------------------
|
125
|
+
# Parses the Ruby arguments into a R list of R objects
|
126
|
+
# @param args [Ruby Parameter list]
|
127
|
+
#----------------------------------------------------------------------------------------
|
128
|
+
|
129
|
+
def self.parse2list(*args)
|
130
|
+
|
131
|
+
params = Polyglot.eval("R", "list()")
|
132
|
+
|
133
|
+
args.each_with_index do |arg, i|
|
134
|
+
if (arg.is_a? Hash)
|
135
|
+
arg.each_pair do |key, value|
|
136
|
+
k = key.to_s.gsub(/__/,".")
|
137
|
+
# HAS CHANGED IN RC6... FIX THIS TO THE NEW API
|
138
|
+
# When evaluating to NA, Interop treats it as FALSE. This breaks
|
139
|
+
# all expectations about NA. We need to protect NA from Interop
|
140
|
+
# unboxing. Class NotAvailable
|
141
|
+
# puts a list around NA, so that no unboxing occurs. We need to treat this
|
142
|
+
# list here
|
143
|
+
if (value.is_a? NotAvailable)
|
144
|
+
# add the key as the name of the NA
|
145
|
+
na_named = R::Support.eval("`names<-`").call(value.r_interop, k)
|
146
|
+
params = R::Support.eval("c").call(params, na_named)
|
147
|
+
else
|
148
|
+
params = R::Support.eval("`[[<-`").
|
149
|
+
call(params, k, R::Support.parse_arg(value))
|
150
|
+
end
|
151
|
+
end
|
152
|
+
elsif (arg.is_a? NotAvailable)
|
153
|
+
params = R::Support.eval("c").call(params, arg.r_interop)
|
154
|
+
else
|
155
|
+
params = R::Support.eval("`[[<-`").
|
156
|
+
call(params, i+1, R::Support.parse_arg(arg))
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
params
|
161
|
+
|
162
|
+
end
|
163
|
+
|
164
|
+
#----------------------------------------------------------------------------------------
|
165
|
+
# Converts a Ruby symbol onto an R symbol. Converts '__' to '.' and 'rclass' to
|
166
|
+
# class
|
167
|
+
# @param symbol [Symbol] A Ruby symbol to convert to R
|
168
|
+
#----------------------------------------------------------------------------------------
|
169
|
+
|
170
|
+
def self.convert_symbol2r(symbol)
|
171
|
+
name = symbol.to_s
|
172
|
+
# convert '__' to '.'
|
173
|
+
name.gsub!(/__/,".")
|
174
|
+
# Method 'rclass' is a substitute for R method 'class'. Needed, as 'class' is also
|
175
|
+
# a Ruby method on an object
|
176
|
+
name.gsub!("rclass", "class")
|
177
|
+
name
|
178
|
+
end
|
179
|
+
|
180
|
+
#----------------------------------------------------------------------------------------
|
181
|
+
# Executes the given R function with the given arguments.
|
182
|
+
#----------------------------------------------------------------------------------------
|
183
|
+
|
184
|
+
def self.exec_function_i(function, *args)
|
185
|
+
pl = R::Support.parse2list(*args)
|
186
|
+
R::Support.eval("do.call").call(function, pl)
|
187
|
+
end
|
188
|
+
|
189
|
+
#----------------------------------------------------------------------------------------
|
190
|
+
# @param function [R function (Interop)] R function to execute
|
191
|
+
# @param internal [Boolean] true if returning to an internal object, i.e., does not
|
192
|
+
# wrap the return object in a Ruby object
|
193
|
+
# @args [Array] Array of arguments for the function
|
194
|
+
#----------------------------------------------------------------------------------------
|
195
|
+
|
196
|
+
def self.exec_function(function, *args)
|
197
|
+
# function has no arguments, call it directly
|
198
|
+
if (args.length == 0)
|
199
|
+
return R::Object.build(function.call) # if args.length == 0
|
200
|
+
end
|
201
|
+
|
202
|
+
pl = R::Support.parse2list(*args)
|
203
|
+
@@exec_from_ruby.call(R::Object.method(:build), function, pl)
|
204
|
+
# R::Object.build(R::Support.eval("do.call").call(function, pl))
|
205
|
+
end
|
206
|
+
|
207
|
+
#----------------------------------------------------------------------------------------
|
208
|
+
# @param function_name [String] Name of the R function to execute
|
209
|
+
# @param internal [Boolean] true if returning to an internal object, i.e., does not
|
210
|
+
# wrap the return object in a Ruby object
|
211
|
+
# @args [Array] Array of arguments for the function
|
212
|
+
#----------------------------------------------------------------------------------------
|
213
|
+
|
214
|
+
def self.exec_function_name(function_name, *args)
|
215
|
+
R::Support.exec_function(R::Support.eval(function_name), *args)
|
216
|
+
end
|
217
|
+
|
218
|
+
#----------------------------------------------------------------------------------------
|
219
|
+
# sets the R symbol <name> to the given value
|
220
|
+
# @param name [String] String representation of the R symbol that needs to be assigned
|
221
|
+
# @param args [Array] Array with one object to be set to the symbol
|
222
|
+
#----------------------------------------------------------------------------------------
|
223
|
+
|
224
|
+
def self.set_symbol(name, *args)
|
225
|
+
args << R::Support.eval("globalenv").call()
|
226
|
+
R::Support.exec_function_name("assign", name, *args)
|
227
|
+
end
|
228
|
+
|
229
|
+
#----------------------------------------------------------------------------------------
|
230
|
+
# Calls the R 'eval' function. This requires some special semantics
|
231
|
+
# R function 'eval' needs to be called in a special way, since it expects
|
232
|
+
# the second argument to be an environment. If the arguments are packed
|
233
|
+
# into a list, then there is no second argument and the function fails to
|
234
|
+
# use the second argument as environment
|
235
|
+
#----------------------------------------------------------------------------------------
|
236
|
+
|
237
|
+
def self.r_evaluate(*args)
|
238
|
+
r_args = args.map { |arg| R::Support.parse_arg(arg) }
|
239
|
+
R::Object.build(eval("eval").call(*r_args))
|
240
|
+
end
|
241
|
+
|
242
|
+
#----------------------------------------------------------------------------------------
|
243
|
+
# Process the missing method
|
244
|
+
# @param symbol [Symbol]
|
245
|
+
# @param internal [Boolean] true if the method will return to an internal method, i.e.,
|
246
|
+
# it should not wrap the return value inside an R::Object
|
247
|
+
# @param object [Ruby Object] the ruby object to which the method is applied, false if
|
248
|
+
# it is not applied to an object
|
249
|
+
#----------------------------------------------------------------------------------------
|
250
|
+
|
251
|
+
def self.process_missing(symbol, internal, *args)
|
252
|
+
|
253
|
+
name = R::Support.convert_symbol2r(symbol)
|
254
|
+
|
255
|
+
case name
|
256
|
+
# missing method has an '=' sign in it...
|
257
|
+
when ->(x) { x =~ /(.*)=$/ }
|
258
|
+
R::Support.set_symbol($1, *args)
|
259
|
+
# missing method is 'eval'... needs special treatment
|
260
|
+
when "eval"
|
261
|
+
R::Support.r_evaluate(*args)
|
262
|
+
else
|
263
|
+
function = R::Support.eval(name)
|
264
|
+
internal ? R::Support.exec_function_i(function, *args) :
|
265
|
+
R::Support.exec_function(function, *args)
|
266
|
+
end
|
267
|
+
|
268
|
+
end
|
269
|
+
|
270
|
+
#----------------------------------------------------------------------------------------
|
271
|
+
# Prints a foreign R interop pointer. Used for debug.
|
272
|
+
#----------------------------------------------------------------------------------------
|
273
|
+
|
274
|
+
def self.print_foreign(interop)
|
275
|
+
puts "===External value==="
|
276
|
+
R::Support.eval("print").call(interop)
|
277
|
+
puts "===end external value==="
|
278
|
+
end
|
279
|
+
|
280
|
+
class << self
|
281
|
+
alias :pf :print_foreign
|
282
|
+
end
|
283
|
+
|
284
|
+
#----------------------------------------------------------------------------------------
|
285
|
+
#
|
286
|
+
#----------------------------------------------------------------------------------------
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
292
|
+
require_relative 'rsupport_scope'
|