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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +9 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +63 -58
- data/blogs/galaaz_ggplot/galaaz_ggplot.log +59 -68
- data/blogs/galaaz_ggplot/galaaz_ggplot.md +91 -84
- data/blogs/galaaz_ggplot/galaaz_ggplot.tex +125 -94
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
- data/blogs/gknit/gknit.Rmd +33 -28
- data/blogs/gknit/gknit.md +47 -42
- data/blogs/gknit/gknit.tex +1368 -0
- data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
- data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
- data/blogs/gknit/gknit_files/figure-latex/bubble-1.png +0 -0
- data/blogs/gknit/gknit_files/gknit_files/figure-latex/bubble-1.png +0 -0
- data/blogs/manual/manual.Rmd +129 -60
- data/blogs/manual/manual.log +289 -545
- data/blogs/manual/manual.md +551 -467
- data/blogs/manual/manual.tex +1059 -485
- data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
- data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
- data/blogs/manual/manual_files/figure-markdown_github/bubble-1.png +0 -0
- data/blogs/manual/manual_files/figure-markdown_github/diverging_bar.png +0 -0
- data/blogs/manual/manual_files/manual_files/figure-latex/bubble-1.png +0 -0
- data/blogs/nse_dplyr/nse_dplyr.Rmd +28 -7
- data/blogs/nse_dplyr/nse_dplyr.log +49 -153
- data/blogs/nse_dplyr/nse_dplyr.md +676 -705
- data/blogs/nse_dplyr/nse_dplyr.tex +1589 -0
- data/blogs/oh_my/oh_my.Rmd +193 -55
- data/blogs/oh_my/oh_my.log +265 -95
- data/blogs/oh_my/oh_my.md +236 -95
- data/blogs/oh_my/oh_my.tex +1976 -68
- data/blogs/ruby_plot/ruby_plot.Rmd +42 -34
- data/blogs/ruby_plot/ruby_plot.log +101 -99
- data/blogs/ruby_plot/ruby_plot.md +52 -46
- data/blogs/ruby_plot/ruby_plot.tex +134 -102
- data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
- data/lib/galaaz/cli.rb +51 -10
- data/script/omarchy/README.md +1 -1
- data/script/omarchy/galaaz-guide.sh +1 -1
- data/sty/galaaz.sty +22 -0
- data/version.rb +1 -1
- metadata +19 -1
data/blogs/oh_my/oh_my.tex
CHANGED
|
@@ -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
|
|
193
|
-
|
|
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}
|
|
206
|
-
\textbf{\href{https://www.jruby.org/}{JRuby}}
|
|
207
|
-
through a \textbf{bridge}, so Ruby code can
|
|
208
|
-
objects and call R functions while staying
|
|
209
|
-
prototype used Oracle's \textbf{GraalVM} with
|
|
210
|
-
\textbf{FastR}; that stack is historical and is
|
|
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
|
|
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
|
|
263
|
-
instance variable) as
|
|
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:
|
|
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
|
|
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
|
|
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{),
|
|
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,
|
|
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{(}
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
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
|
-
##
|
|
460
|
-
##
|
|
461
|
-
##
|
|
462
|
-
##
|
|
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
|
|
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
|
-
|
|
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
|
-
##
|
|
677
|
-
##
|
|
678
|
-
##
|
|
679
|
-
##
|
|
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
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
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
|
-
|
|
729
|
-
|
|
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
|
|
738
|
-
|
|
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
|
|
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{\
|
|
762
|
-
\NormalTok{ ncol\_show }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.min}\NormalTok{(}\DecValTok{10}\NormalTok{, }\OtherTok{@matrix}\AttributeTok{.ncol}\NormalTok{) }\OperatorTok{\
|
|
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{,
|
|
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
|
-
##
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
##
|
|
784
|
-
##
|
|
785
|
-
##
|
|
786
|
-
##
|
|
787
|
-
##
|
|
788
|
-
##
|
|
789
|
-
##
|
|
790
|
-
##
|
|
791
|
-
##
|
|
792
|
-
##
|
|
793
|
-
##
|
|
794
|
-
##
|
|
795
|
-
##
|
|
796
|
-
##
|
|
797
|
-
##
|
|
798
|
-
##
|
|
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
|
-
\
|
|
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}
|