galaaz 0.4.10 → 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 (391) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/LICENSE +0 -0
  4. data/README.md +3123 -882
  5. data/Rakefile +62 -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 +223 -6
  11. data/bin/gknit-draft +105 -0
  12. data/bin/gknit-draft.rb +28 -0
  13. data/bin/gknit_Rscript +127 -0
  14. data/bin/grun +27 -1
  15. data/bin/gstudio +49 -4
  16. data/bin/{gstudio.rb → gstudio_irb.rb} +0 -0
  17. data/bin/gstudio_pry.rb +7 -0
  18. data/bin/install-tinytex +6 -0
  19. data/bin/run_all_rspec +43 -0
  20. data/bin/run_example +14 -0
  21. data/bin/run_old_rspec +19 -0
  22. data/bin/run_rspec +23 -0
  23. data/bin/run_rspec_subset +38 -0
  24. data/bin/run_slow_rspec +19 -0
  25. data/blogs/R-on-Rails-Planning-Document.md +940 -0
  26. data/blogs/README.md +100 -0
  27. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -66
  28. data/blogs/galaaz_ggplot/galaaz_ggplot.log +754 -0
  29. data/blogs/galaaz_ggplot/galaaz_ggplot.md +364 -0
  30. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +607 -0
  31. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  32. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  33. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  34. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  35. data/blogs/galaaz_ggplot/midwest.Rmd +3 -3
  36. data/blogs/galaaz_ggplot/midwest_external_png +0 -0
  37. data/blogs/gknit/gknit.Rmd +52 -55
  38. data/blogs/gknit/gknit.md +94 -94
  39. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  40. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  41. data/blogs/gknit/lst.rds +0 -0
  42. data/blogs/gknit/model.rb +1 -1
  43. data/blogs/gknit/stats.bib +0 -0
  44. data/blogs/manual/include_model_local_repro.Rmd +14 -0
  45. data/blogs/manual/include_model_local_repro.md +75 -0
  46. data/blogs/manual/lst.rds +0 -0
  47. data/blogs/manual/manual.Rmd +1582 -196
  48. data/blogs/manual/manual.log +1786 -0
  49. data/blogs/manual/manual.md +3107 -890
  50. data/blogs/manual/manual.tex +3018 -1086
  51. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  52. data/blogs/manual/manual_files/figure-html/diverging_bar.png +0 -0
  53. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  54. data/blogs/manual/model.rb +41 -0
  55. data/blogs/nse_dplyr/nse_dplyr.Rmd +277 -151
  56. data/blogs/nse_dplyr/nse_dplyr.log +928 -0
  57. data/blogs/nse_dplyr/nse_dplyr.md +457 -293
  58. data/blogs/oh_my/not_so.rb +0 -0
  59. data/blogs/oh_my/oh_my.Rmd +1234 -25
  60. data/blogs/oh_my/oh_my.log +804 -0
  61. data/blogs/oh_my/oh_my.md +1808 -228
  62. data/blogs/oh_my/oh_my.tex +821 -0
  63. data/blogs/oh_my/old.Rmd +15 -14
  64. data/blogs/ruby_plot/ruby_plot.Rmd +58 -82
  65. data/blogs/ruby_plot/ruby_plot.log +885 -0
  66. data/blogs/ruby_plot/ruby_plot.md +71 -103
  67. data/blogs/ruby_plot/ruby_plot.tex +940 -0
  68. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  72. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  73. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  74. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  75. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  77. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  78. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  79. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  80. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  81. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  82. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  83. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  84. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  85. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  86. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  87. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  88. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  89. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  90. data/blogs/test/test.Rmd +14 -0
  91. data/examples/50Plots_MasterList/Images/midwest-scatterplot.PNG +0 -0
  92. data/examples/50Plots_MasterList/ScatterPlot.rb +0 -0
  93. data/examples/50Plots_MasterList/scatter_plot.rb +0 -0
  94. data/examples/Bibliography/master.bib +50 -0
  95. data/examples/Bibliography/stats.bib +72 -0
  96. data/examples/R/calc.R +0 -0
  97. data/examples/R/java_interop.R +0 -0
  98. data/examples/bioconductor_deseq2_airway/Documentation/DESeq2-airway-walkthrough.md +56 -0
  99. data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +53 -0
  100. data/examples/bioconductor_deseq2_airway/bench_r_three_same_process.R +34 -0
  101. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +33 -0
  102. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +34 -0
  103. data/examples/bioconductor_deseq2_airway/deseq2_airway_minimal.R +30 -0
  104. data/examples/bioconductor_deseq2_airway/deseq2_airway_pipeline_for_bench.R +36 -0
  105. data/examples/islr/all.rb +13 -0
  106. data/examples/islr/ch2.spec.rb +37 -7
  107. data/examples/islr/ch3.spec.rb +11 -2
  108. data/examples/islr/ch3_boston.rb +27 -0
  109. data/examples/islr/ch3_multiple_regression.rb +0 -0
  110. data/examples/islr/ch6.spec.rb +24 -1
  111. data/examples/islr/x_y_rnorm.jpg +0 -0
  112. data/examples/latex_templates/Test-acm_article/Makefile +16 -0
  113. data/examples/latex_templates/Test-acm_article/Test-acm_article.Rmd +65 -0
  114. data/examples/latex_templates/Test-acm_article/acm_proc_article-sp.cls +1670 -0
  115. data/examples/latex_templates/Test-acm_article/sensys-abstract.cls +703 -0
  116. data/examples/latex_templates/Test-acm_article/sigproc.bib +59 -0
  117. data/examples/latex_templates/Test-acs_article/Test-acs_article.Rmd +260 -0
  118. data/examples/latex_templates/Test-acs_article/acs-Test-acs_article.bib +11 -0
  119. data/examples/latex_templates/Test-acs_article/acs-my_output.bib +11 -0
  120. data/examples/latex_templates/Test-acs_article/acstest.bib +17 -0
  121. data/examples/latex_templates/Test-aea_article/AEA.cls +1414 -0
  122. data/{blogs/gknit/marshal.dump → examples/latex_templates/Test-aea_article/BibFile.bib} +0 -0
  123. data/examples/latex_templates/Test-aea_article/Test-aea_article.Rmd +108 -0
  124. data/examples/latex_templates/Test-aea_article/aea.bst +1269 -0
  125. data/examples/latex_templates/Test-aea_article/multicol.sty +853 -0
  126. data/examples/latex_templates/Test-aea_article/references.bib +0 -0
  127. data/examples/latex_templates/Test-aea_article/setspace.sty +546 -0
  128. data/examples/latex_templates/Test-amq_article/Test-amq_article.Rmd +256 -0
  129. data/examples/latex_templates/Test-amq_article/Test-amq_article.pdfsync +3397 -0
  130. data/examples/latex_templates/Test-ams_article/Test-ams_article.Rmd +215 -0
  131. data/examples/latex_templates/Test-ams_article/amstest.bib +436 -0
  132. data/examples/latex_templates/Test-asa_article/Test-asa_article.Rmd +153 -0
  133. data/examples/latex_templates/Test-asa_article/agsm.bst +1353 -0
  134. data/examples/latex_templates/Test-asa_article/bibliography.bib +233 -0
  135. data/examples/latex_templates/Test-ieee_article/IEEEtran.bst +2409 -0
  136. data/examples/latex_templates/Test-ieee_article/IEEEtran.cls +6346 -0
  137. data/examples/latex_templates/Test-ieee_article/Test-ieee_article.Rmd +175 -0
  138. data/examples/latex_templates/Test-ieee_article/mybibfile.bib +20 -0
  139. data/examples/latex_templates/Test-rjournal_article/RJournal.sty +335 -0
  140. data/examples/latex_templates/Test-rjournal_article/RJreferences.bib +18 -0
  141. data/examples/latex_templates/Test-rjournal_article/Test-rjournal_article.Rmd +52 -0
  142. data/examples/latex_templates/Test-springer_article/Test-springer_article.Rmd +65 -0
  143. data/examples/latex_templates/Test-springer_article/bibliography.bib +26 -0
  144. data/examples/latex_templates/Test-springer_article/spbasic.bst +1658 -0
  145. data/examples/latex_templates/Test-springer_article/spmpsci.bst +1512 -0
  146. data/examples/latex_templates/Test-springer_article/spphys.bst +1443 -0
  147. data/examples/latex_templates/Test-springer_article/svglov3.clo +113 -0
  148. data/examples/latex_templates/Test-springer_article/svjour3.cls +1431 -0
  149. data/examples/misc/baseball.csv +0 -0
  150. data/examples/misc/ggplot.rb +3 -2
  151. data/examples/misc/moneyball.rb +0 -0
  152. data/examples/misc/subsetting.rb +0 -0
  153. data/examples/multithread_shards_to_r/shards_to_r.rb +67 -0
  154. data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.Rmd +73 -0
  155. data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.Rmd +382 -0
  156. data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.Rmd +164 -0
  157. data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.Rmd +92 -0
  158. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/attend-grade-relationships.csv +482 -0
  159. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.Rmd +280 -0
  160. data/examples/rmarkdown/svm-xaringan-example/svm-xaringan-example.Rmd +386 -0
  161. data/examples/sthda_ggplot/README.md +0 -0
  162. data/examples/sthda_ggplot/RUN.md +41 -0
  163. data/examples/sthda_ggplot/all.rb +0 -0
  164. data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +0 -0
  165. data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +0 -0
  166. data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +2 -0
  167. data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +0 -0
  168. data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +0 -0
  169. data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +0 -0
  170. data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +0 -0
  171. data/examples/sthda_ggplot/one_variable_continuous/stat.rb +0 -0
  172. data/examples/sthda_ggplot/one_variable_discrete/bar.rb +0 -0
  173. data/examples/sthda_ggplot/qplots/box_violin_dot.rb +0 -0
  174. data/examples/sthda_ggplot/qplots/scatter_plots.rb +0 -0
  175. data/examples/sthda_ggplot/scatter_gg.rb +0 -0
  176. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +0 -0
  177. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +0 -0
  178. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +0 -0
  179. data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +0 -0
  180. data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +0 -0
  181. data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +0 -0
  182. data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +4 -3
  183. data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +0 -0
  184. data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +0 -0
  185. data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +0 -0
  186. data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +0 -0
  187. data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +0 -0
  188. data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +0 -0
  189. data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +0 -0
  190. data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +0 -0
  191. data/ext/new_bridge/Makefile +46 -0
  192. data/ext/new_bridge/galaaz_gatekeeper_phase0.cpp +12 -0
  193. data/ext/new_bridge/galaaz_gatekeeper_phase1.cpp +1639 -0
  194. data/lib/R_interface/galaaz_device.R +20 -0
  195. data/lib/R_interface/include_engine.R +109 -0
  196. data/lib/R_interface/new_bridge_adapter.rb +824 -0
  197. data/lib/R_interface/r.rb +177 -25
  198. data/lib/R_interface/r_arrow.rb +113 -0
  199. data/lib/R_interface/r_libs.R +4 -4
  200. data/lib/R_interface/r_methods.rb +13 -116
  201. data/lib/R_interface/r_module_s.rb +0 -0
  202. data/lib/R_interface/rbinary_operators.rb +20 -2
  203. data/lib/R_interface/rclosure.rb +5 -1
  204. data/lib/R_interface/rdata_frame.rb +34 -70
  205. data/lib/R_interface/rdevice.rb +125 -0
  206. data/lib/R_interface/rdevices.R +0 -0
  207. data/lib/R_interface/renvironment.rb +10 -4
  208. data/lib/R_interface/rexpression.rb +5 -1
  209. data/lib/R_interface/rindexed_object.rb +41 -13
  210. data/lib/R_interface/rlanguage.rb +20 -62
  211. data/lib/R_interface/rlist.rb +115 -25
  212. data/lib/R_interface/rlogical_operators.rb +0 -0
  213. data/lib/R_interface/rmatrix.rb +2 -11
  214. data/lib/R_interface/rmd_indexed_object.rb +5 -1
  215. data/lib/R_interface/robject.rb +348 -290
  216. data/lib/R_interface/rpkg.rb +1 -0
  217. data/lib/R_interface/rsupport.rb +610 -331
  218. data/lib/R_interface/rsupport_scope.rb +2 -1
  219. data/lib/R_interface/rsymbol.rb +50 -0
  220. data/lib/R_interface/ruby_callback.rb +2 -3
  221. data/lib/R_interface/ruby_extensions.rb +225 -175
  222. data/lib/R_interface/runary_operators.rb +0 -0
  223. data/lib/R_interface/rvector.rb +147 -31
  224. data/lib/galaaz.rb +0 -0
  225. data/lib/galaaz_jruby.rb +22 -0
  226. data/lib/gknit/diagnostics.rb +50 -0
  227. data/lib/gknit/draft.rb +111 -0
  228. data/lib/gknit/include_engine.rb +15 -7
  229. data/lib/gknit/knitr_engine.rb +223 -107
  230. data/lib/gknit/rb_engine.rb +3 -3
  231. data/lib/gknit/ruby_engine.rb +0 -0
  232. data/lib/gknit.rb +3 -0
  233. data/lib/new_bridge/bootstrap/windows_bootstrap.rb +285 -0
  234. data/lib/new_bridge/envelope.rb +51 -0
  235. data/lib/new_bridge/eval_result.rb +26 -0
  236. data/lib/new_bridge/framing.rb +39 -0
  237. data/lib/new_bridge/instance_pool_client.rb +38 -0
  238. data/lib/new_bridge/r_instance_manager.rb +404 -0
  239. data/lib/new_bridge/session_client.rb +530 -0
  240. data/lib/new_bridge/tcp_framed.rb +44 -0
  241. data/lib/new_bridge.rb +9 -0
  242. data/lib/util/exec_ruby.rb +95 -46
  243. data/lib/util/inline_file.rb +35 -30
  244. data/new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb +96 -0
  245. data/new_bridge_specs/eval_r_async_spec.rb +113 -0
  246. data/new_bridge_specs/integration_phase5_1_concurrent_spec.rb +50 -0
  247. data/new_bridge_specs/integration_phase5_1_eval_spec.rb +16 -0
  248. data/new_bridge_specs/integration_phase5_1_r_api_spec.rb +25 -0
  249. data/new_bridge_specs/integration_phase5_1_smoke_spec.rb +31 -0
  250. data/new_bridge_specs/integration_phase5_2_dataframe_unboxing_spec.rb +19 -0
  251. data/new_bridge_specs/integration_phase5_2_handle_eval_unboxing_spec.rb +25 -0
  252. data/new_bridge_specs/integration_phase5_3_callback_args_spec.rb +28 -0
  253. data/new_bridge_specs/integration_phase5_3_callback_error_spec.rb +22 -0
  254. data/new_bridge_specs/integration_phase5_3_callback_timeout_spec.rb +28 -0
  255. data/new_bridge_specs/integration_phase5_3_callbacks_smoke_spec.rb +22 -0
  256. data/new_bridge_specs/integration_phase5_3_edge_cases_spec.rb +52 -0
  257. data/new_bridge_specs/integration_phase5_3_nested_spec.rb +30 -0
  258. data/new_bridge_specs/integration_phase5_4_concurrent_sessions_spec.rb +53 -0
  259. data/new_bridge_specs/integration_phase5_4_nested_session_callbacks_spec.rb +49 -0
  260. data/new_bridge_specs/integration_phase5_4_session_routing_spec.rb +38 -0
  261. data/new_bridge_specs/integration_phase5_5_stress_concurrency_spec.rb +52 -0
  262. data/new_bridge_specs/integration_phase5_5_unbox_walk_spec.rb +46 -0
  263. data/new_bridge_specs/phase0_protocol_spec.rb +96 -0
  264. data/new_bridge_specs/phase1_req_ret_spec.rb +66 -0
  265. data/new_bridge_specs/phase2_multi_instance_spec.rb +67 -0
  266. data/new_bridge_specs/phase3_callbacks_spec.rb +71 -0
  267. data/new_bridge_specs/phase4_2_hardening_spec.rb +252 -0
  268. data/new_bridge_specs/phase4_3_r_instance_manager_spec.rb +85 -0
  269. data/new_bridge_specs/phase4_nested_callbacks_spec.rb +123 -0
  270. data/r_requires/ggplot.rb +0 -0
  271. data/r_requires/knitr.rb +0 -0
  272. data/specs/all.rb +15 -11
  273. data/specs/arrow_from_ruby_batches_spec.rb +50 -0
  274. data/specs/arrow_semantics_spec.rb +64 -0
  275. data/specs/bridge_concurrent_spec.rb +46 -0
  276. data/specs/bridge_nested_spec.rb +25 -0
  277. data/specs/dataframe_semantics_spec.rb +122 -0
  278. data/specs/dataframe_single_index_logical_filter_spec.rb +21 -0
  279. data/specs/dispatch_probe_cache_spec.rb +38 -0
  280. data/specs/dispatch_probe_error_class_fallback_spec.rb +20 -0
  281. data/specs/dispatch_probe_fallback_spec.rb +18 -0
  282. data/specs/environment_semantics_spec.rb +89 -0
  283. data/specs/field_access_spec.rb +31 -0
  284. data/specs/figures/bg.jpeg +0 -0
  285. data/specs/figures/bg.png +0 -0
  286. data/specs/figures/bg.svg +168 -57
  287. data/specs/figures/dose_len.png +0 -0
  288. data/specs/figures/no_args.jpeg +0 -0
  289. data/specs/figures/no_args.png +0 -0
  290. data/specs/figures/no_args.svg +168 -57
  291. data/specs/figures/width_height.jpeg +0 -0
  292. data/specs/figures/width_height.png +0 -0
  293. data/specs/figures/width_height_units1.jpeg +0 -0
  294. data/specs/figures/width_height_units1.png +0 -0
  295. data/specs/figures/width_height_units2.jpeg +0 -0
  296. data/specs/figures/width_height_units2.png +0 -0
  297. data/specs/formula_semantics_spec.rb +81 -0
  298. data/specs/galaaz_util_exec_ruby_spec.rb +85 -0
  299. data/specs/galaaz_util_inline_file_spec.rb +54 -0
  300. data/specs/gknit_cli_option_permutation_spec.rb +24 -0
  301. data/specs/gknit_include_engine_spec.rb +72 -0
  302. data/specs/gknit_install_timeout_report_spec.rb +69 -0
  303. data/specs/gknit_internal_error_report_spec.rb +57 -0
  304. data/specs/gknit_vector_map_output_spec.rb +59 -0
  305. data/specs/globalenv_guardrail_spec.rb +52 -0
  306. data/specs/language_expression_semantics_spec.rb +145 -0
  307. data/specs/list_semantics_spec.rb +111 -0
  308. data/specs/new_bridge_bulk_dataframe_transfer_spec.rb +44 -0
  309. data/specs/new_bridge_bulk_vector_transfer_spec.rb +73 -0
  310. data/specs/new_bridge_callback_timeout_spec.rb +69 -0
  311. data/specs/new_bridge_eval_r_fallback_spec.rb +55 -0
  312. data/specs/nil_null_spec.rb +42 -0
  313. data/specs/object_build_phase2_spec.rb +53 -0
  314. data/specs/phase1_callback_bridge_spec.rb +84 -0
  315. data/specs/phase2_gknit_generic_rendering_guardrail_spec.rb +46 -0
  316. data/specs/phase2_gknit_no_raw_code_leakage_spec.rb +43 -0
  317. data/specs/phase3_gknit_generic_graphics_capture_spec.rb +71 -0
  318. data/specs/plot_device_semantics_spec.rb +28 -0
  319. data/specs/plot_snapshot_semantics_spec.rb +58 -0
  320. data/specs/protocol_result_spec.rb +236 -0
  321. data/specs/r_batch_fail_fast_spec.rb +47 -0
  322. data/specs/r_bridge_bootstrap_spec.rb +11 -0
  323. data/specs/r_devices.spec.rb +1 -1
  324. data/specs/r_eval.spec.rb +16 -18
  325. data/specs/r_function.spec.rb +1 -1
  326. data/specs/r_instance_manager_spec.rb +285 -0
  327. data/specs/r_list_apply.spec.rb +15 -15
  328. data/specs/r_matrix.spec.rb +0 -0
  329. data/specs/r_nse.spec.rb +5 -5
  330. data/specs/r_object_send_dispatch_spec.rb +13 -0
  331. data/specs/r_vector_comparator_spec.rb +8 -0
  332. data/specs/r_vector_creation.spec.rb +0 -0
  333. data/specs/r_vector_functions.spec.rb +0 -0
  334. data/specs/r_vector_object.spec.rb +0 -0
  335. data/specs/r_vector_operators.spec.rb +0 -0
  336. data/specs/r_vector_structured_scalar_reads_spec.rb +35 -0
  337. data/specs/r_vector_subsetting.spec.rb +0 -0
  338. data/specs/range_helper_spec.rb +21 -0
  339. data/specs/rsupport_scope_spec.rb +28 -0
  340. data/specs/rsupport_var_name_thread_safety_spec.rb +24 -0
  341. data/specs/scalar_character_spec.rb +44 -0
  342. data/specs/scoped_symbol_dsl_refinement_spec.rb +40 -0
  343. data/specs/session_env_bridge_spec.rb +25 -0
  344. data/specs/simplecov_bootstrap_spec.rb +10 -0
  345. data/specs/spec_helper.rb +10 -0
  346. data/specs/tmp.rb +41 -20
  347. data/specs/unboxing_recursion_regression_spec.rb +30 -0
  348. data/specs/unboxing_spec.rb +49 -0
  349. data/specs/verify_callbacks.rb +42 -0
  350. data/sty/galaaz.sty +0 -0
  351. data/version.rb +1 -1
  352. metadata +239 -71
  353. data/blogs/galaaz_ggplot/galaaz_ggplot.aux +0 -41
  354. data/blogs/galaaz_ggplot/galaaz_ggplot.html +0 -705
  355. data/blogs/galaaz_ggplot/galaaz_ggplot.out +0 -10
  356. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  357. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/midwest_rb.pdf +0 -0
  358. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-latex/scatter_plot_rb.pdf +0 -0
  359. data/blogs/galaaz_ggplot/midwest.html +0 -188
  360. data/blogs/gknit/gknit.html +0 -2266
  361. data/blogs/gknit/gknit.pdf +0 -0
  362. data/blogs/gknit/gknit.tex +0 -1358
  363. data/blogs/manual/graph.rb +0 -29
  364. data/blogs/manual/manual.html +0 -2995
  365. data/blogs/manual/manual.pdf +0 -0
  366. data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
  367. data/blogs/nse_dplyr/nse_dplyr.html +0 -960
  368. data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
  369. data/blogs/nse_dplyr/nse_dplyr.tex +0 -1373
  370. data/blogs/oh_my/oh_my.html +0 -680
  371. data/blogs/ruby_plot/ruby_plot.Rmd_external_figs +0 -662
  372. data/blogs/ruby_plot/ruby_plot.html +0 -729
  373. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  374. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.svg +0 -57
  375. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.svg +0 -106
  376. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.svg +0 -110
  377. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.svg +0 -174
  378. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.svg +0 -236
  379. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.svg +0 -296
  380. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.svg +0 -236
  381. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.svg +0 -218
  382. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.svg +0 -128
  383. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.svg +0 -150
  384. data/examples/paper/paper.rb +0 -36
  385. data/specs/r_dataframe.spec.rb +0 -379
  386. data/specs/r_environment.spec.rb +0 -140
  387. data/specs/r_formula.spec.rb +0 -232
  388. data/specs/r_language.spec.rb +0 -112
  389. data/specs/r_list.spec.rb +0 -293
  390. data/specs/r_plots.spec.rb +0 -72
  391. data/specs/ruby_expression.spec.rb +0 -315
@@ -1,351 +1,409 @@
1
- # -*- coding: utf-8 -*-
2
-
3
- ##########################################################################################
4
- # @author Rodrigo Botafogo
1
+ # robject.rb
5
2
  #
6
- # Copyright © 2018 Rodrigo Botafogo. All Rights Reserved. Permission to use, copy, modify,
7
- # and distribute this software and its documentation, without fee and without a signed
8
- # licensing agreement, is hereby granted, provided that the above copyright notice, this
9
- # paragraph and the following two paragraphs appear in all copies, modifications, and
10
- # distributions.
3
+ # R::Object is the Ruby proxy for an R value. It inherits from BasicObject so that most
4
+ # method calls (e.g. .dim, .names, .length) are forwarded to R via method_missing.
11
5
  #
12
- # IN NO EVENT SHALL RODRIGO BOTAFOGO BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
13
- # INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING OUT OF THE USE OF
14
- # THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF RODRIGO BOTAFOGO HAS BEEN ADVISED OF THE
15
- # POSSIBILITY OF SUCH DAMAGE.
6
+ # Each instance holds @r_interop (the R-side handle, e.g. "g2_v42") and optionally
7
+ # @expression (source expression for Language objects). Object.build(...) turns a handle
8
+ # into the appropriate subclass: DataFrame, Matrix, Vector, List, Closure, RSymbol,
9
+ # RExpression, or a plain Object for other R types. Handles "rb_obj_*" are unwrapped
10
+ # to the stored Ruby object; R NULL becomes Ruby nil.
16
11
  #
17
- # RODRIGO BOTAFOGO SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
18
- # THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE
19
- # SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS".
20
- # RODRIGO BOTAFOGO HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
21
- # OR MODIFICATIONS.
22
- ##########################################################################################
23
-
24
12
  require_relative 'r_methods'
25
13
 
26
14
  module R
27
-
28
- #--------------------------------------------------------------------------------------
29
- #
30
- #--------------------------------------------------------------------------------------
15
+ class Object < BasicObject
16
+ include IndexedObject
17
+ include BinaryOperators
18
+ include ExecBinOp
19
+ include UnaryOperators
20
+ include ExecUniOp
21
+
22
+ # Methods we explicitly define (Phase A / BasicObject). respond_to?(sym) is true for these and for any symbol we forward to R.
23
+ EXPLICIT_RUBY_SURFACE = [
24
+ :r_interop, :expression, :expression=,
25
+ :[], :[]=, :>>, :unboxed_get, :to_ruby, :to_i, :to_ary, :length, :size,
26
+ :class, :to_s, :rclass, :typeof, :inspect, :object_id, :__id__,
27
+ :==, :equal?, :call, :nil?, :pretty_print, :send,
28
+ :instance_variable_set, :instance_variable_get,
29
+ :is_a?, :kind_of?, :instance_of?, :respond_to?,
30
+ :method_missing
31
+ ].freeze
31
32
 
32
- class Object
33
-
34
33
  attr_reader :r_interop
35
- attr_accessor :statement
36
-
37
- #--------------------------------------------------------------------------------------
38
- #
39
- #--------------------------------------------------------------------------------------
34
+ attr_accessor :expression
40
35
 
41
- def initialize(r_interop)
42
- @r_interop = r_interop
36
+ # Delegate to Kernel#instance_variable_set so that instance vars work despite BasicObject.
37
+ def instance_variable_set(name, value)
38
+ ::Object.instance_method(:instance_variable_set).bind(self).call(name, value)
43
39
  end
44
40
 
45
- #--------------------------------------------------------------------------------------
46
- # Checks for equality between two R::Objects. This method is used by rspec's
47
- # expectation. It returns a Ruby true or false and not an R::Vector with [TRUE] or
48
- # [FALSE]
49
- #--------------------------------------------------------------------------------------
50
-
51
- def ==(other_object)
52
- res =
53
- R::Support.exec_function_name('identical', @r_interop,
54
- R::Support.parse_arg(other_object))
55
- return nil if (res.length >> 0) == 0
56
- res >> 0
41
+ # Delegate to Kernel#instance_variable_get so that instance vars work despite BasicObject.
42
+ def instance_variable_get(name)
43
+ ::Object.instance_method(:instance_variable_get).bind(self).call(name)
57
44
  end
58
45
 
59
- #--------------------------------------------------------------------------------------
60
- # Use eql to check for equality between two objects and receive in return an R::Vector
61
- #--------------------------------------------------------------------------------------
62
-
63
- def eql(other_object)
64
- # exec_bin_oper("`==`", other_object)
65
- R::Support.exec_function_name("`==`", @r_interop,
66
- R::Support.parse_arg(other_object))
46
+ # BasicObject lacks Kernel#send; provide Ruby dispatch explicitly so calls like
47
+ # obj.send(:mpg) do not get forwarded to R as send(obj, mpg).
48
+ def send(method_name, *args, &block)
49
+ ::Object.instance_method(:send).bind(self).call(method_name, *args, &block)
67
50
  end
68
-
69
- #--------------------------------------------------------------------------------------
70
- # @param r_interop [Interop] pointer to an R object
71
- # @return the R object wrapped in a Ruby class
72
- #--------------------------------------------------------------------------------------
73
-
74
- def self.build(r_interop)
75
-
76
- # if the value is actually not an r_interop, then just return it: native Ruby
77
- # object
78
- if (!Truffle::Interop.foreign?(r_interop))
79
- # puts "I'm native"
80
- return r_interop
81
- # a matrix is also a vector... test should come before
82
- elsif (R::Support.eval("is.matrix").call(r_interop) == true)
83
- # puts "1"
84
- R::Matrix.new(r_interop)
85
- elsif (R::Support.eval("is.atomic").call(r_interop) == true)
86
- # puts "2"
87
- Vector.new(r_interop)
88
- elsif (R::Support.eval("is.function").call(r_interop) == true)
89
- # puts "3"
90
- Closure.new(r_interop)
91
- elsif (R::Support.eval("is.data.frame").call(r_interop) == true)
92
- # puts "4"
93
- DataFrame.new(r_interop)
94
- elsif (R::Support.eval("is.list").call(r_interop) == true)
95
- # puts "5"
96
- List.new(r_interop)
97
- elsif (R::Support.eval("typeof").call(r_interop) == "language")
98
- # @TODO: tests are passing both when we use Language.new
99
- # and RExpression.new. Check what should be and write
100
- # discriminating tests.
101
- # print "robject buid: language\n"
102
- # R::Support.print_foreign(r_interop)
103
- # puts "6"
104
- Language.new(r_interop)
105
- # RExpression.new(r_interop)
106
- elsif (R::Support.eval("typeof").call(r_interop) == "expression")
107
- # puts "7"
108
- RExpression.new(r_interop)
109
- elsif (R::Support.eval("typeof").call(r_interop) == "name")
110
- # puts "8"
111
- p "i'm of type name"
112
- Name.new(r_interop)
113
- elsif (R::Support.eval("typeof").call(r_interop) == "symbol")
114
- # puts "9"
115
- RSymbol.new(r_interop)
116
- elsif (R::Support.eval("typeof").call(r_interop) == "environment")
117
- # puts "10"
118
- Environment.new(r_interop)
119
- else # Generic type
120
- # puts "11"
121
- p "Generic type: #{R::Support.eval("typeof").call(r_interop).to_s}"
122
- r_interop
123
- end
124
51
 
52
+ # R objects are never nil; R NULL is converted to Ruby nil in Object.build.
53
+ def nil?
54
+ false
125
55
  end
126
56
 
127
- #--------------------------------------------------------------------------------------
128
- #
129
- #--------------------------------------------------------------------------------------
130
-
131
- def method_missing(symbol, *args, &block)
132
- name = R::Support.convert_symbol2r(symbol)
133
-
134
- # Need to raise a NoMethodError when method_missing is called by an implicit
135
- # call to "to_ary". The explanation for that is:
136
- # Okay, I've found the source of the behaviour. IOOperations.puts will attempt to
137
- # coerce an argument to an array and print its contents, and R::Vector responds to
138
- # to_ary but returns the empty array which results in no output.
139
- #
140
- # Previously IOOperations.puts only checked the type of the argument, and did not
141
- # attempt coercion, but that meant we didn't match MRI's behaviour and had some test
142
- # failures in other gems. I'd suggest either removing the to_ary methods on
143
- # R::Object and R::Vector or implementing them more fully. I see from the comments on
144
- # those methods that you needed them for RSpec, it might worth seeing if those problems
145
- # still occur and we can look a better way to resolve those.
146
- raise NoMethodError if name == "to_ary"
147
-
148
- case
149
- when block_given?
150
- R::Support.new_scope(symbol, self, *args, &block)
151
- when name =~ /(.*)=$/
152
- method_missing_assign($1, args[0])
153
- when name == "eval"
154
- # R function 'eval' needs to be called in a special way, since it expects
155
- # the second argument to be an environment. If the arguments are packed
156
- # into a list, then there is no second argument and the function fails to
157
- # use the second argument as environment
158
- R::Support.r_evaluate(@r_interop, *args)
159
- when args.length == 0
160
- # no arguments: 2 options: either a named item of the object or apply the function
161
- # to the object
162
- # if name is a named item of the object, then return the named item
163
- named = R::Support.eval("`%in%`").
164
- call(name, R::Support.eval("names").call(@r_interop))
165
- (false === named || !(true === named || named[0])) ?
166
- R::Support.exec_function_name(name, @r_interop) :
167
- R::Support.exec_function_name("`[[`", @r_interop, name)
168
- else
169
- args.unshift(@r_interop)
170
- R::Support.exec_function_name(name, *args)
171
- end
172
-
57
+ # Used by pp/inspect-style pretty printing.
58
+ def pretty_print(pp)
59
+ pp.text(inspect)
173
60
  end
174
-
175
- #----------------------------------------------------------------------------------------
176
- # We use the following notation to access binary R functions such as %in%:
177
- # R.vec_ "in", list.
178
- # @param args [Array] The first element of the array is an R infix function, the other
179
- # arguments are the list of arguments for the function.
180
- #----------------------------------------------------------------------------------------
181
-
182
- def _(*args)
183
- name = "`%#{args.shift.to_s}%`"
184
- args.unshift(@r_interop)
185
- R::Support.exec_function_name(name, *args)
61
+
62
+ def initialize(r_interop, expression = nil)
63
+ @r_interop = r_interop
64
+ @expression = expression
186
65
  end
187
66
 
188
- #--------------------------------------------------------------------------------------
189
- # Sets the current object self interop pointer to the returned value of the execution
190
- # of the given method with arguments. This method should be called when R will copy
191
- # the parameter, but in Ruby we want to hide the copying.
192
- # @param [Interop] Interop pointer to R function
193
- # @param [Array] Array of arguments
194
- #--------------------------------------------------------------------------------------
195
-
196
- def setR(method, *args)
197
- @r_interop = R::Support.exec_function_i(method, @r_interop, *args)
198
- self
67
+ # Number of R `class()` probes issued from Object.build (missing r_class and no usable wrapper_tag).
68
+ # Reset with reset_build_counters! before measuring. See docs/performance_plan.md Phase 2.
69
+ def self.build_class_probe_count
70
+ @build_class_probe_count ||= 0
199
71
  end
200
72
 
201
- #--------------------------------------------------------------------------------------
202
- #
203
- #--------------------------------------------------------------------------------------
73
+ def self.reset_build_counters!
74
+ @build_class_probe_count = 0
75
+ end
204
76
 
205
- def setR_name(method_name, *args)
206
- method = R::Support.eval(method_name)
207
- setR(method, *args)
208
- self
77
+ def self.increment_build_class_probe_count!
78
+ @build_class_probe_count = build_class_probe_count + 1
209
79
  end
210
80
 
211
- #--------------------------------------------------------------------------------------
212
- # Sets the names attribute of the object
213
- # @param [R::Object] names_vector is an RVector with the list of names.
214
- #--------------------------------------------------------------------------------------
81
+ # Factory: build the right Ruby wrapper for an R value. Returns a subclass (DataFrame, Vector, etc.),
82
+ # or the unwrapped Ruby value for rb_obj_* handles and for R NULL. Pass r_class to avoid an R class() call.
83
+ # Pass wrapper_tag from the new-bridge envelope to classify without string-matching r_class and to allow
84
+ # probe-free builds when r_class is absent but tag is present (non-+other+).
85
+ def self.build(r_interop, expression = nil, r_class: nil, wrapper_tag: nil)
86
+ # Ruby object handles stored in R: unwrap to the original Ruby object.
87
+ if r_interop.is_a?(::String) && r_interop.start_with?("rb_obj_")
88
+ return ::R::Support.get_ruby_object(r_interop)
89
+ end
215
90
 
216
- def names=(names_vector)
217
- setR_name("`names<-`", names_vector)
91
+ # If we got a basic Ruby type, it's already unboxed
92
+ return r_interop if r_interop.is_a?(::Numeric) || r_interop.is_a?(::TrueClass) ||
93
+ r_interop.is_a?(::FalseClass) || r_interop.nil? || r_interop.is_a?(::Symbol)
94
+
95
+ if r_interop.is_a?(::String) && r_interop.start_with?("g2_v")
96
+ return new(r_interop, expression) unless ::R.bridge.ready?
97
+
98
+ begin
99
+ rc_in = r_class
100
+ rc = r_class.to_s.strip
101
+ rc = nil if rc.nil? || rc.empty?
102
+ tag = wrapper_tag.to_s.strip
103
+ tag = nil if tag.nil? || tag.empty?
104
+
105
+ # Probe only when we have no class string and no definitive wrapper tag.
106
+ if rc.nil? && (!tag || tag == "other")
107
+ rc = class_probe_fetch_r_class(r_interop)
108
+ elsif rc.nil? && tag && tag != "other"
109
+ # Envelope-style path: tag is enough; avoid class() round-trip.
110
+ end
111
+
112
+ return nil if rc && rc.strip == "NULL"
113
+
114
+ if ::ENV['GALAAZ_DEBUG']
115
+ ::Kernel.puts "DEBUG: Object.build r_interop=#{r_interop.inspect} r_class_arg=#{rc_in.inspect} r_class=#{rc.inspect} wrapper_tag=#{tag.inspect}"
116
+ end
117
+
118
+ if tag && tag != "other"
119
+ obj = build_from_wrapper_tag(r_interop, expression, tag, r_class_hint: rc)
120
+ if obj
121
+ ::Kernel.puts "DEBUG: Object.build returning #{obj.class}" if ::ENV['GALAAZ_DEBUG']
122
+ return obj
123
+ end
124
+ end
125
+
126
+ if rc.nil?
127
+ rc = class_probe_fetch_r_class(r_interop)
128
+ return nil if rc.strip == "NULL"
129
+ end
130
+
131
+ obj = build_from_r_class_string(r_interop, expression, rc)
132
+ ::Kernel.puts "DEBUG: Object.build returning #{obj.class}" if ::ENV['GALAAZ_DEBUG']
133
+ obj
134
+ rescue => e
135
+ ::Kernel.puts "DEBUG: Object.build rescue: #{e.message}" if ::ENV['GALAAZ_DEBUG']
136
+ new(r_interop, expression)
137
+ end
138
+ else
139
+ # Fallback for already unboxed or unexpected strings
140
+ r_interop
141
+ end
218
142
  end
219
143
 
220
- def names(*args)
221
- return R::Support.exec_function_name("names", @r_interop) if (args.length == 0)
222
- setR_name("`names<-`", *args)
223
- self
144
+ def self.class_probe_fetch_r_class(r_interop)
145
+ increment_build_class_probe_count!
146
+ ::R.bridge.eval_r("paste(class(#{r_interop}), collapse=' ')").gsub(/^\[1\] /, "").gsub(/"/, "").strip
224
147
  end
225
-
226
- #--------------------------------------------------------------------------------------
227
- #
228
- #--------------------------------------------------------------------------------------
229
148
 
230
- def rclass=(class_name)
231
- setR_name("`class<-`", class_name)
232
- end
233
-
234
- def rclass
235
- R::Support.exec_function_name("class", @r_interop)
236
- end
237
-
238
- #--------------------------------------------------------------------------------------
239
- #
240
- #--------------------------------------------------------------------------------------
149
+ def self.build_from_wrapper_tag(r_interop, expression, tag, r_class_hint: nil)
150
+ # typeof(formula) is language in R, but class is "formula"; keep plain R::Object (legacy semantics).
151
+ if tag == "language" && r_class_hint && r_class_hint.include?("formula")
152
+ return nil
153
+ end
241
154
 
242
- def comment=(comment_text)
243
- setR_name("`comment<-`", comment_text)
244
- end
245
-
246
- def comment
247
- R::Support.exec_function_name("comment", @r_interop)
155
+ case tag
156
+ when "data_frame"
157
+ ::R::DataFrame.new(r_interop, expression)
158
+ when "matrix"
159
+ ::R::Matrix.new(r_interop, expression)
160
+ when "vector"
161
+ v = ::R::Vector.new(r_interop)
162
+ v.expression = expression if expression
163
+ v
164
+ when "list"
165
+ ::R::List.new(r_interop, expression)
166
+ when "environment"
167
+ ::R::Environment.new(r_interop, expression)
168
+ when "closure"
169
+ ::R::Closure.new(r_interop, expression)
170
+ when "language"
171
+ ::R::Language.new(r_interop, expression)
172
+ when "symbol"
173
+ ::R::RSymbol.new(r_interop, expression)
174
+ else
175
+ nil
176
+ end
248
177
  end
249
-
250
- #--------------------------------------------------------------------------------------
251
- #
252
- #--------------------------------------------------------------------------------------
253
178
 
254
- def dim=(numeric_vector)
255
- setR_name("`dim<-`", numeric_vector)
179
+ def self.build_from_r_class_string(r_interop, expression, r_class)
180
+ case
181
+ when r_class.include?("data.frame") || r_class.include?("tbl_df")
182
+ ::R::DataFrame.new(r_interop, expression)
183
+ when r_class.include?("matrix") || r_class.include?("array")
184
+ ::R::Matrix.new(r_interop, expression)
185
+ when r_class.include?("numeric") || r_class.include?("integer") ||
186
+ r_class.include?("logical") || r_class.include?("character")
187
+ v = ::R::Vector.new(r_interop)
188
+ v.expression = expression if expression
189
+ v
190
+ when r_class.include?("list")
191
+ ::R::List.new(r_interop, expression)
192
+ when r_class.include?("environment")
193
+ ::R::Environment.new(r_interop, expression)
194
+ when r_class.include?("function")
195
+ ::R::Closure.new(r_interop, expression)
196
+ when r_class.include?("language") || r_class == "call"
197
+ ::R::Language.new(r_interop, expression)
198
+ when r_class == "name" || r_class == "symbol"
199
+ ::R::RSymbol.new(r_interop, expression)
200
+ when r_class == "expression"
201
+ ::R::RExpression.new(r_interop, expression)
202
+ else
203
+ ::Kernel.puts "DEBUG: Object.build fell through to else (r_class=#{r_class.inspect})" if ::ENV['GALAAZ_DEBUG']
204
+ new(r_interop, expression)
205
+ end
256
206
  end
257
207
 
258
- def dim
259
- R::Support.exec_function_name("dim", @r_interop)
208
+ # Printed representation of the R object (as R would print it).
209
+ def to_s
210
+ return super unless ::R.bridge.ready?
211
+ ::R.bridge.print_r(@r_interop)
260
212
  end
261
-
262
- #--------------------------------------------------------------------------------------
263
- #
264
- #--------------------------------------------------------------------------------------
265
213
 
266
- def dimnames=(names_vector)
267
- setR_name("`dimnames<-`", names_vector)
214
+ # Phase B: BasicObject has no class; we must define it.
215
+ def class
216
+ ::R::Object
268
217
  end
269
218
 
270
- def dimnames
271
- R::Support.exec_function_name("dimnames", @r_interop)
219
+ # true for EXPLICIT_RUBY_SURFACE and for any other symbol (forwarded to R via method_missing).
220
+ def respond_to?(sym, include_private = false)
221
+ sym = sym.to_sym
222
+ return true if EXPLICIT_RUBY_SURFACE.include?(sym)
223
+ true
272
224
  end
273
-
274
- #--------------------------------------------------------------------------------------
275
- # @bug Needed to create method R.row__names because dispatch is not working properly
276
- #--------------------------------------------------------------------------------------
277
-
278
- # since we need to call a method and the method changes the object, then we need to
279
- # change our internal pointer also @r_interop. Ideally, just setting the row.names
280
- # should work.
281
- def row__names=(names_vector)
282
- setR_name("`row.names<-`", names_vector)
225
+
226
+ # Type check against Ruby modules/classes (e.g. obj.is_a?(R::DataFrame)).
227
+ def is_a?(mod)
228
+ return false unless mod.is_a?(::Module)
229
+ !!(self.class <= mod)
283
230
  end
231
+ alias_method :kind_of?, :is_a?
284
232
 
285
- def row__names
286
- R::Support.exec_function_name("row.names", @r_interop)
233
+ # Exact class check (e.g. obj.instance_of?(R::Object)).
234
+ def instance_of?(mod)
235
+ return false unless mod.is_a?(::Module)
236
+ self.class == mod
287
237
  end
288
-
289
- #--------------------------------------------------------------------------------------
290
- #
291
- #--------------------------------------------------------------------------------------
292
238
 
293
- def tsp=(numeric_vector)
294
- setR_name("`tsp<-`", numeric_vector)
239
+ # Debug string: class, object id, and @r_interop handle.
240
+ def inspect
241
+ "#<#{self.class}:#{__id__.to_s(16)} @r_interop=#{@r_interop.inspect}>"
295
242
  end
296
243
 
297
- def tsp
298
- R::Support.exec_function_name("tsp", @r_interop)
244
+ alias_method :object_id, :__id__
245
+
246
+ # R's class() of this object; unwrapped to a single string when length 1.
247
+ def rclass
248
+ res = ::R::Support.exec_function("class", self)
249
+ val = res.respond_to?(:>>) ? (res >> nil) : res
250
+ val.is_a?(::Array) ? val[0] : val
299
251
  end
300
-
301
- #--------------------------------------------------------------------------------------
302
- #
303
- #--------------------------------------------------------------------------------------
304
-
305
- def attr=(which: w, value: v)
306
- value = (R::Support.interop(value) ? value.r_interop : value)
307
- # setR(@@set_attr, which, value)
308
- setR_name("`attr<-`", which, value)
252
+
253
+ # R's typeof() of this object; unwrapped to a single string when length 1.
254
+ def typeof
255
+ res = ::R::Support.exec_function("typeof", self)
256
+ val = res.respond_to?(:>>) ? (res >> nil) : res
257
+ val.is_a?(::Array) ? val[0] : val
309
258
  end
310
-
311
- #--------------------------------------------------------------------------------------
312
- #
313
- #--------------------------------------------------------------------------------------
314
259
 
315
- def pp
316
- R.print(@r_interop)
260
+ # Unbox this R object to a Ruby value. Recurses until only Ruby values (no R::Object).
261
+ # Plain R::Object: re-evaluates handle; if list (typeof=="list") iterates [[i]] and recurses;
262
+ # if atomic uses [[index+1]] and result protocol (never uses $ on atomic). Raises UnboxDepthError when depth exceeded.
263
+ def unboxed_get(index = nil, depth = 0)
264
+ if depth >= ::R::Support::MAX_UNBOX_DEPTH
265
+ ::Kernel.raise(::R::UnboxDepthError, "unbox: list too deep (max depth #{::R::Support::MAX_UNBOX_DEPTH} exceeded)")
266
+ end
267
+ val = ::R::Support.eval(@r_interop)
268
+ return val unless val.is_a?(::R::Object)
269
+ return val.unboxed_get(index, depth + 1) if val.class.instance_method(:unboxed_get).owner != ::R::Object
270
+
271
+ handle = @r_interop.to_s
272
+ safe_handle = handle =~ /\Ag2_v\d+\z/
273
+
274
+ # Whole object (index.nil?): plain Object may be a list in R — use typeof/length, never $
275
+ if index.nil?
276
+ type_str = self.typeof.to_s.strip
277
+ len_obj = self.length
278
+ n = len_obj.respond_to?(:unboxed_get) ? len_obj.unboxed_get(0) : len_obj
279
+ n = n.to_i if n.respond_to?(:to_i)
280
+ if type_str == "list" && n.is_a?(::Integer) && n >= 1
281
+ list_handle = handle
282
+ unless safe_handle
283
+ list_handle = ::R::Support.generate_var_name
284
+ ::R.bridge.eval_r("#{list_handle} <- #{::R::Support.parse_arg(self)}")
285
+ end
286
+ arr = []
287
+ (1..n).each do |i|
288
+ elt = ::R::Support.eval("#{list_handle}[[#{i}]]")
289
+ if elt.nil?
290
+ arr << nil
291
+ elsif !elt.is_a?(::R::Object)
292
+ arr << elt
293
+ else
294
+ arr << (elt.is__null.unboxed_get(0) ? nil : elt.unboxed_get(nil, depth + 1))
295
+ end
296
+ end
297
+ return arr
298
+ end
299
+ # Atomic (or length 0): treat as single element for consistency
300
+ index = 0
301
+ end
302
+
303
+ idx = index + 1
304
+ r_code = safe_handle ? "#{handle}[[#{idx}]]" : nil
305
+ unless r_code
306
+ var = ::R::Support.generate_var_name
307
+ ::R.bridge.eval_r("#{var} <- #{::R::Support.parse_arg(self)}")
308
+ r_code = "#{var}[[#{idx}]]"
309
+ end
310
+ val2 = ::R::Support.eval(r_code)
311
+ return val2 unless val2.is_a?(::R::Object)
312
+ return val2.unboxed_get(nil, depth + 1) if val2.class.instance_method(:unboxed_get).owner != ::R::Object
313
+
314
+ # Plain R::Object single element: use result protocol until scalar or Vector/List
315
+ r_code = "#{val2.r_interop}[[1]]"
316
+ max_plain = ::R::Support::MAX_UNBOX_DEPTH - depth
317
+ loop do
318
+ var = ::R::Support.generate_var_name
319
+ assignment = "#{var} <- #{r_code}"
320
+ envelope = ::R.bridge.eval_r_with_result(assignment)
321
+ raise "Result protocol: no envelope (buffer missing or invalid)" unless envelope
322
+ case envelope[:type]
323
+ when :scalar_double, :scalar_integer, :scalar_logical, :scalar_symbol
324
+ return envelope[:value]
325
+ when :scalar_character
326
+ v = envelope[:value]
327
+ return (v.is_a?(::String) && v =~ /^rb_obj_\d+$/) ? ::R::Support.get_ruby_object(v) : v
328
+ when :handle
329
+ obj = ::R::Object.build(envelope[:handle], nil, r_class: envelope[:r_class], wrapper_tag: envelope[:wrapper_tag])
330
+ unless obj.instance_of?(::R::Object)
331
+ return obj.unboxed_get(nil, depth + 1)
332
+ end
333
+ r_code = "#{envelope[:handle]}[[1]]"
334
+ max_plain -= 1
335
+ if max_plain <= 0
336
+ ::Kernel.raise(::R::UnboxDepthError, "unbox: list too deep (max depth #{::R::Support::MAX_UNBOX_DEPTH} exceeded)")
337
+ end
338
+ else
339
+ raise "Result protocol: unknown envelope type #{envelope[:type].inspect}"
340
+ end
341
+ end
317
342
  end
318
343
 
319
- #--------------------------------------------------------------------------------------
320
- #
321
- #--------------------------------------------------------------------------------------
344
+ # Unbox via >>: same as unboxed_get so (self >> nil) and (self >> 0) work.
345
+ # << is kept as a compatibility alias for older Galaaz docs/examples.
346
+ alias_method :>>, :unboxed_get
347
+ alias_method :<<, :unboxed_get
348
+
349
+ # Unboxing semantics (>> nil / to_ruby / unboxed_get(nil)): recurse until result contains only Ruby
350
+ # values (Integer, Float, String, true/false, Array, nil). List → Array (single list → [x]).
351
+ # Atomic length 1 → scalar; length > 1 → Array. Can be expensive for large/deep structures.
352
+ # Raises R::UnboxDepthError when recursion exceeds MAX_UNBOX_DEPTH.
322
353
 
323
- def pretty_print(obj)
324
- puts self
354
+ # Simple way to get a Ruby value: (self >> nil). For length-1 vectors returns the scalar; for longer returns array.
355
+ def to_ruby
356
+ self >> nil
325
357
  end
326
-
327
- #--------------------------------------------------------------------------------------
328
- #
329
- #--------------------------------------------------------------------------------------
330
358
 
331
- def to_s
359
+ # Unbox length-1 numeric (or string digits) to Integer without forwarding to R (R has no to_i).
360
+ # Callback procs often use x.to_i when R passes scalars as R::Object.
361
+ def to_i
362
+ v = to_ruby
363
+ v = v.first if v.is_a?(::Array) && v.size == 1
364
+ case v
365
+ when ::Integer then v
366
+ when ::Float then v.to_i
367
+ when ::String then Integer(v)
368
+ else
369
+ Integer(v)
370
+ end
371
+ end
332
372
 
333
- begin
334
- cap = nil
335
- cap = R::Support.capture2.call(r_interop)
336
- str = String.new
337
- (0...(cap.size - 1)).each do |i|
338
- str << cap[i] << "\n"
373
+ # Return nil so RSpec/eq and array conversion don't forward to_ary to R (plain Object is not array-like).
374
+ def to_ary
375
+ nil
376
+ end
377
+
378
+ # Equality: R::Object vs R::Object uses all.equal; vs Ruby scalar uses unboxed value(s).
379
+ def ==(other)
380
+ return true if self.equal?(other)
381
+ if other.is_a?(::R::Object)
382
+ res = ::R.bridge.eval_r("isTRUE(all.equal(#{@r_interop}, #{other.r_interop}))")
383
+ return res == "[1] TRUE"
384
+ elsif other.is_a?(::Numeric) || other.is_a?(::String) || other.is_a?(::TrueClass) ||
385
+ other.is_a?(::FalseClass) || other.nil? || other.is_a?(::Symbol)
386
+ # DataFrame/Matrix etc. are not equal to a scalar even if they contain that value (e.g. row['mpg'] != 21.0).
387
+ return false if self.class == ::R::DataFrame || self.class == ::R::Matrix
388
+ val = (self >> nil)
389
+ if val.is_a?(::Array)
390
+ return val[0] == other if val.size == 1
391
+ return val.include?(other) if other.is_a?(::String)
339
392
  end
340
- str << cap[cap.size - 1] if cap.size >= 1
341
- str
342
- rescue StandardError => e
343
- puts e
393
+ return val == other
394
+ else
395
+ super
344
396
  end
345
-
346
397
  end
347
398
 
348
- end
399
+ # Call this object as an R function with the given args (e.g. obj.call(1, 2)).
400
+ def call(*args)
401
+ ::R::Support.exec_function(self, *args)
402
+ end
349
403
 
350
-
404
+ # Forward unknown methods to R: process_missing(symbol, self, *args) builds and runs the R call.
405
+ def method_missing(symbol, *args)
406
+ ::R::Support.process_missing(symbol, self, *args)
407
+ end
408
+ end
351
409
  end