galaaz 2.1.7 → 2.1.8

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 (77) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +9 -0
  3. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +63 -58
  4. data/blogs/galaaz_ggplot/galaaz_ggplot.log +59 -68
  5. data/blogs/galaaz_ggplot/galaaz_ggplot.md +91 -84
  6. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +125 -94
  7. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  8. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  9. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  10. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  11. data/blogs/gknit/gknit.Rmd +33 -28
  12. data/blogs/gknit/gknit.md +47 -42
  13. data/blogs/gknit/gknit.tex +1368 -0
  14. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  15. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  16. data/blogs/gknit/gknit_files/figure-latex/bubble-1.png +0 -0
  17. data/blogs/gknit/gknit_files/gknit_files/figure-latex/bubble-1.png +0 -0
  18. data/blogs/manual/manual.Rmd +129 -60
  19. data/blogs/manual/manual.log +289 -545
  20. data/blogs/manual/manual.md +551 -467
  21. data/blogs/manual/manual.tex +1059 -485
  22. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  23. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  24. data/blogs/manual/manual_files/figure-markdown_github/bubble-1.png +0 -0
  25. data/blogs/manual/manual_files/figure-markdown_github/diverging_bar.png +0 -0
  26. data/blogs/manual/manual_files/manual_files/figure-latex/bubble-1.png +0 -0
  27. data/blogs/nse_dplyr/nse_dplyr.Rmd +28 -7
  28. data/blogs/nse_dplyr/nse_dplyr.log +49 -153
  29. data/blogs/nse_dplyr/nse_dplyr.md +676 -705
  30. data/blogs/nse_dplyr/nse_dplyr.tex +1589 -0
  31. data/blogs/oh_my/oh_my.Rmd +193 -55
  32. data/blogs/oh_my/oh_my.log +265 -95
  33. data/blogs/oh_my/oh_my.md +236 -95
  34. data/blogs/oh_my/oh_my.tex +1976 -68
  35. data/blogs/ruby_plot/ruby_plot.Rmd +42 -34
  36. data/blogs/ruby_plot/ruby_plot.log +101 -99
  37. data/blogs/ruby_plot/ruby_plot.md +52 -46
  38. data/blogs/ruby_plot/ruby_plot.tex +134 -102
  39. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  40. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  41. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  42. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  43. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  44. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  45. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  46. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  47. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  48. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  49. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  50. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  51. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  52. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  53. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  54. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  55. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  56. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  57. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  58. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  59. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  60. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  61. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/dose_len.png +0 -0
  62. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  63. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  64. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  65. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  66. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  67. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  68. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  72. data/lib/galaaz/cli.rb +51 -10
  73. data/script/omarchy/README.md +1 -1
  74. data/script/omarchy/galaaz-guide.sh +1 -1
  75. data/sty/galaaz.sty +22 -0
  76. data/version.rb +1 -1
  77. metadata +19 -1
@@ -165,6 +165,28 @@
165
165
  % Command to import an R variable to latex
166
166
  \newcommand{\RtoLatex}[2]{\newcommand{#1}{#2}}
167
167
 
168
+ % Soft-wrap Pandoc highlighted code/output boxes (Shaded + Highlighting).
169
+ % This runs after Pandoc's default \DefineVerbatimEnvironment{Highlighting}
170
+ % (header includes come later in the generated .tex). Prefer manual line
171
+ % breaks in Rmd sources; breaklines is a safety net for leftovers/output.
172
+ % Requires TinyTeX/TeX Live package: tlmgr install fvextra
173
+ \IfFileExists{fvextra.sty}{%
174
+ \usepackage{fvextra}%
175
+ \DefineVerbatimEnvironment{Highlighting}{Verbatim}{%
176
+ breaklines=true,
177
+ breakanywhere=true,
178
+ breakindent=1.5em,
179
+ fontsize=\small,
180
+ commandchars=\\\{\}%
181
+ }%
182
+ }{%
183
+ % fancyvrb is already loaded by Pandoc; shrink code so more fits per line.
184
+ \DefineVerbatimEnvironment{Highlighting}{Verbatim}{%
185
+ fontsize=\small,
186
+ commandchars=\\\{\}%
187
+ }%
188
+ }
189
+
168
190
  %
169
191
  %\newcommand{\atraso}[1]{\color{red} \textbf {Tempo desde a Assinatura do Contrato: #1 dias}}
170
192
  \usepackage{bookmark}
@@ -189,8 +211,8 @@
189
211
  }
190
212
  \section{Introduction}\label{introduction}
191
213
 
192
- This paper introduces and compares Galaaz with R's S4. It is a shameless
193
- rip off of
214
+ This paper introduces and compares Galaaz with R's S4. It is
215
+ \textbf{modeled closely} on
194
216
  \href{https://cran.r-project.org/doc/contrib/Genolini-S4tutorialV0-5en.pdf}{``A
195
217
  `(not so)' Short Introduction to S4''} by Christophe Genolini and
196
218
  follows the same structure and examples presented there.
@@ -202,13 +224,13 @@ between RinRuby or similar solutions in Python, such as
202
224
  \href{https://pypi.python.org/pypi/PypeR/1.1.0}{PypeR},
203
225
  \href{http://rpy2.bitbucket.org/}{rpy2} and other similar solutions.
204
226
 
205
- \textbf{Galaaz 2.0} runs on
206
- \textbf{\href{https://www.jruby.org/}{JRuby}} and drives \textbf{GNU R}
207
- through a \textbf{bridge}, so Ruby code can create and manipulate R
208
- objects and call R functions while staying idiomatic Ruby. An earlier
209
- prototype used Oracle's \textbf{GraalVM} with \textbf{TruffleRuby} and
210
- \textbf{FastR}; that stack is historical and is \textbf{not} what
211
- current Galaaz targets.
227
+ \textbf{Galaaz 2.0} supports
228
+ \textbf{\href{https://www.jruby.org/}{JRuby}} or \textbf{CRuby} equally
229
+ and drives \textbf{GNU R} through a \textbf{bridge}, so Ruby code can
230
+ create and manipulate R objects and call R functions while staying
231
+ idiomatic Ruby. An earlier prototype used Oracle's \textbf{GraalVM} with
232
+ \textbf{TruffleRuby} and \textbf{FastR}; that stack is historical and is
233
+ \textbf{not} what current Galaaz targets.
212
234
 
213
235
  \section{Bases of Object Programming}\label{bases-of-object-programming}
214
236
 
@@ -244,7 +266,7 @@ also not a ``compile'' time type, since R is not compiled. The type is
244
266
  checked at runtime. The same checking can be done in Ruby and we will do
245
267
  it later in this document.
246
268
 
247
- In the example bellow, we create class Trajectories with two instance
269
+ In the example below, we create class Trajectories with two instance
248
270
  variables, `times' and `matrix'. We will not go over the details of
249
271
  instance variables in Ruby, but here we created those variables with the
250
272
  keyword `attr\_reader' and a colom before the variables name:
@@ -259,8 +281,8 @@ keyword `attr\_reader' and a colom before the variables name:
259
281
  \end{Shaded}
260
282
 
261
283
  In order to create a new instance of object Trajectories we call method
262
- new on the class and we can store the result in a varible (not an
263
- instance variable) as bellow:
284
+ new on the class and we can store the result in a variable (not an
285
+ instance variable) as below:
264
286
 
265
287
  \begin{Shaded}
266
288
  \begin{Highlighting}[]
@@ -279,7 +301,7 @@ contents as in R.
279
301
  \end{Shaded}
280
302
 
281
303
  \begin{verbatim}
282
- ## #<RC::Trajectories:0x378c2595>
304
+ ## #<RC::Trajectories:0x4433c45f>
283
305
  \end{verbatim}
284
306
 
285
307
  To see the contents of an object, one needs to access its components
@@ -297,7 +319,7 @@ Since there is no content stored in `times' nor `matrix', nil is
297
319
  returned. In order to add a value in the variables, we need to add a
298
320
  constructor to the class Trajectories. In R, a constructor is build by
299
321
  default, in Ruby, this has to be created by adding a method called
300
- `initialize'. In the example bellow, we will create the initializer that
322
+ `initialize'. In the example below, we will create the initializer that
301
323
  accepts two values, a `times' value and a `matrix' value and they are
302
324
  used to initialize the value of the instance variables:
303
325
 
@@ -336,7 +358,7 @@ Since Galaaz is Ruby and not R, some syntax adjustments are sometimes
336
358
  necessary. For instance, in R, a range is represented as `(1:4)', in
337
359
  Ruby, the same range is represented as `(1..4)'. When passing arguments
338
360
  to an R function in R one uses the `=' sign after the slot name; in R,
339
- one uses the `:' operator after parameter's name as we can see bellow:
361
+ one uses the `:' operator after parameter's name as we can see below:
340
362
 
341
363
  \begin{Shaded}
342
364
  \begin{Highlighting}[]
@@ -344,7 +366,8 @@ one uses the `:' operator after parameter's name as we can see bellow:
344
366
  \OtherTok{@traj} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{3}\NormalTok{, }\DecValTok{4}\NormalTok{))}
345
367
 
346
368
  \CommentTok{\# Create a Trajectories with times and matrix}
347
- \OtherTok{@traj2} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{3}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{4}\NormalTok{), }\WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
369
+ \OtherTok{@traj2} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{3}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{4}\NormalTok{),}
370
+ \WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
348
371
  \end{Highlighting}
349
372
  \end{Shaded}
350
373
 
@@ -411,7 +434,8 @@ R and the corresponding Galaaz:
411
434
  + times=c(1: 10, (6: 16) *2),
412
435
  + traj=rbind(
413
436
  + matrix (seq (16,19, length=21), ncol=21, nrow=50, byrow=TRUE),
414
- + matrix (seq (15.8, 18, length=21), ncol=21, nrow=30, byrow=TRUE)
437
+ + matrix (seq (15.8, 18, length=21), ncol=21, nrow=30,
438
+ byrow=TRUE)
415
439
  + )+rnorm (21*80,0,0.2)
416
440
  + )
417
441
  \end{verbatim}
@@ -430,12 +454,16 @@ This same code in Galaaz becomes:
430
454
  \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\FloatTok{15.7}\NormalTok{, }\FloatTok{15.6}\NormalTok{, }\FloatTok{15.8}\NormalTok{, }\DecValTok{16}\NormalTok{)))}
431
455
 
432
456
  \OtherTok{@trajStAnne} \OperatorTok{=}
433
- \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{10}\NormalTok{), }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{6}\OperatorTok{..}\DecValTok{16}\NormalTok{) }\OperatorTok{*} \DecValTok{2}\NormalTok{),}
434
- \WarningTok{matrix:}\NormalTok{ (}\ConstantTok{R}\AttributeTok{.rbind}\NormalTok{(}
435
- \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{(}\ConstantTok{R}\AttributeTok{.seq}\NormalTok{(}\DecValTok{16}\NormalTok{, }\DecValTok{19}\NormalTok{, }\WarningTok{length:} \DecValTok{21}\NormalTok{), }\WarningTok{ncol:} \DecValTok{21}\NormalTok{,}
436
- \WarningTok{nrow:} \DecValTok{50}\NormalTok{, }\WarningTok{byrow:} \DecValTok{true}\NormalTok{),}
437
- \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{(}\ConstantTok{R}\AttributeTok{.seq}\NormalTok{(}\FloatTok{15.8}\NormalTok{, }\DecValTok{18}\NormalTok{, }\WarningTok{length:} \DecValTok{21}\NormalTok{), }\WarningTok{ncol:} \DecValTok{21}\NormalTok{,}
438
- \WarningTok{nrow:} \DecValTok{30}\NormalTok{, }\WarningTok{byrow:} \DecValTok{true}\NormalTok{)) }\OperatorTok{+} \ConstantTok{R}\AttributeTok{.rnorm}\NormalTok{(}\DecValTok{21}\OperatorTok{*}\DecValTok{80}\NormalTok{, }\DecValTok{0}\NormalTok{, }\FloatTok{0.2}\NormalTok{)))}
457
+ \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}
458
+ \WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{10}\NormalTok{), }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{6}\OperatorTok{..}\DecValTok{16}\NormalTok{) }\OperatorTok{*} \DecValTok{2}\NormalTok{),}
459
+ \WarningTok{matrix:}\NormalTok{ (}
460
+ \ConstantTok{R}\AttributeTok{.rbind}\NormalTok{(}
461
+ \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{(}\ConstantTok{R}\AttributeTok{.seq}\NormalTok{(}\DecValTok{16}\NormalTok{, }\DecValTok{19}\NormalTok{, }\WarningTok{length:} \DecValTok{21}\NormalTok{),}
462
+ \WarningTok{ncol:} \DecValTok{21}\NormalTok{, }\WarningTok{nrow:} \DecValTok{50}\NormalTok{, }\WarningTok{byrow:} \DecValTok{true}\NormalTok{),}
463
+ \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{(}\ConstantTok{R}\AttributeTok{.seq}\NormalTok{(}\FloatTok{15.8}\NormalTok{, }\DecValTok{18}\NormalTok{, }\WarningTok{length:} \DecValTok{21}\NormalTok{),}
464
+ \WarningTok{ncol:} \DecValTok{21}\NormalTok{, }\WarningTok{nrow:} \DecValTok{30}\NormalTok{, }\WarningTok{byrow:} \DecValTok{true}\NormalTok{)}
465
+ \NormalTok{ ) }\OperatorTok{+} \ConstantTok{R}\AttributeTok{.rnorm}\NormalTok{(}\DecValTok{21} \OperatorTok{*} \DecValTok{80}\NormalTok{, }\DecValTok{0}\NormalTok{, }\FloatTok{0.2}\NormalTok{)}
466
+ \NormalTok{ ))}
439
467
  \end{Highlighting}
440
468
  \end{Shaded}
441
469
 
@@ -456,10 +484,10 @@ correctly set:
456
484
  ## [1] 1 3 4 5
457
485
  ##
458
486
  ## [,1] [,2] [,3] [,4]
459
- ## g2_v2114 15.0 15.1 15.2 15.2
460
- ## g2_v2115 16.0 15.9 16.0 16.4
461
- ## g2_v2116 15.2 NA 15.3 15.3
462
- ## g2_v2117 15.7 15.6 15.8 16.0
487
+ ## g2_v7095 15.0 15.1 15.2 15.2
488
+ ## g2_v7096 16.0 15.9 16.0 16.4
489
+ ## g2_v7097 15.2 NA 15.3 15.3
490
+ ## g2_v7098 15.7 15.6 15.8 16.0
463
491
  ##
464
492
  ## [1] 1 2 3 4 5 6 7 8 9 10 12 14 16 18 20 22 24 26 28 30 32
465
493
  \end{verbatim}
@@ -477,7 +505,7 @@ default values in this document, with the default being `nil'. This was
477
505
  necessary in order to be able to create our constructor and passing it
478
506
  the proper values.
479
507
 
480
- In the example bellow, a class TrajectoriesBis is created with default
508
+ In the example below, a class TrajectoriesBis is created with default
481
509
  value 1 for times and a matrix with no elements in matrix.
482
510
 
483
511
  \begin{Shaded}
@@ -596,7 +624,7 @@ method `plot' is added to Trajectories. At this point, Renjin and Galaaz
596
624
  do not yet have plotting capabilities, so we will have to skip this
597
625
  method and go directly to the implementation of the `print' method.
598
626
 
599
- Bellow is the R code for method print:
627
+ Below is the R code for method print:
600
628
 
601
629
  \begin{verbatim}
602
630
  > setMethod ("print","Trajectories",
@@ -673,10 +701,10 @@ Trajectories's print we need to write `Kernel.print'.
673
701
  ## 5
674
702
  ## traj =
675
703
  ## [,1] [,2] [,3] [,4]
676
- ## g2_v2114 15.0 15.1 15.2 15.2
677
- ## g2_v2115 16.0 15.9 16.0 16.4
678
- ## g2_v2116 15.2 NA 15.3 15.3
679
- ## g2_v2117 15.7 15.6 15.8 16.0
704
+ ## g2_v7095 15.0 15.1 15.2 15.2
705
+ ## g2_v7096 16.0 15.9 16.0 16.4
706
+ ## g2_v7097 15.2 NA 15.3 15.3
707
+ ## g2_v7098 15.7 15.6 15.8 16.0
680
708
  ## ******* End Print (trajectories) *******
681
709
  \end{verbatim}
682
710
 
@@ -718,15 +746,17 @@ we have already seen, others will be described now:
718
746
  look like a method of the object. For instance, R.nrow(@matrix), can
719
747
  be called by doing @matrix.nrow;
720
748
  \item
721
- In R, every number is converted to a vector and this can be done with
722
- method R.i. Converting a vector with only one number back to a number
723
- can be done with method `.gz'. So if @num is an R vector that holds a
724
- number, then @num.gz is a number that can be used normally with Ruby
725
- methods;
749
+ In R, every number is a length-1 vector. In Galaaz 2.0, unwrap a
750
+ length-1 R vector to a Ruby number with
751
+ \texttt{\textgreater{}\textgreater{}\ 0} (or
752
+ \texttt{unboxed\_get(0)}). Older Galaaz docs used \texttt{.gz} /
753
+ \texttt{\textless{}\textless{}\ 0} for the same idea;
754
+ \texttt{\textless{}\textless{}} still works as a compatibility alias
755
+ for \texttt{\textgreater{}\textgreater{}};
726
756
  \item
727
757
  R functions and Ruby methods can be used freely in Galaaz. We show
728
- bellow two different ways of getting the minimum of a number, either
729
- by calling R.min or by getting the minimum of an array, with the min
758
+ below two different ways of getting the minimum of a number, either by
759
+ calling R.min or by getting the minimum of an array, with the min
730
760
  method;
731
761
  \item
732
762
  Galaaz allows for method `chaining'. Method chaining, also known as
@@ -734,16 +764,16 @@ we have already seen, others will be described now:
734
764
  calls in object-oriented programming languages. Each method returns an
735
765
  object, allowing the calls to be chained together in a single
736
766
  statement without requiring variables to store the intermediate
737
- results. For instance @matrix.nrow.gz, which returns the number of
738
- rows of the matrix as a number;
767
+ results. For instance
768
+ \texttt{@matrix.nrow\ \textgreater{}\textgreater{}\ 0}, which returns
769
+ the number of rows of the matrix as a Ruby number;
739
770
  \item
740
771
  Ranges in Ruby are represented by (x..y), where x is the beginning of
741
772
  the range and y its end. An R matrix can be indexed by range,
742
773
  \href{mailto:object@traj}{\nolinkurl{object@traj}}{[}1:nrowShow,1:ncolShow{]},
743
774
  the same result is obtained in Galaaz by indexing @matrix
744
775
  {[}(1..nrow\_show), (1..ncol\_show){]}. Observe that this statement is
745
- then chained with the format function and with the pp method to print
746
- the matrix.
776
+ then chained with the format function and printed with \texttt{puts}.
747
777
  \end{itemize}
748
778
 
749
779
  \begin{Shaded}
@@ -758,10 +788,11 @@ we have already seen, others will be described now:
758
788
  \FunctionTok{puts}\NormalTok{(}\StringTok{"*** Class Trajectories, method Show *** "}\NormalTok{)}
759
789
  \DataTypeTok{Kernel}\AttributeTok{.print}\NormalTok{(}\StringTok{"times = "}\NormalTok{)}
760
790
  \FunctionTok{puts} \OtherTok{@times}
761
- \NormalTok{ nrow\_show }\OperatorTok{=} \KeywordTok{[}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.nrow} \OperatorTok{\textless{}\textless{}} \DecValTok{0}\KeywordTok{]}\AttributeTok{.min}
762
- \NormalTok{ ncol\_show }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.min}\NormalTok{(}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.ncol}\NormalTok{) }\OperatorTok{\textless{}\textless{}} \DecValTok{0}
791
+ \NormalTok{ nrow\_show }\OperatorTok{=} \KeywordTok{[}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.nrow} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\KeywordTok{]}\AttributeTok{.min}
792
+ \NormalTok{ ncol\_show }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.min}\NormalTok{(}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.ncol}\NormalTok{) }\OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
763
793
  \FunctionTok{puts}\NormalTok{(}\StringTok{"* Traj (limited to a matrix 10x10) = "}\NormalTok{)}
764
- \FunctionTok{puts} \OtherTok{@matrix}\KeywordTok{[}\NormalTok{(}\DecValTok{1}\OperatorTok{..}\NormalTok{nrow\_show), (}\DecValTok{1}\OperatorTok{..}\NormalTok{ncol\_show)}\KeywordTok{]}\AttributeTok{.format}\NormalTok{(}\WarningTok{digits:} \DecValTok{2}\NormalTok{, }\WarningTok{nsmall:} \DecValTok{2}\NormalTok{)}
794
+ \FunctionTok{puts} \OtherTok{@matrix}\KeywordTok{[}\NormalTok{(}\DecValTok{1}\OperatorTok{..}\NormalTok{nrow\_show), (}\DecValTok{1}\OperatorTok{..}\NormalTok{ncol\_show)}\KeywordTok{]}\AttributeTok{.format}\NormalTok{(}\WarningTok{digits:} \DecValTok{2}\NormalTok{,}
795
+ \WarningTok{nsmall:} \DecValTok{2}\NormalTok{)}
765
796
  \FunctionTok{puts}\NormalTok{(}\StringTok{"******* End Show (trajectories) ******* "}\NormalTok{)}
766
797
  \ControlFlowTok{end}
767
798
 
@@ -776,26 +807,52 @@ we have already seen, others will be described now:
776
807
  \end{Shaded}
777
808
 
778
809
  \begin{verbatim}
779
- ## parse error
780
- \end{verbatim}
781
-
782
- \begin{verbatim}
783
- ## /home/rbotafogo/desenv_linux/galaaz/lib/new_bridge/session_client.rb:268:in 'eval_r'
784
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/new_bridge_adapter.rb:231:in 'eval_r_with_result'
785
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/rsupport.rb:359:in 'exec_function'
786
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/rsupport.rb:618:in 'process_missing_dispatch'
787
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/rsupport.rb:468:in 'process_missing'
788
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/robject.rb:404:in 'method_missing'
789
- ## /home/rbotafogo/desenv_linux/galaaz/lib/util/exec_ruby.rb:180:in 'show'
790
- ## /home/rbotafogo/desenv_linux/galaaz/lib/util/exec_ruby.rb:170:in 'exec_ruby'
791
- ## org/jruby/RubyKernel.java:1268:in 'eval'
792
- ## /home/rbotafogo/desenv_linux/galaaz/lib/util/exec_ruby.rb:169:in 'exec_ruby'
793
- ## /home/rbotafogo/desenv_linux/galaaz/lib/gknit/knitr_engine.rb:777:in 'block in initialize'
794
- ## org/jruby/RubyBasicObject.java:2695:in 'instance_eval'
795
- ## org/jruby/RubyBasicObject.java:2723:in 'instance_eval'
796
- ## /home/rbotafogo/desenv_linux/galaaz/lib/gknit/knitr_engine.rb:748:in 'block in initialize'
797
- ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/new_bridge_adapter.rb:358:in 'block in register_callback_proc_stub'
798
- ## /home/rbotafogo/desenv_linux/galaaz/lib/new_bridge/session_client.rb:413:in 'block in handle_call'
810
+ ## *** Class Trajectories, method Show ***
811
+ ## times = 1
812
+ ## 2
813
+ ## 3
814
+ ## 4
815
+ ## 5
816
+ ## 6
817
+ ## 7
818
+ ## 8
819
+ ## 9
820
+ ## 10
821
+ ## 12
822
+ ## 14
823
+ ## 16
824
+ ## 18
825
+ ## 20
826
+ ## 22
827
+ ## 24
828
+ ## 26
829
+ ## 28
830
+ ## 30
831
+ ## 32
832
+ ## * Traj (limited to a matrix 10x10) =
833
+ ## [,1] [,2] [,3] [,4] [,5] [,6] [,7] [,8]
834
+ ## [1,] "16.08" "16.63" "16.39" "16.47" "16.60" "16.90" "17.07" "17.38"
835
+ ## [2,] "16.35" "15.96" "16.29" "16.41" "16.65" "16.45" "17.23" "16.84"
836
+ ## [3,] "15.70" "16.08" "16.70" "16.20" "16.67" "16.67" "16.94" "17.10"
837
+ ## [4,] "15.94" "16.05" "16.30" "16.57" "16.48" "16.80" "16.95" "17.06"
838
+ ## [5,] "16.06" "16.07" "16.33" "16.71" "16.91" "16.92" "17.22" "16.91"
839
+ ## [6,] "16.17" "15.85" "16.61" "16.78" "16.41" "16.78" "17.00" "17.09"
840
+ ## [7,] "16.03" "15.86" "16.46" "16.60" "16.80" "16.79" "16.97" "17.21"
841
+ ## [8,] "16.24" "16.54" "16.21" "16.46" "16.81" "17.07" "16.67" "17.34"
842
+ ## [9,] "15.89" "16.24" "16.30" "16.46" "16.53" "17.11" "17.06" "17.17"
843
+ ## [10,] "16.15" "16.06" "16.38" "16.10" "16.36" "16.94" "16.78" "17.08"
844
+ ## [,9] [,10]
845
+ ## [1,] "17.29" "17.29"
846
+ ## [2,] "16.97" "17.13"
847
+ ## [3,] "16.94" "17.47"
848
+ ## [4,] "16.65" "17.61"
849
+ ## [5,] "17.17" "17.49"
850
+ ## [6,] "16.98" "17.87"
851
+ ## [7,] "17.16" "17.29"
852
+ ## [8,] "17.18" "17.48"
853
+ ## [9,] "17.09" "17.18"
854
+ ## [10,] "17.69" "17.54"
855
+ ## ******* End Show (trajectories) *******
799
856
  \end{verbatim}
800
857
 
801
858
  Our show method has the same problem as SS4, i.e., if an empty
@@ -810,12 +867,1863 @@ an error. Let's see it:
810
867
 
811
868
  \begin{Shaded}
812
869
  \begin{Highlighting}[]
813
- \OtherTok{@empty\_traj}\AttributeTok{.show}
870
+ \ControlFlowTok{begin}
871
+ \OtherTok{@empty\_traj}\AttributeTok{.show}
872
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
873
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
874
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
875
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
876
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
877
+ \ControlFlowTok{end}
814
878
  \end{Highlighting}
815
879
  \end{Shaded}
816
880
 
817
881
  \begin{verbatim}
882
+ ## *** Class Trajectories, method Show ***
883
+ ## times =
884
+ ## NoMethodError
818
885
  ## undefined method 'nrow' for nil
819
886
  \end{verbatim}
820
887
 
888
+ In this example, \texttt{@matrix} is \texttt{nil}, so calling
889
+ \texttt{@matrix.nrow} raises
890
+ \texttt{undefined\ method\ \textquotesingle{}nrow\textquotesingle{}\ for\ nil}.
891
+ To fix this, we can either prevent an empty trajectories class from
892
+ being created, or make sure that method \texttt{show} will not choke on
893
+ the empty object. We will take the second alternative, to follow SS4,
894
+ and will check if either \texttt{@times} or \texttt{@matrix} is empty.
895
+ If either one of them is \texttt{nil}, then we will print a message
896
+ saying so.
897
+
898
+ Although the first alternative, i.e., not allow for empty objects is a
899
+ possibility in Ruby, it seems that this is not the case for S4.
900
+
901
+ \begin{Shaded}
902
+ \begin{Highlighting}[]
903
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
904
+
905
+ \ControlFlowTok{def}\NormalTok{ show}
906
+ \ControlFlowTok{if}\NormalTok{ (}\OtherTok{@times}\AttributeTok{.nil?} \OperatorTok{||} \OtherTok{@matrix}\AttributeTok{.nil?}\NormalTok{)}
907
+ \FunctionTok{puts}\NormalTok{(}\StringTok{"*** Class Trajectories is empty!! *** "}\NormalTok{)}
908
+ \ControlFlowTok{return}
909
+ \ControlFlowTok{end}
910
+ \FunctionTok{puts}\NormalTok{(}\StringTok{"*** Class Trajectories, method Show *** "}\NormalTok{)}
911
+ \DataTypeTok{Kernel}\AttributeTok{.print}\NormalTok{(}\StringTok{"times = "}\NormalTok{)}
912
+ \FunctionTok{puts} \OtherTok{@times}
913
+ \NormalTok{ nrow\_show }\OperatorTok{=} \KeywordTok{[}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.nrow} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\KeywordTok{]}\AttributeTok{.min}
914
+ \NormalTok{ ncol\_show }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.min}\NormalTok{(}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.ncol}\NormalTok{) }\OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
915
+ \FunctionTok{puts}\NormalTok{(}\StringTok{"* Traj (limited to a matrix 10x10) = "}\NormalTok{)}
916
+ \FunctionTok{puts} \OtherTok{@matrix}\KeywordTok{[}\NormalTok{(}\DecValTok{1}\OperatorTok{..}\NormalTok{nrow\_show), (}\DecValTok{1}\OperatorTok{..}\NormalTok{ncol\_show)}\KeywordTok{]}\AttributeTok{.format}\NormalTok{(}\WarningTok{digits:} \DecValTok{2}\NormalTok{,}
917
+ \WarningTok{nsmall:} \DecValTok{2}\NormalTok{)}
918
+ \FunctionTok{puts}\NormalTok{(}\StringTok{"******* End Show (trajectories) ******* "}\NormalTok{)}
919
+ \ControlFlowTok{end}
920
+
921
+ \ControlFlowTok{end}
922
+ \end{Highlighting}
923
+ \end{Shaded}
924
+
925
+ \begin{Shaded}
926
+ \begin{Highlighting}[]
927
+ \OtherTok{@empty\_traj}\AttributeTok{.show}
928
+ \end{Highlighting}
929
+ \end{Shaded}
930
+
931
+ \begin{verbatim}
932
+ ## *** Class Trajectories is empty!! ***
933
+ \end{verbatim}
934
+
935
+ \section{To Remove an Object}\label{to-remove-an-object}
936
+
937
+ As far as I know, there isn't a good way of removing a defined class,
938
+ but there might be one and the interested user is directed to google it!
939
+ In principle, there should not be any real need to remove a defined
940
+ class. Both in R and Galaaz, large programs are usually written in a
941
+ file and the file loaded. If one writes a wrong class, the better
942
+ solution is to correct it and then load it again. If the class is
943
+ written directly on the console, then leaving it there will not have any
944
+ serious impact.
945
+
946
+ \section{Method count\_missing}\label{method-count_missing}
947
+
948
+ In R, methods `print' and `show' are methods that already exist. SS4
949
+ wants to add a method called `countMissing' which does not exist in R,
950
+ and thus requires some special preparation. In Ruby, every method we've
951
+ created is a new method that exists inside the class. The fact that
952
+ `print' happens to be also a method for class Kernel and `show' is not,
953
+ is not of special interest. Actually we've seen that in order to call
954
+ method print from the Kernel class we had to call Kernel.print.
955
+
956
+ To create method `count\_missing' we just need to reopen the
957
+ Trajectories class and add the method the same way we've done with
958
+ method `show'. Again, let's first look at R's `countMissing' and then at
959
+ Ruby's:
960
+
961
+ \begin{verbatim}
962
+ > setMethod(
963
+ + f= "countMissing",
964
+ + signature= "Trajectories",
965
+ + definition=function(object){
966
+ + return(sum(is.na(object@traj)))
967
+ + }
968
+ + )
969
+ \end{verbatim}
970
+
971
+ Here we introduce another particular case of Galaaz. R has many methods
972
+ that have a `.' in their names, such as `is.na'. In Ruby, the dot `.'
973
+ has a special meaning as it is the way we call a method on an object.
974
+ Doing `R.is.na' will not work. So, in Galaaz, R functions that have a
975
+ dot in them will have the dot substituted by '\_\_'. So, method is.na in
976
+ Galaaz, becomes R.is\_\_na. In method count\_missing we use method
977
+ chaining and convert the final count to a Ruby number with
978
+ \texttt{\textgreater{}\textgreater{}\ 0} (unbox).
979
+
980
+ \begin{Shaded}
981
+ \begin{Highlighting}[]
982
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
983
+
984
+ \ControlFlowTok{def}\NormalTok{ count\_missing}
985
+ \ControlFlowTok{return} \OtherTok{@matrix}\AttributeTok{.is\_\_na.sum} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
986
+ \ControlFlowTok{end}
987
+
988
+ \ControlFlowTok{end}
989
+ \end{Highlighting}
990
+ \end{Shaded}
991
+
992
+ \begin{Shaded}
993
+ \begin{Highlighting}[]
994
+ \FunctionTok{puts} \OtherTok{@trajCochin}\AttributeTok{.count\_missing}
995
+ \end{Highlighting}
996
+ \end{Shaded}
997
+
998
+ \begin{verbatim}
999
+ ## 1
1000
+ \end{verbatim}
1001
+
1002
+ \section{To See the Methods}\label{to-see-the-methods}
1003
+
1004
+ In order to see the methods we have defined so far, we call on class
1005
+ Trajectories the method `instance\_methods' passing it one argument,
1006
+ `false', as follows:
1007
+
1008
+ \begin{Shaded}
1009
+ \begin{Highlighting}[]
1010
+ \FunctionTok{puts} \DataTypeTok{Trajectories}\AttributeTok{.instance\_methods}\NormalTok{(}\DecValTok{false}\NormalTok{)}
1011
+ \end{Highlighting}
1012
+ \end{Shaded}
1013
+
1014
+ \begin{verbatim}
1015
+ ## count_missing
1016
+ ## times
1017
+ ## print
1018
+ ## show
1019
+ ## matrix
1020
+ \end{verbatim}
1021
+
1022
+ It is interesting to observe that we see our three methods
1023
+ `count\_missing', `print' and `show', but we also see two other methods
1024
+ `times' and `matrix', but those last two as far as we know are just
1025
+ instance variables and not methods, right? More on that when we talk
1026
+ about Accessors.
1027
+
1028
+ Galaaz and Ruby do not by default provide a way to see a method's code.
1029
+ However, if the user uses a Ruby console such as Pry, then seeing
1030
+ methods and debugging is possible. Pry is beyond the scope of this
1031
+ document.
1032
+
1033
+ \section{Construction}\label{construction}
1034
+
1035
+ Every class in Ruby has a constructor, if not explicitly defined, at
1036
+ least implicitly. Method initialize is the constructor method and the
1037
+ one that coordinates the whole construction process.
1038
+
1039
+ \section{Inspector}\label{inspector}
1040
+
1041
+ There is no default `inspector' in Ruby as in R, although there is
1042
+ nothing that prevents the developer from inspecting and validating the
1043
+ input. For example, in the object Trajectories, one may want to check
1044
+ that the number of elements in `times' is equal to the number of columns
1045
+ in `matrix' and if they are not, issue an error. In order to understand
1046
+ why this restriction exists, the user is again directed to SS4.
1047
+
1048
+ Here we show the R code for this validation:
1049
+
1050
+ \begin{verbatim}
1051
+ > setClass(
1052
+ + Class="Trajectories",
1053
+ + representation(times="numeric",traj="matrix"),
1054
+ + validity=function(object){
1055
+ + cat("~~~ Trajectories: inspector ~~~ \\n")
1056
+ + if(length(object@times)!=ncol(object@traj)){
1057
+ + stop ("[Trajectories: validation] the number of temporal
1058
+ + measurements does not correspond
1059
+ + }else{}
1060
+ + return(TRUE)
1061
+ + }
1062
+ + )
1063
+ \end{verbatim}
1064
+
1065
+ In order to implement this validation we will coordinate it in the
1066
+ initialize method.
1067
+
1068
+ \begin{Shaded}
1069
+ \begin{Highlighting}[]
1070
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1071
+
1072
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1073
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ times}
1074
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ matrix}
1075
+
1076
+ \CommentTok{\# Validate: length(@times) must equal ncol(@matrix)}
1077
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"\textasciitilde{}\textasciitilde{}\textasciitilde{} Trajectories: inspector \textasciitilde{}\textasciitilde{}\textasciitilde{} "}\NormalTok{)}
1078
+ \ControlFlowTok{if}\NormalTok{ ((}\OtherTok{@times}\AttributeTok{.length} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{) }\OperatorTok{!=}\NormalTok{ (}\OtherTok{@matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{))}
1079
+ \FunctionTok{raise}\NormalTok{(}
1080
+ \StringTok{"[Trajectories: validation] the number of temporal "} \OperatorTok{+}
1081
+ \StringTok{"measurements does not correspond with the number of "} \OperatorTok{+}
1082
+ \StringTok{"columns in the matrix"}\NormalTok{)}
1083
+ \ControlFlowTok{end}
1084
+
1085
+ \CommentTok{\# show the object just created}
1086
+ \NormalTok{ show}
1087
+
1088
+ \ControlFlowTok{end}
1089
+
1090
+ \ControlFlowTok{end}
1091
+ \end{Highlighting}
1092
+ \end{Shaded}
1093
+
1094
+ Let's first create a Trajectories that validates fine, i.e., the number
1095
+ of elements in @times is equal to the number of columns of the matrix.
1096
+ In this case, we will show a message saying that validation was done and
1097
+ then print the object.
1098
+
1099
+ \begin{Shaded}
1100
+ \begin{Highlighting}[]
1101
+ \NormalTok{ok }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{),}
1102
+ \WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
1103
+ \end{Highlighting}
1104
+ \end{Shaded}
1105
+
1106
+ \begin{verbatim}
1107
+ ## ~~~ Trajectories: inspector ~~~
1108
+ ## *** Class Trajectories, method Show ***
1109
+ ## times = 1
1110
+ ## 2
1111
+ ## * Traj (limited to a matrix 10x10) =
1112
+ ## 1
1113
+ ## 2
1114
+ ## ******* End Show (trajectories) *******
1115
+ \end{verbatim}
1116
+
1117
+ Now, if we try to create a Trajectories that does not pass the
1118
+ validation criteria, our code will raise an exception. Exceptions are a
1119
+ standard way to deal with errors in Ruby code and many other object
1120
+ oriented languages. The interested reader should look for further
1121
+ documentation on exceptions on the web.
1122
+
1123
+ \begin{Shaded}
1124
+ \begin{Highlighting}[]
1125
+ \ControlFlowTok{begin}
1126
+ \NormalTok{ error }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\OperatorTok{..}\DecValTok{3}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{),}
1127
+ \WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
1128
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
1129
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
1130
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
1131
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
1132
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
1133
+ \ControlFlowTok{end}
1134
+ \end{Highlighting}
1135
+ \end{Shaded}
1136
+
1137
+ \begin{verbatim}
1138
+ ## ~~~ Trajectories: inspector ~~~
1139
+ ## RuntimeError
1140
+ ## [Trajectories: validation] the number of temporal measurements does
1141
+ ## not correspond with the number of columns in the matrix
1142
+ \end{verbatim}
1143
+
1144
+ The validation above does not consider the case when an empty object is
1145
+ created. Here we will check to see if either times or matrix are nil; if
1146
+ either one of them is nil, then we will raise an exception and interrupt
1147
+ the creation of the object. We also create a method validate that is
1148
+ called from our initialize method.
1149
+
1150
+ Method validate has some interesting features about the integration of
1151
+ Galaaz and R. We compare lengths after unboxing with
1152
+ \texttt{\textgreater{}\textgreater{}\ 0}, so the comparison is ordinary
1153
+ Ruby arithmetic on numbers. (A length-1 R logical can likewise be
1154
+ treated as a Ruby boolean via \texttt{\textgreater{}\textgreater{}\ 0}.)
1155
+
1156
+ \begin{Shaded}
1157
+ \begin{Highlighting}[]
1158
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1159
+
1160
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1161
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ times}
1162
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ matrix}
1163
+
1164
+ \CommentTok{\# call method validate to validate our input}
1165
+ \NormalTok{ validate}
1166
+
1167
+ \CommentTok{\# show the object just created}
1168
+ \NormalTok{ show}
1169
+
1170
+ \ControlFlowTok{end}
1171
+
1172
+ \ControlFlowTok{def}\NormalTok{ validate}
1173
+
1174
+ \CommentTok{\# Let\textquotesingle{}s first check that we do not have an empty object}
1175
+ \ControlFlowTok{if}\NormalTok{ (}\OtherTok{@times}\AttributeTok{.nil?} \OperatorTok{||} \OtherTok{@matrix}\AttributeTok{.nil?}\NormalTok{)}
1176
+ \FunctionTok{raise} \StringTok{"Neither times nor matrix can be an empty object"}
1177
+ \ControlFlowTok{end}
1178
+
1179
+ \CommentTok{\# Validate: length(@times) must equal ncol(@matrix)}
1180
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"\textasciitilde{}\textasciitilde{}\textasciitilde{} Trajectories: inspector \textasciitilde{}\textasciitilde{}\textasciitilde{} "}\NormalTok{)}
1181
+ \ControlFlowTok{if}\NormalTok{ ((}\OtherTok{@times}\AttributeTok{.length} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{) }\OperatorTok{!=}\NormalTok{ (}\OtherTok{@matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{))}
1182
+ \FunctionTok{raise}\NormalTok{(}
1183
+ \StringTok{"[Trajectories: validation] the number of temporal "} \OperatorTok{+}
1184
+ \StringTok{"measurements does not correspond with the number of "} \OperatorTok{+}
1185
+ \StringTok{"columns in the matrix"}\NormalTok{)}
1186
+ \ControlFlowTok{end}
1187
+
1188
+ \ControlFlowTok{end}
1189
+
1190
+ \ControlFlowTok{end}
1191
+ \end{Highlighting}
1192
+ \end{Shaded}
1193
+
1194
+ \textbf{Note:} with this stricter \texttt{validate},
1195
+ \texttt{Trajectories.new} no longer accepts empty objects. The earlier
1196
+ \texttt{@empty\_traj\ =\ Trajectories.new} / \texttt{@empty\_traj.show}
1197
+ pattern from part 1 no longer applies for \emph{new} constructions;
1198
+ existing instances created before this reopen still exist in memory, but
1199
+ calling \texttt{new} with missing \texttt{times} or \texttt{matrix} will
1200
+ raise.
1201
+
1202
+ Let's try then creating an empty object:
1203
+
1204
+ \begin{Shaded}
1205
+ \begin{Highlighting}[]
1206
+ \ControlFlowTok{begin}
1207
+ \NormalTok{ error }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}
1208
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
1209
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
1210
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
1211
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
1212
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
1213
+ \ControlFlowTok{end}
1214
+ \end{Highlighting}
1215
+ \end{Shaded}
1216
+
1217
+ \begin{verbatim}
1218
+ ## RuntimeError
1219
+ ## Neither times nor matrix can be an empty object
1220
+ \end{verbatim}
1221
+
1222
+ Another example:
1223
+
1224
+ \begin{Shaded}
1225
+ \begin{Highlighting}[]
1226
+ \ControlFlowTok{begin}
1227
+ \NormalTok{ error }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \DecValTok{1}\NormalTok{)}
1228
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
1229
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
1230
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
1231
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
1232
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
1233
+ \ControlFlowTok{end}
1234
+ \end{Highlighting}
1235
+ \end{Shaded}
1236
+
1237
+ \begin{verbatim}
1238
+ ## RuntimeError
1239
+ ## Neither times nor matrix can be an empty object
1240
+ \end{verbatim}
1241
+
1242
+ Let's see now that the implementation is correct and that it does not
1243
+ raise an error on valid input:
1244
+
1245
+ \begin{Shaded}
1246
+ \begin{Highlighting}[]
1247
+ \NormalTok{ok }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{),}
1248
+ \WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
1249
+ \end{Highlighting}
1250
+ \end{Shaded}
1251
+
1252
+ \begin{verbatim}
1253
+ ## ~~~ Trajectories: inspector ~~~
1254
+ ## *** Class Trajectories, method Show ***
1255
+ ## times = 1
1256
+ ## 2
1257
+ ## * Traj (limited to a matrix 10x10) =
1258
+ ## 1
1259
+ ## 2
1260
+ ## ******* End Show (trajectories) *******
1261
+ \end{verbatim}
1262
+
1263
+ The `initialize' method is called ONLY during the initial creation of
1264
+ the object. If any instance variable is later modified, no control is
1265
+ done. At this moment though, there is no way to change the value of any
1266
+ of our instance variables.
1267
+
1268
+ \begin{verbatim}
1269
+ error.times = R.c(1, 2, 3)
1270
+ \end{verbatim}
1271
+
1272
+ The Trajectories class works for R objects and expects as input R
1273
+ objects. Passing R objects in all examples has been the obligation of
1274
+ the programmer. Galaaz, however, can also accept many Ruby values
1275
+ (ranges, arrays of numbers, and so on) if we convert them at the
1276
+ boundary. There is no \texttt{R.convert} in Galaaz 2.0; a small helper
1277
+ is enough: leave \texttt{nil} alone, keep objects that are already
1278
+ \texttt{R::Object}, and otherwise wrap with \texttt{R.c} (which accepts
1279
+ ranges as well as scalars and vectors). Matrices that are already R
1280
+ objects are kept as-is.
1281
+
1282
+ \begin{Shaded}
1283
+ \begin{Highlighting}[]
1284
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1285
+
1286
+ \ControlFlowTok{def}\NormalTok{ as\_r(x)}
1287
+ \ControlFlowTok{return} \DecValTok{nil} \ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.nil?}
1288
+ \ControlFlowTok{return}\NormalTok{ x }\ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.is\_a?}\NormalTok{(}\ConstantTok{R}\OperatorTok{::}\DataTypeTok{Object}\NormalTok{)}
1289
+ \ConstantTok{R}\AttributeTok{.c}\NormalTok{(x)}
1290
+ \ControlFlowTok{end}
1291
+
1292
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1293
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ as\_r(times)}
1294
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ as\_r(matrix)}
1295
+
1296
+ \CommentTok{\# call method validate to validate our input}
1297
+ \NormalTok{ validate}
1298
+
1299
+ \CommentTok{\# show the object just created}
1300
+ \NormalTok{ show}
1301
+
1302
+ \ControlFlowTok{end}
1303
+
1304
+ \ControlFlowTok{def}\NormalTok{ validate}
1305
+
1306
+ \CommentTok{\# Let\textquotesingle{}s first check that we do not have an empty object}
1307
+ \ControlFlowTok{if}\NormalTok{ (}\OtherTok{@times}\AttributeTok{.nil?} \OperatorTok{||} \OtherTok{@matrix}\AttributeTok{.nil?}\NormalTok{)}
1308
+ \FunctionTok{raise} \StringTok{"Neither times nor matrix can be an empty object"}
1309
+ \ControlFlowTok{end}
1310
+
1311
+ \CommentTok{\# Validate: length(@times) must equal ncol(@matrix)}
1312
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"\textasciitilde{}\textasciitilde{}\textasciitilde{} Trajectories: inspector \textasciitilde{}\textasciitilde{}\textasciitilde{} "}\NormalTok{)}
1313
+ \NormalTok{ tl }\OperatorTok{=} \OtherTok{@times}\AttributeTok{.length} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{; mc }\OperatorTok{=} \OtherTok{@matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
1314
+ \ControlFlowTok{if}\NormalTok{ (tl }\OperatorTok{!=}\NormalTok{ mc)}
1315
+ \FunctionTok{raise}\NormalTok{(}
1316
+ \StringTok{"[Trajectories: validation] the number of temporal "} \OperatorTok{+}
1317
+ \StringTok{"measurements }\SpecialCharTok{\#\{}\NormalTok{tl}\SpecialCharTok{\}}\StringTok{ does not correspond with the number "} \OperatorTok{+}
1318
+ \StringTok{"of columns in the matrix }\SpecialCharTok{\#\{}\NormalTok{mc}\SpecialCharTok{\}}\StringTok{"}\NormalTok{)}
1319
+ \ControlFlowTok{end}
1320
+
1321
+ \ControlFlowTok{end}
1322
+
1323
+ \ControlFlowTok{end}
1324
+ \end{Highlighting}
1325
+ \end{Shaded}
1326
+
1327
+ And now let's create a new Trajectories, but we will now pass a Ruby
1328
+ range for times:
1329
+
1330
+ \begin{Shaded}
1331
+ \begin{Highlighting}[]
1332
+ \NormalTok{ok }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:}\NormalTok{ (}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{), }\WarningTok{ncol:} \DecValTok{2}\NormalTok{))}
1333
+ \end{Highlighting}
1334
+ \end{Shaded}
1335
+
1336
+ \begin{verbatim}
1337
+ ## ~~~ Trajectories: inspector ~~~
1338
+ ## *** Class Trajectories, method Show ***
1339
+ ## times = 1
1340
+ ## 2
1341
+ ## * Traj (limited to a matrix 10x10) =
1342
+ ## 1
1343
+ ## 2
1344
+ ## ******* End Show (trajectories) *******
1345
+ \end{verbatim}
1346
+
1347
+ Perfect! This works fine.
1348
+
1349
+ \emph{(Historical note: an earlier Galaaz prototype on Renjin also
1350
+ demonstrated sharing storage with the MDArray gem. Those shared-store
1351
+ demos are not part of Galaaz 2.0 / the GNU R bridge, and are omitted
1352
+ here.)}
1353
+
1354
+ \section{The Initializator}\label{the-initializator}
1355
+
1356
+ As we have seen, method `initialize' is the main object creator
1357
+ orchestrator. This method can be as complex as needed. So, let's get on
1358
+ with some improvements to our Trajectories class.
1359
+
1360
+ It would be rather pleasant that the columns of the matrix of the
1361
+ trajectories have names, the names of measurements times. In the same
1362
+ way, the lines could be subscripted by a number of individual.
1363
+
1364
+ To do this in R, one also uses method initialize:
1365
+
1366
+ \begin{verbatim}
1367
+ > setMethod(
1368
+ + f="initialize",
1369
+ + signature="Trajectories",
1370
+ + definition=function(.Object,times,traj){
1371
+ + cat("~~~ Trajectories: initializator ~~~ \\n")
1372
+ + colnames(traj) <- paste("T",times,sep="")
1373
+ + rownames(traj) <- paste("I",1:nrow(traj),sep= "")
1374
+ + .Object@traj <- traj # Assignment of the slots
1375
+ + .Object@times <- times
1376
+ + return(.Object) # return of the object
1377
+ + }
1378
+ + )
1379
+ \end{verbatim}
1380
+
1381
+ In R, it is possible to assign a value to the result of a function, for
1382
+ example \texttt{colnames(x)\ \textless{}-\ c("v1",\ "v2",\ "v3")}. In
1383
+ Galaaz 2.0 the same idea is expressed with ordinary Ruby setters on the
1384
+ R object: \texttt{@matrix.colnames\ =\ ...} and
1385
+ \texttt{@matrix.rownames\ =\ ...}.
1386
+
1387
+ \begin{Shaded}
1388
+ \begin{Highlighting}[]
1389
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1390
+
1391
+ \ControlFlowTok{def}\NormalTok{ as\_r(x)}
1392
+ \ControlFlowTok{return} \DecValTok{nil} \ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.nil?}
1393
+ \ControlFlowTok{return}\NormalTok{ x }\ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.is\_a?}\NormalTok{(}\ConstantTok{R}\OperatorTok{::}\DataTypeTok{Object}\NormalTok{)}
1394
+ \ConstantTok{R}\AttributeTok{.c}\NormalTok{(x)}
1395
+ \ControlFlowTok{end}
1396
+
1397
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1398
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ as\_r(times)}
1399
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ as\_r(matrix)}
1400
+
1401
+ \CommentTok{\# call method validate to validate our input}
1402
+ \NormalTok{ validate}
1403
+
1404
+ \CommentTok{\# Add row and column names}
1405
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"\textasciitilde{}\textasciitilde{}\textasciitilde{} Trajectories: initializator \textasciitilde{}\textasciitilde{}\textasciitilde{} "}\NormalTok{)}
1406
+ \OtherTok{@matrix}\AttributeTok{.colnames} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.paste}\NormalTok{(}\StringTok{"T"}\NormalTok{, }\OtherTok{@times}\NormalTok{, }\WarningTok{sep:} \StringTok{""}\NormalTok{)}
1407
+ \OtherTok{@matrix}\AttributeTok{.rownames} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.paste}\NormalTok{(}\StringTok{"I"}\NormalTok{, (}\DecValTok{1}\OperatorTok{..}\NormalTok{(}\OtherTok{@matrix}\AttributeTok{.nrow} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{)), }\WarningTok{sep:} \StringTok{""}\NormalTok{)}
1408
+
1409
+ \CommentTok{\# show the object just created}
1410
+ \NormalTok{ show}
1411
+
1412
+ \ControlFlowTok{end}
1413
+
1414
+ \ControlFlowTok{end}
1415
+ \end{Highlighting}
1416
+ \end{Shaded}
1417
+
1418
+ \begin{Shaded}
1419
+ \begin{Highlighting}[]
1420
+ \OtherTok{@traj} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{,}\DecValTok{2}\NormalTok{,}\DecValTok{4}\NormalTok{,}\DecValTok{8}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{8}\NormalTok{),}
1421
+ \WarningTok{nrow:} \DecValTok{2}\NormalTok{))}
1422
+ \end{Highlighting}
1423
+ \end{Shaded}
1424
+
1425
+ \begin{verbatim}
1426
+ ## ~~~ Trajectories: inspector ~~~
1427
+ ## ~~~ Trajectories: initializator ~~~
1428
+ ## *** Class Trajectories, method Show ***
1429
+ ## times = 1
1430
+ ## 2
1431
+ ## 4
1432
+ ## 8
1433
+ ## * Traj (limited to a matrix 10x10) =
1434
+ ## T1 T2 T4 T8
1435
+ ## I1 "1" "3" "5" "7"
1436
+ ## I2 "2" "4" "6" "8"
1437
+ ## ******* End Show (trajectories) *******
1438
+ \end{verbatim}
1439
+
1440
+ Note that we still call our `validate' method and it is still an error
1441
+ to create an empty Trajectories or one in which the sizes are wrong:
1442
+
1443
+ \begin{Shaded}
1444
+ \begin{Highlighting}[]
1445
+ \ControlFlowTok{begin}
1446
+ \NormalTok{ error }\OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{48}\NormalTok{), }\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{8}\NormalTok{),}
1447
+ \WarningTok{nrow:} \DecValTok{2}\NormalTok{))}
1448
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
1449
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
1450
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
1451
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
1452
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
1453
+ \ControlFlowTok{end}
1454
+ \end{Highlighting}
1455
+ \end{Shaded}
1456
+
1457
+ \begin{verbatim}
1458
+ ## ~~~ Trajectories: inspector ~~~
1459
+ ## RuntimeError
1460
+ ## [Trajectories: validation] the number of temporal measurements 3 doe
1461
+ ## s not correspond with the number of columns in the matrix 4
1462
+ \end{verbatim}
1463
+
1464
+ A constructor does not necessarily take the instance variable of the
1465
+ object as argument. For example, if we know (that is not the case in
1466
+ reality, but let us imagine so) that the BMI increases by 0.1 every
1467
+ week, we could build trajectories by providing the number of weeks and
1468
+ the initial weights.
1469
+
1470
+ First the code in R, we skip the definition of class TrajectoriesBis:
1471
+
1472
+ \begin{verbatim}
1473
+ > setMethod ("initialize",
1474
+ + "TrajectoriesBis",
1475
+ + function(.Object,nbWeek,BMIinit){
1476
+ + traj <- outer(BMIinit, 1:nbWeek,
1477
+ + function(init, week) { return(init + 0.1 * week) })
1478
+ + colnames(traj) <- paste("T",1:nbWeek,sep="")
1479
+ + rownames(traj) <- paste("I",1:nrow(traj),sep="")
1480
+ + .Object@times <- 1:nbWeek
1481
+ + .Object@traj <- traj
1482
+ + return(.Object)
1483
+ + }
1484
+ + )
1485
+ \end{verbatim}
1486
+
1487
+ Now, let's make a TrajectoriesBis in Galaaz. Here again, we should point
1488
+ out some characteristics of our code:
1489
+
1490
+ \begin{itemize}
1491
+ \item
1492
+ We made initialize with two positional arguments, instead of named
1493
+ arguments, i.e., the first argument is the number of weeks and the
1494
+ second bmi\_init. In this case, when making a new object the position
1495
+ of the arguments is important and there is no way to pass the argument
1496
+ by name;
1497
+ \item
1498
+ R function outer was called as if a method from bmi\_init using dot
1499
+ notation, although one could use R.outer without problem;
1500
+ \item
1501
+ Function `outer' expects an R function as its 3rd argument. In order
1502
+ to build an R function from Galaaz, we need to pass the function
1503
+ definition as a string to R.eval.
1504
+ \end{itemize}
1505
+
1506
+ \begin{Shaded}
1507
+ \begin{Highlighting}[]
1508
+ \ControlFlowTok{class} \DataTypeTok{TrajectoriesBis}
1509
+
1510
+ \OtherTok{attr\_reader} \WarningTok{:times}
1511
+ \OtherTok{attr\_reader} \WarningTok{:matrix}
1512
+
1513
+ \ControlFlowTok{def}\NormalTok{ initialize(number\_weeks, bmi\_init)}
1514
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ bmi\_init}\AttributeTok{.outer}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks),}
1515
+ \ConstantTok{R}\AttributeTok{.eval}\NormalTok{(}\StringTok{"function(init,}
1516
+ \StringTok{ week) \{return(init + 0.1 * week)\}"}\NormalTok{))}
1517
+ \OtherTok{@times} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks))}
1518
+ \ControlFlowTok{end}
1519
+
1520
+ \ControlFlowTok{end}
1521
+
1522
+ \OtherTok{@traj\_bis} \OperatorTok{=} \DataTypeTok{TrajectoriesBis}\AttributeTok{.new}\NormalTok{(}\DecValTok{4}\NormalTok{, }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{16}\NormalTok{,}\DecValTok{17}\NormalTok{,}\FloatTok{15.6}\NormalTok{))}
1523
+ \end{Highlighting}
1524
+ \end{Shaded}
1525
+
1526
+ \begin{Shaded}
1527
+ \begin{Highlighting}[]
1528
+ \FunctionTok{puts} \OtherTok{@traj\_bis}\AttributeTok{.matrix}
1529
+ \end{Highlighting}
1530
+ \end{Shaded}
1531
+
1532
+ \begin{verbatim}
1533
+ ## [,1] [,2] [,3] [,4]
1534
+ ## [1,] 16.1 16.2 16.3 16.4
1535
+ ## [2,] 17.1 17.2 17.3 17.4
1536
+ ## [3,] 15.7 15.8 15.9 16.0
1537
+ \end{verbatim}
1538
+
1539
+ It is always possible to pass a Ruby variable into a string by
1540
+ interpolating it. Put the variable inside \texttt{\#\{...\}}. As an
1541
+ example, let's also require the BMI increase as a parameter. (A common
1542
+ mistake is to escape the interpolation --- writing
1543
+ \texttt{\textbackslash{}\#\{increment\}} --- which leaves the characters
1544
+ literally in the R source and does not substitute the Ruby value. Use
1545
+ real interpolation:)
1546
+
1547
+ \begin{Shaded}
1548
+ \begin{Highlighting}[]
1549
+ \ControlFlowTok{class} \DataTypeTok{TrajectoriesBis}
1550
+
1551
+ \ControlFlowTok{def}\NormalTok{ initialize(number\_weeks, bmi\_init, increment)}
1552
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ bmi\_init}\AttributeTok{.outer}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks),}
1553
+ \ConstantTok{R}\AttributeTok{.eval}\NormalTok{(}\StringTok{"function(init,}
1554
+ \StringTok{ week) \{return(init +}
1555
+ \StringTok{ }\SpecialCharTok{\#\{}\NormalTok{increment}\SpecialCharTok{\}}\StringTok{ * week)\}"}\NormalTok{))}
1556
+ \OtherTok{@times} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks))}
1557
+ \ControlFlowTok{end}
1558
+
1559
+ \ControlFlowTok{end}
1560
+
1561
+ \OtherTok{@traj\_bis} \OperatorTok{=} \DataTypeTok{TrajectoriesBis}\AttributeTok{.new}\NormalTok{(}\DecValTok{4}\NormalTok{, }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{16}\NormalTok{,}\DecValTok{17}\NormalTok{,}\FloatTok{15.6}\NormalTok{), }\FloatTok{0.3}\NormalTok{)}
1562
+ \end{Highlighting}
1563
+ \end{Shaded}
1564
+
1565
+ \begin{Shaded}
1566
+ \begin{Highlighting}[]
1567
+ \FunctionTok{puts} \OtherTok{@traj\_bis}\AttributeTok{.matrix}
1568
+ \end{Highlighting}
1569
+ \end{Shaded}
1570
+
1571
+ \begin{verbatim}
1572
+ ## [,1] [,2] [,3] [,4]
1573
+ ## [1,] 16.3 16.6 16.9 17.2
1574
+ ## [2,] 17.3 17.6 17.9 18.2
1575
+ ## [3,] 15.9 16.2 16.5 16.8
1576
+ \end{verbatim}
1577
+
1578
+ \section{Constructors for Users}\label{constructors-for-users}
1579
+
1580
+ Many times, it is interesting to have different ways of constructing an
1581
+ object depending on what information our users have or want to provide
1582
+ to the constructor. Although we have only one initialize method, we can
1583
+ create multiple methods, that do some preprocessing and then call the
1584
+ initialize method to carry out the object building.
1585
+
1586
+ In order to do that, we use what are called class methods, instead of
1587
+ instance methods. All the methods we've created so far are instance
1588
+ methods; class methods are defined by prepending the self keyword to the
1589
+ method's name. Still using the assumption that the BMI will grow by 0.1
1590
+ per week, let's define a regular trajectory without having to define a
1591
+ TrajectoriesBis as above:
1592
+
1593
+ \begin{verbatim}
1594
+ > regularTrajectories <- function(nbWeek,BMIinit) {
1595
+ + traj <- outer(BMIinit, 1:nbWeek,
1596
+ + function(init, week) { return(init + 0.1 * week) })
1597
+ + times <- 1: nbWeek
1598
+ + return(new(Class="Trajectories",times=times,traj=traj))
1599
+ + }
1600
+ > regularTrajectories(nbWeek=3,BMIinit=c(14,15,16))
1601
+ \end{verbatim}
1602
+
1603
+ Notice how method `regular' is defined as `self.regular', making it a
1604
+ class method. The last statement of the method definition is actually a
1605
+ call to the Trajectories constructor `new' passing the calculated values
1606
+ for times and matrix.
1607
+
1608
+ Notice also how method regular is called, similar to the way new is
1609
+ called by adding it after class Trajectories name:
1610
+ `Trajectories.regular'.
1611
+
1612
+ \begin{Shaded}
1613
+ \begin{Highlighting}[]
1614
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1615
+
1616
+ \ControlFlowTok{def} \DecValTok{self}\AttributeTok{.regular}\NormalTok{(}\WarningTok{number\_weeks:} \DecValTok{nil}\NormalTok{, }\WarningTok{bmi\_init:} \DecValTok{nil}\NormalTok{)}
1617
+ \NormalTok{ matrix }\OperatorTok{=}\NormalTok{ bmi\_init}\AttributeTok{.outer}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks),}
1618
+ \ConstantTok{R}\AttributeTok{.eval}\NormalTok{(}\StringTok{"function(init,}
1619
+ \StringTok{ week) \{return(init + 0.1 * week)\}"}\NormalTok{))}
1620
+ \NormalTok{ times }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{number\_weeks))}
1621
+ \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:}\NormalTok{ times, }\WarningTok{matrix:}\NormalTok{ matrix)}
1622
+ \ControlFlowTok{end}
1623
+
1624
+ \ControlFlowTok{end}
1625
+ \end{Highlighting}
1626
+ \end{Shaded}
1627
+
1628
+ \begin{Shaded}
1629
+ \begin{Highlighting}[]
1630
+ \OtherTok{@regular} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.regular}\NormalTok{(}\WarningTok{bmi\_init:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{14}\NormalTok{, }\DecValTok{15}\NormalTok{, }\DecValTok{16}\NormalTok{),}
1631
+ \WarningTok{number\_weeks:} \DecValTok{3}\NormalTok{)}
1632
+ \end{Highlighting}
1633
+ \end{Shaded}
1634
+
1635
+ \begin{verbatim}
1636
+ ## ~~~ Trajectories: inspector ~~~
1637
+ ## ~~~ Trajectories: initializator ~~~
1638
+ ## *** Class Trajectories, method Show ***
1639
+ ## times = 1
1640
+ ## 2
1641
+ ## 3
1642
+ ## * Traj (limited to a matrix 10x10) =
1643
+ ## T1 T2 T3
1644
+ ## I1 "14.10" "14.20" "14.30"
1645
+ ## I2 "15.10" "15.20" "15.30"
1646
+ ## I3 "16.10" "16.20" "16.30"
1647
+ ## ******* End Show (trajectories) *******
1648
+ \end{verbatim}
1649
+
1650
+ We have already seen that constructors can be as complex as needed,
1651
+ calling other methods and doing calculations on the received parameters.
1652
+ On this last example, we will check if the times variable was provided.
1653
+ If it is not provided, then we will use matrix columns to define the
1654
+ times:
1655
+
1656
+ \begin{Shaded}
1657
+ \begin{Highlighting}[]
1658
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1659
+
1660
+ \ControlFlowTok{def} \DecValTok{self}\AttributeTok{.init}\NormalTok{(}\WarningTok{times:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1661
+ \NormalTok{ times }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\NormalTok{(matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{))) }\ControlFlowTok{if}\NormalTok{ times}\AttributeTok{.nil?}
1662
+ \DataTypeTok{Trajectories}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:}\NormalTok{ times, }\WarningTok{matrix:}\NormalTok{ matrix)}
1663
+ \ControlFlowTok{end}
1664
+
1665
+ \ControlFlowTok{end}
1666
+ \end{Highlighting}
1667
+ \end{Shaded}
1668
+
1669
+ \begin{Shaded}
1670
+ \begin{Highlighting}[]
1671
+ \OtherTok{@traj} \OperatorTok{=} \DataTypeTok{Trajectories}\AttributeTok{.init}\NormalTok{(}\WarningTok{matrix:} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{8}\NormalTok{), }\WarningTok{ncol:} \DecValTok{4}\NormalTok{))}
1672
+ \end{Highlighting}
1673
+ \end{Shaded}
1674
+
1675
+ \begin{verbatim}
1676
+ ## ~~~ Trajectories: inspector ~~~
1677
+ ## ~~~ Trajectories: initializator ~~~
1678
+ ## *** Class Trajectories, method Show ***
1679
+ ## times = 1
1680
+ ## 2
1681
+ ## 3
1682
+ ## 4
1683
+ ## * Traj (limited to a matrix 10x10) =
1684
+ ## T1 T2 T3 T4
1685
+ ## I1 "1" "3" "5" "7"
1686
+ ## I2 "2" "4" "6" "8"
1687
+ ## ******* End Show (trajectories) *******
1688
+ \end{verbatim}
1689
+
1690
+ \section{Accessors}\label{accessors}
1691
+
1692
+ Accessors are methods for getting and setting the value of instance
1693
+ variables.
1694
+
1695
+ \section{Get}\label{get}
1696
+
1697
+ Getters are methods for getting the value of an instance variable. We
1698
+ have been using getters since the beginning of this document, without
1699
+ explicitly saying so. When defining attr\_reader :times and attr\_reader
1700
+ :matrix, we have actually defined two getter methods for reading the
1701
+ values of variables times and matrix respectively. We can however define
1702
+ getters explicitly:
1703
+
1704
+ \begin{Shaded}
1705
+ \begin{Highlighting}[]
1706
+ \ControlFlowTok{class} \DataTypeTok{TrajectoriesBis}
1707
+
1708
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1709
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ times}
1710
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ matrix}
1711
+ \ControlFlowTok{end}
1712
+
1713
+ \ControlFlowTok{def}\NormalTok{ times}
1714
+ \OtherTok{@times}
1715
+ \ControlFlowTok{end}
1716
+
1717
+ \ControlFlowTok{def}\NormalTok{ matrix}
1718
+ \OtherTok{@matrix}
1719
+ \ControlFlowTok{end}
1720
+
1721
+ \ControlFlowTok{end}
1722
+
1723
+ \OtherTok{@traj} \OperatorTok{=} \DataTypeTok{TrajectoriesBis}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \DecValTok{1}\NormalTok{, }\WarningTok{matrix:} \DecValTok{2}\NormalTok{)}
1724
+ \end{Highlighting}
1725
+ \end{Shaded}
1726
+
1727
+ \begin{Shaded}
1728
+ \begin{Highlighting}[]
1729
+ \FunctionTok{puts} \OtherTok{@traj}\AttributeTok{.times}
1730
+ \end{Highlighting}
1731
+ \end{Shaded}
1732
+
1733
+ \begin{verbatim}
1734
+ ## 1
1735
+ \end{verbatim}
1736
+
1737
+ \begin{Shaded}
1738
+ \begin{Highlighting}[]
1739
+ \FunctionTok{puts} \OtherTok{@traj}\AttributeTok{.matrix}
1740
+ \end{Highlighting}
1741
+ \end{Shaded}
1742
+
1743
+ \begin{verbatim}
1744
+ ## 2
1745
+ \end{verbatim}
1746
+
1747
+ It is also possible to define more sophisticated getters. For example
1748
+ one can regularly need the BMI at inclusion. In R, one would index a
1749
+ matrix as matrix{[},1{]}. In Ruby, it is a syntax error to have a `,'
1750
+ just after the `{[}'. In this case we need to add `nil' as in
1751
+ matrix{[}nil, 1{]}:
1752
+
1753
+ \begin{Shaded}
1754
+ \begin{Highlighting}[]
1755
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1756
+
1757
+ \ControlFlowTok{def}\NormalTok{ get\_traj\_inclusion}
1758
+ \OtherTok{@matrix}\KeywordTok{[}\DecValTok{nil}\NormalTok{, }\DecValTok{1}\KeywordTok{]}
1759
+ \ControlFlowTok{end}
1760
+
1761
+ \ControlFlowTok{end}
1762
+ \end{Highlighting}
1763
+ \end{Shaded}
1764
+
1765
+ \begin{Shaded}
1766
+ \begin{Highlighting}[]
1767
+ \FunctionTok{puts} \OtherTok{@trajCochin}\AttributeTok{.get\_traj\_inclusion}
1768
+ \end{Highlighting}
1769
+ \end{Shaded}
1770
+
1771
+ \begin{verbatim}
1772
+ ## numeric(0)
1773
+ \end{verbatim}
1774
+
1775
+ \section{Set}\label{set}
1776
+
1777
+ A setter is a method that assigns a value to a variable. As with
1778
+ getters, Ruby also provides an easy way to write setters and allow you
1779
+ to also write them explicitly. Let's first use the simple way:
1780
+
1781
+ \begin{Shaded}
1782
+ \begin{Highlighting}[]
1783
+ \ControlFlowTok{class} \DataTypeTok{TrajectoriesBis}
1784
+
1785
+ \OtherTok{attr\_writer} \WarningTok{:times}
1786
+ \OtherTok{attr\_writer} \WarningTok{:matrix}
1787
+
1788
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{)}
1789
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ times}
1790
+ \OtherTok{@matrix} \OperatorTok{=}\NormalTok{ matrix}
1791
+ \ControlFlowTok{end}
1792
+
1793
+ \ControlFlowTok{end}
1794
+
1795
+ \OtherTok{@traj} \OperatorTok{=} \DataTypeTok{TrajectoriesBis}\AttributeTok{.new}
1796
+ \OtherTok{@traj}\AttributeTok{.times} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{)}
1797
+ \OtherTok{@traj}\AttributeTok{.matrix} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.matrix}\NormalTok{((}\DecValTok{1}\OperatorTok{..}\DecValTok{2}\NormalTok{), }\WarningTok{ncol:} \DecValTok{2}\NormalTok{)}
1798
+ \end{Highlighting}
1799
+ \end{Shaded}
1800
+
1801
+ \begin{Shaded}
1802
+ \begin{Highlighting}[]
1803
+ \FunctionTok{puts} \OtherTok{@traj}\AttributeTok{.matrix}
1804
+ \end{Highlighting}
1805
+ \end{Shaded}
1806
+
1807
+ \begin{verbatim}
1808
+ ## [,1] [,2]
1809
+ ## [1,] 1 2
1810
+ \end{verbatim}
1811
+
1812
+ Note that now we can use `=' to assign a value to both variables times
1813
+ and matrix. Without setters, changing the value of variables times and
1814
+ matrix was not possible. Our class, up to this point was protected from
1815
+ any changes to those variables. If we need to allow changes to those
1816
+ variables, then setters are needed. In this case, the simple setter as
1817
+ shown above is not ideal, since it would allow changes that break the
1818
+ restriction that variable times has to have the same length as the
1819
+ number of columns of matrix. In order to do the verification we need to
1820
+ implement a more sophisticated setter. In the example below, we add the
1821
+ `times=' setter that receives as input one argument. First we convert
1822
+ the given argument to an R object, then check to see that the length of
1823
+ times is the same as the number of columns and if everything is fine,
1824
+ then we set the value of instance variable times:
1825
+
1826
+ \begin{Shaded}
1827
+ \begin{Highlighting}[]
1828
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1829
+
1830
+ \ControlFlowTok{def}\NormalTok{ as\_r(x)}
1831
+ \ControlFlowTok{return} \DecValTok{nil} \ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.nil?}
1832
+ \ControlFlowTok{return}\NormalTok{ x }\ControlFlowTok{if}\NormalTok{ x}\AttributeTok{.is\_a?}\NormalTok{(}\ConstantTok{R}\OperatorTok{::}\DataTypeTok{Object}\NormalTok{)}
1833
+ \ConstantTok{R}\AttributeTok{.c}\NormalTok{(x)}
1834
+ \ControlFlowTok{end}
1835
+
1836
+ \ControlFlowTok{def}\NormalTok{ times}\OperatorTok{=}\NormalTok{(times)}
1837
+ \NormalTok{ times }\OperatorTok{=}\NormalTok{ as\_r(times)}
1838
+ \NormalTok{ tl }\OperatorTok{=}\NormalTok{ times}\AttributeTok{.length} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}\NormalTok{; mc }\OperatorTok{=} \OtherTok{@matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
1839
+ \ControlFlowTok{if}\NormalTok{ (tl }\OperatorTok{!=}\NormalTok{ mc)}
1840
+ \FunctionTok{raise}\NormalTok{(}
1841
+ \StringTok{"[Trajectories: validation] the number of temporal "} \OperatorTok{+}
1842
+ \StringTok{"measurements }\SpecialCharTok{\#\{}\NormalTok{tl}\SpecialCharTok{\}}\StringTok{ does not correspond with the number "} \OperatorTok{+}
1843
+ \StringTok{"of columns in the matrix }\SpecialCharTok{\#\{}\NormalTok{mc}\SpecialCharTok{\}}\StringTok{"}\NormalTok{)}
1844
+ \ControlFlowTok{end}
1845
+ \OtherTok{@times} \OperatorTok{=}\NormalTok{ times}
1846
+ \ControlFlowTok{end}
1847
+
1848
+ \ControlFlowTok{end}
1849
+ \end{Highlighting}
1850
+ \end{Shaded}
1851
+
1852
+ \begin{Shaded}
1853
+ \begin{Highlighting}[]
1854
+ \ControlFlowTok{begin}
1855
+ \OtherTok{@trajCochin}\AttributeTok{.times} \OperatorTok{=}\NormalTok{ (}\DecValTok{1}\OperatorTok{..}\DecValTok{5}\NormalTok{)}
1856
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
1857
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
1858
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
1859
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
1860
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
1861
+ \ControlFlowTok{end}
1862
+ \end{Highlighting}
1863
+ \end{Shaded}
1864
+
1865
+ \begin{verbatim}
1866
+ ## RuntimeError
1867
+ ## [Trajectories: validation] the number of temporal measurements 5 doe
1868
+ ## s not correspond with the number of columns in the matrix 4
1869
+ \end{verbatim}
1870
+
1871
+ We now set the value appropriately and will not get any errors:
1872
+
1873
+ \begin{Shaded}
1874
+ \begin{Highlighting}[]
1875
+ \OtherTok{@trajCochin}\AttributeTok{.times} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{5}\NormalTok{, }\DecValTok{6}\NormalTok{, }\DecValTok{8}\NormalTok{)}
1876
+ \end{Highlighting}
1877
+ \end{Shaded}
1878
+
1879
+ \section{The Operator `{[}'}\label{the-operator}
1880
+
1881
+ It is also possible to define getters by using the operator `{[}'. This
1882
+ operator is not usually used for returning instance variables and it is
1883
+ preferable to use the methods we've used above; however, for
1884
+ completeness with SS4 we are showing how to define this here. Operator
1885
+ `{[}' is better left to be used for array/matrix indices.
1886
+
1887
+ \begin{Shaded}
1888
+ \begin{Highlighting}[]
1889
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
1890
+
1891
+ \ControlFlowTok{def} \WarningTok{[]}\NormalTok{(var\_name)}
1892
+
1893
+ \ControlFlowTok{case}\NormalTok{ var\_name}
1894
+ \ControlFlowTok{when} \StringTok{"times"}
1895
+ \OtherTok{@times}
1896
+ \ControlFlowTok{when} \StringTok{"matrix"}
1897
+ \OtherTok{@matrix}
1898
+ \ControlFlowTok{else}
1899
+ \FunctionTok{raise} \StringTok{"Unknown instance variable"}
1900
+ \ControlFlowTok{end}
1901
+
1902
+ \ControlFlowTok{end}
1903
+
1904
+ \ControlFlowTok{end}
1905
+ \end{Highlighting}
1906
+ \end{Shaded}
1907
+
1908
+ \begin{Shaded}
1909
+ \begin{Highlighting}[]
1910
+ \FunctionTok{puts} \OtherTok{@trajCochin}\KeywordTok{[}\StringTok{"times"}\KeywordTok{]}
1911
+ \end{Highlighting}
1912
+ \end{Shaded}
1913
+
1914
+ \begin{verbatim}
1915
+ ## [1] 1 5 6 8
1916
+ \end{verbatim}
1917
+
1918
+ Similarly, we could use operator `{[}{]}=' to assign a value to times
1919
+ and matrix. We will not do this here as we think that the other options
1920
+ are better and the interested user can easily find help, if needed to
1921
+ implement such method.
1922
+
1923
+ \section{To Go Further}\label{to-go-further}
1924
+
1925
+ This section will introduce advanced features of Object Oriented
1926
+ programming such as Inheritance and Modules and will also show some
1927
+ aspects of S4 that do not apply to Ruby.
1928
+
1929
+ \section{Methods Using Several
1930
+ Arguments}\label{methods-using-several-arguments}
1931
+
1932
+ In Ruby, methods can have as many arguments as needed and those methods
1933
+ are defined the way we have already seen in many of the examples above.
1934
+ The example in SS4 presents a method that prints different output if its
1935
+ input is numeric, character or both. Let's write a class in Ruby that
1936
+ does the same for Numeric and String. In Ruby we do not define global
1937
+ functions, we always define methods inside classes or modules (as we
1938
+ will see later). Also, Ruby is not typed, so methods are not called
1939
+ depending on their types as in SS4 examples. Below, method test will be
1940
+ called with one parameter. At the time of calling we do not know the
1941
+ type of the argument; the method can then check if the received argument
1942
+ is a Numeric or a String and at this time, decide what should be
1943
+ printed.
1944
+
1945
+ \begin{Shaded}
1946
+ \begin{Highlighting}[]
1947
+ \ControlFlowTok{class} \DataTypeTok{Test}
1948
+
1949
+ \ControlFlowTok{def} \FunctionTok{test}\NormalTok{(input)}
1950
+
1951
+ \ControlFlowTok{case}\NormalTok{ input}
1952
+ \ControlFlowTok{when} \DataTypeTok{Numeric}
1953
+ \FunctionTok{puts} \StringTok{"The input is numeric: }\SpecialCharTok{\#\{}\NormalTok{input}\SpecialCharTok{\}}\StringTok{"}
1954
+ \ControlFlowTok{when} \DataTypeTok{String}
1955
+ \FunctionTok{puts} \StringTok{"The input is a string: }\SpecialCharTok{\#\{}\NormalTok{input}\SpecialCharTok{\}}\StringTok{"}
1956
+ \ControlFlowTok{else}
1957
+ \FunctionTok{puts} \StringTok{"The input is neither a number nor a string"}
1958
+ \ControlFlowTok{end}
1959
+
1960
+ \ControlFlowTok{end}
1961
+
1962
+ \ControlFlowTok{end}
1963
+
1964
+ \OtherTok{@t} \OperatorTok{=} \DataTypeTok{Test}\AttributeTok{.new}
1965
+ \end{Highlighting}
1966
+ \end{Shaded}
1967
+
1968
+ \begin{Shaded}
1969
+ \begin{Highlighting}[]
1970
+ \OtherTok{@t}\AttributeTok{.test}\NormalTok{(}\DecValTok{5}\NormalTok{)}
1971
+ \end{Highlighting}
1972
+ \end{Shaded}
1973
+
1974
+ \begin{verbatim}
1975
+ ## The input is numeric: 5
1976
+ \end{verbatim}
1977
+
1978
+ \begin{Shaded}
1979
+ \begin{Highlighting}[]
1980
+ \OtherTok{@t}\AttributeTok{.test}\NormalTok{(}\StringTok{"Hello"}\NormalTok{)}
1981
+ \end{Highlighting}
1982
+ \end{Shaded}
1983
+
1984
+ \begin{verbatim}
1985
+ ## The input is a string: Hello
1986
+ \end{verbatim}
1987
+
1988
+ Ruby has ways of dealing with multiple arguments, missing arguments,
1989
+ undefined number of arguments, named arguments, unnamed arguments, etc.
1990
+ This is beyond the scope of this document and we suggest the interested
1991
+ reader to go to the many resources about Ruby that can easily be found
1992
+ on the web.
1993
+
1994
+ We will now create a new class `Partition' that we will use later in
1995
+ this document. This class will have only the basic methods needed for
1996
+ the examples to work.
1997
+
1998
+ \begin{Shaded}
1999
+ \begin{Highlighting}[]
2000
+ \ControlFlowTok{class} \DataTypeTok{Partition}
2001
+
2002
+ \OtherTok{attr\_reader} \WarningTok{:nb\_groups}
2003
+ \OtherTok{attr\_reader} \WarningTok{:part}
2004
+
2005
+ \ControlFlowTok{def}\NormalTok{ initialize(nb\_groups, part)}
2006
+ \OtherTok{@nb\_groups} \OperatorTok{=}\NormalTok{ nb\_groups}
2007
+ \OtherTok{@part} \OperatorTok{=}\NormalTok{ part}
2008
+ \ControlFlowTok{end}
2009
+
2010
+ \ControlFlowTok{end}
2011
+
2012
+ \OtherTok{@partCochin} \OperatorTok{=} \DataTypeTok{Partition}\AttributeTok{.new}\NormalTok{(}\DecValTok{2}\NormalTok{, }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\StringTok{"A"}\NormalTok{,}\StringTok{"B"}\NormalTok{,}\StringTok{"A"}\NormalTok{,}\StringTok{"B"}\NormalTok{)}\AttributeTok{.factor}\NormalTok{)}
2013
+ \OtherTok{@partStAnne} \OperatorTok{=} \DataTypeTok{Partition}\AttributeTok{.new}\NormalTok{(}\DecValTok{2}\NormalTok{, }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\StringTok{"A"}\NormalTok{,}\StringTok{"B"}\NormalTok{)}\AttributeTok{.rep}\NormalTok{(}\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{50}\NormalTok{,}\DecValTok{30}\NormalTok{))}\AttributeTok{.factor}\NormalTok{)}
2014
+ \end{Highlighting}
2015
+ \end{Shaded}
2016
+
2017
+ \begin{Shaded}
2018
+ \begin{Highlighting}[]
2019
+ \FunctionTok{puts} \OtherTok{@partCochin}\AttributeTok{.part}
2020
+ \end{Highlighting}
2021
+ \end{Shaded}
2022
+
2023
+ \begin{verbatim}
2024
+ ## [1] A B A B
2025
+ ## Levels: A B
2026
+ \end{verbatim}
2027
+
2028
+ \begin{Shaded}
2029
+ \begin{Highlighting}[]
2030
+ \FunctionTok{puts} \OtherTok{@partStAnne}\AttributeTok{.part}
2031
+ \end{Highlighting}
2032
+ \end{Shaded}
2033
+
2034
+ \begin{verbatim}
2035
+ ## [1] A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A A
2036
+ ## [34] A A A A A A A A A A A A A A A A A B B B B B B B B B B B B B B B B
2037
+ ## [67] B B B B B B B B B B B B B B
2038
+ ## Levels: A B
2039
+ \end{verbatim}
2040
+
2041
+ We will suppose that part is always composed of capital letters going
2042
+ from A to LETTERS{[}nb\_groups{]}.
2043
+
2044
+ \section{Inheritance}\label{inheritance}
2045
+
2046
+ Ruby being a powerful Object Oriented language has the concept of
2047
+ Inheritance, but it does not allow for multiple inheritance. Multiple
2048
+ inheritance has many drawbacks and Ruby just does not support it.
2049
+ However, Ruby has other concepts that make up for the lack of multiple
2050
+ inheritance as we will see in the following examples.
2051
+
2052
+ So, let's go back to SS4 examples. We want now to define a class called
2053
+ TrajPartitioned that inherits from class Trajectories. When a class has
2054
+ a parent, all methods available for the parent are also available to the
2055
+ child.
2056
+
2057
+ \begin{Shaded}
2058
+ \begin{Highlighting}[]
2059
+ \ControlFlowTok{class} \DataTypeTok{TrajPartitioned} \OperatorTok{\textless{}} \DataTypeTok{Trajectories}
2060
+
2061
+ \OtherTok{attr\_reader} \WarningTok{:list\_partitions}
2062
+
2063
+ \ControlFlowTok{end}
2064
+ \end{Highlighting}
2065
+ \end{Shaded}
2066
+
2067
+ That's all there is to it! We've just created a class TrajPartitioned
2068
+ that inherits all methods from class Trajectories and at this point does
2069
+ nothing different from Trajectories, but adds a new instance variable:
2070
+ list\_partitions.
2071
+
2072
+ Creating TrajPartitioned without arguments will generate an error, since
2073
+ a Trajectories requires both times and matrix to be non null.
2074
+
2075
+ \begin{Shaded}
2076
+ \begin{Highlighting}[]
2077
+ \ControlFlowTok{begin}
2078
+ \OtherTok{@tdPitie} \OperatorTok{=} \DataTypeTok{TrajPartitioned}\AttributeTok{.new}
2079
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
2080
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
2081
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
2082
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
2083
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
2084
+ \ControlFlowTok{end}
2085
+ \end{Highlighting}
2086
+ \end{Shaded}
2087
+
2088
+ \begin{verbatim}
2089
+ ## RuntimeError
2090
+ ## Neither times nor matrix can be an empty object
2091
+ \end{verbatim}
2092
+
2093
+ Let's try to create a TrajPartitioned, but passing to it two partitions.
2094
+ For that, let's first create a new Partition:
2095
+
2096
+ \begin{Shaded}
2097
+ \begin{Highlighting}[]
2098
+ \OtherTok{@partCochin2} \OperatorTok{=} \DataTypeTok{Partition}\AttributeTok{.new}\NormalTok{(}\DecValTok{3}\NormalTok{, }\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\StringTok{"A"}\NormalTok{, }\StringTok{"C"}\NormalTok{, }\StringTok{"C"}\NormalTok{, }\StringTok{"B"}\NormalTok{)}\AttributeTok{.factor}\NormalTok{)}
2099
+ \end{Highlighting}
2100
+ \end{Shaded}
2101
+
2102
+ And now let's create the TrajPartitioned:
2103
+
2104
+ \begin{Shaded}
2105
+ \begin{Highlighting}[]
2106
+ \ControlFlowTok{begin}
2107
+ \OtherTok{@tdCochin} \OperatorTok{=} \DataTypeTok{TrajPartitioned}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{,}\DecValTok{3}\NormalTok{,}\DecValTok{4}\NormalTok{,}\DecValTok{5}\NormalTok{),}
2108
+ \WarningTok{matrix:} \OtherTok{@trajCochin}\AttributeTok{.matrix}\NormalTok{,}
2109
+ \WarningTok{list\_partitions:} \ConstantTok{R}\AttributeTok{.list}\NormalTok{(}\OtherTok{@partCochin}\NormalTok{,}
2110
+ \OtherTok{@partCochin2}\NormalTok{))}
2111
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
2112
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
2113
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
2114
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
2115
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
2116
+ \ControlFlowTok{end}
2117
+ \end{Highlighting}
2118
+ \end{Shaded}
2119
+
2120
+ \begin{verbatim}
2121
+ ## ArgumentError
2122
+ ## unknown keyword: :list_partitions
2123
+ \end{verbatim}
2124
+
2125
+ This didn't work: R function `list' expects R objects, and in this case,
2126
+ @partCochin and @partCochin2 are Ruby classes, so trying to apply
2127
+ function list to them does not work. Clearly, we will have to work in
2128
+ the realm of Ruby to keep the list of partitions. This is not a problem
2129
+ as Ruby has data structures to maintain a list of objects, the Array.
2130
+ Let's then try another solution:
2131
+
2132
+ \begin{Shaded}
2133
+ \begin{Highlighting}[]
2134
+ \ControlFlowTok{begin}
2135
+ \OtherTok{@tdCochin} \OperatorTok{=} \DataTypeTok{TrajPartitioned}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{,}\DecValTok{3}\NormalTok{,}\DecValTok{4}\NormalTok{,}\DecValTok{5}\NormalTok{),}
2136
+ \WarningTok{matrix:} \OtherTok{@trajCochin}\AttributeTok{.matrix}\NormalTok{,}
2137
+ \WarningTok{list\_partitions:} \KeywordTok{[}\OtherTok{@partCochin}\NormalTok{,}
2138
+ \OtherTok{@partCochin2}\KeywordTok{]}\NormalTok{)}
2139
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
2140
+ \CommentTok{\# Short message only — full backtraces overflow PDF boxes.}
2141
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
2142
+ \CommentTok{\# Wrap long messages for PDF code{-}box width.}
2143
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
2144
+ \ControlFlowTok{end}
2145
+ \end{Highlighting}
2146
+ \end{Shaded}
2147
+
2148
+ \begin{verbatim}
2149
+ ## ArgumentError
2150
+ ## unknown keyword: :list_partitions
2151
+ \end{verbatim}
2152
+
2153
+ We now get a second error: `unknown keyword: list\_partitions'. Class
2154
+ TrajPartitioned inherits from class Trajectories and class Trajectories
2155
+ has an initialize function that requires two parameters, times and
2156
+ matrix; list\_partitions is not a parameter for initialize and is thus
2157
+ unknown. In order to fix this problem we need to create an initialize
2158
+ method for class TrajPartitioned.
2159
+
2160
+ \section{The `super' Keyword}\label{the-super-keyword}
2161
+
2162
+ R has a method called `callNextMethod' for control flow between
2163
+ inherited classes. In Ruby, we have a model that is a bit different.
2164
+ When a method is called on a subclass, if this method is not found it
2165
+ will be searched in the parent class and it will go up the hierarchy of
2166
+ classes until it is found or an error is issued. If we want the parent
2167
+ method to be called we can call `super':
2168
+
2169
+ \begin{Shaded}
2170
+ \begin{Highlighting}[]
2171
+ \ControlFlowTok{class} \DataTypeTok{TrajPartitioned}
2172
+
2173
+ \ControlFlowTok{def}\NormalTok{ initialize(times}\OperatorTok{:} \DecValTok{nil}\NormalTok{, }\WarningTok{matrix:} \DecValTok{nil}\NormalTok{, }\WarningTok{list\_partitions:} \DecValTok{nil}\NormalTok{)}
2174
+ \DecValTok{super}\NormalTok{(}\WarningTok{times:}\NormalTok{ times, }\WarningTok{matrix:}\NormalTok{ matrix)}
2175
+ \OtherTok{@list\_partitions} \OperatorTok{=}\NormalTok{ list\_partitions}
2176
+ \ControlFlowTok{end}
2177
+
2178
+ \ControlFlowTok{end}
2179
+ \end{Highlighting}
2180
+ \end{Shaded}
2181
+
2182
+ Let's try our example again:
2183
+
2184
+ \begin{Shaded}
2185
+ \begin{Highlighting}[]
2186
+ \OtherTok{@tdCochin} \OperatorTok{=} \DataTypeTok{TrajPartitioned}\AttributeTok{.new}\NormalTok{(}\WarningTok{times:} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{,}\DecValTok{3}\NormalTok{,}\DecValTok{4}\NormalTok{,}\DecValTok{5}\NormalTok{),}
2187
+ \WarningTok{matrix:} \OtherTok{@trajCochin}\AttributeTok{.matrix}\NormalTok{,}
2188
+ \WarningTok{list\_partitions:} \KeywordTok{[}\OtherTok{@partCochin}\NormalTok{,}
2189
+ \OtherTok{@partCochin2}\KeywordTok{]}\NormalTok{)}
2190
+ \end{Highlighting}
2191
+ \end{Shaded}
2192
+
2193
+ \begin{verbatim}
2194
+ ## ~~~ Trajectories: inspector ~~~
2195
+ ## ~~~ Trajectories: initializator ~~~
2196
+ ## *** Class Trajectories, method Show ***
2197
+ ## times = 1
2198
+ ## 3
2199
+ ## 4
2200
+ ## 5
2201
+ ## * Traj (limited to a matrix 10x10) =
2202
+ ## T1 T3 T4 T5
2203
+ ## I1 "15.00" "15.10" "15.20" "15.20"
2204
+ ## I2 "16.00" "15.90" "16.00" "16.40"
2205
+ ## I3 "15.20" " NA" "15.30" "15.30"
2206
+ ## I4 "15.70" "15.60" "15.80" "16.00"
2207
+ ## ******* End Show (trajectories) *******
2208
+ \end{verbatim}
2209
+
2210
+ Now @tdCochin is created correctly; however, the `show' method only
2211
+ shows information about times and matrix, there is nothing about our new
2212
+ list\_partitions variable. This is so, since there is no method `show'
2213
+ in TrajPartitioned, so method `show' from Trajectories is executed.
2214
+
2215
+ So, let's start by writing a `print' method, that will print all the
2216
+ information we have in TrajPartitioned. The flow of control for this
2217
+ method is: Ruby sees a call to `print', so it checks to see if `print'
2218
+ is a method for TrajPartitioned. Since we have just defined this method,
2219
+ Ruby finds it and executes it. The first command in print is a call to
2220
+ `super', which will call the parent `print' method, that prints
2221
+ information for `times' and `matrix'. When the parent `print' finishes
2222
+ control continues after the `super' call, printing the number of
2223
+ available partitions.
2224
+
2225
+ \begin{Shaded}
2226
+ \begin{Highlighting}[]
2227
+ \ControlFlowTok{class} \DataTypeTok{TrajPartitioned}
2228
+
2229
+ \ControlFlowTok{def} \FunctionTok{print}
2230
+ \DecValTok{super}
2231
+ \FunctionTok{puts}\NormalTok{(}
2232
+ \StringTok{"the object also contains "} \OperatorTok{+}
2233
+ \StringTok{"}\SpecialCharTok{\#\{}\OtherTok{@list\_partitions}\AttributeTok{.length}\SpecialCharTok{\}}\StringTok{ partition"}\NormalTok{)}
2234
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"***** Fine of print (TrajPartitioned) *****"}\NormalTok{)}
2235
+ \ControlFlowTok{end}
2236
+
2237
+ \ControlFlowTok{end}
2238
+ \end{Highlighting}
2239
+ \end{Shaded}
2240
+
2241
+ \begin{Shaded}
2242
+ \begin{Highlighting}[]
2243
+ \OtherTok{@tdCochin}\AttributeTok{.print}
2244
+ \end{Highlighting}
2245
+ \end{Shaded}
2246
+
2247
+ \begin{verbatim}
2248
+ ## *** Class Trajectories, method Print ***
2249
+ ## times = 1
2250
+ ## 3
2251
+ ## 4
2252
+ ## 5
2253
+ ## traj =
2254
+ ## T1 T3 T4 T5
2255
+ ## I1 15.0 15.1 15.2 15.2
2256
+ ## I2 16.0 15.9 16.0 16.4
2257
+ ## I3 15.2 NA 15.3 15.3
2258
+ ## I4 15.7 15.6 15.8 16.0
2259
+ ## ******* End Print (trajectories) *******
2260
+ ## the object also contains 2 partition
2261
+ ## ***** Fine of print (TrajPartitioned) *****
2262
+ \end{verbatim}
2263
+
2264
+ Notice that this model is much cleaner than `callNextMethod' and is not
2265
+ subject to any of the difficulties presented in SS4 and there is no need
2266
+ for the keywords ``is'', ``as'' and ``as\textless-'', although Ruby
2267
+ provides methods to check the class of an object, its hierarchy, etc.
2268
+ when needed.
2269
+
2270
+ In Ruby there is no similar method as ``setIs'' and it is not possible
2271
+ to convert one class into another, but there are other ways of getting
2272
+ the necessary results. Let's then implement a method that returns the
2273
+ partition with the least number of groups. First, as usual, the R code
2274
+ with `setIs':
2275
+
2276
+ \begin{verbatim}
2277
+ > setIs(
2278
+ + class1="TrajPartitioned",
2279
+ + class2="Partition",
2280
+ + coerce=function(from,to){
2281
+ + numberGroups <- sapply(tdCochin@listPartitions,getNbGroups)
2282
+ + Smallest <- which.min(-numberGroups)
2283
+ + to<-new("Partition")
2284
+ + to@nbGroups <- getNbGroups(from@listPartitions[[Smallest]])
2285
+ + to@part <- getPart(from@listPartitions[[Smallest]])
2286
+ + return(to)
2287
+ + }
2288
+ + )
2289
+ \end{verbatim}
2290
+
2291
+ And now the Ruby code. Here we are getting deeper into Ruby and it is
2292
+ becoming harder for a pure R developer to understand the code. We will
2293
+ describe it in more detail:
2294
+
2295
+ \begin{itemize}
2296
+ \item
2297
+ We define a method called `to\_part' that has one argument `which'. By
2298
+ default `which' is `:min', the name of the minimum method. This means
2299
+ that if no argument is given to to\_part it will assume which = :min;
2300
+ \item
2301
+ @list\_partitions is a Ruby array. Method map is similar to method
2302
+ sapply in R, it applies a `block' to every element of the array,
2303
+ returning an array. Describing blocks is beyond the scope of this
2304
+ document, but we can think of it as if it were a function. The block
2305
+ is in `\{\}' and has one argument named `part'. Thus, map goes through
2306
+ all elements of the array, and gets the nb\_groups of the element and
2307
+ returns them into the number\_groups array.
2308
+ \item
2309
+ number\_groups is an array and doing number\_groups.min returns the
2310
+ minimum value in number\_groups and number\_groups.max the maximum. We
2311
+ can call a method on an object by `sending' the method name to the
2312
+ object, so, number\_groups.send(:min) is equivalent to
2313
+ number\_groups.min;
2314
+ \item
2315
+ Method `index' for array, returns the index of a given element. So,
2316
+ number\_groups.index(3) would return the index of the element `3'.
2317
+ Then number\_groups.index(number\_groups.min) returns the index of the
2318
+ minimum element in the array. This is the equivalent of R
2319
+ which.min(number\_groups);
2320
+ \item
2321
+ Finally, number\_groups.index(number\_groups.send(which)), will return
2322
+ the index of the element we ask for, be it :min or :max. Note that if
2323
+ we pass another value, this would be an error.
2324
+ \end{itemize}
2325
+
2326
+ \begin{Shaded}
2327
+ \begin{Highlighting}[]
2328
+ \ControlFlowTok{class} \DataTypeTok{TrajPartitioned}
2329
+
2330
+ \ControlFlowTok{def}\NormalTok{ to\_part(which }\OperatorTok{=} \WarningTok{:min}\NormalTok{)}
2331
+ \NormalTok{ number\_groups }\OperatorTok{=} \OtherTok{@list\_partitions}\AttributeTok{.map} \OperatorTok{\{} \OperatorTok{|}\NormalTok{part}\OperatorTok{|}\NormalTok{ part}\AttributeTok{.nb\_groups} \OperatorTok{\}}
2332
+ \NormalTok{ selected }\OperatorTok{=}\NormalTok{ number\_groups}\AttributeTok{.index}\NormalTok{(number\_groups}\AttributeTok{.send}\NormalTok{(which))}
2333
+ \ControlFlowTok{return} \OtherTok{@list\_partitions}\KeywordTok{[}\NormalTok{selected}\KeywordTok{]}
2334
+ \ControlFlowTok{end}
2335
+
2336
+ \ControlFlowTok{end}
2337
+ \end{Highlighting}
2338
+ \end{Shaded}
2339
+
2340
+ To get the partition with the minimum number of elements:
2341
+
2342
+ \begin{Shaded}
2343
+ \begin{Highlighting}[]
2344
+ \FunctionTok{puts} \OtherTok{@tdCochin}\AttributeTok{.to\_part.part}
2345
+ \end{Highlighting}
2346
+ \end{Shaded}
2347
+
2348
+ \begin{verbatim}
2349
+ ## [1] A B A B
2350
+ ## Levels: A B
2351
+ \end{verbatim}
2352
+
2353
+ To get the partition with the maximum number of elements:
2354
+
2355
+ \begin{Shaded}
2356
+ \begin{Highlighting}[]
2357
+ \FunctionTok{puts} \OtherTok{@tdCochin}\AttributeTok{.to\_part}\NormalTok{(}\WarningTok{:max}\NormalTok{)}\AttributeTok{.part}
2358
+ \end{Highlighting}
2359
+ \end{Shaded}
2360
+
2361
+ \begin{verbatim}
2362
+ ## [1] A C C B
2363
+ ## Levels: A B C
2364
+ \end{verbatim}
2365
+
2366
+ In this example we did not follow exactly the R code from SS4. The
2367
+ reason for that is that `list\_partitions' is a list of Ruby classes and
2368
+ we cannot run sapply on this list. If we try to call a `getNbGroups' or
2369
+ in the Ruby case nb\_groups via R's sapply, the code will crash.
2370
+
2371
+ \section{Virtual Classes}\label{virtual-classes}
2372
+
2373
+ In Ruby there are no ``Virtual Classes'', but it is possible to
2374
+ implement derived classes from a parent class with methods that behave
2375
+ properly according to the object's class. Following SS4 we will
2376
+ implement two classes: PartitionSimple and PartitionEval which are
2377
+ subclasses of class PartitionFather. PartitionFather will just be a
2378
+ regular class. Methods defined in PartitionFather will be available to
2379
+ be used in the subclasses
2380
+
2381
+ Here is the R code of those classes and the implementation of a method
2382
+ in PartitionFather that multiplies the number of groups by 2:
2383
+
2384
+ \begin{verbatim}
2385
+ > setClass(
2386
+ + Class="PartitionFather",
2387
+ + representation=representation(nbGroups="numeric","VIRTUAL")
2388
+ + )
2389
+
2390
+ > setClass(
2391
+ + Class="PartitionSimple",
2392
+ + representation=representation(part="factor"),
2393
+ + contains="PartitionFather"
2394
+ + )
2395
+
2396
+ > setClass(
2397
+ + Class="PartitionEval",
2398
+ + representation=representation(part="ordered"),
2399
+ + contains="PartitionFather"
2400
+ + )
2401
+
2402
+ > setGeneric("nbMultTwo",function(object){standardGeneric("nbMultTwo")})
2403
+
2404
+ > setMethod("nbMultTwo","PartitionFather",
2405
+ + function(object){
2406
+ + object@nbGroups <- object@nbGroups*2
2407
+ + return (object)
2408
+ + }
2409
+ + )
2410
+ \end{verbatim}
2411
+
2412
+ Since Ruby has no type definition, there is no really need for a parent
2413
+ class and subclasses. However, we will implement those classes in order
2414
+ to show Ruby's inheritance:
2415
+
2416
+ \begin{Shaded}
2417
+ \begin{Highlighting}[]
2418
+ \CommentTok{\# Parent class. Differently from SS4, both \textquotesingle{}nb\_groups\textquotesingle{} and \textquotesingle{}part\textquotesingle{} are}
2419
+ \CommentTok{\# defined in the}
2420
+ \CommentTok{\# parent class.}
2421
+ \ControlFlowTok{class} \DataTypeTok{PartitionFather}
2422
+
2423
+ \OtherTok{attr\_reader} \WarningTok{:nb\_groups}
2424
+ \OtherTok{attr\_reader} \WarningTok{:part}
2425
+
2426
+ \CommentTok{\# initialize class PartitionFather with the number of groups and}
2427
+ \CommentTok{\# parts. Note that we}
2428
+ \CommentTok{\# use R.c for nb\_groups in order to convert the number of groups into}
2429
+ \CommentTok{\# an R vector.}
2430
+ \ControlFlowTok{def}\NormalTok{ initialize(nb\_groups}\OperatorTok{:} \DecValTok{0}\NormalTok{, }\WarningTok{part:} \DecValTok{nil}\NormalTok{)}
2431
+ \OtherTok{@nb\_groups} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.c}\NormalTok{(nb\_groups)}
2432
+ \OtherTok{@part} \OperatorTok{=}\NormalTok{ part}
2433
+ \ControlFlowTok{end}
2434
+
2435
+ \CommentTok{\# method nb\_mult\_two can be called from all subclasses}
2436
+ \ControlFlowTok{def}\NormalTok{ nb\_mult\_two}
2437
+ \OtherTok{@nb\_groups} \OperatorTok{*} \DecValTok{2}
2438
+ \ControlFlowTok{end}
2439
+
2440
+ \CommentTok{\# method \textquotesingle{}to\_s\textquotesingle{} is called whenever we try to print a Ruby object.}
2441
+ \CommentTok{\# This method emulates}
2442
+ \CommentTok{\# R \textquotesingle{}print\textquotesingle{} method that prints all the slots.}
2443
+ \ControlFlowTok{def}\NormalTok{ to\_s}
2444
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"Variable \textquotesingle{}nb\_groups\textquotesingle{}:"}\NormalTok{)}
2445
+ \FunctionTok{puts} \OtherTok{@nb\_groups}
2446
+ \FunctionTok{puts}
2447
+ \FunctionTok{puts}\NormalTok{ (}\StringTok{"Variable \textquotesingle{}part\textquotesingle{}:"}\NormalTok{)}
2448
+ \FunctionTok{puts} \OtherTok{@part}
2449
+ \FunctionTok{puts}
2450
+ \ControlFlowTok{end}
2451
+
2452
+ \ControlFlowTok{end}
2453
+
2454
+ \CommentTok{\# Class PartitionSimple is a subclass of PartitionFather. To make a}
2455
+ \CommentTok{\# subclass of a}
2456
+ \CommentTok{\# class we use the operator \textquotesingle{}\textless{}\textquotesingle{}. Since the whole logic is in the parent}
2457
+ \CommentTok{\# class}
2458
+ \CommentTok{\# PartitionSimple is just an empty class}
2459
+ \ControlFlowTok{class} \DataTypeTok{PartitionSimple} \OperatorTok{\textless{}} \DataTypeTok{PartitionFather}
2460
+
2461
+ \ControlFlowTok{end}
2462
+
2463
+ \CommentTok{\# PartitionEval is also only an empty class}
2464
+ \ControlFlowTok{class} \DataTypeTok{PartitionEval} \OperatorTok{\textless{}} \DataTypeTok{PartitionFather}
2465
+
2466
+ \ControlFlowTok{end}
2467
+ \end{Highlighting}
2468
+ \end{Shaded}
2469
+
2470
+ \begin{Shaded}
2471
+ \begin{Highlighting}[]
2472
+ \OtherTok{@a} \OperatorTok{=} \DataTypeTok{PartitionSimple}\AttributeTok{.new}\NormalTok{(}
2473
+ \WarningTok{nb\_groups:} \DecValTok{3}\NormalTok{,}
2474
+ \WarningTok{part:}\NormalTok{ ((}\OperatorTok{\textasciitilde{}}\ConstantTok{R}\KeywordTok{[}\WarningTok{:LETTERS}\KeywordTok{]}\NormalTok{)}\KeywordTok{[}\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{3}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{1}\NormalTok{)}\KeywordTok{]}\AttributeTok{.factor}\NormalTok{))}
2475
+ \FunctionTok{puts} \OtherTok{@a}
2476
+ \end{Highlighting}
2477
+ \end{Shaded}
2478
+
2479
+ \begin{verbatim}
2480
+ ## Variable 'nb_groups':
2481
+ ## 3
2482
+ ##
2483
+ ## Variable 'part':
2484
+ ## [1] A B C B B A
2485
+ ## Levels: A B C
2486
+ ##
2487
+ ## #<RC::PartitionSimple:0x5f44865c>
2488
+ \end{verbatim}
2489
+
2490
+ \begin{Shaded}
2491
+ \begin{Highlighting}[]
2492
+ \FunctionTok{puts} \OtherTok{@a}\AttributeTok{.nb\_mult\_two}
2493
+ \end{Highlighting}
2494
+ \end{Shaded}
2495
+
2496
+ \begin{verbatim}
2497
+ ## [1] 6
2498
+ \end{verbatim}
2499
+
2500
+ \begin{Shaded}
2501
+ \begin{Highlighting}[]
2502
+ \OtherTok{@b} \OperatorTok{=} \DataTypeTok{PartitionEval}\AttributeTok{.new}\NormalTok{(}
2503
+ \WarningTok{nb\_groups:} \DecValTok{5}\NormalTok{,}
2504
+ \WarningTok{part:}\NormalTok{ (}\OperatorTok{\textasciitilde{}}\ConstantTok{R}\KeywordTok{[}\WarningTok{:LETTERS}\KeywordTok{]}\NormalTok{)}\KeywordTok{[}\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{5}\NormalTok{, }\DecValTok{3}\NormalTok{, }\DecValTok{4}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{4}\NormalTok{)}\KeywordTok{]}\AttributeTok{.ordered}\NormalTok{)}
2505
+ \FunctionTok{puts} \OtherTok{@b}
2506
+ \end{Highlighting}
2507
+ \end{Shaded}
2508
+
2509
+ \begin{verbatim}
2510
+ ## Variable 'nb_groups':
2511
+ ## 5
2512
+ ##
2513
+ ## Variable 'part':
2514
+ ## [1] A E C D B D
2515
+ ## Levels: A < B < C < D < E
2516
+ ##
2517
+ ## #<RC::PartitionEval:0x45e699f1>
2518
+ \end{verbatim}
2519
+
2520
+ \begin{Shaded}
2521
+ \begin{Highlighting}[]
2522
+ \FunctionTok{puts} \OtherTok{@b}\AttributeTok{.nb\_mult\_two}
2523
+ \end{Highlighting}
2524
+ \end{Shaded}
2525
+
2526
+ \begin{verbatim}
2527
+ ## [1] 10
2528
+ \end{verbatim}
2529
+
2530
+ The example above, although it replicates SS4 is not actually very
2531
+ useful from the point of view of class hierarchy in Ruby. We will then
2532
+ write a new function to\_s in class PartitionSimple that will print the
2533
+ name of the class:
2534
+
2535
+ \begin{Shaded}
2536
+ \begin{Highlighting}[]
2537
+ \ControlFlowTok{class} \DataTypeTok{PartitionSimple}
2538
+
2539
+ \ControlFlowTok{def}\NormalTok{ to\_s}
2540
+ \FunctionTok{puts}\NormalTok{(}\StringTok{"Class PartitionSimple"}\NormalTok{)}
2541
+ \DecValTok{super}
2542
+ \ControlFlowTok{end}
2543
+
2544
+ \ControlFlowTok{end}
2545
+ \end{Highlighting}
2546
+ \end{Shaded}
2547
+
2548
+ \begin{Shaded}
2549
+ \begin{Highlighting}[]
2550
+ \FunctionTok{puts} \OtherTok{@a}
2551
+ \end{Highlighting}
2552
+ \end{Shaded}
2553
+
2554
+ \begin{verbatim}
2555
+ ## Class PartitionSimple
2556
+ ## Variable 'nb_groups':
2557
+ ## 3
2558
+ ##
2559
+ ## Variable 'part':
2560
+ ## [1] A B C B B A
2561
+ ## Levels: A B C
2562
+ ##
2563
+ ## #<RC::PartitionSimple:0x5f44865c>
2564
+ \end{verbatim}
2565
+
2566
+ As can be seen, `puts @a' now calls method `to\_s' defined in class
2567
+ PartitionSimple. This method prints `Class PartitionSimple' and then
2568
+ calls the super method, i.e., method `to\_s' from class PartitionFather.
2569
+
2570
+ Note though that `puts @b' still prints the same output, since it has no
2571
+ particular `to\_s' method.
2572
+
2573
+ \begin{Shaded}
2574
+ \begin{Highlighting}[]
2575
+ \FunctionTok{puts} \OtherTok{@b}
2576
+ \end{Highlighting}
2577
+ \end{Shaded}
2578
+
2579
+ \begin{verbatim}
2580
+ ## Variable 'nb_groups':
2581
+ ## 5
2582
+ ##
2583
+ ## Variable 'part':
2584
+ ## [1] A E C D B D
2585
+ ## Levels: A < B < C < D < E
2586
+ ##
2587
+ ## #<RC::PartitionEval:0x45e699f1>
2588
+ \end{verbatim}
2589
+
2590
+ \section{Internal Modification of an
2591
+ Object}\label{internal-modification-of-an-object}
2592
+
2593
+ \subsection{Method to Modify a Field}\label{method-to-modify-a-field}
2594
+
2595
+ Let us return to our trajectories example and define a third method that
2596
+ imputes data for missing values. To simplify, we will impute by
2597
+ replacing by the mean values. This is the R code to do this:
2598
+
2599
+ \begin{verbatim}
2600
+ > meanWithoutNa <- function (x){mean(x,na.rm=TRUE)}
2601
+ > setGeneric("impute",function (.Object){standardGeneric("impute")})
2602
+ > setMethod(
2603
+ + f="impute",
2604
+ + signature="Trajectories",
2605
+ + def=function(.Object){
2606
+ + average <- apply(.Object@traj,2,meanWithoutNa)
2607
+ + for (iCol in 1:ncol(.Object@traj)){
2608
+ + .Object@traj[is.na(.Object@traj[,iCol]),iCol] <- average[iCol]
2609
+ + }
2610
+ + return(.Object)
2611
+ + }
2612
+ + )
2613
+ \end{verbatim}
2614
+
2615
+ The code above, as explained in SS4 creates a new object and does not
2616
+ change the original one. So, calling impute(trajCochin) will work
2617
+ correctly by creating a new object but will not change trajCochin. This
2618
+ works fine, but can be memory expensive if the matrix is a large one.
2619
+
2620
+ Let's now implement the same method in Galaaz 2.0. We stay on the R side
2621
+ of the bridge: for each column, compute the mean with
2622
+ \texttt{na.rm\ =\ true}, then replace NA entries with that mean (via
2623
+ \texttt{R.ifelse} / \texttt{is\_\_na}), and rebuild the matrix with
2624
+ \texttt{R.cbind}. No MDArray iteration is required.
2625
+
2626
+ \begin{Shaded}
2627
+ \begin{Highlighting}[]
2628
+ \ControlFlowTok{class} \DataTypeTok{Trajectories}
2629
+
2630
+ \ControlFlowTok{def}\NormalTok{ impute}
2631
+ \NormalTok{ ncols }\OperatorTok{=} \OtherTok{@matrix}\AttributeTok{.ncol} \OperatorTok{\textgreater{}\textgreater{}} \DecValTok{0}
2632
+ \NormalTok{ imputed }\OperatorTok{=}\NormalTok{ (}\DecValTok{1}\OperatorTok{..}\NormalTok{ncols)}\AttributeTok{.map} \ControlFlowTok{do} \OperatorTok{|}\NormalTok{j}\OperatorTok{|}
2633
+ \NormalTok{ col }\OperatorTok{=} \OtherTok{@matrix}\KeywordTok{[}\DecValTok{nil}\NormalTok{, j}\KeywordTok{]}
2634
+ \NormalTok{ avg }\OperatorTok{=}\NormalTok{ col}\AttributeTok{.mean}\NormalTok{(}\WarningTok{na\_\_rm:} \DecValTok{true}\NormalTok{)}
2635
+ \ConstantTok{R}\AttributeTok{.ifelse}\NormalTok{(col}\AttributeTok{.is\_\_na}\NormalTok{, avg, col)}
2636
+ \ControlFlowTok{end}
2637
+ \NormalTok{ col\_names }\OperatorTok{=} \OtherTok{@matrix}\AttributeTok{.colnames}
2638
+ \NormalTok{ row\_names }\OperatorTok{=} \OtherTok{@matrix}\AttributeTok{.rownames}
2639
+ \OtherTok{@matrix} \OperatorTok{=} \ConstantTok{R}\AttributeTok{.cbind}\NormalTok{(}\OperatorTok{*}\NormalTok{imputed)}
2640
+ \OtherTok{@matrix}\AttributeTok{.colnames} \OperatorTok{=}\NormalTok{ col\_names }\ControlFlowTok{unless}\NormalTok{ col\_names}\AttributeTok{.nil?}
2641
+ \OtherTok{@matrix}\AttributeTok{.rownames} \OperatorTok{=}\NormalTok{ row\_names }\ControlFlowTok{unless}\NormalTok{ row\_names}\AttributeTok{.nil?}
2642
+ \DecValTok{self}
2643
+ \ControlFlowTok{end}
2644
+
2645
+ \ControlFlowTok{end}
2646
+ \end{Highlighting}
2647
+ \end{Shaded}
2648
+
2649
+ \begin{Shaded}
2650
+ \begin{Highlighting}[]
2651
+ \OtherTok{@trajCochin}\AttributeTok{.impute}
2652
+ \FunctionTok{puts} \OtherTok{@trajCochin}\AttributeTok{.matrix}
2653
+ \end{Highlighting}
2654
+ \end{Shaded}
2655
+
2656
+ \begin{verbatim}
2657
+ ## $rownames
2658
+ ## [1] "I1" "I2" "I3" "I4"
2659
+ \end{verbatim}
2660
+
2661
+ It works, and \texttt{@trajCochin.matrix} was updated. Under GNU R,
2662
+ assignment follows R's usual copy-on-write semantics: replacing
2663
+ \texttt{@matrix} (or assigning into an R object through the bridge)
2664
+ binds a new vector/matrix rather than mutating a shared MDArray store.
2665
+ That is a deliberate difference from the Renjin/MDArray mutation
2666
+ experiments in the older paper; those demos are not part of Galaaz 2.0.
2667
+
2668
+ \section{Conclusions I}\label{conclusions-i}
2669
+
2670
+ This ends the SS4 paper material for classes and inheritance. We believe
2671
+ we have shown that R S4 can be substituted by Galaaz and Ruby classes
2672
+ and that Galaaz makes an easy transition from R developers to Ruby. Ruby
2673
+ is a very flexible and powerful language and has many interesting
2674
+ libraries, where Rails is maybe one of the best known, but there are
2675
+ thousands of others. For those interested in getting deeper into Ruby's
2676
+ libraries, we suggest they look at:
2677
+
2678
+ \begin{itemize}
2679
+ \tightlist
2680
+ \item
2681
+ \url{https://github.com/markets/awesome-ruby}
2682
+ \item
2683
+ \url{http://bestgems.org/}
2684
+ \end{itemize}
2685
+
2686
+ For those interested in Ruby and science, we recommend:
2687
+
2688
+ \begin{itemize}
2689
+ \tightlist
2690
+ \item
2691
+ \url{http://sciruby.com/}
2692
+ \end{itemize}
2693
+
2694
+ \textbf{Galaaz 2.0} runs on \textbf{JRuby or CRuby} and talks to
2695
+ \textbf{GNU R} through the bridge described in this series --- the same
2696
+ integration model used throughout the examples above.
2697
+
2698
+ \section{Callbacks and R calling into
2699
+ Ruby}\label{callbacks-and-r-calling-into-ruby}
2700
+
2701
+ On this paper we have focused on accessing R functions from Ruby and
2702
+ have shown how to integrate Ruby with R from the point of view of a Ruby
2703
+ developer. The complementary direction --- R calling back into Ruby ---
2704
+ is also supported in Galaaz 2.0.
2705
+
2706
+ Galaaz 2.0 uses the \textbf{bridge callback} mechanism: Ruby procs (and
2707
+ related callables) can be passed where R expects functions, so
2708
+ algorithms written in R (for example optimizers or higher-order
2709
+ \texttt{*apply} helpers) can invoke Ruby logic without leaving the
2710
+ bridge session. Details, options such as callback timeouts, and further
2711
+ examples are in the project manual and on the documentation site:
2712
+ \url{https://rbotafogo.github.io/galaaz/}.
2713
+
2714
+ We do not reproduce here the older Renjin-era material on packing Ruby
2715
+ objects as R external pointers, constructing Ruby classes from R via JVM
2716
+ APIs, or calling Java collections from R scripts. Those sections
2717
+ belonged to a different runtime; the callback bridge is the supported
2718
+ path in Galaaz 2.0.
2719
+
2720
+ \section{Conclusions II}\label{conclusions-ii}
2721
+
2722
+ \textbf{JRuby or CRuby + GNU R + Galaaz} gives a practical polyglot
2723
+ stack: idiomatic Ruby for structure and libraries, GNU R for statistics
2724
+ and the CRAN/Bioconductor ecosystem, and Galaaz as the bridge between
2725
+ them. As always, choose the right tools for the job at hand --- and when
2726
+ the job sits between an R-only workflow and a broader polyglot
2727
+ application, Galaaz is designed to connect those worlds.
2728
+
821
2729
  \end{document}