galaaz 0.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/LICENSE +0 -0
  4. data/README.md +1360 -636
  5. data/Rakefile +61 -41
  6. data/bin/galaaz-bootstrap +137 -0
  7. data/bin/galaaz-jruby +14 -0
  8. data/bin/galaaz_jruby_env.inc.sh +6 -0
  9. data/bin/gbookdown +64 -0
  10. data/bin/gknit +84 -13
  11. data/bin/gknit-draft.rb +0 -0
  12. data/bin/gstudio +5 -3
  13. data/bin/gstudio_irb.rb +0 -0
  14. data/bin/gstudio_pry.rb +0 -0
  15. data/bin/install-tinytex +6 -0
  16. data/bin/run_all_rspec +43 -0
  17. data/bin/run_example +14 -0
  18. data/bin/run_old_rspec +19 -0
  19. data/bin/run_rspec +23 -0
  20. data/bin/run_rspec_subset +38 -0
  21. data/bin/run_slow_rspec +19 -0
  22. data/blogs/R-on-Rails-Planning-Document.md +940 -0
  23. data/blogs/README.md +100 -0
  24. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -66
  25. data/blogs/galaaz_ggplot/galaaz_ggplot.log +754 -0
  26. data/blogs/galaaz_ggplot/galaaz_ggplot.md +115 -155
  27. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +607 -0
  28. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  29. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  30. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  31. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  32. data/blogs/galaaz_ggplot/midwest.Rmd +3 -3
  33. data/blogs/galaaz_ggplot/midwest_external_png +0 -0
  34. data/blogs/gknit/gknit.Rmd +47 -52
  35. data/blogs/gknit/gknit.md +1430 -0
  36. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  37. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  38. data/blogs/gknit/lst.rds +0 -0
  39. data/blogs/gknit/model.rb +1 -1
  40. data/blogs/gknit/stats.bib +0 -0
  41. data/blogs/manual/include_model_local_repro.Rmd +14 -0
  42. data/blogs/manual/include_model_local_repro.md +75 -0
  43. data/blogs/manual/lst.rds +0 -0
  44. data/blogs/manual/manual.Rmd +852 -239
  45. data/blogs/manual/manual.log +1786 -0
  46. data/blogs/manual/manual.md +1360 -636
  47. data/blogs/manual/manual.tex +1883 -1161
  48. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  49. data/blogs/manual/manual_files/figure-html/diverging_bar.png +0 -0
  50. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  51. data/blogs/manual/model.rb +1 -1
  52. data/blogs/nse_dplyr/nse_dplyr.Rmd +84 -111
  53. data/blogs/nse_dplyr/nse_dplyr.log +928 -0
  54. data/blogs/nse_dplyr/nse_dplyr.md +198 -229
  55. data/blogs/oh_my/not_so.rb +0 -0
  56. data/blogs/oh_my/oh_my.Rmd +1234 -25
  57. data/blogs/oh_my/oh_my.log +804 -0
  58. data/blogs/oh_my/oh_my.md +1663 -86
  59. data/blogs/oh_my/oh_my.tex +821 -0
  60. data/blogs/oh_my/old.Rmd +15 -14
  61. data/blogs/ruby_plot/ruby_plot.Rmd +58 -82
  62. data/blogs/ruby_plot/ruby_plot.log +885 -0
  63. data/blogs/ruby_plot/ruby_plot.md +71 -102
  64. data/blogs/ruby_plot/ruby_plot.tex +940 -0
  65. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  66. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  67. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  68. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  72. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  73. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  74. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  75. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  77. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  78. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  79. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  80. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  81. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  82. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  83. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  84. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  85. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  86. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  87. data/blogs/test/test.Rmd +14 -0
  88. data/examples/50Plots_MasterList/Images/midwest-scatterplot.PNG +0 -0
  89. data/examples/50Plots_MasterList/ScatterPlot.rb +0 -0
  90. data/examples/50Plots_MasterList/scatter_plot.rb +0 -0
  91. data/examples/Bibliography/master.bib +0 -0
  92. data/examples/Bibliography/stats.bib +0 -0
  93. data/examples/R/calc.R +0 -0
  94. data/examples/R/java_interop.R +0 -0
  95. data/examples/bioconductor_deseq2_airway/Documentation/DESeq2-airway-walkthrough.md +56 -0
  96. data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +53 -0
  97. data/examples/bioconductor_deseq2_airway/bench_r_three_same_process.R +34 -0
  98. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +33 -0
  99. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +34 -0
  100. data/examples/bioconductor_deseq2_airway/deseq2_airway_minimal.R +30 -0
  101. data/examples/bioconductor_deseq2_airway/deseq2_airway_pipeline_for_bench.R +36 -0
  102. data/examples/islr/all.rb +13 -0
  103. data/examples/islr/ch2.spec.rb +37 -7
  104. data/examples/islr/ch3.spec.rb +11 -2
  105. data/examples/islr/ch3_boston.rb +27 -0
  106. data/examples/islr/ch3_multiple_regression.rb +0 -0
  107. data/examples/islr/ch6.spec.rb +24 -1
  108. data/examples/islr/x_y_rnorm.jpg +0 -0
  109. data/examples/latex_templates/Test-acm_article/acm_proc_article-sp.cls +0 -0
  110. data/examples/latex_templates/Test-acm_article/sigproc.bib +0 -0
  111. data/examples/latex_templates/Test-acs_article/acs-Test-acs_article.bib +0 -0
  112. data/examples/latex_templates/Test-acs_article/acs-my_output.bib +0 -0
  113. data/examples/latex_templates/Test-aea_article/BibFile.bib +0 -0
  114. data/examples/latex_templates/Test-aea_article/Test-aea_article.Rmd +0 -0
  115. data/examples/latex_templates/Test-aea_article/references.bib +0 -0
  116. data/examples/latex_templates/Test-amq_article/Test-amq_article.Rmd +0 -0
  117. data/examples/latex_templates/Test-amq_article/Test-amq_article.pdfsync +0 -0
  118. data/examples/latex_templates/Test-ieee_article/IEEEtran.bst +0 -0
  119. data/examples/latex_templates/Test-ieee_article/mybibfile.bib +0 -0
  120. data/examples/latex_templates/Test-rjournal_article/RJournal.sty +0 -0
  121. data/examples/latex_templates/Test-rjournal_article/RJreferences.bib +0 -0
  122. data/examples/latex_templates/Test-rjournal_article/Test-rjournal_article.Rmd +0 -0
  123. data/examples/misc/baseball.csv +0 -0
  124. data/examples/misc/ggplot.rb +3 -2
  125. data/examples/misc/moneyball.rb +0 -0
  126. data/examples/misc/subsetting.rb +0 -0
  127. data/examples/multithread_shards_to_r/shards_to_r.rb +67 -0
  128. data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.Rmd +0 -0
  129. data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.Rmd +0 -0
  130. data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.Rmd +0 -0
  131. data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.Rmd +0 -0
  132. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/attend-grade-relationships.csv +0 -0
  133. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.Rmd +0 -0
  134. data/examples/rmarkdown/svm-xaringan-example/svm-xaringan-example.Rmd +0 -0
  135. data/examples/sthda_ggplot/README.md +0 -0
  136. data/examples/sthda_ggplot/RUN.md +41 -0
  137. data/examples/sthda_ggplot/all.rb +0 -0
  138. data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +0 -0
  139. data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +0 -0
  140. data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +2 -0
  141. data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +0 -0
  142. data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +0 -0
  143. data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +0 -0
  144. data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +0 -0
  145. data/examples/sthda_ggplot/one_variable_continuous/stat.rb +0 -0
  146. data/examples/sthda_ggplot/one_variable_discrete/bar.rb +0 -0
  147. data/examples/sthda_ggplot/qplots/box_violin_dot.rb +0 -0
  148. data/examples/sthda_ggplot/qplots/scatter_plots.rb +0 -0
  149. data/examples/sthda_ggplot/scatter_gg.rb +0 -0
  150. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +0 -0
  151. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +0 -0
  152. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +0 -0
  153. data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +0 -0
  154. data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +0 -0
  155. data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +0 -0
  156. data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +4 -3
  157. data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +0 -0
  158. data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +0 -0
  159. data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +0 -0
  160. data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +0 -0
  161. data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +0 -0
  162. data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +0 -0
  163. data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +0 -0
  164. data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +0 -0
  165. data/ext/new_bridge/Makefile +46 -0
  166. data/ext/new_bridge/galaaz_gatekeeper_phase0.cpp +12 -0
  167. data/ext/new_bridge/galaaz_gatekeeper_phase1.cpp +1639 -0
  168. data/lib/R_interface/galaaz_device.R +20 -0
  169. data/lib/R_interface/include_engine.R +109 -0
  170. data/lib/R_interface/new_bridge_adapter.rb +824 -0
  171. data/lib/R_interface/r.rb +177 -25
  172. data/lib/R_interface/r_arrow.rb +113 -0
  173. data/lib/R_interface/r_libs.R +3 -3
  174. data/lib/R_interface/r_methods.rb +13 -126
  175. data/lib/R_interface/r_module_s.rb +0 -0
  176. data/lib/R_interface/rbinary_operators.rb +20 -2
  177. data/lib/R_interface/rclosure.rb +5 -1
  178. data/lib/R_interface/rdata_frame.rb +34 -70
  179. data/lib/R_interface/rdevice.rb +125 -0
  180. data/lib/R_interface/rdevices.R +0 -0
  181. data/lib/R_interface/renvironment.rb +10 -4
  182. data/lib/R_interface/rexpression.rb +5 -1
  183. data/lib/R_interface/rindexed_object.rb +41 -13
  184. data/lib/R_interface/rlanguage.rb +20 -62
  185. data/lib/R_interface/rlist.rb +115 -25
  186. data/lib/R_interface/rlogical_operators.rb +0 -0
  187. data/lib/R_interface/rmatrix.rb +2 -11
  188. data/lib/R_interface/rmd_indexed_object.rb +5 -1
  189. data/lib/R_interface/robject.rb +348 -290
  190. data/lib/R_interface/rpkg.rb +0 -0
  191. data/lib/R_interface/rsupport.rb +609 -328
  192. data/lib/R_interface/rsupport_scope.rb +2 -1
  193. data/lib/R_interface/rsymbol.rb +50 -0
  194. data/lib/R_interface/ruby_callback.rb +2 -3
  195. data/lib/R_interface/ruby_extensions.rb +225 -175
  196. data/lib/R_interface/runary_operators.rb +0 -0
  197. data/lib/R_interface/rvector.rb +147 -31
  198. data/lib/galaaz.rb +0 -0
  199. data/lib/galaaz_jruby.rb +22 -0
  200. data/lib/gknit/diagnostics.rb +50 -0
  201. data/lib/gknit/draft.rb +23 -17
  202. data/lib/gknit/include_engine.rb +15 -7
  203. data/lib/gknit/knitr_engine.rb +223 -74
  204. data/lib/gknit/rb_engine.rb +3 -3
  205. data/lib/gknit/ruby_engine.rb +0 -0
  206. data/lib/gknit.rb +1 -0
  207. data/lib/new_bridge/bootstrap/windows_bootstrap.rb +285 -0
  208. data/lib/new_bridge/envelope.rb +51 -0
  209. data/lib/new_bridge/eval_result.rb +26 -0
  210. data/lib/new_bridge/framing.rb +39 -0
  211. data/lib/new_bridge/instance_pool_client.rb +38 -0
  212. data/lib/new_bridge/r_instance_manager.rb +404 -0
  213. data/lib/new_bridge/session_client.rb +530 -0
  214. data/lib/new_bridge/tcp_framed.rb +44 -0
  215. data/lib/new_bridge.rb +9 -0
  216. data/lib/util/exec_ruby.rb +95 -20
  217. data/lib/util/inline_file.rb +35 -30
  218. data/new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb +96 -0
  219. data/new_bridge_specs/eval_r_async_spec.rb +113 -0
  220. data/new_bridge_specs/integration_phase5_1_concurrent_spec.rb +50 -0
  221. data/new_bridge_specs/integration_phase5_1_eval_spec.rb +16 -0
  222. data/new_bridge_specs/integration_phase5_1_r_api_spec.rb +25 -0
  223. data/new_bridge_specs/integration_phase5_1_smoke_spec.rb +31 -0
  224. data/new_bridge_specs/integration_phase5_2_dataframe_unboxing_spec.rb +19 -0
  225. data/new_bridge_specs/integration_phase5_2_handle_eval_unboxing_spec.rb +25 -0
  226. data/new_bridge_specs/integration_phase5_3_callback_args_spec.rb +28 -0
  227. data/new_bridge_specs/integration_phase5_3_callback_error_spec.rb +22 -0
  228. data/new_bridge_specs/integration_phase5_3_callback_timeout_spec.rb +28 -0
  229. data/new_bridge_specs/integration_phase5_3_callbacks_smoke_spec.rb +22 -0
  230. data/new_bridge_specs/integration_phase5_3_edge_cases_spec.rb +52 -0
  231. data/new_bridge_specs/integration_phase5_3_nested_spec.rb +30 -0
  232. data/new_bridge_specs/integration_phase5_4_concurrent_sessions_spec.rb +53 -0
  233. data/new_bridge_specs/integration_phase5_4_nested_session_callbacks_spec.rb +49 -0
  234. data/new_bridge_specs/integration_phase5_4_session_routing_spec.rb +38 -0
  235. data/new_bridge_specs/integration_phase5_5_stress_concurrency_spec.rb +52 -0
  236. data/new_bridge_specs/integration_phase5_5_unbox_walk_spec.rb +46 -0
  237. data/new_bridge_specs/phase0_protocol_spec.rb +96 -0
  238. data/new_bridge_specs/phase1_req_ret_spec.rb +66 -0
  239. data/new_bridge_specs/phase2_multi_instance_spec.rb +67 -0
  240. data/new_bridge_specs/phase3_callbacks_spec.rb +71 -0
  241. data/new_bridge_specs/phase4_2_hardening_spec.rb +252 -0
  242. data/new_bridge_specs/phase4_3_r_instance_manager_spec.rb +85 -0
  243. data/new_bridge_specs/phase4_nested_callbacks_spec.rb +123 -0
  244. data/r_requires/ggplot.rb +0 -0
  245. data/r_requires/knitr.rb +0 -0
  246. data/specs/all.rb +15 -11
  247. data/specs/arrow_from_ruby_batches_spec.rb +50 -0
  248. data/specs/arrow_semantics_spec.rb +64 -0
  249. data/specs/bridge_concurrent_spec.rb +46 -0
  250. data/specs/bridge_nested_spec.rb +25 -0
  251. data/specs/dataframe_semantics_spec.rb +122 -0
  252. data/specs/dataframe_single_index_logical_filter_spec.rb +21 -0
  253. data/specs/dispatch_probe_cache_spec.rb +38 -0
  254. data/specs/dispatch_probe_error_class_fallback_spec.rb +20 -0
  255. data/specs/dispatch_probe_fallback_spec.rb +18 -0
  256. data/specs/environment_semantics_spec.rb +89 -0
  257. data/specs/field_access_spec.rb +31 -0
  258. data/specs/figures/bg.jpeg +0 -0
  259. data/specs/figures/bg.png +0 -0
  260. data/specs/figures/bg.svg +168 -57
  261. data/specs/figures/dose_len.png +0 -0
  262. data/specs/figures/no_args.jpeg +0 -0
  263. data/specs/figures/no_args.png +0 -0
  264. data/specs/figures/no_args.svg +168 -57
  265. data/specs/figures/width_height.jpeg +0 -0
  266. data/specs/figures/width_height.png +0 -0
  267. data/specs/figures/width_height_units1.jpeg +0 -0
  268. data/specs/figures/width_height_units1.png +0 -0
  269. data/specs/figures/width_height_units2.jpeg +0 -0
  270. data/specs/figures/width_height_units2.png +0 -0
  271. data/specs/formula_semantics_spec.rb +81 -0
  272. data/specs/galaaz_util_exec_ruby_spec.rb +85 -0
  273. data/specs/galaaz_util_inline_file_spec.rb +54 -0
  274. data/specs/gknit_cli_option_permutation_spec.rb +24 -0
  275. data/specs/gknit_include_engine_spec.rb +72 -0
  276. data/specs/gknit_install_timeout_report_spec.rb +69 -0
  277. data/specs/gknit_internal_error_report_spec.rb +57 -0
  278. data/specs/gknit_vector_map_output_spec.rb +59 -0
  279. data/specs/globalenv_guardrail_spec.rb +52 -0
  280. data/specs/language_expression_semantics_spec.rb +145 -0
  281. data/specs/list_semantics_spec.rb +111 -0
  282. data/specs/new_bridge_bulk_dataframe_transfer_spec.rb +44 -0
  283. data/specs/new_bridge_bulk_vector_transfer_spec.rb +73 -0
  284. data/specs/new_bridge_callback_timeout_spec.rb +69 -0
  285. data/specs/new_bridge_eval_r_fallback_spec.rb +55 -0
  286. data/specs/nil_null_spec.rb +42 -0
  287. data/specs/object_build_phase2_spec.rb +53 -0
  288. data/specs/phase1_callback_bridge_spec.rb +84 -0
  289. data/specs/phase2_gknit_generic_rendering_guardrail_spec.rb +46 -0
  290. data/specs/phase2_gknit_no_raw_code_leakage_spec.rb +43 -0
  291. data/specs/phase3_gknit_generic_graphics_capture_spec.rb +71 -0
  292. data/specs/plot_device_semantics_spec.rb +28 -0
  293. data/specs/plot_snapshot_semantics_spec.rb +58 -0
  294. data/specs/protocol_result_spec.rb +236 -0
  295. data/specs/r_batch_fail_fast_spec.rb +47 -0
  296. data/specs/r_bridge_bootstrap_spec.rb +11 -0
  297. data/specs/r_devices.spec.rb +1 -1
  298. data/specs/r_eval.spec.rb +16 -18
  299. data/specs/r_function.spec.rb +1 -1
  300. data/specs/r_instance_manager_spec.rb +285 -0
  301. data/specs/r_list_apply.spec.rb +15 -15
  302. data/specs/r_matrix.spec.rb +0 -0
  303. data/specs/r_nse.spec.rb +5 -5
  304. data/specs/r_object_send_dispatch_spec.rb +13 -0
  305. data/specs/r_vector_comparator_spec.rb +8 -0
  306. data/specs/r_vector_creation.spec.rb +0 -0
  307. data/specs/r_vector_functions.spec.rb +0 -0
  308. data/specs/r_vector_object.spec.rb +0 -0
  309. data/specs/r_vector_operators.spec.rb +0 -0
  310. data/specs/r_vector_structured_scalar_reads_spec.rb +35 -0
  311. data/specs/r_vector_subsetting.spec.rb +0 -0
  312. data/specs/range_helper_spec.rb +21 -0
  313. data/specs/rsupport_scope_spec.rb +28 -0
  314. data/specs/rsupport_var_name_thread_safety_spec.rb +24 -0
  315. data/specs/scalar_character_spec.rb +44 -0
  316. data/specs/scoped_symbol_dsl_refinement_spec.rb +40 -0
  317. data/specs/session_env_bridge_spec.rb +25 -0
  318. data/specs/simplecov_bootstrap_spec.rb +10 -0
  319. data/specs/spec_helper.rb +10 -0
  320. data/specs/tmp.rb +0 -0
  321. data/specs/unboxing_recursion_regression_spec.rb +30 -0
  322. data/specs/unboxing_spec.rb +49 -0
  323. data/specs/verify_callbacks.rb +42 -0
  324. data/sty/galaaz.sty +0 -0
  325. data/version.rb +1 -1
  326. metadata +194 -64
  327. data/blogs/galaaz_ggplot/galaaz_ggplot.html +0 -520
  328. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  329. data/blogs/galaaz_ggplot/midwest.html +0 -188
  330. data/blogs/gknit/gknit.html +0 -2266
  331. data/blogs/gknit/gknit.pdf +0 -0
  332. data/blogs/manual/manual.html +0 -4638
  333. data/blogs/manual/manual.pdf +0 -0
  334. data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
  335. data/blogs/nse_dplyr/nse_dplyr.html +0 -878
  336. data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
  337. data/blogs/oh_my/oh_my.html +0 -568
  338. data/blogs/ruby_plot/ruby_plot.html +0 -544
  339. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  340. data/examples/latex_templates/Test-acs_article/Test-acs_article.pdf +0 -0
  341. data/examples/latex_templates/Test-aea_article/Test-aea_article.pdf +0 -0
  342. data/examples/latex_templates/Test-amq_article/Test-amq_article.pdf +0 -0
  343. data/examples/latex_templates/Test-amq_article/pics/Figure2.pdf +0 -0
  344. data/examples/latex_templates/Test-asa_article/Test-asa_article.pdf +0 -0
  345. data/examples/latex_templates/Test-ieee_article/Test-ieee_article.pdf +0 -0
  346. data/examples/latex_templates/Test-rjournal_article/RJwrapper.pdf +0 -0
  347. data/examples/latex_templates/Test-springer_article/Test-springer_article.pdf +0 -0
  348. data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.pdf +0 -0
  349. data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.pdf +0 -0
  350. data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.pdf +0 -0
  351. data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.pdf +0 -0
  352. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.pdf +0 -0
  353. data/specs/r_dataframe.spec.rb +0 -379
  354. data/specs/r_environment.spec.rb +0 -140
  355. data/specs/r_formula.spec.rb +0 -232
  356. data/specs/r_language.spec.rb +0 -112
  357. data/specs/r_list.spec.rb +0 -293
  358. data/specs/r_plots.spec.rb +0 -72
  359. data/specs/ruby_expression.spec.rb +0 -316
@@ -0,0 +1,940 @@
1
+ # R-on-Rails (Galaaz 2.0): Planning Document
2
+
3
+ ## Vision Statement
4
+
5
+ A landmark document that positions **R-on-Rails** as the natural evolution for R developers who need production-grade infrastructure—just as Ruby on Rails revolutionized web development by making it accessible and productive.
6
+
7
+ **Target Audience**: R developers, data scientists, bioinformaticians, and scientific computing practitioners who need to move their R code from analysis notebooks to production systems.
8
+
9
+ ---
10
+
11
+ ## Introduction: The Two-Engine Architecture
12
+
13
+ ### Opening Hook (Compelling Narrative)
14
+
15
+ Start with the familiar story: In 2005, Ruby on Rails transformed web development. Before Rails, building web applications required deep expertise in multiple technologies, complex configuration, and weeks of boilerplate code. Rails introduced convention over configuration, scaffolding, and a productive framework that let developers focus on their application logic rather than infrastructure.
16
+
17
+ Today, data science faces a similar challenge. R is unmatched for statistical analysis, visualization, and scientific computing. But taking an R script from a Jupyter notebook or RStudio into a production environment—where it needs user authentication, database connections, job scheduling, error recovery, and API endpoints—is still a formidable barrier.
18
+
19
+ ### The Problem: R's Strengths and Production Weaknesses
20
+
21
+ **R's Strengths (Why we love R):**
22
+ - Unparalleled statistical and bioinformatics ecosystem (Bioconductor, thousands of packages)
23
+ - Excellent visualization with ggplot2, lattice, plotly
24
+ - Interactive, REPL-driven development perfect for exploration
25
+ - Domain-specific languages for data manipulation (dplyr, data.table)
26
+ - Rich modeling capabilities (caret, glm, randomForest, etc.)
27
+ - Reproducible research with R Markdown
28
+
29
+ **R's Production Challenges (Why R struggles in production):**
30
+ - **Single-threaded**: R's interpreter is fundamentally single-threaded. Parallel processing requires forking or external orchestration
31
+ - **Memory management**: R's copy-on-modify semantics can be inefficient for large-scale data processing
32
+ - **Web infrastructure**: Shiny is great for dashboards but lacks enterprise-grade user management, authentication flows, and API design patterns
33
+ - **Error isolation**: A crash in one R session takes down the entire process
34
+ - **Database integration**: DBI works but lacks the Rails ActiveRecord ecosystem for migrations, connection pooling, ORM patterns
35
+ - **Data transfer costs**: Moving data between R and other languages typically requires expensive serialization (CSV, JSON)
36
+ - **Deployment complexity**: R environments are notoriously difficult to reproduce (packrat, renv help but aren't seamless)
37
+ - **Security**: No built-in user session management, authorization patterns, or CSRF protection
38
+
39
+ ### Why Python Took the Mindshare
40
+
41
+ Python became the lingua franca of data science not because it's better than R at statistics (it isn't), but because it offered a **path to production**:
42
+
43
+ - **Django/Flask**: Web frameworks with auth, ORM, migrations, testing built-in
44
+ - **Jupyter + Production**: Easy transition from notebook to `.py` script to deployed service
45
+ - **Industry adoption**: Tech companies standardized on Python for ML pipelines
46
+ - **Deep Learning**: PyTorch and TensorFlow's Python-first APIs
47
+
48
+ But R still dominates in:
49
+ - Biostatistics and clinical trials (FDA submissions often require R)
50
+ - Epidemiology and public health research
51
+ - Academic statistical research
52
+ - Survey analysis and social sciences
53
+ - Any domain where the statistical method is the product
54
+
55
+ ### Why Ruby on Rails Now (The Rails Renaissance)
56
+
57
+ Rails never went away—it matured. Several factors make Rails compelling again:
58
+
59
+ - **HTML5 and Hotwire**: Modern browsers reduce the need for complex JavaScript SPAs. Rails with Hotwire delivers reactive UIs with minimal JS.
60
+ - **JRuby and Modern JVM**: JRuby on modern JVMs delivers excellent performance, true multi-threading, and Java ecosystem integration
61
+ - **Developer Experience**: Rails 7+ with import maps, esbuild, and modern asset pipeline is cleaner than ever
62
+ - **The "One-Person Framework"**: Rails excels when a small team (or single developer) needs to ship a complete product
63
+ - **Convention over Configuration**: Less decision fatigue, faster development
64
+
65
+ ### The Thesis: R-on-Rails
66
+
67
+ **R-on-Rails** is a two-engine architecture:
68
+
69
+ 1. **Rails (Ruby)**: Handles web requests, authentication, authorization, database operations, background jobs, email, APIs, caching, sessions, and orchestration
70
+ 2. **R**: Handles statistical modeling, machine learning, visualization, and data analysis
71
+ 3. **Galaaz**: The seamless bridge that makes this integration feel like a single system—using Apache Arrow for zero-copy data transfer at scale
72
+
73
+ **The Value Proposition**: Keep everything you love about R—the packages, the syntax, the statistical rigor—while gaining everything Rails provides for production applications. Move data between languages at memory speed, not serialization speed.
74
+
75
+ ---
76
+
77
+ ## The Galaaz 2.0 Architecture (Important Technical Clarification)
78
+
79
+ **Galaaz 2.0 uses JRuby + GNU R, not GraalVM/FastR**
80
+
81
+ Earlier versions of Galaaz explored GraalVM's polyglot capabilities with FastR (Oracle's R implementation). However, **FastR is no longer actively developed**, and Galaaz 2.0 has moved to a more robust architecture:
82
+
83
+ ```
84
+ ┌─────────────────────────────────────────────────────────────────┐
85
+ │ Galaaz 2.0 Architecture │
86
+ ├─────────────────────────────────────────────────────────────────┤
87
+ │ │
88
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────┐ │
89
+ │ │ JRuby │ ←─────→ │ Galaaz Bridge│ ←─────→ │ GNU R │ │
90
+ │ │ (JVM) │ (Java) │ (JNI/R API) │ (C/R) │ Process │ │
91
+ │ └──────────────┘ └──────────────┘ └──────────┘ │
92
+ │ │ │ │
93
+ │ │ │ │
94
+ │ ▼ ▼ │
95
+ │ ┌──────────────┐ ┌──────────┐│
96
+ │ │ Rails App │ │ Arrow ││
97
+ │ │ Multi-thread │ │ Shared ││
98
+ │ │ ActiveRecord │ │ Memory ││
99
+ │ └──────────────┘ └──────────┘│
100
+ │ │
101
+ └─────────────────────────────────────────────────────────────────┘
102
+ ```
103
+
104
+ **How it works:**
105
+ 1. **JRuby** runs on the JVM with true multi-threading, running Rails and application code
106
+ 2. **Galaaz Bridge** communicates with a GNU R process via R's C API (or alternative mechanisms)
107
+ 3. **Apache Arrow** (optional) provides efficient, shared-memory data transfer for large datasets
108
+ 4. **GNU R** is the actual R interpreter—full compatibility with all R packages (ggplot2, dplyr, Bioconductor, etc.)
109
+
110
+ **Why this is better than FastR/GraalVM:**
111
+ - **Full package compatibility**: GNU R runs every CRAN and Bioconductor package
112
+ - **Stable foundation**: No dependency on Oracle's experimental R implementation
113
+ - **Production-ready**: Battle-tested JRuby + battle-tested GNU R
114
+ - **Process isolation**: R runs in separate processes—crash in one R process doesn't take down the Rails app
115
+ - **Multiple R workers**: Ruby can orchestrate multiple R processes for parallel computation
116
+
117
+ **Comparison with other bridges:**
118
+
119
+ | Approach | How it works | Limitations |
120
+ |----------|--------------|-------------|
121
+ | **rpy2** (Python) | Embeds R in Python process | Single-threaded, crashes affect host |
122
+ | **RinRuby** | Parses R code over stdout | String-based, no type safety, slow |
123
+ | **reticulate** (R→Python) | Python embedded in R | Limited to Python, not R-in-Python |
124
+ | **Galaaz 1.0** (GraalVM) | FastR + TruffleRuby polyglot | FastR discontinued, limited packages |
125
+ | **Galaaz 2.0** (JRuby+GNU R) | JRuby → Bridge → GNU R process | Full compatibility, process isolation |
126
+
127
+ ---
128
+
129
+ ## Section-by-Section Outline with Code Examples
130
+
131
+ ### Section 1: What Makes Galaaz Different (The Bridge Architecture)
132
+
133
+ **Key Message**: Traditional bridges (rpy2, RinRuby) require string manipulation. Galaaz provides native object interaction without marshaling overhead.
134
+
135
+ **Comparison:**
136
+
137
+ Traditional approach (rpy2):
138
+ ```python
139
+ # Python with rpy2 - string-based interaction
140
+ import rpy2.robjects as ro
141
+ ro.r('library(ggplot2)')
142
+ ro.r('data(mpg, package="ggplot2")')
143
+ ro.r('''
144
+ ggplot(mpg, aes(displ, hwy)) +
145
+ geom_point() +
146
+ geom_smooth(method="loess")
147
+ ''')
148
+ ```
149
+
150
+ Galaaz approach:
151
+ ```ruby
152
+ # Ruby with Galaaz - native object interaction
153
+ require 'galaaz'
154
+ require 'ggplot'
155
+
156
+ R.install_and_loads('ggplot2')
157
+ mpg = ~R[:mpg] # Access R's mpg dataset
158
+
159
+ # Native Ruby method calls, not string evaluation
160
+ plot = mpg.ggplot(E.aes(x: :displ, y: :hwy)) +
161
+ R.geom_point +
162
+ R.geom_smooth(method: "loess")
163
+
164
+ plot.print
165
+ ```
166
+
167
+ **Why this matters**:
168
+ - Type safety and IDE autocomplete work naturally
169
+ - No string escaping hell
170
+ - R errors propagate as Ruby exceptions
171
+ - Efficient data transfer between JRuby and GNU R processes
172
+
173
+ **Example from specs** (r_vector_functions.spec.rb):
174
+ ```ruby
175
+ # R's %in% operator becomes a native method call
176
+ vec1 = R.c(1, 2, 3, 4)
177
+ vec2 = R.c(3, 4, 5)
178
+
179
+ # In R: vec1 %in% vec2
180
+ # In Galaaz:
181
+ result = vec1._ :in, vec2 # Returns R vector of booleans
182
+ ```
183
+
184
+ ---
185
+
186
+ ### Section 2: dplyr and Non-Standard Evaluation (NSE) - Solved
187
+
188
+ **Key Message**: Programming with dplyr in R is famously tricky due to NSE. Galaaz makes it straightforward with explicit expression handling.
189
+
190
+ **The Problem** (from nse_dplyr blog):
191
+ In R, this works interactively:
192
+ ```r
193
+ library(dplyr)
194
+ df %>% filter(x == 1) # x refers to column, not variable
195
+ ```
196
+
197
+ But programming with it fails:
198
+ ```r
199
+ my_var <- 1
200
+ df %>% filter(x == my_var) # Error: object 'my_var' not found
201
+ ```
202
+
203
+ You need tidyeval, `{{}}` operators, `ensym()`, `enquo()`—concepts that take months to master.
204
+
205
+ **The Galaaz Solution**:
206
+ ```ruby
207
+ require 'galaaz'
208
+
209
+ df = R.data__frame(x: (1..5), y: (5..1))
210
+
211
+ # Simple filtering with expressions
212
+ filtered = df.filter(R[:x].eq 1) # Filter where column x equals 1
213
+
214
+ # Using variables is explicit and unambiguous
215
+ my_var = 1
216
+ filtered = df.filter(R[:x].eq my_var) # Column x equals Ruby variable my_var
217
+
218
+ # Column-to-column comparison
219
+ filtered = df.filter(R[:x].eq :y) # Column x equals column y
220
+
221
+ # Complex expressions
222
+ filtered = df.filter((R[:x] + R[:y]).gte 5)
223
+ ```
224
+
225
+ **Why this works**: Galaaz expressions (`R[:x].eq 1`) are explicit about what's a column reference (symbol `:x`) vs. what's a Ruby value (`my_var`). No ambiguity, no tidyeval complexity.
226
+
227
+ **Example from specs** (r_nse.spec.rb):
228
+ ```ruby
229
+ def subset(df, condition)
230
+ # Evaluate condition in the scope of the dataframe
231
+ r = R.eval(condition, df)
232
+ df[r, :all]
233
+ end
234
+
235
+ # Usage: explicit expression with symbol :a
236
+ subset(df, :a >= 4)
237
+ subset(df, R[:a].eq 4)
238
+ ```
239
+
240
+ ---
241
+
242
+ ### Section 3: ggplot2 Continuity - Same Power, Better Orchestration
243
+
244
+ **Key Message**: Your ggplot2 skills transfer completely. Galaaz adds Ruby's organizational power—classes, modules, themes as code.
245
+
246
+ **Side-by-Side Example** (from ruby_plot blog):
247
+
248
+ R code:
249
+ ```r
250
+ library(ggplot2)
251
+ data(ToothGrowth)
252
+
253
+ ggplot(ToothGrowth, aes(x=dose, y=len)) +
254
+ geom_boxplot() +
255
+ facet_grid(. ~ supp) +
256
+ labs(title="Tooth Growth", x="Dose", y="Length")
257
+ ```
258
+
259
+ Galaaz code:
260
+ ```ruby
261
+ require 'galaaz'
262
+ require 'ggplot'
263
+
264
+ tooth_growth = ~R[:ToothGrowth]
265
+
266
+ plot = tooth_growth.ggplot(E.aes(x: :dose, y: :len)) +
267
+ R.geom_boxplot +
268
+ R.facet_grid(R[:all].til R[:supp]) + # Formula: ~supp
269
+ R.labs(title: "Tooth Growth", x: "Dose", y: "Length")
270
+
271
+ plot.print
272
+ ```
273
+
274
+ **The Ruby Advantage - Corporate Themes as Modules** (from ruby_plot blog):
275
+ ```ruby
276
+ module CorpTheme
277
+ def self.global_theme(faceted: false)
278
+ R.options(scipen: 999) # No scientific notation
279
+
280
+ gb = R.theme(panel__grid__major: E.element_blank)
281
+ gb = gb + R.theme(panel__grid__minor: E.element_blank)
282
+ gb = gb + R.theme(panel__border: E.element_blank)
283
+ gb = gb + R.theme(panel__background: E.element_blank) unless faceted
284
+ gb = gb + R.theme(axis__title: text_element(10, face: "bold", hjust: 1))
285
+ gb
286
+ end
287
+ end
288
+
289
+ # Apply theme consistently
290
+ final_plot = plot + CorpTheme.global_theme(faceted: true)
291
+ ```
292
+
293
+ **Key insight**: In R, creating a reusable theme requires understanding ggplot2's theme system. In Galaaz, it's just a Ruby module—standard Ruby knowledge any developer has.
294
+
295
+ ---
296
+
297
+ ### Section 4: Modeling and Statistics - ISLR Examples
298
+
299
+ **Key Message**: Statistical modeling with caret, lm, glm works identically. Ruby adds train/test split abstractions and model management.
300
+
301
+ **Example** (from examples/islr/ch3_boston.rb):
302
+
303
+ ```ruby
304
+ require 'galaaz'
305
+ require 'ggplot'
306
+
307
+ R.install_and_loads('ISLR', 'MASS') # Install if needed, then load
308
+
309
+ # Access R's Boston dataset
310
+ boston = ~R[:Boston]
311
+
312
+ # Simple linear regression
313
+ # R: lm(medv ~ lstat, data=Boston)
314
+ boston_lm = R.lm((R[:medv].til :lstat), data: :Boston)
315
+
316
+ puts boston_lm.coef # Coefficients
317
+ puts boston_lm.confint # Confidence intervals
318
+
319
+ # Predictions with intervals
320
+ conf = R.predict(boston_lm,
321
+ R.data__frame(lstat: R.c(5, 10, 15)),
322
+ interval: "confidence")
323
+
324
+ pred = R.predict(boston_lm,
325
+ R.data__frame(lstat: R.c(5, 10, 15)),
326
+ interval: "prediction")
327
+
328
+ # Multiple regression (from ch3_multiple_regression.rb)
329
+ lm_fit = R.lm((R[:medv].til R[:lstat] + R[:age]), data: :Boston)
330
+ puts lm_fit.summary
331
+
332
+ # Polynomial terms
333
+ lm_fit5 = R.lm((R[:medv].til E.poly(:lstat, 5)), data: :Boston)
334
+ puts lm_fit5.summary
335
+ ```
336
+
337
+ **Multiple Regression with caret** (from model.rb):
338
+ ```ruby
339
+ require 'galaaz'
340
+
341
+ class Model
342
+ attr_reader :data, :test, :train
343
+
344
+ def initialize(data, percent_train:, seed: 123)
345
+ R.set__seed(seed)
346
+ @data = data
347
+ @percent_train = percent_train
348
+ end
349
+
350
+ def partition(field)
351
+ # R's createDataPartition for train/test split
352
+ train_index = R.createDataPartition(
353
+ @data.send(field),
354
+ p: @percent_train,
355
+ list: false,
356
+ times: 1
357
+ )
358
+ @train = @data[train_index, :all]
359
+ @test = @data[-train_index, :all]
360
+ end
361
+ end
362
+
363
+ # Usage
364
+ model = Model.new(boston_data, percent_train: 0.8, seed: 42)
365
+ model.partition(:medv) # Partition based on medv column
366
+ # model.train and model.test now available
367
+ ```
368
+
369
+ ---
370
+
371
+ ### Section 5: Object-Oriented R - Classes, Modules, and Reusable Code
372
+
373
+ **Key Message**: R's S4 and R6 provide OOP, but Ruby's object model is more expressive and easier to learn. Galaaz brings real OOP to statistical workflows.
374
+
375
+ **Comparison** (from oh_my blog):
376
+
377
+ R S4:
378
+ ```r
379
+ setClass(
380
+ Class="Trajectories",
381
+ representation=representation(
382
+ times = "numeric",
383
+ traj = "matrix"
384
+ )
385
+ )
386
+
387
+ trajCochin <- new(
388
+ Class="Trajectories",
389
+ times=c(1,3,4,5),
390
+ traj=rbind(
391
+ c(15,15.1, 15.2, 15.2),
392
+ c(16,15.9, 16,16.4)
393
+ )
394
+ )
395
+
396
+ # Add a method
397
+ setMethod("print", "Trajectories",
398
+ function(x, ...) {
399
+ cat("*** Class Trajectories ***\n")
400
+ cat("* Times ="); print(x@times)
401
+ }
402
+ )
403
+ ```
404
+
405
+ Galaaz Ruby:
406
+ ```ruby
407
+ class Trajectories
408
+ attr_reader :times, :matrix
409
+
410
+ def initialize(times: nil, matrix: nil)
411
+ @times = times
412
+ @matrix = matrix
413
+ end
414
+
415
+ def print
416
+ puts("*** Class Trajectories, method Print ***")
417
+ puts("times = #{@times}")
418
+ puts("traj = #{@matrix}")
419
+ end
420
+
421
+ # Can add methods later without redefining class
422
+ def show
423
+ nrow_show = [10, @matrix.nrow.gz].min
424
+ puts("* Traj (limited to 10x10) =")
425
+ puts @matrix[(1..nrow_show), (1..nrow_show)].format(digits: 2)
426
+ end
427
+ end
428
+
429
+ # Usage with R data
430
+ @trajCochin = Trajectories.new(
431
+ times: R.c(1, 3, 4, 5),
432
+ matrix: R.rbind(
433
+ R.c(15, 15.1, 15.2, 15.2),
434
+ R.c(16, 15.9, 16, 16.4)
435
+ )
436
+ )
437
+
438
+ @trajCochin.print
439
+ @trajCochin.show
440
+ ```
441
+
442
+ **Key advantages**:
443
+ - Constructor with default parameters
444
+ - Easy method addition (reopen classes)
445
+ - Mixins and modules for shared behavior
446
+ - Clear separation between R data and Ruby logic
447
+ - Full introspection: `@traj.instance_variables`
448
+
449
+ ---
450
+
451
+ ### Section 6: Apache Arrow - Zero-Copy Data at Scale
452
+
453
+ **Key Message**: Traditional bridges serialize data (JSON, CSV) to pass between languages. Galaaz uses Apache Arrow for zero-copy, memory-mapped data transfer—enabling huge datasets to move from Ruby to R instantly.
454
+
455
+ **The Problem: Data Transfer Overhead**
456
+
457
+ In traditional polyglot systems (rpy2, reticulate), passing data between languages requires serialization:
458
+
459
+ ```python
460
+ # Python → R via JSON/CSV serialization (SLOW)
461
+ import pandas as pd
462
+ import rpy2.robjects as ro
463
+ from rpy2.robjects import pandas2ri
464
+
465
+ df = pd.DataFrame({'x': range(1000000), 'y': range(1000000)})
466
+ # Converts Python DataFrame → CSV string → R data.frame (expensive!)
467
+ ro.globalenv['r_df'] = pandas2ri.py2rpy(df)
468
+ ```
469
+
470
+ This approach:
471
+ - Copies all data through a text format
472
+ - Loses type information (factors become strings, dates become strings)
473
+ - Consumes 2-3x memory during transfer
474
+ - Becomes a bottleneck at ~100K+ rows
475
+
476
+ **The Galaaz Solution: Apache Arrow**
477
+
478
+ Apache Arrow is a columnar, in-memory format designed for zero-copy data sharing across languages. With Galaaz:
479
+
480
+ ```ruby
481
+ require 'galaaz'
482
+
483
+ # 1. Build data in Ruby—using parallel threads for multi-source ingestion
484
+ batches = []
485
+ mutex = Mutex.new
486
+ threads = []
487
+
488
+ # Simulate parallel data ingestion from multiple sources
489
+ [0, 1, 2, 3].each do |tid|
490
+ threads << Thread.new do
491
+ # Each thread queries its own database/shard/API
492
+ local_data = fetch_from_source(tid) # Returns array of hashes
493
+ mutex.synchronize { batches << local_data }
494
+ end
495
+ end
496
+ threads.each(&:join)
497
+
498
+ # 2. Convert to Arrow Table—zero-copy transfer to R
499
+ # This is the key: data moves to R without serialization!
500
+ table = R::Arrow.from_ruby_batches(batches)
501
+
502
+ # 3. Use R's dplyr directly on the Arrow table
503
+ R.install_and_loads('dplyr', 'arrow')
504
+
505
+ grouped = R.dplyr___group_by(table, :region)
506
+ summarised = R.dplyr___summarise(
507
+ grouped,
508
+ count: E.n(),
509
+ avg_value: E.mean(:value),
510
+ total: E.sum(:value)
511
+ )
512
+ results = R.dplyr___collect(summarised)
513
+
514
+ puts results
515
+ #> # A tibble: 4 × 4
516
+ #> region count avg_value total
517
+ #> <chr> <int> <dbl> <dbl>
518
+ #> 1 North 25000 5.5 137500
519
+ #> 2 South 25000 5.5 137500
520
+ #> 3 East 25000 5.5 137500
521
+ #> 4 West 25000 5.5 137500
522
+ ```
523
+
524
+ **Why This Matters:**
525
+
526
+ - **No serialization cost**: Data stays in Arrow's columnar format throughout
527
+ - **Type preservation**: Factors, dates, timestamps remain intact
528
+ - **Memory efficiency**: No intermediate copies; Ruby and R share the same memory
529
+ - **Scale**: Tested with millions of rows (see slow-specs/arrow_large_pipeline_spec.rb with 200K+ rows)
530
+ - **Lazy evaluation**: Arrow datasets can be filtered/aggregated before materializing
531
+
532
+ **Real-World Example: Multi-DB Aggregation**:
533
+
534
+ ```ruby
535
+ # Aggregate data from multiple PostgreSQL shards in Ruby,
536
+ # then analyze in R with zero-copy transfer
537
+
538
+ require 'galaaz'
539
+ require 'active_record'
540
+
541
+ # Connect to multiple database shards
542
+ SHARDS = ['shard_1', 'shard_2', 'shard_3', 'shard_4'].map do |shard_name|
543
+ ActiveRecord::Base.establish_connection(
544
+ adapter: 'postgresql',
545
+ host: "#{shard_name}.db.internal",
546
+ database: 'analytics'
547
+ )
548
+ end
549
+
550
+ # Parallel data collection from all shards
551
+ batches = []
552
+ mutex = Mutex.new
553
+
554
+ SHARDS.each do |shard|
555
+ Thread.new do
556
+ # Query this shard
557
+ records = shard.connection.select_all(<<-SQL).cast_values
558
+ SELECT user_id, region, event_type, value, created_at
559
+ FROM events
560
+ WHERE created_at > NOW() - INTERVAL '7 days'
561
+ SQL
562
+
563
+ # Convert to array of hashes for Arrow
564
+ batch = records.map do |row|
565
+ {
566
+ user_id: row[0],
567
+ region: row[1],
568
+ event_type: row[2],
569
+ value: row[3],
570
+ created_at: row[4]
571
+ }
572
+ end
573
+
574
+ mutex.synchronize { batches << batch }
575
+ end
576
+ end
577
+
578
+ # Zero-copy transfer to R as Arrow Table
579
+ table = R::Arrow.from_ruby_batches(batches)
580
+
581
+ # Now use R's full power on the complete dataset
582
+ R.install_and_loads('dplyr', 'arrow', 'lubridate')
583
+
584
+ # R's dplyr works directly on Arrow tables (lazy evaluation)
585
+ analysis = table \
586
+ .dplyr___filter(E.created_at > (E.now() - E.days(7))) \
587
+ .dplyr___group_by(:region, :event_type) \
588
+ .dplyr___summarise(
589
+ count: E.n(),
590
+ total_value: E.sum(:value),
591
+ avg_value: E.mean(:value),
592
+ unique_users: E.n_distinct(:user_id)
593
+ )
594
+
595
+ # Materialize results when ready
596
+ results = R.dplyr___collect(analysis)
597
+
598
+ # Convert back to Ruby objects for API response
599
+ results_hash = results.to_ruby
600
+ render json: { analytics: results_hash }
601
+ ```
602
+
603
+ **Parquet and Feather: Persistence Without Conversion**:
604
+
605
+ ```ruby
606
+ # Save Ruby data as Parquet (columnar, compressed)
607
+ # Then read directly into R without parsing
608
+
609
+ # 1. Build large dataset in Ruby
610
+ data = (1..1_000_000).map do |i|
611
+ {
612
+ id: i,
613
+ category: ["A", "B", "C", "D"][i % 4],
614
+ value: rand * 100,
615
+ timestamp: Time.now - (i % 86400)
616
+ }
617
+ end
618
+
619
+ # 2. Convert to R data.frame, then write as Parquet
620
+ df = R.data__frame(data)
621
+ R::Arrow.write_parquet(df, '/data/events.parquet')
622
+
623
+ # 3. Later, read directly into R as a dataset (lazy, memory-mapped)
624
+ dataset = R::Arrow.dataset('/data/events.parquet')
625
+
626
+ # Query without loading entire file
627
+ summary = R.dplyr___collect(
628
+ dataset \
629
+ .dplyr___filter(R[:value] > 50) \
630
+ .dplyr___group_by(:category) \
631
+ .dplyr___summarise(count: E.n(), avg: E.mean(:value))
632
+ )
633
+ ```
634
+
635
+ **Large-Scale Test Results** (from `slow-specs/arrow_large_pipeline_spec.rb`):
636
+
637
+ ```ruby
638
+ # Test: 8 threads × 25,000 rows = 200,000 rows
639
+ # With weighted aggregations in R
640
+ thread_count = 8
641
+ rows_per_thread = 25_000
642
+ group_count = 10
643
+
644
+ # Ruby parallel batch construction... 8 threads
645
+ # Arrow table creation from batches → instant
646
+ # R dplyr group_by + summarise → native speed
647
+ # Results verified accurate against Ruby reference implementation
648
+ ```
649
+
650
+ **Key Insight**: With Arrow, the boundary between Ruby and R disappears for data. You can build data pipelines in Ruby (with its superior concurrency and database libraries) and analyze in R (with its statistical ecosystem)—with **zero overhead** at the language boundary.
651
+
652
+ ---
653
+
654
+ ### Section 7: Parallelism and Process Orchestration
655
+
656
+ **Key Message**: R is single-threaded. Galaaz solves this by orchestrating multiple R processes from Ruby's multi-threaded environment—now with Arrow for efficient data distribution.
657
+
658
+ **The Architecture**:
659
+ ```
660
+ ┌─────────────────────────────────────────────────────────────┐
661
+ │ Rails Application │
662
+ │ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
663
+ │ │ Request │ │ Request │ │ Request │ │
664
+ │ │ Handler 1 │ │ Handler 2 │ │ Handler 3 │ │
665
+ │ │ (Thread 1) │ │ (Thread 2) │ │ (Fiber) │ │
666
+ │ └──────┬───────┘ └──────┬───────┘ └──────┬───────┘ │
667
+ │ │ │ │ │
668
+ │ └──────────────────┼──────────────────┘ │
669
+ │ │ │
670
+ │ ┌─────────▼─────────┐ │
671
+ │ │ Galaaz Bridge │ │
672
+ │ │ (Process Pool) │ │
673
+ │ └─────────┬─────────┘ │
674
+ │ │ │
675
+ │ ┌──────────────────┼──────────────────┐ │
676
+ │ │ │ │ │
677
+ │ ┌──────▼──────┐ ┌──────▼──────┐ ┌──────▼──────┐ │
678
+ │ │ R Process 1 │ │ R Process 2 │ │ R Process 3 │ │
679
+ │ │ (Worker) │ │ (Worker) │ │ (Worker) │ │
680
+ │ │ Arrow Table │ │ Arrow Table │ │ Arrow Table │ │
681
+ │ └─────────────┘ └─────────────┘ └─────────────┘ │
682
+ └─────────────────────────────────────────────────────────────┘
683
+ ```
684
+
685
+ **Code Example**:
686
+ ```ruby
687
+ # Parallel data processing with multiple R workers
688
+ require 'galaaz'
689
+
690
+ # Data partitioned by region
691
+ regions = ['North', 'South', 'East', 'West']
692
+ data_partitions = partition_data_by_region(large_dataset, regions)
693
+
694
+ # Launch parallel R computations
695
+ results = Parallel.map(data_partitions, in_processes: 4) do |region_data|
696
+ R.session do |r|
697
+ # Each block runs in its own R process
698
+ r.install_and_loads('dplyr', 'caret')
699
+
700
+ # R computation
701
+ model = r.lm((R[:sales].til :marketing_spend + :competition_index),
702
+ data: region_data)
703
+
704
+ predictions = r.predict(model, newdata: region_data)
705
+
706
+ # Return Ruby object (automatic unboxing)
707
+ { region: region_data.name,
708
+ r_squared: model.summary.r.squared.gz,
709
+ predictions: predictions }
710
+ end
711
+ end
712
+
713
+ # Consolidate results in Ruby
714
+ combined = consolidate_predictions(results)
715
+ ```
716
+
717
+ **Fault Isolation**:
718
+ ```ruby
719
+ # If an R process crashes, Galaaz can restart and retry
720
+ R.session(restart_on_error: true, max_retries: 3) do |r|
721
+ r.long_running_computation(data)
722
+ end
723
+ ```
724
+
725
+ ---
726
+
727
+ ### Section 8: Production Architecture - The Full Stack
728
+
729
+ **Key Message**: A complete production system with Rails handling web concerns and R handling analytics.
730
+
731
+ **Example: Analytics API Endpoint**:
732
+ ```ruby
733
+ # app/controllers/analytics_controller.rb
734
+ class AnalyticsController < ApplicationController
735
+ before_action :authenticate_user!
736
+ before_action :authorize_analytics!
737
+
738
+ def forecast
739
+ # Rails handles auth, params, response formatting
740
+ product_id = params[:product_id]
741
+ days = params[:days]&.to_i || 30
742
+
743
+ # Database query with ActiveRecord
744
+ historical_data = SalesData
745
+ .where(product_id: product_id)
746
+ .where('date > ?', days.days.ago)
747
+ .to_galaaz_df # Convert to R dataframe
748
+
749
+ # Delegate to R for statistical modeling
750
+ forecast_result = R.session do |r|
751
+ r.install_and_loads('forecast')
752
+
753
+ ts = r.ts(historical_data.sales, frequency: 7)
754
+ model = r.auto.arima(ts)
755
+ forecast = r.forecast(model, h: days)
756
+
757
+ {
758
+ mean: forecast.mean,
759
+ lower: forecast.lower,
760
+ upper: forecast.upper,
761
+ model_aic: model.aic
762
+ }
763
+ end
764
+
765
+ # Rails formats response
766
+ render json: {
767
+ product_id: product_id,
768
+ forecast: forecast_result,
769
+ generated_at: Time.current
770
+ }
771
+ end
772
+ end
773
+ ```
774
+
775
+ **Background Job with Sidekiq**:
776
+ ```ruby
777
+ # app/jobs/model_training_job.rb
778
+ class ModelTrainingJob < ApplicationJob
779
+ queue_as :ml_training
780
+
781
+ def perform(training_data_id, model_config)
782
+ training_data = TrainingData.find(training_data_id)
783
+
784
+ # Large computation in isolated R process
785
+ R.session(timeout: 1.hour) do |r|
786
+ r.install_and_loads('caret', 'randomForest')
787
+
788
+ # Train model
789
+ model = r.train(
790
+ target ~ .,
791
+ data: training_data.to_r,
792
+ method: model_config[:algorithm],
793
+ trControl: r.trainControl(method: "cv", number: 5)
794
+ )
795
+
796
+ # Save model (R's native format)
797
+ model_path = "/models/#{training_data_id}.rds"
798
+ r.saveRDS(model, model_path)
799
+
800
+ # Store metadata in Rails database
801
+ training_data.update!(
802
+ model_path: model_path,
803
+ accuracy: model.results.Accuracy.max.gz,
804
+ trained_at: Time.current
805
+ )
806
+ end
807
+ end
808
+ end
809
+ ```
810
+
811
+ ---
812
+
813
+ ### Section 9: Migration Path - From R Script to R-on-Rails
814
+
815
+ **Key Message**: You don't rewrite everything. You migrate incrementally, starting with the web layer.
816
+
817
+ **Phase 1: Wrap R Script in API** (Week 1):
818
+ ```ruby
819
+ # Before: R script run manually
820
+ # Rscript generate_report.R --input data.csv --output report.pdf
821
+
822
+ # After: Rails API endpoint
823
+ class ReportsController < ApplicationController
824
+ def create
825
+ uploaded_file = params[:data_file]
826
+
827
+ R.session do |r|
828
+ r.eval("data <- read.csv('#{uploaded_file.path}')")
829
+ r.eval("rmarkdown::render('report_template.Rmd', output_file='report.pdf')")
830
+ end
831
+
832
+ send_file 'report.pdf', type: 'application/pdf'
833
+ end
834
+ end
835
+ ```
836
+
837
+ **Phase 2: Replace R Data Manipulation with Ruby** (Weeks 2-4):
838
+ ```ruby
839
+ # Gradually move from R dplyr to Ruby ActiveRecord/SQL
840
+ # Before (R):
841
+ # R.filter(df, :region == "North" & :sales > 1000)
842
+
843
+ # After (Rails):
844
+ SalesData.where(region: "North").where("sales > ?", 1000)
845
+ ```
846
+
847
+ **Phase 3: Full Object-Oriented Refactor** (Month 2+):
848
+ ```ruby
849
+ # Extract R logic into Ruby service objects
850
+ class SalesForecaster
851
+ def initialize(product)
852
+ @product = product
853
+ end
854
+
855
+ def forecast(days: 30)
856
+ R.session do |r|
857
+ # Only statistical core remains in R
858
+ # Everything else is Ruby
859
+ end
860
+ end
861
+ end
862
+ ```
863
+
864
+ ---
865
+
866
+ ## Conclusion: The Best of Both Worlds
867
+
868
+ ### Summary of Value Propositions
869
+
870
+ **For R Developers**:
871
+ - Keep using ggplot2, dplyr, caret, Bioconductor—your knowledge transfers
872
+ - Write statistical code the way you always have
873
+ - Gain real web infrastructure: auth, APIs, databases, caching
874
+ - Deploy with confidence using Rails' battle-tested patterns
875
+ - No need to learn Python or JavaScript frameworks
876
+
877
+ **For Rails Developers**:
878
+ - Add world-class statistical capabilities to your applications
879
+ - Access thousands of R packages without rewriting them
880
+ - Maintain your productivity with familiar Rails patterns
881
+ - Serve data science customers without context-switching languages
882
+
883
+ **For Organizations**:
884
+ - Bridge the gap between data science and engineering teams
885
+ - Deploy R models in production with proper infrastructure
886
+ - Reduce technical debt from "R scripts running on someone's laptop"
887
+ - Enable reproducible research that scales to production
888
+
889
+ ### The Future: Galaaz 2.0
890
+
891
+ Galaaz 2.0 represents the maturation of the Ruby-R bridge:
892
+ - **JRuby + GNU R architecture**: Moved from experimental GraalVM/FastR to battle-tested JRuby and standard GNU R for full package compatibility and production stability
893
+ - **New bridge architecture**: More robust, faster, better error handling
894
+ - **Process management**: Built-in support for R process pools
895
+ - **Apache Arrow integration**: Zero-copy data transfer for large datasets—build data pipelines in Ruby's multi-threaded environment, analyze in R with zero serialization overhead
896
+ - **gKnit improvements**: Better R Markdown integration
897
+ - **Rails integration**: First-class support for Rails patterns
898
+
899
+ ---
900
+
901
+ ## Appendix: Code Reference Quick Links
902
+
903
+ For the full blog post, include references to:
904
+
905
+ - **ISLR Examples**: `examples/islr/ch3_boston.rb`, `examples/islr/ch3_multiple_regression.rb`
906
+ - **ggplot2 Examples**: `examples/sthda_ggplot/` (all geom types)
907
+ - **NSE/dplyr**: `blogs/nse_dplyr/nse_dplyr.md`
908
+ - **Object-Oriented**: `blogs/oh_my/oh_my.md`
909
+ - **Plotting Tutorial**: `blogs/ruby_plot/ruby_plot.md`
910
+ - **Apache Arrow**: `specs/arrow_semantics_spec.rb`, `specs/arrow_from_ruby_batches_spec.rb`, `slow-specs/arrow_large_pipeline_spec.rb`
911
+ - **Specs**: `specs/r_nse.spec.rb`, `specs/r_vector_functions.spec.rb`
912
+
913
+ ---
914
+
915
+ ## Writing Notes for the Final Post
916
+
917
+ ### Tone Guidelines
918
+ - **Respectful of R**: Never disparage R. Position this as "adding production capabilities" not "fixing R."
919
+ - **Practical**: Show real code, not theoretical benefits.
920
+ - **Incremental**: Emphasize that migration can happen piece by piece.
921
+ - **Excited**: This is a genuine breakthrough—let that enthusiasm show.
922
+
923
+ ### Code Example Format
924
+ Each section should have:
925
+ 1. R version (familiar to readers)
926
+ 2. Galaaz version (showing similarity)
927
+ 3. Ruby-only enhancement (showing the value add)
928
+
929
+ ### Visual Diagrams to Create
930
+ 1. Two-engine architecture diagram
931
+ 2. Process pool for parallel R
932
+ 3. Request flow through Rails-R integration
933
+ 4. Migration path timeline
934
+
935
+ ### Call to Action
936
+ Invite readers to:
937
+ - Try the examples in `examples/islr/`
938
+ - Read the full dplyr tutorial in `blogs/nse_dplyr/`
939
+ - Explore ggplot examples in `examples/sthda_ggplot/`
940
+ - Join the Galaaz community (GitHub discussions, etc.)