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
@@ -22,6 +22,7 @@
22
22
  ##########################################################################################
23
23
 
24
24
  require 'stringio'
25
+ require 'tmpdir'
25
26
 
26
27
  #----------------------------------------------------------------------------------------
27
28
  # Class RC is used only as a context for all ruby chunks in the rmarkdown file.
@@ -40,6 +41,24 @@ class RC
40
41
  @out_list = R.c(@out_list, obj)
41
42
  end
42
43
 
44
+ # In gknit, stdout is redirected to StringIO. Under JRuby, Kernel.puts can treat
45
+ # R::Vector as array-like (to_ary) and print one element per line. Normalize R
46
+ # objects to their R printed form first, so `puts vec` matches gstudio (`[1] ...`).
47
+ def normalize_output_arg(arg)
48
+ return arg.to_s if arg.is_a?(::R::Object)
49
+ return arg.map { |item| normalize_output_arg(item) } if arg.is_a?(::Array)
50
+ arg
51
+ end
52
+
53
+ def puts(*args)
54
+ return ::Kernel.puts if args.empty?
55
+ ::Kernel.puts(*args.map { |arg| normalize_output_arg(arg) })
56
+ end
57
+
58
+ def print(*args)
59
+ ::Kernel.print(*args.map { |arg| normalize_output_arg(arg) })
60
+ end
61
+
43
62
  def reset_outputs
44
63
  @out_list = nil
45
64
  end
@@ -59,6 +78,39 @@ RCbinding = RChunk.get_binding
59
78
 
60
79
  module GalaazUtil
61
80
 
81
+ # Read a logical-ish knitr option directly from the options list on the R side.
82
+ # This avoids wrapper-shape differences when values arrive as handles/lists via NewBridge.
83
+ def self.knitr_option_trueish?(options, key, default: true)
84
+ return default unless options && options.respond_to?(:r_interop)
85
+
86
+ key_esc = key.to_s.gsub("'", "\\\\'")
87
+ txt = R.bridge.eval_r("as.character(#{options.r_interop}[['#{key_esc}']])").to_s
88
+ token = txt.sub(/\A\[\d+\]\s*/, '').gsub('"', '').strip.upcase
89
+ return true if token == 'TRUE'
90
+ return false if token == 'FALSE'
91
+ return default if token == '' || token == 'NA' || token == 'NULL'
92
+ return token.to_f != 0.0 if token.match?(/\A-?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?\z/)
93
+
94
+ default
95
+ rescue StandardError
96
+ default
97
+ end
98
+
99
+ # Knitr chunk options are often R logical NA ("inherit global default"). Those must not be
100
+ # treated as false (see R::Vector#unboxed_get: NA → nil). Defaults match knitr: eval/echo/include/message/warning TRUE.
101
+ def self.knitr_logical_trueish?(opt)
102
+ return true if opt.nil?
103
+ return opt if opt == true || opt == false
104
+
105
+ raw = opt.unboxed_get(0) if opt.respond_to?(:unboxed_get)
106
+ return true if raw.nil?
107
+ return raw if raw == true || raw == false
108
+ return raw != 0 if raw.is_a?(Numeric)
109
+ return !raw.to_s.strip.casecmp('FALSE').zero? if raw.respond_to?(:to_s)
110
+
111
+ true
112
+ end
113
+
62
114
  #----------------------------------------------------------------------------------------
63
115
  # Executes the ruby code with the given options.
64
116
  # @param options [R::List] An R list of options
@@ -78,15 +130,30 @@ module GalaazUtil
78
130
  def self.exec_ruby(options)
79
131
 
80
132
  # RubyChunk.init
81
-
82
- # read the chunk code
83
- code = R.paste(options.code, collapse: "\n") >> 0
84
-
133
+
134
+ # Read chunk code via a temp file (avoids result-protocol limits on long strings). Use Dir.tmpdir
135
+ # so gknit works without /dev/shm (macOS, sandboxes, minimal containers).
136
+ chunk_code_file = File.join(Dir.tmpdir, "galaaz_chunk_code_#{Process.pid}_#{Thread.current.object_id}.txt")
137
+ path_lit = ::R::Support.parse_arg(chunk_code_file)
138
+ begin
139
+ R.bridge.eval_r("writeLines(paste(#{options.r_interop}[['code']], collapse='\\n'), #{path_lit})")
140
+ code = File.read(chunk_code_file)
141
+ ensure
142
+ File.unlink(chunk_code_file) if chunk_code_file && File.file?(chunk_code_file)
143
+ end
144
+ # If the string arrived with literal \n (e.g. from R→Ruby transport), convert to real newlines so eval does not hit "unexpected backslash"
145
+ code = code.gsub("\\n", "\n") if code.is_a?(String)
85
146
  # the output should be a list with the proper structure to pass to
86
- # function engine_output. We first add the souce code from the block to
87
- # the list
88
- out_list = R.list(R.structure(R.list(src: code), class: 'source')) if
89
- options.echo >> 0
147
+ # function engine_output. We first add the source code from the block to
148
+ # the list. Pass src as a character vector of lines (not one string with \n)
149
+ # so knitr preserves line breaks and indentation in the rendered chunk.
150
+ if knitr_option_trueish?(options, 'echo', default: true)
151
+ src_lines = code.lines.map(&:chomp)
152
+ src_lines = [" "] if src_lines.empty?
153
+ out_list = R.list(R.structure(R.list(src: R.c(*src_lines)), class: 'source'))
154
+ else
155
+ out_list = R.list
156
+ end
90
157
 
91
158
  begin
92
159
 
@@ -98,8 +165,8 @@ module GalaazUtil
98
165
  # Execute the Ruby code in the scope of class RubyChunk. This is done
99
166
  # so that instance variables created in one chunk can be used again on
100
167
  # another chunk
101
- # RChunk.instance_eval(code) if (options[["eval"]] >> 0)
102
- eval(code, RCbinding, __FILE__, __LINE__ + 1) if (options[["eval"]] >> 0)
168
+ # RChunk.instance_eval(code) if (options[["eval"]].unboxed_get(0))
169
+ eval(code, RCbinding, __FILE__, __LINE__ + 1) if knitr_option_trueish?(options, 'eval', default: true)
103
170
 
104
171
  # add the returned value to the list
105
172
  # this should have captured everything in the evaluation code
@@ -109,23 +176,29 @@ module GalaazUtil
109
176
  out_list = R.c(out_list, out)
110
177
 
111
178
  rescue StandardError => e
179
+ begin
180
+ label = options['label'].unboxed_get(0).to_s
181
+ GknitDiagnostics.record(chunk_label: label, error: e) if defined?(GknitDiagnostics)
182
+ rescue StandardError
183
+ nil
184
+ end
112
185
 
113
- # print the error message
114
- if (options.message >> 0)
115
- message = R.list(R.structure(R.list(message: e.message), class: 'message'))
116
- out_list = R.c(out_list, message)
186
+ # Use R's simpleMessage/simpleWarning so knitr's engine_output can call conditionMessage() on them
187
+ # g_simpleMessage transforms "; " to newlines then calls simpleMessage (defined in R engine setup)
188
+ if knitr_option_trueish?(options, 'message', default: true)
189
+ msg_cond = R.g_simpleMessage(e.message.to_s)
190
+ out_list = R.c(out_list, msg_cond)
117
191
  end
118
192
 
119
- # Print the backtrace of the error message
120
- if (options.warning >> 0)
193
+ if knitr_option_trueish?(options, 'warning', default: true)
121
194
  bt = ""
122
195
  e.backtrace.each { |line| bt << line + "\n"}
123
- warning = R.list(R.structure(R.list(message: bt), class: 'message'))
124
- out_list = R.c(out_list, warning)
196
+ warn_cond = R.g_simpleWarning(bt)
197
+ out_list = R.c(out_list, warn_cond)
125
198
  end
126
199
 
127
200
  rescue SyntaxError => e
128
- STDERR.puts "A syntax error occured in ruby block '#{options.label >> 0}'"
201
+ STDERR.puts "A syntax error occured in ruby block '#{options['label'].unboxed_get(0)}'"
129
202
  raise SyntaxError.new(e)
130
203
 
131
204
  ensure
@@ -133,7 +206,9 @@ module GalaazUtil
133
206
  $stdout = STDOUT
134
207
  end
135
208
 
136
- (options.include >> 0)? out_list : R.list
209
+ # include=FALSE must still execute code (knitr semantics). Output suppression is handled
210
+ # at engine emission stage, not here.
211
+ out_list
137
212
 
138
213
  end
139
214
 
@@ -24,22 +24,20 @@
24
24
  module GalaazUtil
25
25
 
26
26
  #========================================================================================
27
- # Opens the given filename for reading and returns the file content so that it can be
28
- # printed as a code chunk in rmarkdown
29
- # @param filename [String] the name of the file to be found. If the file has no
30
- # extension then '.rb' is assumed
31
- # @param relative [String] containing either 'require_relative ' or 'require '. In the
32
- # first case looks on the current directory, on the latter, searches the $LOAD_PATH
33
- # @param pwd [String] Directory to look at when 'require_relative ', by default, its
34
- # the pwd directory
27
+ # Resolves the path of the file (same logic as inline_file) and returns it. Does not
28
+ # read the file. Use this when the content will be read by R (e.g. readLines) to avoid
29
+ # embedding file content in R code.
30
+ # @param filename [String] same as inline_file
31
+ # @param relative [String] same as inline_file
32
+ # @param pwd [String] same as inline_file
33
+ # @return [String] resolved absolute path
35
34
  #========================================================================================
36
-
37
- def self.inline_file(filename, relative, pwd = Dir.pwd)
35
+ def self.inline_file_path(filename, relative, pwd = Dir.pwd)
36
+ f = filename.dup
37
+ f << ".rb" if File.extname(f) == ""
38
+ file = "#{pwd}/#{f}"
38
39
 
39
- filename << ".rb" if File.extname(filename) == ""
40
- file = "#{pwd}/#{filename}"
41
-
42
- if (relative == false)
40
+ if (relative == false) && !R.file__exists(file).unboxed_get(0)
43
41
  $LOAD_PATH.each do |path|
44
42
  begin
45
43
  files = Dir.entries(path)
@@ -48,28 +46,35 @@ module GalaazUtil
48
46
  end
49
47
 
50
48
  if files != nil
51
- file = "#{path}/#{filename}"
52
- # break if File.exist?(file)
53
- break if (R.file__exists(file) >> 0)
49
+ file = "#{path}/#{f}"
50
+ break if (R.file__exists(file).unboxed_get(0))
54
51
  end
55
52
  end
56
53
  end
57
54
 
58
- # There is a bug(?) in > RC15 that when the bellow command
59
- # is called, there is a call to R Polyglot eval passing to_i
60
- # if File.exist?(file)
61
- if (R.file__exists(file) >> 0)
62
- code = ""
63
- File.open(file, "r") do |fileObj|
64
- while (line = fileObj.gets)
65
- code << line
66
- end
55
+ raise Errno::ENOENT, "file #{filename} not found in #{$LOAD_PATH}" unless R.file__exists(file).unboxed_get(0)
56
+ file
57
+ end
58
+
59
+ #========================================================================================
60
+ # Opens the given filename for reading and returns the file content so that it can be
61
+ # printed as a code chunk in rmarkdown
62
+ # @param filename [String] the name of the file to be found. If the file has no
63
+ # extension then '.rb' is assumed
64
+ # @param relative [String] containing either 'require_relative ' or 'require '. In the
65
+ # first case looks on the current directory, on the latter, searches the $LOAD_PATH
66
+ # @param pwd [String] Directory to look at when 'require_relative ', by default, its
67
+ # the pwd directory
68
+ #========================================================================================
69
+
70
+ def self.inline_file(filename, relative, pwd = Dir.pwd)
71
+ file = inline_file_path(filename, relative, pwd)
72
+ code = ""
73
+ File.open(file, "r") do |fileObj|
74
+ while (line = fileObj.gets)
75
+ code << line
67
76
  end
68
-
69
- else
70
- raise Errno::ENOENT, "file #{filename} not found in #{$LOAD_PATH}"
71
77
  end
72
-
73
78
  code
74
79
  end
75
80
 
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Benchmark-only spec for Phase 5.5 deep unboxing performance.
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/benchmark_phase5_5_unboxing_spec.rb --format documentation
6
+ #
7
+ # Optional env:
8
+ # BENCH_ITERS=5 # default: 5
9
+ # BENCH_TARGET_DEPTH=100 # default: 100 (nested list depth)
10
+
11
+
12
+ require_relative '../lib/R_interface/r'
13
+
14
+ RSpec.describe 'Phase 5.5 benchmark deep unboxing (R.bridge seam)' do
15
+ before(:all) do
16
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
17
+ end
18
+
19
+ def measure_seconds
20
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
21
+ yield
22
+ Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0
23
+ end
24
+
25
+ def stats(arr)
26
+ return { avg: 0.0, min: 0.0, max: 0.0 } if arr.empty?
27
+
28
+ {
29
+ avg: arr.sum / arr.size.to_f,
30
+ min: arr.min,
31
+ max: arr.max
32
+ }
33
+ end
34
+
35
+ it 'benchmarks unpack time for a nested list of depth 100' do
36
+ bridge = R.bridge
37
+ expect(bridge).to respond_to(:unbox_walk)
38
+ expect(bridge).to respond_to(:unbox_materialize)
39
+
40
+ iters = (ENV['BENCH_ITERS'] || '5').to_i
41
+ target_depth = (ENV['BENCH_TARGET_DEPTH'] || '100').to_i
42
+
43
+ deep = nil
44
+ build_s = measure_seconds do
45
+ deep = R.list(1)
46
+ target_depth.times { deep = R.list(deep) }
47
+ end
48
+
49
+ walk_times = []
50
+ materialize_times = []
51
+ unbox_times = []
52
+ walk_statuses = []
53
+ materialize_statuses = []
54
+ unbox_statuses = []
55
+
56
+ iters.times do
57
+ walk_times << measure_seconds do
58
+ result = bridge.unbox_walk(deep.r_interop,
59
+ max_depth: R::Support::MAX_UNBOX_DEPTH,
60
+ max_nodes: 300_000)
61
+ walk_statuses << result[:status]
62
+ end
63
+
64
+ materialize_times << measure_seconds do
65
+ result = bridge.unbox_materialize(deep.r_interop,
66
+ max_depth: R::Support::MAX_UNBOX_DEPTH,
67
+ max_nodes: 300_000)
68
+ materialize_statuses << result[:status]
69
+ end
70
+
71
+ unbox_times << measure_seconds do
72
+ begin
73
+ deep >> nil
74
+ unbox_statuses << :ok
75
+ rescue StandardError => e
76
+ unbox_statuses << :"error:#{e.class}"
77
+ end
78
+ end
79
+ end
80
+
81
+ w = stats(walk_times)
82
+ m = stats(materialize_times)
83
+ u = stats(unbox_times)
84
+
85
+ puts "\n[BENCH] nested-depth benchmark"
86
+ puts "[BENCH] target_depth=#{target_depth} max_unbox_depth=#{R::Support::MAX_UNBOX_DEPTH} iters=#{iters}"
87
+ puts format('[BENCH] build_once %.3fs', build_s)
88
+ puts format('[BENCH] unbox_walk avg=%.3fs min=%.3fs max=%.3fs statuses=%s',
89
+ w[:avg], w[:min], w[:max], walk_statuses.inspect)
90
+ puts format('[BENCH] materialize avg=%.3fs min=%.3fs max=%.3fs statuses=%s',
91
+ m[:avg], m[:min], m[:max], materialize_statuses.inspect)
92
+ puts format('[BENCH] deep >> nil avg=%.3fs min=%.3fs max=%.3fs statuses=%s',
93
+ u[:avg], u[:min], u[:max], unbox_statuses.inspect)
94
+ end
95
+ end
96
+
@@ -0,0 +1,113 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Async Ruby→R completion (+eval_r_async+, +R.eval_r_async+, +R::Async+).
4
+ # Run: bin/run_all_rspec new_bridge_specs/eval_r_async_spec.rb
5
+
6
+ require 'thread'
7
+
8
+ require_relative '../lib/new_bridge'
9
+ require_relative '../lib/R_interface/r'
10
+
11
+ RSpec.describe 'NewBridge::SessionClient#eval_r_async' do
12
+ cpp = File.expand_path('../ext/new_bridge/galaaz_gatekeeper_phase1.cpp', __dir__)
13
+
14
+ before(:all) do
15
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
16
+ @client = NewBridge::SessionClient.new(source_path: cpp)
17
+ @client.start
18
+ end
19
+
20
+ after(:all) { @client&.stop }
21
+
22
+ it 'returns call_id immediately and completes with success payload' do
23
+ done = Queue.new
24
+ cid = @client.eval_r_async('42L', timeout: nil) do |result|
25
+ done.push(result)
26
+ end
27
+ expect(cid).to match(/\A[0-9a-f-]{36}\z/i)
28
+
29
+ r = done.pop
30
+ expect(r).to be_ok
31
+ expect(r.value['kind']).to eq('integer')
32
+ expect(r.value['value']).to eq(42)
33
+ end
34
+
35
+ it 'runs Ruby work before R completion when R sleeps' do
36
+ order = Queue.new
37
+ @client.eval_r_async('({ Sys.sleep(0.15); 1L })', timeout: nil) do |result|
38
+ order.push [:r_done, result.ok?]
39
+ end
40
+ order.push [:ruby_after_start]
41
+ sleep 0.05
42
+ order.push [:ruby_mid]
43
+
44
+ expect(order.pop).to eq([:ruby_after_start])
45
+ expect(order.pop).to eq([:ruby_mid])
46
+ expect(order.pop).to eq([:r_done, true])
47
+ end
48
+
49
+ it 'completes with failure on Ruby-side timeout' do
50
+ done = Queue.new
51
+ @client.eval_r_async('({ Sys.sleep(0.3); 1L })', timeout: 0.05) do |result|
52
+ done.push(result)
53
+ end
54
+ r = done.pop
55
+ expect(r).not_to be_ok
56
+ expect(r.error).to be_a(NewBridge::SessionClient::TimeoutError)
57
+ end
58
+
59
+ it 'completes with failure on R error' do
60
+ done = Queue.new
61
+ @client.eval_r_async('stop("galaaz_async_test_error")', timeout: nil) do |result|
62
+ done.push(result)
63
+ end
64
+ r = done.pop
65
+ expect(r).not_to be_ok
66
+ expect(r.error).to be_a(NewBridge::SessionClient::RProcessError)
67
+ expect(r.error.message).to match(/galaaz_async_test_error/)
68
+ end
69
+
70
+ it 'raises without a block' do
71
+ expect { @client.eval_r_async('1L') }.to raise_error(ArgumentError, /block/)
72
+ end
73
+ end
74
+
75
+ RSpec.describe 'R.eval_r_async and R::Async (integration)' do
76
+ before(:all) do
77
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
78
+ end
79
+
80
+ it 'formats scalar like sync eval_r' do
81
+ done = Queue.new
82
+ R.eval_r_async('({ Sys.sleep(0.05); 7L })', timeout: nil) do |result|
83
+ done.push(result)
84
+ end
85
+ r = done.pop
86
+ expect(r).to be_ok
87
+ expect(r.value).to eq('[1] 7')
88
+ end
89
+
90
+ it 'R::Async returns an R::Object for rnorm(1)' do
91
+ done = Queue.new
92
+ R::Async.rnorm(1) do |result|
93
+ done.push(result)
94
+ end
95
+ r = done.pop
96
+ expect(r).to be_ok
97
+ expect(r.value).to be_a(R::Object)
98
+ end
99
+
100
+ it 'R::Async accepts timeout: and fails when R is too slow' do
101
+ done = Queue.new
102
+ R::Async.Sys__sleep(0.3, timeout: 0.05) do |result|
103
+ done.push(result)
104
+ end
105
+ r = done.pop
106
+ expect(r).not_to be_ok
107
+ expect(r.error).to be_a(NewBridge::SessionClient::TimeoutError)
108
+ end
109
+
110
+ it 'raises when R::Async is called without a block' do
111
+ expect { R::Async.rnorm(1) }.to raise_error(ArgumentError, /block/)
112
+ end
113
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.1 concurrent semantics on the R.bridge seam.
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_1_concurrent_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.1 integration concurrent (R.bridge seam)' do
11
+ it 'serializes concurrent eval_r_with_result calls and returns correct results' do
12
+ bridge = R.bridge
13
+ n_threads = 5
14
+ rounds_per_thread = 10
15
+ results_mutex = Mutex.new
16
+ results = []
17
+ errors = []
18
+
19
+ threads = n_threads.times.map do |thread_id|
20
+ Thread.new do
21
+ rounds_per_thread.times do |round|
22
+ expected_value = (thread_id * 1000) + round
23
+ assignment = "g2_v_t#{thread_id}_r#{round} <- #{expected_value}L"
24
+ env = bridge.eval_r_with_result(assignment)
25
+ results_mutex.synchronize do
26
+ if env && env[:type] == :scalar_integer && env[:value] == expected_value
27
+ results << { thread_id: thread_id, round: round, value: env[:value] }
28
+ else
29
+ errors << { thread_id: thread_id, round: round, env: env, expected: expected_value }
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
35
+
36
+ threads.each(&:join)
37
+
38
+ expect(errors).to eq([])
39
+ expect(results.size).to eq(n_threads * rounds_per_thread)
40
+
41
+ seen = {}
42
+ results.each do |r|
43
+ key = [r[:thread_id], r[:round]]
44
+ expect(seen[key]).to be_nil
45
+ seen[key] = true
46
+ expect(r[:value]).to eq((r[:thread_id] * 1000) + r[:round])
47
+ end
48
+ end
49
+ end
50
+
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.1 seam check for eval/handle roundtrip semantics (no callbacks).
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_1_eval_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.1 integration eval semantics (no callbacks)' do
11
+ it 'evaluates scalar expression through R::Support.eval' do
12
+ value = R::Support.eval('1L + 2L')
13
+ expect(value).to eq(3)
14
+ end
15
+ end
16
+
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.1 seam check for basic R module call path (no callbacks).
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_1_r_api_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.1 integration basic R API (no callbacks)' do
11
+ it 'supports simple R function dispatch through R::Support' do
12
+ result = R.sum(R.c(1, 2, 3))
13
+ expect(result).to be_a(R::Object)
14
+ expect(result.to_ruby).to eq(6)
15
+ end
16
+
17
+ it 'supports handle-producing calls and follow-up scalar access' do
18
+ vec = R.c(10, 20, 30)
19
+ expect(vec).to be_a(R::Object)
20
+
21
+ size = R.length(vec)
22
+ expect(size.to_ruby).to eq(3)
23
+ end
24
+ end
25
+
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.1 smoke: verify R.bridge seam can route to NewBridge adapter.
4
+ # Run: bundle exec rspec specs/new_bridge/integration_phase5_1_smoke_spec.rb
5
+
6
+
7
+ require_relative '../lib/R_interface/r'
8
+
9
+ RSpec.describe 'Phase 5.1 integration smoke (R.bridge seam)' do
10
+ before(:all) do
11
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
12
+ end
13
+
14
+ it 'routes R.bridge to NewBridgeAdapter by default' do
15
+ expect(R.bridge).to be_a(R::NewBridgeAdapter)
16
+ expect(R.bridge.ready?).to eq(true)
17
+ end
18
+
19
+ it 'supports basic eval_r through seam' do
20
+ out = R.bridge.eval_r('1L + 1L')
21
+ expect(out).to include('2')
22
+ end
23
+
24
+ it 'supports basic eval_r_with_result through seam' do
25
+ env = R.bridge.eval_r_with_result('g2_v_p51 <- 123L')
26
+ expect(env).not_to be_nil
27
+ expect(env[:type]).to eq(:scalar_integer)
28
+ expect(env[:value]).to eq(123)
29
+ end
30
+ end
31
+
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.2 data.frame unboxing compatibility.
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_2_dataframe_unboxing_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.2 integration data.frame unboxing' do
11
+ it 'unboxes a tiny data.frame handle returned by R::Support into a Ruby hash' do
12
+ df = R.data__frame(x: R.c(1, 2), y: R.c('a', 'b'))
13
+ ruby = df.to_ruby
14
+ expect(ruby).to be_a(Hash)
15
+ expect(ruby['x']).to eq([1, 2])
16
+ expect(ruby['y']).to eq(['a', 'b'])
17
+ end
18
+ end
19
+
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.2 decoding/unboxing compatibility for eval handles.
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_2_handle_eval_unboxing_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.2 integration handle eval unboxing' do
11
+ it 'unboxes a vector handle returned by R::Support.eval' do
12
+ vec = R.c(7, 8, 9)
13
+ out = R::Support.eval(vec)
14
+ expect(out).to be_a(R::Object)
15
+ expect(out.to_ruby).to eq([7, 8, 9])
16
+ end
17
+
18
+ it 'unboxes a character vector handle returned by R::Support.eval' do
19
+ vec = R.c('a', 'b')
20
+ out = R::Support.eval(vec)
21
+ expect(out).to be_a(R::Object)
22
+ expect(out.to_ruby).to eq(['a', 'b'])
23
+ end
24
+ end
25
+
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Phase 5.3 callback argument compatibility on the R.bridge seam.
4
+ # Run:
5
+ # bin/run_rspec specs/new_bridge/integration_phase5_3_callback_args_spec.rb
6
+
7
+
8
+ require_relative '../lib/R_interface/r'
9
+
10
+ RSpec.describe 'Phase 5.3 integration callback args (R.bridge seam)' do
11
+ before(:all) do
12
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
13
+ R.bridge.eval_r('call_with_arg <- function(f, x) { f(x) }')
14
+ end
15
+
16
+ it 'passes a numeric scalar argument from R into Ruby callback' do
17
+ result = R.call_with_arg(proc { |x| x.to_i + 1 }, 41)
18
+ expect(result).to be_a(R::Object)
19
+ expect(result.to_ruby).to eq(42.0)
20
+ end
21
+
22
+ it 'passes a character scalar argument from R into Ruby callback' do
23
+ result = R.call_with_arg(proc { |x| x.to_ruby.to_s.upcase == 'ABC' ? 1 : 0 }, 'abc')
24
+ expect(result).to be_a(R::Object)
25
+ expect(result.to_ruby).to eq(1.0)
26
+ end
27
+ end
28
+