galaaz 0.4.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/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'
|