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,404 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'open3'
4
+ require_relative 'session_client'
5
+
6
+ module NewBridge
7
+ # Phase 4.3 (local): Manage a dynamic set of R instances.
8
+ #
9
+ # This is the first slice of the planned production-grade instance manager:
10
+ # - spawn local R processes on demand
11
+ # - evaluate code via the spawned SessionClient instances
12
+ # - stop one or all instances
13
+ #
14
+ # Container provisioning and multi-version orchestration are deferred.
15
+ class RInstanceManager
16
+ class Error < StandardError; end
17
+
18
+ attr_reader :default_instance_id, :preferred_bridge_host
19
+
20
+ def initialize(source_path:, host: '127.0.0.1', default_r_cmd: 'R', session_client_class: SessionClient, out: $stdout, docker_access_checker: nil)
21
+ @source_path = File.expand_path(source_path)
22
+ @host = host
23
+ @default_r_cmd = default_r_cmd
24
+ @session_client_class = session_client_class
25
+ @out = out
26
+ @docker_access_checker = docker_access_checker
27
+ @clients = {} # instance_id => SessionClient
28
+ @meta = {} # instance_id => { provider:, runtime:, version:, r_cmd:, status:, image: }
29
+ @default_instance_id = nil
30
+ @preferred_bridge_host = nil
31
+ end
32
+
33
+ # Spawn a new local R gatekeeper process.
34
+ #
35
+ # @param instance_id [String]
36
+ # @param r_cmd [String] R executable (or full path to it)
37
+ # @param version [String, nil] semantic/version label for routing (e.g., "4.3.3")
38
+ # @return [SessionClient]
39
+ def spawn_local(instance_id:, r_cmd: @default_r_cmd, version: nil)
40
+ raise ArgumentError, "instance already exists: #{instance_id}" if @clients.key?(instance_id)
41
+
42
+ @out.puts("[RInstanceManager] starting local instance #{instance_id} version=#{version || 'n/a'}")
43
+ c = @session_client_class.new(source_path: @source_path, host: @host, r_cmd: r_cmd)
44
+ c.start
45
+ @clients[instance_id] = c
46
+ @meta[instance_id] = {
47
+ provider: 'local',
48
+ runtime: 'local',
49
+ version: version,
50
+ r_cmd: r_cmd,
51
+ status: :healthy
52
+ }
53
+ @default_instance_id ||= instance_id
54
+ c
55
+ end
56
+
57
+ # Spawn R in a container image.
58
+ #
59
+ # Notes:
60
+ # - This uses Docker and assumes the image can execute `R` with Rcpp available.
61
+ # - We mount the project root into /workspace and source the gatekeeper from that path.
62
+ def spawn_container(instance_id:, image:, version:, container_name: nil, r_exec: 'R', accept_timeout: 30,
63
+ bridge_host: nil, bridge_hosts: nil, relearn_bridge_host: false)
64
+ raise ArgumentError, "instance already exists: #{instance_id}" if @clients.key?(instance_id)
65
+ ensure_docker_daemon_access!
66
+
67
+ source_dir = File.dirname(@source_path)
68
+ project_root = File.expand_path('../..', source_dir)
69
+ runtime_source = "/workspace/ext/new_bridge/#{File.basename(@source_path)}"
70
+ base_name = container_name || "galaaz-#{instance_id}"
71
+ host_candidates = if bridge_host
72
+ [bridge_host]
73
+ elsif bridge_hosts
74
+ bridge_hosts
75
+ else
76
+ bridge_host_candidates(relearn: relearn_bridge_host)
77
+ end
78
+ @out.puts("[RInstanceManager] starting container instance #{instance_id} image=#{image} version=#{version}")
79
+ @out.puts("[RInstanceManager] bridge host candidates: #{host_candidates.join(', ')}")
80
+
81
+ c = nil
82
+ last_error = nil
83
+ selected_name = nil
84
+ selected_host = nil
85
+ selected_launch = nil
86
+
87
+ host_candidates.each_with_index do |bridge_host, idx|
88
+ name = "#{base_name}-#{idx}"
89
+ @out.puts("[RInstanceManager] trying bridge host #{bridge_host} (attempt #{idx + 1}/#{host_candidates.size})")
90
+ launch = [
91
+ 'docker', 'run',
92
+ '--name', name,
93
+ '--add-host', 'host.docker.internal:host-gateway',
94
+ '-v', "#{project_root}:/workspace",
95
+ image, r_exec
96
+ ]
97
+
98
+ c = @session_client_class.new(
99
+ source_path: @source_path,
100
+ runtime_source_path: runtime_source,
101
+ host: '0.0.0.0',
102
+ bridge_host: bridge_host,
103
+ r_cmd: launch
104
+ )
105
+ begin
106
+ c.start(accept_timeout: accept_timeout)
107
+ selected_name = name
108
+ selected_host = bridge_host
109
+ selected_launch = launch
110
+ @out.puts("[RInstanceManager] container instance #{instance_id} connected via #{bridge_host}")
111
+ break
112
+ rescue StandardError => e
113
+ last_error = e
114
+ logs = docker_logs(name, tail: 120)
115
+ @out.puts("[RInstanceManager] bridge host #{bridge_host} failed: #{e.message}")
116
+ if bridge_host == @preferred_bridge_host
117
+ @out.puts("[RInstanceManager] cached bridge host failed, trying fallback candidates...")
118
+ end
119
+ @out.puts(logs) unless logs.nil? || logs.empty?
120
+ docker_rm_force(name)
121
+ c = nil
122
+ end
123
+ end
124
+
125
+ if c.nil?
126
+ raise Error, "container runtime start failed instance=#{instance_id} image=#{image}: #{last_error&.message}"
127
+ end
128
+ if selected_host && selected_host != @preferred_bridge_host
129
+ @preferred_bridge_host = selected_host
130
+ @out.puts("[RInstanceManager] learned preferred bridge host: #{@preferred_bridge_host}")
131
+ end
132
+
133
+ @clients[instance_id] = c
134
+ @meta[instance_id] = {
135
+ provider: 'docker',
136
+ runtime: 'container',
137
+ version: version,
138
+ image: image,
139
+ bridge_host: selected_host,
140
+ container_name: selected_name,
141
+ r_cmd: selected_launch,
142
+ status: :healthy
143
+ }
144
+ @default_instance_id ||= instance_id
145
+ c
146
+ end
147
+
148
+ # Unified spawn API.
149
+ # runtime: 'local' or 'container'
150
+ def spawn(instance_id:, runtime:, version:, r_cmd: @default_r_cmd, image: nil, container_name: nil, accept_timeout: 30,
151
+ bridge_host: nil, bridge_hosts: nil, relearn_bridge_host: false)
152
+ case runtime.to_s
153
+ when 'local'
154
+ spawn_local(instance_id: instance_id, r_cmd: r_cmd, version: version)
155
+ when 'container'
156
+ raise ArgumentError, 'image is required for container runtime' if image.nil? || image.empty?
157
+
158
+ spawn_container(
159
+ instance_id: instance_id,
160
+ image: image,
161
+ version: version,
162
+ container_name: container_name,
163
+ accept_timeout: accept_timeout,
164
+ bridge_host: bridge_host,
165
+ bridge_hosts: bridge_hosts,
166
+ relearn_bridge_host: relearn_bridge_host
167
+ )
168
+ else
169
+ raise ArgumentError, "unsupported runtime=#{runtime} (expected 'local' or 'container')"
170
+ end
171
+ end
172
+
173
+ def instance_ids
174
+ @clients.keys
175
+ end
176
+
177
+ # Lightweight metadata view suitable for management UIs and tests.
178
+ # Example:
179
+ # [{ id: "a", provider: "local", version: "4.3.3", status: :healthy, r_cmd: "R" }]
180
+ def instances
181
+ @clients.keys.map do |id|
182
+ m = @meta.fetch(id, {})
183
+ {
184
+ id: id,
185
+ provider: m[:provider] || 'local',
186
+ runtime: m[:runtime] || 'local',
187
+ version: m[:version],
188
+ status: m[:status] || :healthy,
189
+ r_cmd: m[:r_cmd],
190
+ image: m[:image],
191
+ container_name: m[:container_name],
192
+ default: (id == @default_instance_id)
193
+ }
194
+ end
195
+ end
196
+
197
+ def eval_r(code, session_id:, instance_id:, parent_id: nil, timeout: 60)
198
+ c = @clients.fetch(instance_id)
199
+ c.eval_r(code, session_id: session_id, instance_id: instance_id, parent_id: parent_id, timeout: timeout)
200
+ rescue StandardError => e
201
+ raise unless infrastructure_retryable_error?(e)
202
+ raise unless @clients.key?(instance_id)
203
+
204
+ @out.puts("[RInstanceManager] runtime failure on instance=#{instance_id}: #{e.class}: #{e.message}")
205
+ @out.puts("[RInstanceManager] attempting one restart+retry for instance=#{instance_id}")
206
+ restart_instance(instance_id)
207
+ c2 = @clients.fetch(instance_id)
208
+ c2.eval_r(code, session_id: session_id, instance_id: instance_id, parent_id: parent_id, timeout: timeout)
209
+ end
210
+
211
+ # Route to an instance by version label.
212
+ # If multiple instances share a version, first match is used (deterministic by insertion order).
213
+ def eval_with_version(code, version:, session_id: 'default', timeout: 60)
214
+ entry = @meta.find { |_id, m| m[:version] == version }
215
+ raise KeyError, "no instance for version=#{version}" unless entry
216
+
217
+ instance_id, = entry
218
+ eval_r(code, session_id: session_id, instance_id: instance_id, timeout: timeout)
219
+ end
220
+
221
+ # Run the same code once per distinct version.
222
+ # Returns a map keyed by version label.
223
+ def eval_all_versions(code, session_id: 'default', timeout: 60)
224
+ by_version = {}
225
+ @meta.each do |id, m|
226
+ v = m[:version]
227
+ next if v.nil? || by_version.key?(v)
228
+
229
+ by_version[v] = eval_r(code, session_id: session_id, instance_id: id, timeout: timeout)
230
+ end
231
+ by_version
232
+ end
233
+
234
+ def set_default_instance(instance_id)
235
+ raise KeyError, "unknown instance_id=#{instance_id}" unless @clients.key?(instance_id)
236
+
237
+ @default_instance_id = instance_id
238
+ end
239
+
240
+ # Stop one instance or all instances.
241
+ # - keep_default: when stopping all, leaves default instance alive.
242
+ # - force_container: when stopping container instances, force-remove docker container.
243
+ def stop(instance_id = nil, keep_default: false, force_container: false)
244
+ if instance_id
245
+ c = @clients.delete(instance_id)
246
+ c&.stop
247
+ m = @meta.delete(instance_id)
248
+ cleanup_container(m, force: force_container)
249
+ @default_instance_id = @clients.keys.first if @default_instance_id == instance_id
250
+ return self
251
+ end
252
+
253
+ ids = @clients.keys
254
+ ids.each do |id|
255
+ next if keep_default && id == @default_instance_id
256
+
257
+ c = @clients.delete(id)
258
+ c&.stop
259
+ m = @meta.delete(id)
260
+ cleanup_container(m, force: force_container)
261
+ end
262
+
263
+ if @clients.empty?
264
+ @default_instance_id = nil
265
+ elsif @default_instance_id.nil? || !@clients.key?(@default_instance_id)
266
+ @default_instance_id = @clients.keys.first
267
+ end
268
+ self
269
+ end
270
+
271
+ def stop_all(keep_default: false, force_container: false)
272
+ stop(nil, keep_default: keep_default, force_container: force_container)
273
+ end
274
+
275
+ # Explicitly force-kill a container-backed runtime instance.
276
+ # Useful when user wants to ensure no container stays alive after a versioned run.
277
+ def kill_container(instance_id)
278
+ m = @meta.fetch(instance_id)
279
+ raise ArgumentError, "instance #{instance_id} is not container runtime" unless m[:runtime] == 'container'
280
+
281
+ stop(instance_id, force_container: true)
282
+ end
283
+
284
+ private
285
+
286
+ def restart_instance(instance_id)
287
+ m = @meta.fetch(instance_id)
288
+ stop(instance_id, force_container: true)
289
+ case m[:runtime]
290
+ when 'container'
291
+ spawn_container(
292
+ instance_id: instance_id,
293
+ image: m[:image],
294
+ version: m[:version],
295
+ container_name: m[:container_name],
296
+ accept_timeout: 30,
297
+ bridge_host: m[:bridge_host]
298
+ )
299
+ else
300
+ spawn_local(instance_id: instance_id, r_cmd: m[:r_cmd] || @default_r_cmd, version: m[:version])
301
+ end
302
+ end
303
+
304
+ def infrastructure_retryable_error?(e)
305
+ return true if e.is_a?(Timeout::Error)
306
+ return true if e.is_a?(Errno::EPIPE) || e.is_a?(Errno::ECONNRESET) || e.is_a?(IOError)
307
+ return true if e.is_a?(NewBridge::SessionClient::TimeoutError)
308
+ return false unless e.is_a?(NewBridge::SessionClient::RProcessError)
309
+
310
+ msg = e.message.to_s.downcase
311
+ return false if msg.include?('evaluation error') || msg.include?('parse error')
312
+ msg.include?('connection closed') || msg.include?('failed to accept runtime connection')
313
+ end
314
+
315
+ def cleanup_container(meta, force:)
316
+ return unless meta && meta[:runtime] == 'container'
317
+ return unless force
318
+
319
+ name = meta[:container_name]
320
+ docker_rm_force(name)
321
+ end
322
+
323
+ def docker_rm_force(name)
324
+ return if name.nil? || name.empty?
325
+
326
+ Open3.capture3('docker', 'rm', '-f', name)
327
+ rescue StandardError
328
+ nil
329
+ end
330
+
331
+ def docker_logs(container_name, tail: 80)
332
+ out, err, st = Open3.capture3('docker', 'logs', '--tail', tail.to_s, container_name)
333
+ return out if st.success?
334
+
335
+ err.to_s
336
+ rescue StandardError
337
+ ''
338
+ end
339
+
340
+ # Hostnames/IPs the container should try when dialing back to JRuby.
341
+ #
342
+ # On WSL2 + Docker Desktop, +host.docker.internal+ / host-gateway points at the
343
+ # Desktop VM, not the WSL distro where JRuby listens — so prefer the WSL eth0 IP
344
+ # first. Elsewhere, prefer +host.docker.internal+ and keep the local IP as fallback.
345
+ def bridge_host_candidates(relearn: false)
346
+ wsl_ip = local_wsl_ip
347
+ wsl_ip = nil if wsl_ip.nil? || wsl_ip.empty?
348
+
349
+ cands = if running_in_wsl?
350
+ [wsl_ip, 'host.docker.internal'].compact
351
+ else
352
+ ['host.docker.internal', wsl_ip].compact
353
+ end
354
+
355
+ if !relearn && @preferred_bridge_host
356
+ ([@preferred_bridge_host] + cands).uniq
357
+ else
358
+ cands.uniq
359
+ end
360
+ end
361
+
362
+ def running_in_wsl?
363
+ return true unless ENV['WSL_DISTRO_NAME'].to_s.empty?
364
+ return true unless ENV['WSL_INTEROP'].to_s.empty?
365
+
366
+ ver = File.exist?('/proc/version') ? File.read('/proc/version') : ''
367
+ !!(ver =~ /microsoft|wsl/i)
368
+ rescue StandardError
369
+ false
370
+ end
371
+
372
+ def local_wsl_ip
373
+ out, _err, st = Open3.capture3('bash', '-lc', "hostname -I | awk '{print $1}'")
374
+ return nil unless st.success?
375
+
376
+ out.to_s.strip
377
+ rescue StandardError
378
+ nil
379
+ end
380
+
381
+ def ensure_docker_daemon_access!
382
+ if @docker_access_checker
383
+ ok, err = @docker_access_checker.call
384
+ return if ok
385
+
386
+ msg = +'docker daemon is not accessible'
387
+ msg << ": #{err}" unless err.to_s.strip.empty?
388
+ msg << '. Try: `newgrp docker` (or reopen WSL terminal) and verify `docker info`.'
389
+ raise Error, msg
390
+ end
391
+
392
+ _out, err, st = Open3.capture3('docker', 'info')
393
+ return if st.success?
394
+
395
+ msg = +'docker daemon is not accessible'
396
+ unless err.to_s.strip.empty?
397
+ msg << ": #{err.to_s.strip}"
398
+ end
399
+ msg << '. Try: `newgrp docker` (or reopen WSL terminal) and verify `docker info`.'
400
+ raise Error, msg
401
+ end
402
+ end
403
+ end
404
+