galaaz 0.4.2 → 0.4.5

Sign up to get free protection for your applications and to get access to all the features.
Files changed (114) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +25 -0
  3. data/Rakefile +8 -0
  4. data/bin/gknit +9 -5
  5. data/bin/gstudio +4 -2
  6. data/bin/gstudio.rb +32 -2
  7. data/blogs/dev/dev.html +219 -34
  8. data/blogs/dev/dev.md +26 -26
  9. data/blogs/dev/dev_files/figure-html/bubble-1.png +0 -0
  10. data/blogs/dev/dev_files/figure-html/diverging_bar.png +0 -0
  11. data/blogs/dplyr/dplyr.rb +63 -0
  12. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -26
  13. data/blogs/galaaz_ggplot/galaaz_ggplot.aux +16 -17
  14. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  15. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +65 -31
  16. data/blogs/oh_my/not_so.rb +2342 -0
  17. data/blogs/oh_my/oh_my.Rmd +493 -0
  18. data/blogs/oh_my/oh_my.html +680 -0
  19. data/blogs/oh_my/oh_my.md +597 -0
  20. data/blogs/oh_my/old.Rmd +2100 -0
  21. data/blogs/ruby_plot/figures/facets_with_decorations.png +0 -0
  22. data/blogs/ruby_plot/figures/facets_with_jitter.png +0 -0
  23. data/blogs/ruby_plot/figures/final_box_plot.png +0 -0
  24. data/blogs/ruby_plot/figures/final_violin_plot.png +0 -0
  25. data/blogs/ruby_plot/figures/violin_with_jitter.png +0 -0
  26. data/blogs/ruby_plot/ruby_plot.Rmd +147 -122
  27. data/blogs/ruby_plot/ruby_plot.Rmd_external_figs +662 -0
  28. data/blogs/ruby_plot/ruby_plot.html +49 -54
  29. data/blogs/ruby_plot/ruby_plot.md +147 -122
  30. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  31. data/blogs/ruby_plot/ruby_plot.tex +776 -157
  32. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.svg +57 -0
  33. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.svg +106 -0
  34. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.svg +110 -0
  35. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.svg +174 -0
  36. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.svg +236 -0
  37. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  38. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.svg +296 -0
  39. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.svg +236 -0
  40. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.svg +218 -0
  41. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.svg +128 -0
  42. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.svg +150 -0
  43. data/examples/islr/ch2.spec.rb +21 -18
  44. data/examples/islr/ch3_boston.rb +14 -5
  45. data/examples/islr/ch3_multiple_regression.rb +2 -3
  46. data/examples/islr/ch6.spec.rb +1 -1
  47. data/examples/islr/x_y_rnorm.jpg +0 -0
  48. data/lib/R_interface/r.rb +14 -10
  49. data/lib/R_interface/r_libs.R +9 -0
  50. data/lib/R_interface/r_methods.rb +77 -6
  51. data/lib/R_interface/{expression.rb → r_module_s.rb} +13 -14
  52. data/lib/R_interface/rbinary_operators.rb +58 -71
  53. data/lib/R_interface/rdata_frame.rb +2 -1
  54. data/lib/R_interface/rdevices.R +4 -0
  55. data/lib/R_interface/rdevices.rb +1 -1
  56. data/lib/R_interface/renvironment.rb +34 -1
  57. data/lib/R_interface/rexpression.rb +108 -2
  58. data/lib/R_interface/rindexed_object.rb +3 -1
  59. data/lib/R_interface/rlanguage.rb +18 -2
  60. data/lib/R_interface/rmatrix.rb +14 -0
  61. data/lib/R_interface/rmd_indexed_object.rb +5 -1
  62. data/lib/R_interface/robject.rb +61 -23
  63. data/lib/R_interface/rsupport.rb +111 -53
  64. data/lib/R_interface/rsymbol.rb +6 -5
  65. data/lib/R_interface/ruby_extensions.rb +130 -4
  66. data/lib/R_interface/runary_operators.rb +35 -3
  67. data/lib/R_interface/rvector.rb +1 -0
  68. data/lib/galaaz.rb +0 -2
  69. data/lib/gknit/knitr_engine.rb +58 -4
  70. data/lib/gknit/ruby_engine.rb +5 -6
  71. data/lib/util/exec_ruby.rb +55 -9
  72. data/specs/all.rb +13 -3
  73. data/specs/figures/dose_len.png +0 -0
  74. data/specs/r_dataframe.spec.rb +49 -26
  75. data/specs/r_environment.spec.rb +140 -0
  76. data/specs/r_eval.spec.rb +0 -15
  77. data/specs/r_formula.spec.rb +232 -0
  78. data/specs/r_function.spec.rb +7 -8
  79. data/specs/r_list.spec.rb +4 -0
  80. data/specs/r_list_apply.spec.rb +11 -11
  81. data/specs/r_matrix.spec.rb +3 -3
  82. data/specs/{r_plots.spec.rb~ → r_nse.spec.rb} +29 -6
  83. data/specs/r_vector_creation.spec.rb +6 -0
  84. data/specs/r_vector_object.spec.rb +2 -2
  85. data/specs/r_vector_operators.spec.rb +3 -3
  86. data/specs/r_vector_subsetting.spec.rb +4 -4
  87. data/specs/ruby_expression.spec.rb +324 -0
  88. data/specs/tmp.rb +12 -524
  89. data/sty/galaaz.sty +71 -0
  90. data/version.rb +1 -1
  91. metadata +31 -41
  92. data/bin/gknit2~ +0 -6
  93. data/bin/ogk~ +0 -4
  94. data/bin/prepareR.rb~ +0 -1
  95. data/blogs/dev/dev.Rmd~ +0 -104
  96. data/blogs/galaaz_ggplot/galaaz_ggplot.dvi +0 -0
  97. data/blogs/galaaz_ggplot/midwest_external_png~ +0 -1
  98. data/blogs/gknit/gknit.Rmd~ +0 -184
  99. data/blogs/gknit/gknit.Rnd~ +0 -17
  100. data/blogs/gknit/model.rb~ +0 -46
  101. data/blogs/ruby_plot/ruby_plot.Rmd~ +0 -215
  102. data/examples/islr/Figure.jpg +0 -0
  103. data/examples/misc/moneyball.rb~ +0 -16
  104. data/examples/misc/subsetting.rb~ +0 -372
  105. data/lib/R/eng_ruby.R~ +0 -63
  106. data/lib/R_interface/capture_plot.rb~ +0 -23
  107. data/lib/R_interface/r.rb~ +0 -121
  108. data/lib/R_interface/rdevices.rb~ +0 -27
  109. data/lib/gknit.rb~ +0 -26
  110. data/lib/gknit/knitr_engine.rb~ +0 -102
  111. data/lib/gknit/ruby_engine.rb~ +0 -72
  112. data/lib/util/inline_file.rb~ +0 -23
  113. data/r_requires/knitr.rb~ +0 -4
  114. data/specs/r_language.spec.rb +0 -157
@@ -0,0 +1,493 @@
1
+ ---
2
+ title: "Extending R with classes, modules, procs, lambdas, oh my!"
3
+ author:
4
+ - "Rodrigo Botafogo"
5
+ - "Daniel Mossé - University of Pittsburgh"
6
+ tags: [Tech, Data Science, Ruby, R, GraalVM]
7
+ date: "November 19th, 2018"
8
+ output:
9
+ html_document:
10
+ self_contained: true
11
+ keep_md: true
12
+ pdf_document:
13
+ includes:
14
+ in_header: "../../sty/galaaz.sty"
15
+ keep_tex: yes
16
+ number_sections: yes
17
+ toc: true
18
+ toc_depth: 2
19
+ fontsize: 11pt
20
+ ---
21
+
22
+ ```{r setup, echo=FALSE}
23
+
24
+ ```
25
+
26
+ # Introduction
27
+
28
+ This paper introduces and compares Galaaz with R's S4. It is a shameless rip off of
29
+ ["A '(not so)' Short Introduction to S4"](https://cran.r-project.org/doc/contrib/Genolini-S4tutorialV0-5en.pdf) by Christophe Genolini and follows the same structure and examples presented there.
30
+
31
+ Galaaz is a Ruby Gem (library) that allows very tight integration between Ruby and R.
32
+ It's integration is much tigher and transparent from what one can get beetween RinRuby
33
+ or similar solutions in Python
34
+ such as [PypeR](https://pypi.python.org/pypi/PypeR/1.1.0), [rpy2](http://rpy2.bitbucket.org/)
35
+ and other similar solutions. Galaaz targets the GraalVM and it
36
+ integrates with FastR, a high performance R interpreter for the GraalVM.
37
+
38
+ GraalVM:
39
+
40
+
41
+ # Bases of Object Programming
42
+
43
+ In this paper, we will start our discussion from Part II of "The (not so) Short Introduction
44
+ to S4", which from now on we will reference as SS4 for "short S4". Interested readers are directed
45
+ to this paper to understand the motivation and examples in that paper. In this paper we will
46
+ present the S4 code from SS4 and then the same code in Ruby/Galaaz. We will not comment on the
47
+ S4 code, as all the comments can be found in SS4, we will only focus on the Ruby/Galaaz
48
+ description.
49
+
50
+ S4 defines classes by using the setClass function:
51
+
52
+ # Classes Declaration
53
+
54
+ ```
55
+ # > setClass(
56
+ # + Class="Trajectories",
57
+ # + representation=representation(
58
+ # + times = "numeric",
59
+ # + traj = "matrix"
60
+ # + )
61
+ # + )
62
+ ```
63
+
64
+ # Instance Variables
65
+
66
+ In Ruby a class is defined by the keyword 'class'. Every class should start with a capital
67
+ letter. S4 'slots' are called 'instance variables' in Ruby. Differently from R's S4,
68
+ instance variables in Ruby do not have type information. It should be clear though, that S4
69
+ type information is also not a "compile" time type, since R is not compiled. The type is
70
+ checked at runtime. The same checking can be done in Ruby and we will do it later in this
71
+ document.
72
+
73
+ In the example bellow, we create
74
+ class Trajectories with two instance variables, 'times' and 'matrix'. We will not go over
75
+ the details of instance variables in Ruby, but here we created those variables with the
76
+ keyword 'attr_reader' and a colom before the variables name:
77
+
78
+
79
+ ```{ruby class_trajectories}
80
+ class Trajectories
81
+ attr_reader :times
82
+ attr_reader :matrix
83
+ end
84
+ ```
85
+
86
+
87
+ In order to create a new instance of object Trajectories we call method new on the class and
88
+ we can store the result in a varible (not an instance variable) as bellow:
89
+
90
+ ```{ruby traj_variable}
91
+ @traj = Trajectories.new
92
+ ```
93
+
94
+ We now have in variable '@traj' a Trajectories object. In Ruby, printing variable 'traj' will
95
+ only print the class name of the object and not it contents as in R.
96
+
97
+ ```{ruby traj_val}
98
+ puts @traj
99
+ ```
100
+
101
+ To see the contents of an object, one needs to access its components using the '.' operator:
102
+
103
+ ```{ruby traj_times}
104
+ puts @traj.times
105
+ ```
106
+
107
+ # Constructor
108
+
109
+ Since there is no content stored in 'times' nor 'matrix', nil is returned. In order to add
110
+ a value in the variables, we need to add a constructor to the class Trajectories. In R, a
111
+ constructor is build by default, in Ruby, this has to be created by adding a method called
112
+ 'initialize'. In the example bellow, we will create the initializer that accepts two values,
113
+ a 'times' value and a 'matrix' value and they are used to initialize the value of the
114
+ instance variables:
115
+
116
+ ```{ruby traj_initialize}
117
+ class Trajectories
118
+
119
+ attr_reader :times
120
+ attr_reader :matrix
121
+
122
+ #----------------------------------------------------------
123
+ # Initializes the Trajectories class. Takes two parameters
124
+ # @param times
125
+ # @param matrix
126
+ #----------------------------------------------------------
127
+
128
+ def initialize(times: nil, matrix: nil)
129
+ @times = times
130
+ @matrix = matrix
131
+ end
132
+
133
+ end
134
+ ```
135
+
136
+ Up to this point, everything described is pure Ruby code and has absolutely no relationship
137
+ with R.
138
+ We now want to create a Trajectories with a 'times' vector. Ruby has a vector class and we could
139
+ use this class to create a vector and add it to the 'times' instance variable; however, in order
140
+ to make use of R's functions, we want to create a R vector to add to 'times'. In Galaaz,
141
+ creating R objects is done using the corresponding R functions by just preceding them with 'R.',
142
+ i.e., R functions are all defined in Galaaz in the R namespace.
143
+
144
+ Since Galaaz is Ruby and not R, some syntax adjustments are sometimes necessary. For instance,
145
+ in R, a range is represented as '(1:4)', in Ruby, the same range is represented as '(1..4)'.
146
+ When passing arguments to an R function in R one uses the '=' sign after the slot name; in R,
147
+ one uses the ':' operator after parameter's name as we can see bellow:
148
+
149
+ ```{ruby initializing_trajectories}
150
+ # Create a Trajectories passing a times vector, but no matrix parameter
151
+ @traj = Trajectories.new(times: R.c(1, 2, 3, 4))
152
+
153
+ # Create a Trajectories with times and matrix
154
+ @traj2 = Trajectories.new(times: R.c(1, 3), matrix: R.matrix((1..4), ncol: 2))
155
+ ```
156
+
157
+ # Access to Instance Variables (to reach a slot)
158
+
159
+ In order to access data in an instance variable the operator '.' is used. In R, a similar
160
+ result is obtained by use of the '@' operator, but SS4 does not recommend its use. In Galaaz,
161
+ the '.' operator is the recommended way of accessing an instance variable.
162
+
163
+ Now that we have created two trajectories, let's try to print its instance variables to see
164
+ that everything is fine:
165
+
166
+
167
+ ```{ruby}
168
+ puts @traj.times
169
+ ```
170
+
171
+ We now have the expected value. Note that the 'times' vector is printed exactly as it would
172
+ if we were using GNU R. Let's now take a look at variable 'traj2':
173
+
174
+ ```{ruby}
175
+ puts @traj2.times
176
+ puts
177
+ puts @traj2.matrix
178
+ ```
179
+
180
+ Let's now build the same examples as in SS4: Three hospitals take part in a
181
+ study. The Pitié Salpêtriere (which has not yet returned its data file, shame on them!),
182
+ Cochin and Saint-Anne. We first show the code in R and the corresponding Galaaz:
183
+
184
+ ```
185
+ > trajPitie <- new(Class="Trajectories")
186
+ > trajCochin <- new(
187
+ + Class= "Trajectories",
188
+ + times=c(1,3,4,5),
189
+ + traj=rbind (
190
+ + c(15,15.1, 15.2, 15.2),
191
+ + c(16,15.9, 16,16.4),
192
+ + c(15.2, NA, 15.3, 15.3),
193
+ + c(15.7, 15.6, 15.8, 16)
194
+ + )
195
+ + )
196
+ > trajStAnne <- new(
197
+ + Class= "Trajectories",
198
+ + times=c(1: 10, (6: 16) *2),
199
+ + traj=rbind(
200
+ + matrix (seq (16,19, length=21), ncol=21, nrow=50, byrow=TRUE),
201
+ + matrix (seq (15.8, 18, length=21), ncol=21, nrow=30, byrow=TRUE)
202
+ + )+rnorm (21*80,0,0.2)
203
+ + )
204
+ ```
205
+
206
+ This same code in Galaaz becomes:
207
+
208
+ ```{ruby}
209
+ @trajPitie = Trajectories.new
210
+
211
+ @trajCochin = Trajectories.new(times: R.c(1,3,4,5),
212
+ matrix: R.rbind(
213
+ R.c(15,15.1, 15.2, 15.2),
214
+ R.c(16,15.9, 16,16.4),
215
+ R.c(15.2, R::NA, 15.3, 15.3),
216
+ R.c(15.7, 15.6, 15.8, 16)))
217
+
218
+ @trajStAnne =
219
+ Trajectories.new(times: R.c((1..10), R.c(6..16) * 2),
220
+ matrix: (R.rbind(
221
+ R.matrix(R.seq(16, 19, length: 21), ncol: 21,
222
+ nrow: 50, byrow: true),
223
+ R.matrix(R.seq(15.8, 18, length: 21), ncol: 21,
224
+ nrow: 30, byrow: true)) + R.rnorm(21*80, 0, 0.2)))
225
+
226
+ ```
227
+
228
+ Let's check that the 'times' and 'matrix' instance variables were correctly set:
229
+
230
+ ```{ruby}
231
+ puts @trajCochin.times
232
+ puts
233
+ puts @trajCochin.matrix
234
+ puts
235
+ puts @trajStAnne.times
236
+ ```
237
+
238
+ We will not at this time print trajStAnne.matrix, since this is a huge matrix and the result
239
+ would just take too much space. Later we will print just a partial view of the matrix.
240
+
241
+ # Default Values
242
+
243
+ Default values are very useful and quite often used in Ruby programs. Although SS4 does not
244
+ recommend its use, there are many cases in which default values are useful and make code simpler.
245
+ We have already seen default values in this document, with the default being 'nil'. This was
246
+ necessary in order to be able to create our constructor and passing it the proper values.
247
+
248
+ In the example bellow, a class TrajectoriesBis is created with default value 1 for times and a
249
+ matrix with no elements in matrix.
250
+
251
+ ```{ruby}
252
+ class TrajectoriesBis
253
+
254
+ attr_reader :times
255
+ attr_reader :matrix
256
+
257
+ #----------------------------------------------------------
258
+ # Initializes the Trajectories class. Takes two parameters
259
+ # @param times
260
+ # @param matrix
261
+ #----------------------------------------------------------
262
+
263
+ def initialize(times: 1, matrix: R.matrix(0))
264
+ @times = times
265
+ @matrix = matrix
266
+ end
267
+
268
+ end
269
+
270
+ @traj_bis = TrajectoriesBis.new
271
+ ```
272
+
273
+ Let's take a look at our new class:
274
+
275
+ ```{ruby}
276
+ puts @traj_bis.times
277
+ puts
278
+ puts @traj_bis.matrix
279
+ ```
280
+
281
+ Note that '@traj_bis.times' is the numeric 1, and what we actually want is a vector
282
+ with [1] in it.
283
+
284
+ ```{ruby}
285
+ class TrajectoriesBis
286
+
287
+ attr_reader :times
288
+ attr_reader :matrix
289
+
290
+ #----------------------------------------------------------
291
+ # Initializes the Trajectories class. Takes two parameters
292
+ # @param times [R::Vector] should be an R vector.
293
+ # @param matrix [R::Matrix] should be an R matrix.
294
+ #----------------------------------------------------------
295
+
296
+ # Use R.c to convert number 1 to a vector
297
+ def initialize(times: R.c(1), matrix: R.matrix(0))
298
+ @times = times
299
+ @matrix = matrix
300
+ end
301
+
302
+ end
303
+
304
+ @traj_bis = TrajectoriesBis.new
305
+ ```
306
+
307
+ ```{ruby}
308
+ puts @traj_bis.times
309
+ puts
310
+ puts @traj_bis.matrix
311
+ ```
312
+
313
+
314
+ # The Empty Object
315
+
316
+ When a Trajectories is created with new, and no argument is given, all its instance variables
317
+ will have the default nil value. Since Ruby has no type information, then there is only one
318
+ type (or actually no type) of nil. To check if a variable is empty, we check it against the nil
319
+ value.
320
+
321
+ # To See an Object
322
+
323
+ Ruby has very strong meta-programming features, in particular, one can use introspection to
324
+ see methods and instance variables from a given class. Method 'instance_variables' shows all
325
+ the instance variables of an object:
326
+
327
+ ```
328
+ puts @traj.instance_variables
329
+ ```
330
+
331
+ The description of all meta-programming features of Ruby is well beyond the scope of this
332
+ document, but it is a very frequent a powerful feature of Ruby, that makes programming in
333
+ Ruby a different experience than programming in other languages.
334
+
335
+ # Methods
336
+
337
+ Methods are a fundamental feature of object oriented programming. We will now extend our class
338
+ Trajectories to add methods to it. In SS4, a method 'plot' is added to Trajectories. At this
339
+ point, Renjin and Galaaz do not yet have plotting capabilities, so we will have to skip this
340
+ method and go directly to the implementation of the 'print' method.
341
+
342
+ Bellow is the R code for method print:
343
+
344
+ ```
345
+ > setMethod ("print","Trajectories",
346
+ + function(x,...){
347
+ + cat("*** Class Trajectories, method Print *** \\n")
348
+ + cat("* Times ="); print (x@times)
349
+ + cat("* Traj = \\n"); print (x@traj)
350
+ + cat("******* End Print (trajectories) ******* \\n")
351
+ + }
352
+ + )
353
+ ```
354
+
355
+ Now the same code for class Trajectories in Galaaz. In general methods are defined in a class
356
+ together with all the class definition. We will first use this approach. Later, we will show
357
+ how to 'reopen' a class to add new methods to it.
358
+
359
+ In this example, we are defining a method named 'print'. We have being using method 'puts' to
360
+ output data. There is a Ruby method that is more flexible than puts and that we need to use to
361
+ implement our function: 'print'. However, trying to use Ruby print inside the definition of
362
+ Trajectories's print will not work, as Ruby will understand that as a recursive call to print.
363
+ Ruby's print is defined inside the Kernel class, so, in order to call Ruby's print inside the
364
+ definition of Trajectories's print we need to write 'Kernel.print'.
365
+
366
+ ```{ruby}
367
+ class Trajectories
368
+
369
+ attr_reader :times
370
+ attr_reader :matrix
371
+
372
+
373
+ #----------------------------------------------------------
374
+ # Initializes the Trajectories class. Takes two parameters
375
+ # @param times [R::Vector] should be an R vector.
376
+ # @param matrix [R::Matrix] should be an R matrix.
377
+ #----------------------------------------------------------
378
+
379
+ def initialize(times: nil, matrix: nil)
380
+ @times = times
381
+ @matrix = matrix
382
+ end
383
+
384
+ #----------------------------------------------------------
385
+ #
386
+ #----------------------------------------------------------
387
+
388
+ def print
389
+ puts("*** Class Trajectories, method Print *** ")
390
+ Kernel.print("times = ")
391
+ puts @times
392
+ puts("traj =")
393
+ puts @matrix
394
+ puts("******* End Print (trajectories) ******* ")
395
+ end
396
+
397
+ end
398
+ ```
399
+
400
+ ```{ruby puts_trajCochin}
401
+ @trajCochin.print
402
+ ```
403
+
404
+ For Cochin, the result is correct. For Saint-Anne, print will display too much
405
+ information. So we need a second method.
406
+
407
+ Show is the default R method used to show an object when its name is written in the
408
+ console. We thus define 'show' by taking into account the size of the object: if there are too
409
+ many trajectories, 'show' posts only part of them.
410
+
411
+ Here is the R code for method 'show':
412
+
413
+ ```
414
+ > setMethod("show","Trajectories",
415
+ + function(object){
416
+ + cat("*** Class Trajectories, method Show *** \\n")
417
+ + cat("* Times ="); print(object@times)
418
+ + nrowShow <- min(10,nrow(object@traj))
419
+ + ncolShow <- min(10,ncol(object@traj))
420
+ + cat("* Traj (limited to a matrix 10x10) = \\n")
421
+ + print(formatC(object@traj[1:nrowShow,1:ncolShow]),quote=FALSE)
422
+ + cat("******* End Show (trajectories) ******* \\n")
423
+ + }
424
+ + )
425
+ ```
426
+
427
+ Now, let's write it with Galaaz. This time though, we will not rewrite the whole Trajectories
428
+ class, but just reopen it to add this specific method. The next example has many interesting
429
+ features of Galaaz, some we have already seen, others will be described now:
430
+
431
+ * As we have already seen, to call an R function one uses the R.<function> notation. There
432
+ is however another way: when the first argument to the R function is an R object such as a
433
+ matrix, a list, a vector, etc. we can use '.' notation to call the function. This makes the
434
+ function look like a method of the object. For instance, R.nrow(@matrix), can be called by
435
+ doing @matrix.nrow;
436
+
437
+ * In R, every number is converted to a vector and this can be done with method R.i. Converting
438
+ a vector with only one number back to a number can be done with method '.gz'. So if @num is
439
+ an R vector that holds a number, then @num.gz is a number that can be used normally with Ruby
440
+ methods;
441
+
442
+ * R functions and Ruby methods can be used freely in Galaaz. We show bellow two different ways
443
+ of getting the minimum of a number, either by calling R.min or by getting the minimum of an
444
+ array, with the min method;
445
+
446
+ * Galaaz allows for method 'chaining'. Method chaining, also known as named parameter idiom, is
447
+ a common syntax for invoking multiple method calls in object-oriented programming languages.
448
+ Each method returns an object, allowing the calls to be chained together in a single statement
449
+ without requiring variables to store the intermediate results. For instance @matrix.nrow.gz,
450
+ which returns the number of rows of the matrix as a number;
451
+
452
+ * Ranges in Ruby are represented by (x..y), where x is the beginning of the range and y its end.
453
+ An R matrix can be indexed by range, object@traj[1:nrowShow,1:ncolShow], the same result is
454
+ obtained in Galaaz by indexing @matrix[(1..nrow_show), (1..ncol_show)]. Observe that this
455
+ statement is then chained with the format function and with the pp method to print the matrix.
456
+
457
+
458
+ ```{ruby}
459
+ class Trajectories
460
+
461
+ #----------------------------------------------------------
462
+ #
463
+ #----------------------------------------------------------
464
+
465
+ def show
466
+ puts("*** Class Trajectories, method Show *** ")
467
+ Kernel.print("times = ")
468
+ puts @times
469
+ nrow_show = [10, @matrix.nrow << 0].min
470
+ ncol_show = R.min(10, @matrix.ncol) << 0
471
+ puts("* Traj (limited to a matrix 10x10) = ")
472
+ puts @matrix[(1..nrow_show), (1..ncol_show)].format(digits: 2, nsmall: 2)
473
+ puts("******* End Show (trajectories) ******* ")
474
+ end
475
+
476
+ end
477
+ ```
478
+
479
+ ```{ruby}
480
+ @trajStAnne.show
481
+ ```
482
+
483
+ Our show method has the same problem as SS4, i.e., if an empty trajectories object is created and
484
+ we try to 'show' it, it will generate an error. Let's see it:
485
+
486
+ ```{ruby}
487
+ @empty_traj = Trajectories.new
488
+ ```
489
+
490
+ ```{ruby eval_error, warning = FALSE}
491
+ @empty_traj.show
492
+ ```
493
+