galaaz 2.1.7 → 2.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/Rakefile +20 -2
  4. data/bin/check_gemfile_lock_version +46 -0
  5. data/bin/release_bump +26 -0
  6. data/blogs/README.md +4 -0
  7. data/blogs/galaaz_2_0/galaaz_2_0.Rmd +385 -0
  8. data/blogs/galaaz_2_0/galaaz_2_0.md +409 -0
  9. data/blogs/galaaz_2_0/galaaz_2_0.tex +756 -0
  10. data/blogs/galaaz_2_0/images/galaaz-header.png +0 -0
  11. data/blogs/galaaz_2_0/images/galaaz-lockup-stacked.png +0 -0
  12. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +76 -58
  13. data/blogs/galaaz_ggplot/galaaz_ggplot.md +188 -161
  14. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +185 -117
  15. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  16. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  17. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  18. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  19. data/blogs/galaaz_ggplot/images/galaaz-lockup-stacked.png +0 -0
  20. data/blogs/gknit/gknit.Rmd +48 -28
  21. data/blogs/gknit/gknit.md +60 -43
  22. data/blogs/gknit/gknit.tex +1409 -0
  23. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  24. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  25. data/blogs/gknit/gknit_files/figure-latex/bubble-1.png +0 -0
  26. data/blogs/gknit/images/galaaz-lockup-stacked.png +0 -0
  27. data/blogs/manual/images/galaaz-lockup-stacked.png +0 -0
  28. data/blogs/manual/manual.Rmd +161 -71
  29. data/blogs/manual/manual.md +573 -482
  30. data/blogs/manual/manual.tex +1113 -517
  31. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  32. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  33. data/blogs/manual/manual_files/figure-markdown_github/bubble-1.png +0 -0
  34. data/blogs/manual/manual_files/figure-markdown_github/diverging_bar.png +0 -0
  35. data/blogs/nse_dplyr/images/galaaz-lockup-stacked.png +0 -0
  36. data/blogs/nse_dplyr/nse_dplyr.Rmd +42 -8
  37. data/blogs/nse_dplyr/nse_dplyr.md +69 -50
  38. data/blogs/nse_dplyr/nse_dplyr.tex +1626 -0
  39. data/blogs/oh_my/images/galaaz-lockup-stacked.png +0 -0
  40. data/blogs/oh_my/oh_my.Rmd +206 -55
  41. data/blogs/oh_my/oh_my.md +247 -96
  42. data/blogs/oh_my/oh_my.tex +2038 -93
  43. data/blogs/r_on_rails_ledger/images/00_portfolio_page.png +0 -0
  44. data/blogs/r_on_rails_ledger/images/01_results_panel.png +0 -0
  45. data/blogs/r_on_rails_ledger/images/02_density_tail_risk.png +0 -0
  46. data/blogs/r_on_rails_ledger/images/03_mc_cone.png +0 -0
  47. data/blogs/r_on_rails_ledger/images/04_rolling_var.png +0 -0
  48. data/blogs/r_on_rails_ledger/images/galaaz-lockup-stacked.png +0 -0
  49. data/blogs/r_on_rails_ledger/r_on_rails_ledger.Rmd +354 -0
  50. data/blogs/r_on_rails_ledger/r_on_rails_ledger.md +365 -0
  51. data/blogs/r_on_rails_ledger/r_on_rails_ledger.tex +670 -0
  52. data/blogs/ruby_plot/images/galaaz-lockup-stacked.png +0 -0
  53. data/blogs/ruby_plot/ruby_plot.Rmd +56 -35
  54. data/blogs/ruby_plot/ruby_plot.md +63 -47
  55. data/blogs/ruby_plot/ruby_plot.tex +194 -125
  56. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  57. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  58. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  59. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  60. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  61. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  62. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  63. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  64. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  65. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  66. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  67. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  68. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  72. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  73. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  74. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  75. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  77. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  78. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/dose_len.png +0 -0
  79. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  80. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  81. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  82. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  83. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  84. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  85. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  86. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  87. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  88. data/blogs/ruby_plot/ruby_plot_files/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  89. data/lib/galaaz/cli.rb +98 -13
  90. data/logos/icon-font/README.md +27 -0
  91. data/logos/icon-font/build_font.py +130 -0
  92. data/logos/icon-font/galaaz-mark.svg +34 -0
  93. data/script/omarchy/README.md +9 -2
  94. data/script/omarchy/fonts/galaaz.ttf +0 -0
  95. data/script/omarchy/galaaz-guide.sh +1 -1
  96. data/script/omarchy/install-galaaz.sh +8 -1
  97. data/script/omarchy/omarchy-menu.jsonc +21 -9
  98. data/sty/galaaz-header.png +0 -0
  99. data/sty/galaaz-headers-from-p3.tex +4 -0
  100. data/sty/galaaz.sty +76 -23
  101. data/version.rb +1 -1
  102. metadata +46 -7
  103. data/blogs/galaaz_ggplot/galaaz_ggplot.log +0 -754
  104. data/blogs/manual/manual.log +0 -1786
  105. data/blogs/nse_dplyr/nse_dplyr.log +0 -928
  106. data/blogs/oh_my/oh_my.log +0 -804
  107. data/blogs/ruby_plot/ruby_plot.log +0 -885
@@ -0,0 +1,756 @@
1
+ % Options for packages loaded elsewhere
2
+ \PassOptionsToPackage{unicode}{hyperref}
3
+ \PassOptionsToPackage{hyphens}{url}
4
+ \documentclass[
5
+ 11pt,
6
+ ]{article}
7
+ \usepackage{xcolor}
8
+ \usepackage[margin=1in]{geometry}
9
+ \usepackage{amsmath,amssymb}
10
+ \setcounter{secnumdepth}{5}
11
+ \usepackage{iftex}
12
+ \ifPDFTeX
13
+ \usepackage[T1]{fontenc}
14
+ \usepackage[utf8]{inputenc}
15
+ \usepackage{textcomp} % provide euro and other symbols
16
+ \else % if luatex or xetex
17
+ \usepackage{unicode-math} % this also loads fontspec
18
+ \defaultfontfeatures{Scale=MatchLowercase}
19
+ \defaultfontfeatures[\rmfamily]{Ligatures=TeX,Scale=1}
20
+ \fi
21
+ \usepackage{lmodern}
22
+ \ifPDFTeX\else
23
+ % xetex/luatex font selection
24
+ \fi
25
+ % Use upquote if available, for straight quotes in verbatim environments
26
+ \IfFileExists{upquote.sty}{\usepackage{upquote}}{}
27
+ \IfFileExists{microtype.sty}{% use microtype if available
28
+ \usepackage[]{microtype}
29
+ \UseMicrotypeSet[protrusion]{basicmath} % disable protrusion for tt fonts
30
+ }{}
31
+ \makeatletter
32
+ \@ifundefined{KOMAClassName}{% if non-KOMA class
33
+ \IfFileExists{parskip.sty}{%
34
+ \usepackage{parskip}
35
+ }{% else
36
+ \setlength{\parindent}{0pt}
37
+ \setlength{\parskip}{6pt plus 2pt minus 1pt}}
38
+ }{% if KOMA class
39
+ \KOMAoptions{parskip=half}}
40
+ \makeatother
41
+ \usepackage{color}
42
+ \usepackage{fancyvrb}
43
+ \newcommand{\VerbBar}{|}
44
+ \newcommand{\VERB}{\Verb[commandchars=\\\{\}]}
45
+ \DefineVerbatimEnvironment{Highlighting}{Verbatim}{commandchars=\\\{\}}
46
+ % Add ',fontsize=\small' for more characters per line
47
+ \usepackage{framed}
48
+ \definecolor{shadecolor}{RGB}{248,248,248}
49
+ \newenvironment{Shaded}{\begin{snugshade}}{\end{snugshade}}
50
+ \newcommand{\AlertTok}[1]{\textcolor[rgb]{0.94,0.16,0.16}{#1}}
51
+ \newcommand{\AnnotationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
52
+ \newcommand{\AttributeTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{#1}}
53
+ \newcommand{\BaseNTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
54
+ \newcommand{\BuiltInTok}[1]{#1}
55
+ \newcommand{\CharTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
56
+ \newcommand{\CommentTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textit{#1}}}
57
+ \newcommand{\CommentVarTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
58
+ \newcommand{\ConstantTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{#1}}
59
+ \newcommand{\ControlFlowTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{\textbf{#1}}}
60
+ \newcommand{\DataTypeTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{#1}}
61
+ \newcommand{\DecValTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
62
+ \newcommand{\DocumentationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
63
+ \newcommand{\ErrorTok}[1]{\textcolor[rgb]{0.64,0.00,0.00}{\textbf{#1}}}
64
+ \newcommand{\ExtensionTok}[1]{#1}
65
+ \newcommand{\FloatTok}[1]{\textcolor[rgb]{0.00,0.00,0.81}{#1}}
66
+ \newcommand{\FunctionTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{\textbf{#1}}}
67
+ \newcommand{\ImportTok}[1]{#1}
68
+ \newcommand{\InformationTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
69
+ \newcommand{\KeywordTok}[1]{\textcolor[rgb]{0.13,0.29,0.53}{\textbf{#1}}}
70
+ \newcommand{\NormalTok}[1]{#1}
71
+ \newcommand{\OperatorTok}[1]{\textcolor[rgb]{0.81,0.36,0.00}{\textbf{#1}}}
72
+ \newcommand{\OtherTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{#1}}
73
+ \newcommand{\PreprocessorTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textit{#1}}}
74
+ \newcommand{\RegionMarkerTok}[1]{#1}
75
+ \newcommand{\SpecialCharTok}[1]{\textcolor[rgb]{0.81,0.36,0.00}{\textbf{#1}}}
76
+ \newcommand{\SpecialStringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
77
+ \newcommand{\StringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
78
+ \newcommand{\VariableTok}[1]{\textcolor[rgb]{0.00,0.00,0.00}{#1}}
79
+ \newcommand{\VerbatimStringTok}[1]{\textcolor[rgb]{0.31,0.60,0.02}{#1}}
80
+ \newcommand{\WarningTok}[1]{\textcolor[rgb]{0.56,0.35,0.01}{\textbf{\textit{#1}}}}
81
+ \usepackage{longtable,booktabs,array}
82
+ \newcounter{none} % for unnumbered tables
83
+ \usepackage{calc} % for calculating minipage widths
84
+ % Correct order of tables after \paragraph or \subparagraph
85
+ \usepackage{etoolbox}
86
+ \makeatletter
87
+ \patchcmd\longtable{\par}{\if@noskipsec\mbox{}\fi\par}{}{}
88
+ \makeatother
89
+ % Allow footnotes in longtable head/foot
90
+ \IfFileExists{footnotehyper.sty}{\usepackage{footnotehyper}}{\usepackage{footnote}}
91
+ \makesavenoteenv{longtable}
92
+ \usepackage{graphicx}
93
+ \makeatletter
94
+ \newsavebox\pandoc@box
95
+ \newcommand*\pandocbounded[1]{% scales image to fit in text height/width
96
+ \sbox\pandoc@box{#1}%
97
+ \Gscale@div\@tempa{\textheight}{\dimexpr\ht\pandoc@box+\dp\pandoc@box\relax}%
98
+ \Gscale@div\@tempb{\linewidth}{\wd\pandoc@box}%
99
+ \ifdim\@tempb\p@<\@tempa\p@\let\@tempa\@tempb\fi% select the smaller of both
100
+ \ifdim\@tempa\p@<\p@\scalebox{\@tempa}{\usebox\pandoc@box}%
101
+ \else\usebox{\pandoc@box}%
102
+ \fi%
103
+ }
104
+ % Set default figure placement to htbp
105
+ \def\fps@figure{htbp}
106
+ \makeatother
107
+ \setlength{\emergencystretch}{3em} % prevent overfull lines
108
+ \providecommand{\tightlist}{%
109
+ \setlength{\itemsep}{0pt}\setlength{\parskip}{0pt}}
110
+ % usar portugues do Brasil
111
+ % \usepackage[brazilian]{babel}
112
+ \usepackage[utf8]{inputenc}
113
+
114
+ \usepackage{geometry}
115
+ \geometry{a4paper, top=1.05in, headheight=30pt, headsep=14pt}
116
+
117
+ % needed for kableExtra
118
+ \usepackage{longtable}
119
+ \usepackage{multirow}
120
+ \usepackage[table]{xcolor}
121
+ \usepackage{wrapfig}
122
+ \usepackage{float}
123
+ \usepackage{colortbl}
124
+ \usepackage{pdflscape}
125
+ \usepackage{tabu}
126
+ \usepackage{threeparttable}
127
+ \usepackage[normalem]{ulem}
128
+
129
+ \usepackage{bbm}
130
+ \usepackage{booktabs}
131
+ \usepackage{expex}
132
+
133
+ \usepackage{graphicx}
134
+
135
+ \usepackage{fancyhdr}
136
+ % Header: small Galaaz mark (left); page number + section title (right),
137
+ % matching classic LaTeX style: "4 AN EXTENSION TO THE EXAMPLE"
138
+ % (upright page number, uppercase italic section name).
139
+ % Logo paths cover repo blogs (../../sty/), installed ~/sty/, and local images/.
140
+ % Blogs may delay headers with \renewcommand{\galaazheaderfrompage}{3} after this sty
141
+ % (e.g. skip title/TOC and a logo splash page).
142
+ \newcommand{\galaazheaderfrompage}{1}
143
+ \newcommand{\galaazheaderlogo}{%
144
+ \raisebox{-0.12\height}{%
145
+ \IfFileExists{../../sty/galaaz-header.png}{%
146
+ \includegraphics[height=0.32in]{../../sty/galaaz-header.png}%
147
+ }{%
148
+ \IfFileExists{galaaz-header.png}{%
149
+ \includegraphics[height=0.32in]{galaaz-header.png}%
150
+ }{%
151
+ \IfFileExists{images/galaaz-header.png}{%
152
+ \includegraphics[height=0.32in]{images/galaaz-header.png}%
153
+ }{}%
154
+ }%
155
+ }%
156
+ }%
157
+ }
158
+ % Section title only in marks (no \thesection); page number is separate.
159
+ \renewcommand{\sectionmark}[1]{\markboth{#1}{}}
160
+ \renewcommand{\subsectionmark}[1]{}% keep the current section in the header
161
+ \newcommand{\galaazmaybeheaderlogo}{%
162
+ \ifnum\value{page}<\galaazheaderfrompage\relax\else\galaazheaderlogo\fi}
163
+ \newcommand{\galaazmayberighthead}{%
164
+ \ifnum\value{page}<\galaazheaderfrompage\relax
165
+ \else
166
+ \textup{\thepage}\hspace{1em}\textit{\MakeUppercase{\leftmark}}%
167
+ \fi
168
+ }
169
+ \pagestyle{fancy}
170
+ \fancyhf{}
171
+ \fancyhead[L]{\galaazmaybeheaderlogo}
172
+ \fancyhead[R]{\galaazmayberighthead}
173
+ \renewcommand{\headrulewidth}{0.3pt}
174
+ \makeatletter
175
+ \renewcommand{\headrule}{%
176
+ \ifnum\value{page}<\galaazheaderfrompage\relax
177
+ \else
178
+ \hrule\@height\headrulewidth\@width\headwidth
179
+ \vskip-\headrulewidth
180
+ \fi
181
+ }
182
+ \makeatother
183
+ % First page often uses plain; same conditional header logic.
184
+ \fancypagestyle{plain}{%
185
+ \fancyhf{}%
186
+ \fancyhead[L]{\galaazmaybeheaderlogo}%
187
+ \fancyhead[R]{\galaazmayberighthead}%
188
+ \renewcommand{\headrulewidth}{0.3pt}%
189
+ }
190
+
191
+ % make available command lastpage
192
+ \usepackage{lastpage}
193
+
194
+ % default fontsize 11pt better to add
195
+ % fontsize on the yaml header
196
+ % \usepackage[fontsize=11pt]{scrextend}
197
+
198
+ % comandos para formatar uma tabela
199
+ \usepackage{array}
200
+ \newcolumntype{L}[1]{>{\raggedright\let\newline\\\arraybackslash\hspace{0pt}}m{#1}}
201
+ \newcolumntype{C}[1]{>{\centering\let\newline\\\arraybackslash\hspace{0pt}}m{#1}}
202
+ \newcolumntype{R}[1]{>{\raggedleft\let\newline\\\arraybackslash\hspace{0pt}}m{#1}}
203
+
204
+ % necessário if we need to import other latex documents
205
+ \usepackage{import}
206
+
207
+ % Command to import an R variable to latex
208
+ \newcommand{\RtoLatex}[2]{\newcommand{#1}{#2}}
209
+
210
+ % Soft-wrap Pandoc highlighted code/output boxes (Shaded + Highlighting).
211
+ % This runs after Pandoc's default \DefineVerbatimEnvironment{Highlighting}
212
+ % (header includes come later in the generated .tex). Prefer manual line
213
+ % breaks in Rmd sources; breaklines is a safety net for leftovers/output.
214
+ % Requires TinyTeX/TeX Live package: tlmgr install fvextra
215
+ \IfFileExists{fvextra.sty}{%
216
+ \usepackage{fvextra}%
217
+ \DefineVerbatimEnvironment{Highlighting}{Verbatim}{%
218
+ breaklines=true,
219
+ breakanywhere=true,
220
+ breakindent=1.5em,
221
+ fontsize=\small,
222
+ commandchars=\\\{\}%
223
+ }%
224
+ }{%
225
+ % fancyvrb is already loaded by Pandoc; shrink code so more fits per line.
226
+ \DefineVerbatimEnvironment{Highlighting}{Verbatim}{%
227
+ fontsize=\small,
228
+ commandchars=\\\{\}%
229
+ }%
230
+ }
231
+
232
+ %
233
+ %\newcommand{\atraso}[1]{\color{red} \textbf {Tempo desde a Assinatura do Contrato: #1 dias}}
234
+ % No header on title/TOC (p.1) or splash logo page (p.2);
235
+ % logo + page number + section title from page 3 onward.
236
+ % Load after galaaz.sty.
237
+ \renewcommand{\galaazheaderfrompage}{3}
238
+ \usepackage{bookmark}
239
+ \IfFileExists{xurl.sty}{\usepackage{xurl}}{} % add URL line breaks if available
240
+ \urlstyle{same}
241
+ \hypersetup{
242
+ pdftitle={Galaaz 2.0: Ruby meets real GNU R (again)},
243
+ pdfauthor={Rodrigo Botafogo},
244
+ hidelinks,
245
+ pdfcreator={LaTeX via pandoc}}
246
+
247
+ \title{Galaaz 2.0: Ruby meets real GNU R (again)}
248
+ \usepackage{etoolbox}
249
+ \makeatletter
250
+ \providecommand{\subtitle}[1]{% add subtitle to \maketitle
251
+ \apptocmd{\@title}{\par {\large #1 \par}}{}{}
252
+ }
253
+ \makeatother
254
+ \subtitle{NewBridge, JRuby or CRuby, CRAN/Bioconductor, and Arrow-shaped
255
+ data paths}
256
+ \author{Rodrigo Botafogo}
257
+ \date{2026}
258
+
259
+ \begin{document}
260
+ \maketitle
261
+
262
+ {
263
+ \setcounter{tocdepth}{2}
264
+ \tableofcontents
265
+ }
266
+ \begin{center}\includegraphics[width=0.45\linewidth]{images/galaaz-lockup-stacked} \end{center}
267
+
268
+ \section{Introduction}\label{introduction}
269
+
270
+ Ruby is excellent for web apps, orchestration, and expressive object
271
+ models. It has never matched \textbf{R} for statistics, Bioconductor
272
+ pipelines, or the depth of CRAN. \textbf{Python} closed a similar gap
273
+ with NumPy, pandas, and a huge scientific ecosystem. For Ruby, the
274
+ practical answer is not to reimplement that world --- it is to
275
+ \textbf{drive real R} from idiomatic Ruby.
276
+
277
+ \textbf{Galaaz} is that coupling. An earlier line of work ran on
278
+ Oracle's \textbf{GraalVM} with \textbf{TruffleRuby} and \textbf{FastR}
279
+ in one JVM. \textbf{Galaaz 2.0} is a different architecture:
280
+ \textbf{JRuby or CRuby} talk to \textbf{standard GNU R} over a process
281
+ bridge we call \textbf{NewBridge}. You keep CRAN and Bioconductor
282
+ (including compiled packages), and you keep a normal Ruby toolchain.
283
+
284
+ This post is the 2.0 story: what changed, how the bridge works, how to
285
+ pin R versions in containers, how data moves (including \textbf{Apache
286
+ Arrow}), and how to keep the bridge free for long R jobs. Deep API
287
+ detail lives in the \href{https://rbotafogo.github.io/galaaz/}{Galaaz
288
+ Manual}; here we stay at blog length with a few runnable sketches.
289
+
290
+ \section{What changed}\label{what-changed}
291
+
292
+ {\def\LTcaptype{none} % do not increment counter
293
+ \begin{longtable}[]{@{}
294
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}
295
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}
296
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}@{}}
297
+ \toprule\noalign{}
298
+ \begin{minipage}[b]{\linewidth}\raggedright
299
+ \end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
300
+ Historical stack
301
+ \end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
302
+ Galaaz 2.0
303
+ \end{minipage} \\
304
+ \midrule\noalign{}
305
+ \endhead
306
+ \bottomrule\noalign{}
307
+ \endlastfoot
308
+ Ruby & TruffleRuby (Graal) & \textbf{JRuby} or \textbf{CRuby} \\
309
+ R & FastR (subset of GNU R) & \textbf{GNU R} (CRAN / Bioconductor) \\
310
+ Coupling & Same-JVM interop & \textbf{NewBridge} (separate processes) \\
311
+ Install & Special Graal distribution & \texttt{gem\ install} + compile
312
+ gatekeeper \\
313
+ Legacy tools & \texttt{grun}, polyglot \texttt{gknit-draft} &
314
+ \texttt{bin/galaaz-ruby}, \texttt{bin/gknit} \\
315
+ \end{longtable}
316
+ }
317
+
318
+ Ideas from the older articles still matter --- ggplot layers, dplyr
319
+ pipes, gKnit literate docs --- but the \textbf{engine} underneath is
320
+ different. If you land on a 2018 ``Ruby + R on GraalVM'' post, treat the
321
+ plots and narrative as inspiration and this post (plus the manual) as
322
+ the current stack.
323
+
324
+ \section{NewBridge in one picture}\label{newbridge-in-one-picture}
325
+
326
+ Galaaz 2.0 does \textbf{not} embed Renjin or FastR. Roughly:
327
+
328
+ \begin{enumerate}
329
+ \def\labelenumi{\arabic{enumi}.}
330
+ \tightlist
331
+ \item
332
+ Your \textbf{Ruby} process (JRuby or CRuby) loads Galaaz.
333
+ \item
334
+ A native \textbf{gatekeeper} (\texttt{ext/new\_bridge}, Rcpp / C++)
335
+ mediates the protocol.
336
+ \item
337
+ A \textbf{GNU R} process evaluates calls, holds large objects, and
338
+ runs packages.
339
+ \end{enumerate}
340
+
341
+ Ruby stays Ruby: \texttt{R.mean}, \texttt{E.aes}, method chaining,
342
+ classes and modules. R stays R: the same \texttt{lm}, \texttt{DESeq2},
343
+ or \texttt{ggplot2} you would run in RStudio. Large panels should
344
+ usually \textbf{stay in R}; Ruby orchestrates and pulls small results
345
+ (Remote Control). Opt in to unbox scalars when you need a plain Ruby
346
+ number (\texttt{\textgreater{}\textgreater{}\ 0} for length-1 vectors is
347
+ the common 2.0 idiom).
348
+
349
+ A minimal session looks like this:
350
+
351
+ \begin{Shaded}
352
+ \begin{Highlighting}[]
353
+ \FunctionTok{require} \VerbatimStringTok{\textquotesingle{}galaaz\textquotesingle{}}
354
+
355
+ \FunctionTok{puts} \ConstantTok{R}\AttributeTok{.sum}\NormalTok{(}\ConstantTok{R}\AttributeTok{.c}\NormalTok{(}\DecValTok{1}\NormalTok{, }\DecValTok{2}\NormalTok{, }\DecValTok{3}\NormalTok{, }\DecValTok{4}\NormalTok{, }\DecValTok{5}\NormalTok{))}
356
+ \NormalTok{mtcars }\OperatorTok{=} \OperatorTok{\textasciitilde{}}\ConstantTok{R}\KeywordTok{[}\WarningTok{:mtcars}\KeywordTok{]}
357
+ \FunctionTok{puts}\NormalTok{ mtcars}\AttributeTok{.dim}
358
+ \FunctionTok{puts} \ConstantTok{R}\AttributeTok{.summary}\NormalTok{(mtcars}\AttributeTok{.mpg}\NormalTok{)}
359
+ \end{Highlighting}
360
+ \end{Shaded}
361
+
362
+ \begin{verbatim}
363
+ ## [1] 15
364
+ ## [1] 32 11
365
+ ## Min. 1st Qu. Median Mean 3rd Qu. Max.
366
+ ## 10.40 15.43 19.20 20.09 22.80 33.90
367
+ \end{verbatim}
368
+
369
+ Callbacks still exist: Ruby procs can be registered so R code can call
370
+ back into Ruby when a package expects an R function. That path is
371
+ documented in the manual; the important product point is that
372
+ \textbf{real GNU R} is on the other end of the wire.
373
+
374
+ \section{Either Ruby engine}\label{either-ruby-engine}
375
+
376
+ NewBridge is tested on both:
377
+
378
+ \begin{itemize}
379
+ \tightlist
380
+ \item
381
+ \textbf{JRuby} (e.g.~10.x + JDK 21) --- real OS threads, JVM
382
+ ecosystem, natural fit for Rails under load.
383
+ \item
384
+ \textbf{CRuby} (e.g.~3.3+) --- MRI gem ecosystem, familiar for many
385
+ Ruby shops.
386
+ \end{itemize}
387
+
388
+ The public API is the same. Launchers honor
389
+ \textbf{\texttt{GALAAZ\_RUBY}}. Use \textbf{\texttt{bin/galaaz-ruby}},
390
+ or \textbf{\texttt{bin/galaaz-jruby}} to force JRuby. Prefer
391
+ \textbf{JRuby} when you want parallel Ruby threads feeding R; prefer
392
+ \textbf{CRuby} when your app and gems already live there. Arrow helpers
393
+ need engine-specific native bits (Java Arrow + \texttt{JAVA\_OPTS} nio
394
+ opens on JRuby; Arrow GLib + \texttt{red-arrow} on CRuby) --- see the
395
+ manual's Arrow section.
396
+
397
+ \begin{Shaded}
398
+ \begin{Highlighting}[]
399
+ \CommentTok{\# From a checkout or installed layout:}
400
+ \ExtensionTok{bin/galaaz{-}ruby} \AttributeTok{{-}e} \DataTypeTok{\textbackslash{}}
401
+ \StringTok{\textquotesingle{}require "galaaz"; puts R.R\_\_version[["version.string"]]\textquotesingle{}}
402
+ \VariableTok{GALAAZ\_RUBY}\OperatorTok{=}\NormalTok{jruby }\ExtensionTok{bin/galaaz{-}ruby} \AttributeTok{{-}e} \DataTypeTok{\textbackslash{}}
403
+ \StringTok{\textquotesingle{}require "galaaz"; puts R.pi\textquotesingle{}}
404
+ \end{Highlighting}
405
+ \end{Shaded}
406
+
407
+ \section{Multiple R versions via
408
+ containers}\label{multiple-r-versions-via-containers}
409
+
410
+ Because R is a \textbf{separate process}, the Ruby gem does not
411
+ hard-wire one R build. Whatever \texttt{R} / \texttt{Rscript} is on
412
+ \texttt{PATH} (and can load the gatekeeper) is the R you drive. That
413
+ makes \textbf{containers} a clean way to pin versions:
414
+
415
+ \begin{itemize}
416
+ \tightlist
417
+ \item
418
+ Image A: Ubuntu + \textbf{R 4.3} + system libs for your Bioconductor
419
+ set.
420
+ \item
421
+ Image B: same app code + \textbf{R 4.4} (or a rocker image) for
422
+ comparison.
423
+ \item
424
+ Your Galaaz gem and Ruby code stay the same; only the image's R
425
+ changes.
426
+ \end{itemize}
427
+
428
+ Sketch (conceptual):
429
+
430
+ \begin{Shaded}
431
+ \begin{Highlighting}[]
432
+ \CommentTok{\# Dev against the R that the image provides}
433
+ \ExtensionTok{docker}\NormalTok{ run }\AttributeTok{{-}{-}rm} \AttributeTok{{-}it}\NormalTok{ myorg/galaaz{-}r43 }\DataTypeTok{\textbackslash{}}
434
+ \NormalTok{ bin/galaaz{-}ruby script/analysis.rb}
435
+
436
+ \ExtensionTok{docker}\NormalTok{ run }\AttributeTok{{-}{-}rm} \AttributeTok{{-}it}\NormalTok{ myorg/galaaz{-}r44 }\DataTypeTok{\textbackslash{}}
437
+ \NormalTok{ bin/galaaz{-}ruby script/analysis.rb}
438
+ \end{Highlighting}
439
+ \end{Shaded}
440
+
441
+ Inside each image, \texttt{R\ -\/-version} differs; NewBridge still
442
+ speaks the same protocol. For a first taste without building your own
443
+ Dockerfile, the repo ships \textbf{try} images and runners:
444
+
445
+ \begin{Shaded}
446
+ \begin{Highlighting}[]
447
+ \CommentTok{\# From a Galaaz checkout}
448
+ \ExtensionTok{./docker/try{-}gstudio/run.sh} \CommentTok{\# JRuby + gstudio{-}oriented image}
449
+ \ExtensionTok{./docker/try{-}cruby/run.sh} \CommentTok{\# CRuby try image}
450
+ \end{Highlighting}
451
+ \end{Shaded}
452
+
453
+ \textbf{Cold-install} proofs (\texttt{docker/cold-install},
454
+ \texttt{docker/cold-install-cruby}) install the gem on a throwaway
455
+ Ubuntu and compile the gatekeeper --- useful when you want ``empty
456
+ machine → working bridge'' confidence. Multi-runtime Docker R matrices
457
+ are still evolving (slow integration coverage); the sketch above is the
458
+ pattern to build on.
459
+
460
+ \section{Moving data: Apache Arrow}\label{moving-data-apache-arrow}
461
+
462
+ Crossing a process boundary means you must be honest about
463
+ \textbf{copies}. Galaaz's Arrow roadmap has three stages:
464
+
465
+ {\def\LTcaptype{none} % do not increment counter
466
+ \begin{longtable}[]{@{}
467
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}
468
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}
469
+ >{\raggedright\arraybackslash}p{(\linewidth - 4\tabcolsep) * \real{0.3333}}@{}}
470
+ \toprule\noalign{}
471
+ \begin{minipage}[b]{\linewidth}\raggedright
472
+ Stage
473
+ \end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
474
+ Idea
475
+ \end{minipage} & \begin{minipage}[b]{\linewidth}\raggedright
476
+ Status
477
+ \end{minipage} \\
478
+ \midrule\noalign{}
479
+ \endhead
480
+ \bottomrule\noalign{}
481
+ \endlastfoot
482
+ \textbf{A} & Copy columnar data into R; return an R-side Arrow/proxy
483
+ handle & Available (\texttt{from\_ruby\_batches}, \texttt{table\_from},
484
+ \ldots) \\
485
+ \textbf{B} & Same-machine \textbf{IPC file}: bulk bytes stay off the
486
+ MsgPack bridge; only a \textbf{file path} crosses NewBridge & Shipped
487
+ (two directions: B1 and B2) \\
488
+ \textbf{C} & Shared-memory bus (true shared RAM) & Future \\
489
+ \end{longtable}
490
+ }
491
+
492
+ Do \textbf{not} read Stage A as ``zero-copy shared RAM.'' Stage A is
493
+ ``build the table in R efficiently, then Remote-Control it.'' Stage B is
494
+ still a file/\texttt{mmap} handoff on one machine---not Stage C---but it
495
+ keeps large columns out of the control plane.
496
+
497
+ \subsection{Stage B in plain words}\label{stage-b-in-plain-words}
498
+
499
+ \textbf{IPC} here means Apache Arrow's \textbf{Inter-Process
500
+ Communication} file format: a portable columnar dump on disk (often
501
+ under \texttt{/dev/shm} so it lives in RAM-backed tmpfs). Ruby and R
502
+ never shove megabytes through NewBridge; they agree on a path, then each
503
+ side's Arrow stack reads or writes that file.
504
+
505
+ Stage B splits by \textbf{direction}:
506
+
507
+ \begin{itemize}
508
+ \tightlist
509
+ \item
510
+ \textbf{B1 --- Ruby → R (ingest).} Ruby writes an IPC file
511
+ (\texttt{Galaaz::ArrowIpc.write} / \texttt{write\_batches}). R opens
512
+ it with \texttt{R::Arrow.open\_ipc(path)} and gets a table proxy for
513
+ dplyr or modeling. After R has materialised the table, Ruby can
514
+ \texttt{Galaaz::ArrowIpc.release(path)} (unlink the scratch file).
515
+ \item
516
+ \textbf{B2 --- R → Ruby (export).} After analytics in R,
517
+ \texttt{R::Arrow.write\_ipc} writes another IPC file and returns its
518
+ path over the bridge. Ruby reads columns or row hashes with
519
+ \texttt{Galaaz::ArrowIpc.read} / \texttt{read\_batches}---handy when
520
+ the next step is a DB write or an API payload in Ruby.
521
+ \end{itemize}
522
+
523
+ Needs: R package \texttt{arrow}, plus a Ruby writer/reader (CRuby:
524
+ \textbf{red-arrow}; JRuby: Arrow Java JARs). Specs skip when those are
525
+ missing; the sketch below does the same.
526
+
527
+ \subsection{Stage B sketch (B1 ingest + B2
528
+ export)}\label{stage-b-sketch-b1-ingest-b2-export}
529
+
530
+ This is the path to prefer for large same-machine handoffs. Ruby threads
531
+ build row batches; \textbf{B1} writes one IPC file and R opens it by
532
+ path; dplyr summarises in R; \textbf{B2} writes the result IPC and Ruby
533
+ reads row hashes. NewBridge only carries paths.
534
+
535
+ \begin{Shaded}
536
+ \begin{Highlighting}[]
537
+ \NormalTok{ipc\_ok }\OperatorTok{=} \DataTypeTok{Galaaz}\OperatorTok{::}\DataTypeTok{ArrowIpc}\AttributeTok{.available?} \OperatorTok{\&\&}
538
+ \NormalTok{ (}\ConstantTok{R}\OperatorTok{::}\DataTypeTok{Support}\AttributeTok{.eval}\NormalTok{(}
539
+ \StringTok{"requireNamespace(\textquotesingle{}arrow\textquotesingle{}, quietly=TRUE) \&\& "} \OperatorTok{+}
540
+ \StringTok{"requireNamespace(\textquotesingle{}dplyr\textquotesingle{}, quietly=TRUE)"}\NormalTok{) }\OperatorTok{==} \DecValTok{true}\NormalTok{)}
541
+ \ControlFlowTok{unless}\NormalTok{ ipc\_ok}
542
+ \FunctionTok{puts} \VerbatimStringTok{\textquotesingle{}(Skip: need Arrow IPC backend + R arrow/dplyr.)\textquotesingle{}}
543
+ \ControlFlowTok{else}
544
+ \NormalTok{ thread\_count }\OperatorTok{=} \DecValTok{2}
545
+ \NormalTok{ rows\_per\_thread }\OperatorTok{=} \DecValTok{250}
546
+ \NormalTok{ group\_count }\OperatorTok{=} \DecValTok{5}
547
+ \NormalTok{ batches }\OperatorTok{=} \KeywordTok{[]}
548
+ \NormalTok{ mutex }\OperatorTok{=} \DataTypeTok{Mutex}\AttributeTok{.new}
549
+ \NormalTok{ threads }\OperatorTok{=} \KeywordTok{[]}
550
+
551
+ \NormalTok{ thread\_count}\AttributeTok{.times} \ControlFlowTok{do} \OperatorTok{|}\NormalTok{tid}\OperatorTok{|}
552
+ \NormalTok{ threads }\OperatorTok{\textless{}\textless{}} \DataTypeTok{Thread}\AttributeTok{.new} \ControlFlowTok{do}
553
+ \NormalTok{ start }\OperatorTok{=}\NormalTok{ tid }\OperatorTok{*}\NormalTok{ rows\_per\_thread}
554
+ \NormalTok{ local }\OperatorTok{=}\NormalTok{ (start}\OperatorTok{...}\NormalTok{(start }\OperatorTok{+}\NormalTok{ rows\_per\_thread))}\AttributeTok{.map} \ControlFlowTok{do} \OperatorTok{|}\NormalTok{i}\OperatorTok{|}
555
+ \OperatorTok{\{}
556
+ \WarningTok{id:}\NormalTok{ i,}
557
+ \WarningTok{grp:} \StringTok{"g}\SpecialCharTok{\#\{}\NormalTok{i }\OperatorTok{\%}\NormalTok{ group\_count}\SpecialCharTok{\}}\StringTok{"}\NormalTok{,}
558
+ \WarningTok{value:}\NormalTok{ (i }\OperatorTok{\%} \DecValTok{17}\NormalTok{) }\OperatorTok{+} \DecValTok{1}\NormalTok{,}
559
+ \WarningTok{weight:}\NormalTok{ ((i }\OperatorTok{\%} \DecValTok{5}\NormalTok{) }\OperatorTok{+} \DecValTok{1}\NormalTok{) }\OperatorTok{*} \FloatTok{0.5}
560
+ \OperatorTok{\}}
561
+ \ControlFlowTok{end}
562
+ \NormalTok{ mutex}\AttributeTok{.synchronize} \OperatorTok{\{}\NormalTok{ batches }\OperatorTok{\textless{}\textless{}}\NormalTok{ local }\OperatorTok{\}}
563
+ \ControlFlowTok{end}
564
+ \ControlFlowTok{end}
565
+ \NormalTok{ threads}\AttributeTok{.each}\NormalTok{(}\OperatorTok{\&}\WarningTok{:join}\NormalTok{)}
566
+
567
+ \NormalTok{ paths }\OperatorTok{=} \KeywordTok{[]}
568
+ \ControlFlowTok{begin}
569
+ \CommentTok{\# B1: Ruby → IPC file → R table proxy}
570
+ \CommentTok{\# write\_batches wants flat row Hashes (not nested batches)}
571
+ \NormalTok{ in\_path }\OperatorTok{=} \DataTypeTok{Galaaz}\OperatorTok{::}\DataTypeTok{ArrowIpc}\AttributeTok{.write\_batches}\NormalTok{(batches}\AttributeTok{.flatten}\NormalTok{)}
572
+ \NormalTok{ paths }\OperatorTok{\textless{}\textless{}}\NormalTok{ in\_path}
573
+ \NormalTok{ tbl }\OperatorTok{=} \ConstantTok{R}\OperatorTok{::}\DataTypeTok{Arrow}\AttributeTok{.open\_ipc}\NormalTok{(in\_path)}
574
+ \FunctionTok{puts} \StringTok{"R class: }\SpecialCharTok{\#\{}\NormalTok{tbl}\AttributeTok{.rclass}\SpecialCharTok{\}}\StringTok{"}
575
+ \FunctionTok{puts} \StringTok{"IPC in: }\SpecialCharTok{\#\{}\DataTypeTok{File}\AttributeTok{.basename}\NormalTok{(in\_path)}\SpecialCharTok{\}}\StringTok{"}
576
+
577
+ \NormalTok{ grouped }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.dplyr\_\_\_group\_by}\NormalTok{(tbl, }\WarningTok{:grp}\NormalTok{)}
578
+ \NormalTok{ summed }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.dplyr\_\_\_summarise}\NormalTok{(}
579
+ \NormalTok{ grouped,}
580
+ \WarningTok{n:} \ConstantTok{E}\AttributeTok{.n}\NormalTok{(),}
581
+ \WarningTok{total:} \ConstantTok{E}\AttributeTok{.sum}\NormalTok{(}\WarningTok{:value}\NormalTok{),}
582
+ \WarningTok{wsum:} \ConstantTok{E}\AttributeTok{.sum}\NormalTok{(}\ConstantTok{R}\KeywordTok{[}\WarningTok{:value}\KeywordTok{]} \OperatorTok{*} \ConstantTok{R}\KeywordTok{[}\WarningTok{:weight}\KeywordTok{]}\NormalTok{)}
583
+ \NormalTok{ )}
584
+
585
+ \CommentTok{\# B2: R → IPC file → Ruby row hashes}
586
+ \NormalTok{ out\_path }\OperatorTok{=} \ConstantTok{R}\OperatorTok{::}\DataTypeTok{Arrow}\AttributeTok{.write\_ipc}\NormalTok{(summed)}
587
+ \NormalTok{ paths }\OperatorTok{\textless{}\textless{}}\NormalTok{ out\_path}
588
+ \NormalTok{ rows }\OperatorTok{=} \DataTypeTok{Galaaz}\OperatorTok{::}\DataTypeTok{ArrowIpc}\AttributeTok{.read\_batches}\NormalTok{(out\_path)}
589
+ \FunctionTok{puts} \StringTok{"IPC out: }\SpecialCharTok{\#\{}\DataTypeTok{File}\AttributeTok{.basename}\NormalTok{(out\_path)}\SpecialCharTok{\}}\StringTok{"}
590
+ \NormalTok{ rows}\AttributeTok{.first}\NormalTok{(}\DecValTok{5}\NormalTok{)}\AttributeTok{.each} \ControlFlowTok{do} \OperatorTok{|}\NormalTok{r}\OperatorTok{|}
591
+ \FunctionTok{puts} \StringTok{"}\SpecialCharTok{\#\{}\NormalTok{r}\KeywordTok{[}\WarningTok{:grp}\KeywordTok{]}\SpecialCharTok{\}}\StringTok{ n=}\SpecialCharTok{\#\{}\NormalTok{r}\KeywordTok{[}\WarningTok{:n}\KeywordTok{]}\SpecialCharTok{\}}\StringTok{ "} \OperatorTok{+}
592
+ \StringTok{"total=}\SpecialCharTok{\#\{}\NormalTok{r}\KeywordTok{[}\WarningTok{:total}\KeywordTok{]}\SpecialCharTok{\}}\StringTok{ wsum=}\SpecialCharTok{\#\{}\NormalTok{r}\KeywordTok{[}\WarningTok{:wsum}\KeywordTok{]}\SpecialCharTok{\}}\StringTok{"}
593
+ \ControlFlowTok{end}
594
+
595
+ \NormalTok{ total\_n }\OperatorTok{=}\NormalTok{ rows}\AttributeTok{.map} \OperatorTok{\{} \OperatorTok{|}\NormalTok{r}\OperatorTok{|}\NormalTok{ r}\KeywordTok{[}\WarningTok{:n}\KeywordTok{]}\AttributeTok{.to\_i} \OperatorTok{\}}\AttributeTok{.sum}
596
+ \NormalTok{ expect\_n }\OperatorTok{=}\NormalTok{ thread\_count }\OperatorTok{*}\NormalTok{ rows\_per\_thread}
597
+ \FunctionTok{puts} \StringTok{"Sum of n (expect }\SpecialCharTok{\#\{}\NormalTok{expect\_n}\SpecialCharTok{\}}\StringTok{): }\SpecialCharTok{\#\{}\NormalTok{total\_n}\SpecialCharTok{\}}\StringTok{"}
598
+ \ControlFlowTok{ensure}
599
+ \NormalTok{ paths}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\FunctionTok{p}\OperatorTok{|} \DataTypeTok{Galaaz}\OperatorTok{::}\DataTypeTok{ArrowIpc}\AttributeTok{.release}\NormalTok{(}\FunctionTok{p}\NormalTok{) }\OperatorTok{\}}
600
+ \ControlFlowTok{end}
601
+ \ControlFlowTok{end}
602
+ \end{Highlighting}
603
+ \end{Shaded}
604
+
605
+ \begin{verbatim}
606
+ ## R class: Table
607
+ ## IPC in: galaaz_ipc_34797_f9f16fd1b739f5ed.arrow
608
+ ## IPC out: galaaz_ipc_34797_0f200cc9e2be2726.arrow
609
+ ## g0 n=100 total=897 wsum=448.5
610
+ ## g1 n=100 total=895 wsum=895.0
611
+ ## g2 n=100 total=893 wsum=1339.5
612
+ ## g3 n=100 total=891 wsum=1782.0
613
+ ## g4 n=100 total=889 wsum=2222.5
614
+ ## Sum of n (expect 500): 500
615
+ \end{verbatim}
616
+
617
+ What to notice: \texttt{write\_batches} / \texttt{open\_ipc} is
618
+ \textbf{B1}; after dplyr, \texttt{write\_ipc} / \texttt{read\_batches}
619
+ is \textbf{B2}. Specs: \texttt{arrow\_ipc\_handoff\_spec.rb},
620
+ \texttt{arrow\_ipc\_export\_spec.rb}. Deeper notes:
621
+ \texttt{Documentation/ROADMAP\_ARROW\_RUBY\_R.md}.
622
+
623
+ \subsection{Stage A (still useful)}\label{stage-a-still-useful}
624
+
625
+ Stage A copies batches straight into R with
626
+ \texttt{R::Arrow.from\_ruby\_batches}---no IPC file. Fine for modest
627
+ tables or when you do not have a Ruby Arrow writer installed. Same
628
+ threaded shape as above, one call instead of B1:
629
+
630
+ \begin{Shaded}
631
+ \begin{Highlighting}[]
632
+ \NormalTok{arrow\_ok }\OperatorTok{=} \ConstantTok{R}\OperatorTok{::}\DataTypeTok{Support}\AttributeTok{.eval}\NormalTok{(}
633
+ \StringTok{"requireNamespace(\textquotesingle{}arrow\textquotesingle{}, quietly=TRUE) \&\& "} \OperatorTok{+}
634
+ \StringTok{"requireNamespace(\textquotesingle{}dplyr\textquotesingle{}, quietly=TRUE)"}\NormalTok{)}
635
+ \ControlFlowTok{unless}\NormalTok{ arrow\_ok }\OperatorTok{==} \DecValTok{true}
636
+ \FunctionTok{puts} \VerbatimStringTok{\textquotesingle{}(Skip: need arrow + dplyr in R.)\textquotesingle{}}
637
+ \ControlFlowTok{else}
638
+ \NormalTok{ batches }\OperatorTok{=} \KeywordTok{[}
639
+ \KeywordTok{[}\OperatorTok{\{} \WarningTok{id:} \DecValTok{1}\NormalTok{, }\WarningTok{grp:} \CharTok{\textquotesingle{}a\textquotesingle{}}\NormalTok{, }\WarningTok{value:} \DecValTok{10}\NormalTok{, }\WarningTok{weight:} \FloatTok{1.0} \OperatorTok{\}}\NormalTok{,}
640
+ \OperatorTok{\{} \WarningTok{id:} \DecValTok{2}\NormalTok{, }\WarningTok{grp:} \CharTok{\textquotesingle{}b\textquotesingle{}}\NormalTok{, }\WarningTok{value:} \DecValTok{20}\NormalTok{, }\WarningTok{weight:} \FloatTok{0.5} \OperatorTok{\}}\KeywordTok{]}\NormalTok{,}
641
+ \KeywordTok{[}\OperatorTok{\{} \WarningTok{id:} \DecValTok{3}\NormalTok{, }\WarningTok{grp:} \CharTok{\textquotesingle{}a\textquotesingle{}}\NormalTok{, }\WarningTok{value:} \DecValTok{30}\NormalTok{, }\WarningTok{weight:} \FloatTok{1.5} \OperatorTok{\}}\KeywordTok{]}
642
+ \KeywordTok{]}
643
+ \NormalTok{ tbl }\OperatorTok{=} \ConstantTok{R}\OperatorTok{::}\DataTypeTok{Arrow}\AttributeTok{.from\_ruby\_batches}\NormalTok{(batches)}
644
+ \FunctionTok{puts} \StringTok{"R class: }\SpecialCharTok{\#\{}\NormalTok{tbl}\AttributeTok{.rclass}\SpecialCharTok{\}}\StringTok{"}
645
+ \NormalTok{ grouped }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.dplyr\_\_\_group\_by}\NormalTok{(tbl, }\WarningTok{:grp}\NormalTok{)}
646
+ \NormalTok{ summarised }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.dplyr\_\_\_summarise}\NormalTok{(}
647
+ \NormalTok{ grouped, }\WarningTok{n:} \ConstantTok{E}\AttributeTok{.n}\NormalTok{(), }\WarningTok{total:} \ConstantTok{E}\AttributeTok{.sum}\NormalTok{(}\WarningTok{:value}\NormalTok{))}
648
+ \NormalTok{ out }\OperatorTok{=} \ConstantTok{R}\AttributeTok{.dplyr\_\_\_collect}\NormalTok{(summarised)}
649
+ \FunctionTok{puts} \ConstantTok{R}\AttributeTok{.as\_\_data\_\_frame}\NormalTok{(out)}
650
+ \ControlFlowTok{end}
651
+ \end{Highlighting}
652
+ \end{Shaded}
653
+
654
+ \begin{verbatim}
655
+ ## R class: Table
656
+ ## grp n total
657
+ ## 1 a 2 40
658
+ ## 2 b 1 20
659
+ \end{verbatim}
660
+
661
+ Larger Stage A demos live in
662
+ \texttt{arrow\_from\_ruby\_batches\_spec.rb} and
663
+ \texttt{arrow\_large\_pipeline\_spec.rb} (under \texttt{specs/} /
664
+ \texttt{slow-specs/}).
665
+
666
+ \section{Keeping the bridge free}\label{keeping-the-bridge-free}
667
+
668
+ Two different ``don't block'' stories:
669
+
670
+ \begin{itemize}
671
+ \tightlist
672
+ \item
673
+ \textbf{\texttt{R::Async} / \texttt{R.eval\_r\_async}} --- free a
674
+ \textbf{Ruby} thread while the \textbf{same} bridge R process works.
675
+ Good for short/medium calls when you still want one R session.
676
+ \item
677
+ \textbf{\texttt{R::Job}} --- run heavy work in a \textbf{child
678
+ \texttt{Rscript}}. The bridge stays free for other traffic. Package
679
+ installs (\texttt{R.install\_and\_loads}) use this path so
680
+ \texttt{make}/\texttt{gcc} do not wedge the gatekeeper.
681
+ \end{itemize}
682
+
683
+ \begin{Shaded}
684
+ \begin{Highlighting}[]
685
+ \ControlFlowTok{begin}
686
+ \NormalTok{ coef }\OperatorTok{=} \ConstantTok{R}\OperatorTok{::}\DataTypeTok{Job}\AttributeTok{.eval}\NormalTok{(}\OperatorTok{\textless{}\textless{}\textasciitilde{}}\ControlFlowTok{R}\DocumentationTok{) \{ |job| job.load\_rds \}}
687
+ \DocumentationTok{ fit \textless{}{-} lm(mpg \textasciitilde{} wt, data = mtcars)}
688
+ \DocumentationTok{ saveRDS(unname(coef(fit)), result\_path)}
689
+ \DocumentationTok{ }\ControlFlowTok{R}
690
+ \FunctionTok{puts}\NormalTok{ coef}
691
+ \ControlFlowTok{rescue} \OperatorTok{=\textgreater{}}\NormalTok{ e}
692
+ \FunctionTok{puts}\NormalTok{ e}\AttributeTok{.class.to\_s}
693
+ \NormalTok{ e}\AttributeTok{.message.to\_s.scan}\NormalTok{(}\SpecialStringTok{/.\{1,68\}/}\NormalTok{)}\AttributeTok{.each} \OperatorTok{\{} \OperatorTok{|}\NormalTok{line}\OperatorTok{|} \FunctionTok{puts}\NormalTok{ line }\OperatorTok{\}}
694
+ \ControlFlowTok{end}
695
+ \end{Highlighting}
696
+ \end{Shaded}
697
+
698
+ \begin{verbatim}
699
+ ## [1] 37.285126 -5.344472
700
+ \end{verbatim}
701
+
702
+ Rule of thumb: short interactive analytics on the bridge; installs and
703
+ multi-minute fits in \textbf{\texttt{R::Job}}. Details and timeouts
704
+ (\texttt{GALAAZ\_INSTALL\_TIMEOUT\_SEC}, \texttt{GALAAZ\_JOBS\_DIR}) are
705
+ in the manual.
706
+
707
+ \section{What stayed the same}\label{what-stayed-the-same}
708
+
709
+ Galaaz 2.0 is a new \textbf{runtime}, not a new plotting language. These
710
+ still apply:
711
+
712
+ \begin{itemize}
713
+ \tightlist
714
+ \item
715
+ \textbf{ggplot2} from Ruby --- see \emph{Ruby Plotting with Galaaz} /
716
+ \emph{Beautiful Ruby Plots}.
717
+ \item
718
+ \textbf{dplyr / NSE} --- see \emph{Non Standard Evaluation in dplyr
719
+ with Galaaz}.
720
+ \item
721
+ \textbf{Literate docs} --- \textbf{gKnit} still wraps knitr so Ruby
722
+ chunks render next to R (HTML/PDF).
723
+ \item
724
+ \textbf{Classes, modules, procs} --- the \emph{oh my} S4 comparison
725
+ still teaches structure; unwrap and bridge details follow 2.0 rules.
726
+ \end{itemize}
727
+
728
+ R-on-Rails (Ruby web + R science) is the product framing: Rails (or any
729
+ Ruby app) orchestrates; GNU R computes.
730
+
731
+ \section{Conclusion}\label{conclusion}
732
+
733
+ \textbf{Galaaz 2.0} bets on \textbf{boring, powerful defaults}: standard
734
+ Ruby engines, standard GNU R, a clear process bridge, containers to pin
735
+ R, and Arrow-shaped paths for larger tables --- with zero-copy shared
736
+ memory still on the roadmap. The Graal-era prototype proved the
737
+ \emph{idea}; 2.0 makes the \emph{ecosystem} reachable.
738
+
739
+ \subsection{Further reading}\label{further-reading}
740
+
741
+ \begin{itemize}
742
+ \tightlist
743
+ \item
744
+ Manual (GitHub Pages): \url{https://rbotafogo.github.io/galaaz/}
745
+ \item
746
+ Arrow roadmap: \texttt{Documentation/ROADMAP\_ARROW\_RUBY\_R.md}
747
+ \item
748
+ Repo blogs under \texttt{blogs/} (ggplot, dplyr, gKnit, oh my, manual)
749
+ \item
750
+ Try images: \texttt{docker/try-gstudio}, \texttt{docker/try-cruby}
751
+ \item
752
+ Older Graal-era plot narrative (historical): search ``Ruby Plotting
753
+ with Galaaz in GraalVM'' on Towards Data Science
754
+ \end{itemize}
755
+
756
+ \end{document}