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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +32 -0
  3. data/Rakefile +177 -0
  4. data/bin/galaaz +8 -0
  5. data/examples/50Plots_MasterList/scatter_plot.rb +51 -0
  6. data/examples/baseball.csv +1 -0
  7. data/examples/baseball.rb +16 -0
  8. data/examples/ggplot.rb +178 -0
  9. data/examples/islr/Figure.jpg +0 -0
  10. data/examples/islr/all.rb +32 -0
  11. data/examples/islr/ch2.spec.rb +148 -0
  12. data/examples/islr/ch3.spec.rb +28 -0
  13. data/examples/islr/ch3_boston.rb +77 -0
  14. data/examples/islr/ch3_multiple_regression.rb +36 -0
  15. data/examples/islr/ch6.spec.rb +64 -0
  16. data/examples/paper/paper.rb +36 -0
  17. data/examples/sthda_ggplot/README.md +38 -0
  18. data/examples/sthda_ggplot/all.rb +68 -0
  19. data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +52 -0
  20. data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +61 -0
  21. data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +77 -0
  22. data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +69 -0
  23. data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +69 -0
  24. data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +62 -0
  25. data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +55 -0
  26. data/examples/sthda_ggplot/one_variable_continuous/stat.rb +62 -0
  27. data/examples/sthda_ggplot/one_variable_discrete/bar.rb +54 -0
  28. data/examples/sthda_ggplot/qplots/box_violin_dot.rb +57 -0
  29. data/examples/sthda_ggplot/qplots/scatter_plots.rb +67 -0
  30. data/examples/sthda_ggplot/scatter_gg.rb +60 -0
  31. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +49 -0
  32. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +64 -0
  33. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +52 -0
  34. data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +65 -0
  35. data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +66 -0
  36. data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +83 -0
  37. data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +63 -0
  38. data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +85 -0
  39. data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +62 -0
  40. data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +75 -0
  41. data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +74 -0
  42. data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +55 -0
  43. data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +70 -0
  44. data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +40 -0
  45. data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +108 -0
  46. data/examples/subsetting.rb +372 -0
  47. data/lib/expression.rb +45 -0
  48. data/lib/galaaz.rb +27 -0
  49. data/lib/r.rb +118 -0
  50. data/lib/r_methods.rb +89 -0
  51. data/lib/rbinary_operators.rb +226 -0
  52. data/lib/rclosure.rb +34 -0
  53. data/lib/rdata_frame.rb +63 -0
  54. data/lib/renvironment.rb +34 -0
  55. data/lib/rexpression.rb +34 -0
  56. data/lib/rindexed_object.rb +68 -0
  57. data/lib/rlanguage.rb +64 -0
  58. data/lib/rlist.rb +72 -0
  59. data/lib/rmatrix.rb +38 -0
  60. data/lib/rmd_indexed_object.rb +43 -0
  61. data/lib/robject.rb +297 -0
  62. data/lib/rpkg.rb +53 -0
  63. data/lib/rsupport.rb +292 -0
  64. data/lib/rsupport_scope.rb +77 -0
  65. data/lib/rsymbol.rb +57 -0
  66. data/lib/ruby_callback.rb +83 -0
  67. data/lib/ruby_extensions.rb +74 -0
  68. data/lib/runary_operators.rb +58 -0
  69. data/lib/rvector.rb +117 -0
  70. data/r_requires/ggplot.rb +31 -0
  71. data/specs/all.rb +45 -0
  72. data/specs/r_dataframe.spec.rb +181 -0
  73. data/specs/r_eval.spec.rb +164 -0
  74. data/specs/r_function.spec.rb +105 -0
  75. data/specs/r_language.spec.rb +135 -0
  76. data/specs/r_list.spec.rb +129 -0
  77. data/specs/r_list_apply.spec.rb +99 -0
  78. data/specs/r_matrix.spec.rb +83 -0
  79. data/specs/r_vector_creation.spec.rb +99 -0
  80. data/specs/r_vector_functions.spec.rb +59 -0
  81. data/specs/r_vector_object.spec.rb +94 -0
  82. data/specs/r_vector_operators.spec.rb +174 -0
  83. data/specs/r_vector_subsetting.spec.rb +136 -0
  84. data/specs/tmp.rb +134 -0
  85. data/version.rb +2 -0
  86. metadata +198 -0
@@ -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
@@ -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
+
@@ -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'