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
@@ -3,8 +3,8 @@ title: "Non Standard Evaluation in dplyr with Galaaz"
3
3
  author:
4
4
  - "Rodrigo Botafogo"
5
5
  - "Daniel Mossé - University of Pittsburgh"
6
- tags: [Tech, Data Science, Ruby, R, GraalVM]
7
- date: "10/05/2019"
6
+ tags: [Tech, Data Science, Ruby, R, JRuby, "GNU R", Galaaz, dplyr]
7
+ date: "10/05/2019 (narrative updated for Galaaz 2.0, 2026)"
8
8
  output:
9
9
  html_document:
10
10
  self_contained: true
@@ -21,80 +21,104 @@ fontsize: 11pt
21
21
  ---
22
22
 
23
23
  ```{r setup, echo=FALSE, message = FALSE}
24
+ #R.options(crayon__enabled: false)
25
+ options(crayon.enabled = FALSE)
24
26
  library('dplyr')
25
27
  library('tibble')
26
28
  ```
27
29
 
28
30
  # Introduction
29
31
 
30
- In this post we will see how to program with _dplyr_ in Galaaz.
32
+ According to Steven Sagaert’s answer on Quora about “Is programming language R overrated?”:
31
33
 
32
- ## But first, what is Galaaz??
34
+ > R is a sophisticated language with an unusual (i.e. non-mainstream) set of features. It‘s
35
+ > an impure functional programming language with sophisticated metaprogramming and 3
36
+ > different OO systems.
37
+
38
+ > Just like common lisp you can completely customise how things work via metaprogramming.
39
+ > The biggest example is the tidyverse: by creating it’s own evaluation system (tidyeval)
40
+ > was able to create a custom syntax for dplyr.
41
+
42
+ > Mastering R (the language) and its ecosystem is not a matter of weeks or months but
43
+ > takes years. The rabbit hole goes pretty deep…
44
+
45
+ Although a highly configurable language can give programmers a great deal of power,
46
+ it can also take years to master—as noted above. Programming with _dplyr_, for instance,
47
+ means learning evaluation rules that are not always approachable for **statisticians and
48
+ analysts who are not full-time software engineers**. That is not a criticism: R was **built**
49
+ for **statisticians** who need trustworthy results on a deadline, not necessarily for building
50
+ large applications.
51
+
52
+ **Unfortunately**, when such a user moves on to more **sophisticated** programming patterns,
53
+ the learning curve can become a real hurdle.
54
+
55
+ In this post we will see how to program with _dplyr_ in Galaaz and how Ruby can simplify
56
+ the learning curve of mastering _dplyr_ coding.
57
+
58
+ # But first, what is Galaaz??
33
59
 
34
60
  Galaaz is a system for tightly coupling Ruby and R. Ruby is a powerful language, with
35
- a large community, a very large set of libraries and great for web development. However,
61
+ a large community, a very large set of libraries and great for web development. It is also
62
+ easy to learn. However,
36
63
  it lacks libraries for data science, statistics, scientific plotting and machine learning.
37
64
  On the other hand, R is considered one of the most powerful languages for solving all of the
38
- above problems. Maybe the strongest competitor to R is Python with libraries such as NumPy,
39
- Pandas, SciPy, SciKit-Learn and many more.
65
+ above problems. **Python** is a strong competitor, with NumPy, pandas, SciPy, scikit-learn,
66
+ and **many thousands** of other packages on PyPI. We will not dwell on R **versus** Python here:
67
+ both are excellent languages with different strengths.
68
+ Our interest is to bring to yet another excellent language, Ruby, the data science libraries
69
+ that it lacks.
40
70
 
41
71
  With Galaaz we do not intend to re-implement any of the scientific libraries in R. However, we
42
72
  allow for very tight coupling between the two languages to the point that the Ruby
43
73
  developer does not need to know that there is an R engine running. Also, from the point of
44
- view of the R user/developer Galaaz looks a lot like R, with just minor syntactic difference,
45
- so there is almost no learning courve for the R developer. And as we will see in this
46
- post, programming with _dplyr_ is easier in Galaaz than in R.
74
+ view of the R user/developer, Galaaz looks a lot like R, with just minor syntactic difference,
75
+ so there is almost no learning curve for the R developer. And as we will see in this
76
+ post that programming with _dplyr_ is easier in Galaaz than in R.
47
77
 
48
- R users are probably quite knowledgeable about _dplyr_, for the Ruby developer, _dplyr_ and
78
+ R users are probably quite knowledgeable about _dplyr_. For the Ruby developer, _dplyr_ and
49
79
  the _tidyverse_ libraries are a set of libraries for data manipulation in R, developed by
50
- Hardley Wickham, chief scientis at RStudio and a prolific R coder and writer.
51
-
52
- For the coupling of Ruby and R we use new technologies provided by Oracle: GraalVM,
53
- TruffleRuby and FastR:
54
-
55
- GraalVM is a universal virtual machine for running applications
56
- written in JavaScript, Python 3, Ruby, R, JVM-based languages like Java,
57
- Scala, Kotlin, and LLVM-based languages such as C and C++.
58
-
59
- GraalVM removes the isolation between programming languages and enables
60
- interoperability in a shared runtime. It can run either standalone or in
61
- the context of OpenJDK, Node.js, Oracle Database, or MySQL.
62
-
63
- GraalVM allows you to write polyglot applications with a seamless way to
64
- pass values from one language to another. With GraalVM there is no copying
65
- or marshaling necessary as it is with other polyglot systems. This lets
66
- you achieve high performance when language boundaries are crossed. Most
67
- of the time there is no additional cost for crossing a language boundary
68
- at all.
69
-
70
- Often developers have to make uncomfortable compromises that require them
71
- to rewrite their software in other languages. For example:
72
-
73
- * “That library is not available in my language. I need to rewrite it.”
74
- * “That language would be the perfect fit for my problem, but we cannot
75
- run it in our environment.”
76
- * “That problem is already solved in my language, but the language is
77
- too slow.”
78
-
79
- With GraalVM we aim to allow developers to freely choose the right language
80
- for the task at hand without making compromises.
81
-
82
- Interested readers should also check out the following sites:
83
-
84
- * [GraalVM Home](https://www.graalvm.org/)
85
- * [TruffleRuby](https://github.com/oracle/truffleruby)
86
- * [FastR](https://github.com/oracle/fastr)
87
- * [Faster R with FastR](https://medium.com/graalvm/faster-r-with-fastr-4b8db0e0dceb)
88
- * [How to make Beautiful Ruby Plots with Galaaz](https://medium.freecodecamp.org/how-to-make-beautiful-ruby-plots-with-galaaz-320848058857)
89
- * [Ruby Plotting with Galaaz: An example of tightly coupling Ruby and R in GraalVM](https://towardsdatascience.com/ruby-plotting-with-galaaz-an-example-of-tightly-coupling-ruby-and-r-in-graalvm-520b69e21021)
90
- * [How to do reproducible research in Ruby with gKnit](https://towardsdatascience.com/how-to-do-reproducible-research-in-ruby-with-gknit-c26d2684d64e)
91
- * [R for Data Science](https://r4ds.had.co.nz/)
92
- * [Advanced R](https://adv-r.hadley.nz/)
80
+ Hadley Wickham, Chief Scientist at Posit (formerly RStudio) and a prolific R coder and writer.
81
+
82
+ For the coupling of Ruby and R, **Galaaz 2.0** uses **[JRuby](https://www.jruby.org/)** (Ruby on the JVM)
83
+ together with **GNU R**. A **bridge** sends expressions and data between Ruby and an R process so that
84
+ Ruby can call **dplyr** and the rest of the tidyverse as if they were part of the same workflow.
85
+ An **earlier** Galaaz line of work used Oracle’s **GraalVM** with **TruffleRuby** and **FastR** in a single
86
+ runtime; that approach is **no longer** the supported stack—see the project **manual** for setup,
87
+ **`bin/galaaz-jruby`**, and **gKnit**.
88
+
89
+
90
+ # Tidyverse and dplyr
91
+
92
+ In [What is the tidyverse?](https://rviews.rstudio.com/2017/06/08/what-is-the-tidyverse/) the
93
+ tidyverse is explained as follows:
94
+
95
+ > The tidyverse is a coherent system of packages for data manipulation, exploration and
96
+ > visualization that share a common design philosophy. These were mostly developed by
97
+ > Hadley Wickham himself, but they are now being expanded by several contributors. Tidyverse
98
+ > packages are intended to make statisticians and data scientists more productive by
99
+ > guiding them through workflows that facilitate communication, and result in reproducible
100
+ > work products. Fundamentally, the tidyverse is about the connections between the tools
101
+ > that make the workflow possible.
93
102
 
94
- ## Programming with dplyr
103
+ _dplyr_ is one of the many packages that are part of the tidyverse. It is:
95
104
 
96
- This post will follow closely the work done in https://dplyr.tidyverse.org/articles/programming.html,
97
- by Hardley Wickham. In it, Hardley states:
105
+ > a grammar of data manipulation, providing a consistent set of verbs that help you solve
106
+ > the most common data manipulation challenges:
107
+
108
+ > 1. mutate() adds new variables that are functions of existing variables
109
+ > 2. select() picks variables based on their names.
110
+ > 3. filter() picks cases based on their values.
111
+ > 4. summarise() reduces multiple values down to a single summary.
112
+ > 5. arrange() changes the ordering of the rows.
113
+
114
+ Very often R is used interactively and users use _dplyr_ to manipulate a single dataset
115
+ without programming. When users want to replicate their work for
116
+ multiple datasets, programming becomes necessary.
117
+
118
+ # Programming with dplyr
119
+
120
+ In the vignette ["Programming with dplyr"](https://dplyr.tidyverse.org/articles/programming.html),
121
+ Hadley Wickham states:
98
122
 
99
123
  > Most dplyr functions use non-standard evaluation (NSE). This is a catch-all term that
100
124
  > means they don’t follow the usual R rules of evaluation. Instead, they capture the
@@ -109,6 +133,8 @@ by Hardley Wickham. In it, Hardley states:
109
133
  > database backends because dplyr itself doesn’t do any work, but instead generates the SQL
110
134
  > that tells the database what to do.
111
135
 
136
+ But then he goes on:
137
+
112
138
  > Unfortunately these benefits do not come for free. There are two main drawbacks:
113
139
 
114
140
  > Most dplyr arguments are not referentially transparent. That means you can’t replace a value
@@ -132,8 +158,27 @@ filter(df, my_var == 1)
132
158
  ```
133
159
  > This makes it hard to create functions with arguments that change how dplyr verbs are computed.
134
160
 
135
- In this post we will see that programming with _dplyr_ in Galaaz does not require knowledge of
136
- non-standard evaluation in R and can be accomplished by utilizing normal Ruby constructs.
161
+ As a result of this, programming with _dplyr_ requires learning a set of new ideas and concepts.
162
+ In this vignette Hadley goes on showing how to program ever more difficult problems with _dplyr_,
163
+ showing the problems it faces and the new concepts needed to solve them.
164
+
165
+ In this blog, we will look at all the problems presented by Harley on the vignette and show how
166
+ those same problems can be solved using Galaaz and the Ruby language.
167
+
168
+ This blog is organized as follows: first we show how to write expressions using Galaaz.
169
+ Expressions are a fundamental concept in _dplyr_ and are not part of basic Ruby. We extend
170
+ the Ruby language create a manipulate expressions that will be used by _dplyr_ functions.
171
+
172
+ Then we show very succintly how Ruby and R can be integrated and how R functions are
173
+ transparently called from Ruby. Galaaz [user manual](https://github.com/rbotafogo/galaaz/wiki)
174
+ (still in development) goes in much deeper detail about this integration.
175
+
176
+ Next in section "Data manipulation wiht _dplyr_" we go through all the problems on the
177
+ _dplyr_ vignette and look at how they are solved in Galaaz. We then discuss why programming
178
+ with Galaaz and _dplyr_ is easier than programming with _dplyr_ in plain R.
179
+
180
+ The following section looks at another more advanced problem and shows that Galaaz can still
181
+ handle it without any difficulty. We then provide further reading and concluding remarks.
137
182
 
138
183
  # Writing Expressions in Galaaz
139
184
 
@@ -142,37 +187,55 @@ Galaaz extends Ruby to work with expressions, similar to R's expressions build w
142
187
  formulae. For instance, in mathematics, the expression $y = sin(x)$ describes a function but cannot
143
188
  be computed unless the value of $x$ is bound to some value.
144
189
 
145
- Let's take a look at some of those expressions in Ruby:
190
+ Expressions are fundamental in _dplyr_ programming as they are the input to _dplyr_ functions,
191
+ for instance, as we will see shortly, if a data frame has a column named 'x' and we want
192
+ to add another column, y, to this dataframe that has the values of 'x' times 2, then we would
193
+ call a _dplyr_ function with the expression 'y = x * 2'.
194
+
195
+ ## A note on notation
196
+
197
+ This blog was written in Rmarkdown and automatically converted to HTML or PDF (depending on
198
+ where you are reading this blog) with gKnit (a tool provided by Galaaz). In Rmarkdown, it is
199
+ possible to write text and code blocks that are executed to generate the final report. Code
200
+ blocks appear inside a 'box' and the result of their execution appear either in another type
201
+ of 'box' with a different background (HTML) or as normal text (PDF). Every output line from
202
+ the code execution is preceded by '##'.
146
203
 
147
204
  ## Expressions from operators
148
205
 
149
- The code bellow creates an expression summing two symbols. Note that :a and :b are Ruby symbols and
150
- are not bound to any value at the time of expression definition:
206
+ The code below creates an expression summing two symbols. Note that :a and :b are Ruby symbols and
207
+ are not bound to any values at the time of expression definition:
151
208
 
152
209
  ```{ruby expressions}
153
210
  exp1 = :a + :b
154
211
  puts exp1
155
212
  ```
156
- We can build any complex mathematical expression such as:
213
+ In Galaaz, we can build any complex mathematical expression such as:
157
214
 
158
215
  ```{ruby expr2}
159
- exp2 = (:a + :b) * 2.0 + :c ** 2 / :z
216
+ exp2 = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
160
217
  puts exp2
161
218
  ```
162
- The 'L' after two indicates that 2 is an integer.
219
+ Expressions are printed with the same format as the equivalent R expressions. The 'L' after
220
+ 2 indicates that 2 is an integer.
221
+
222
+ The R developer should note that in R, if she writes the
223
+ number '2', the R interpreter will convert it to float. In order to get an interger she
224
+ should write '2L'. Galaaz follows Ruby notation and '2' is an integer, while '2.0' is a
225
+ float.
163
226
 
164
227
  It is also possible to use inequality operators in building expressions:
165
228
 
166
229
  ```{ruby expr3}
167
- exp3 = (:a + :b) >= :z
230
+ exp3 = (R[:a] + R[:b]) >= R[:z]
168
231
  puts exp3
169
232
  ```
170
233
  Expressions' definition can also make use of normal Ruby variables without any problem:
171
234
 
172
235
  ```{ruby expr_with_var}
173
236
  x = 20
174
- y = 30
175
- exp_var = (:a + :b) * x <= :z - y
237
+ y = 30.0
238
+ exp_var = (R[:a] + R[:b]) * x <= R[:z] - y
176
239
  puts exp_var
177
240
  ```
178
241
 
@@ -181,75 +244,82 @@ notation for those operators such as (.gt, .ge, etc.). So the same expression w
181
244
  above can also be written as
182
245
 
183
246
  ```{ruby expr4}
184
- exp4 = (:a + :b).ge :z
247
+ exp4 = (R[:a] + R[:b]).ge R[:z]
185
248
  puts exp4
186
249
  ```
187
250
 
188
- Two type of expression, however, can only be created with the functional representation
189
- of the operators, those are expressions involving '==', and '='. In order to write an
190
- expression involving '==' we
191
- need to use the method '.eq' and for '=' we need the function '.assign'
251
+ Two types of expressions, however, can only be created with the functional representation
252
+ of the operators. Those are expressions involving '==', and '='. This is the case since
253
+ those symbols have special meaning in Ruby and should not be redefined.
254
+
255
+ In order to write an expression involving '==' we
256
+ need to use the method '.eq' and for '=' we need the function '.assign':
192
257
 
193
258
  ```{ruby expr5}
194
- exp5 = (:a + :b).eq :z
259
+ exp5 = (R[:a] + R[:b]).eq R[:z]
195
260
  puts exp5
196
261
  ```
197
262
 
198
263
  ```{ruby expr6}
199
- exp6 = :y.assign :a + :b
264
+ exp6 = R[:y].assign R[:a] + R[:b]
200
265
  puts exp6
201
266
  ```
202
- In general we think that using the functional notation is preferable to using the
203
- symbolic notation as otherwise, we end up writing invalid expressions such as
267
+ Users should be careful when writing expressions not to inadvertently use '==' or '=' as
268
+ this will generate an error, that might be a bit cryptic (in future releases of Galaza, we
269
+ plan to improve the error message).
204
270
 
205
271
  ```{ruby exp_wrong, warning=FALSE}
206
- exp_wrong = (:a + :b) == :z
272
+ exp_wrong = (R[:a] + R[:b]) == R[:z]
207
273
  puts exp_wrong
208
274
  ```
209
- and it might be difficult to understand what is going on here. The problem lies with the fact that
210
- when using '==' we are comparing expression (:a + :b) to expression :z with '=='. When the
211
- comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols at
212
- this time are not bound to anything and we get a "object 'a' not found" message.
213
- If we only use functional notation, this type of error will not occur.
275
+ The problem lies with the fact that
276
+ when using '==' we are comparing expression (R[:a] + R[:b]) to expression R[:z] with '=='. When this
277
+ comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols, at
278
+ this time, are not bound to anything giving the "object 'a' not found" message.
214
279
 
215
280
  ## Expressions with R methods
216
281
 
217
282
  It is often necessary to create an expression that uses a method or function. For instance, in
218
283
  mathematics, it's quite natural to write an expressin such as $y = sin(x)$. In this case, the
219
- 'sin' function is part of the expression and should not immediately be executed. When we want
284
+ 'sin' function is part of the expression and should not be immediately executed. When we want
220
285
  the function to be part of the expression, we call the function preceeding it
221
286
  by the letter E, such as 'E.sin(x)'
222
287
 
223
288
  ```{ruby method_expression}
224
- exp7 = :y.assign E.sin(:x)
289
+ exp7 = R[:y].assign E.sin(R[:x])
225
290
  puts exp7
226
291
  ```
227
-
228
- Expressions can also be written using '.' notation:
292
+ Function expressions can also be written using '.' notation:
229
293
 
230
294
  ```{ruby expression_with_dot}
231
- exp8 = :y.assign :x.sin
295
+ exp8 = R[:y].assign R[:x].sin
232
296
  puts exp8
233
297
  ```
234
-
235
- When a function has multiple arguments, the first one can be used before the '.':
298
+ When a function has multiple arguments, the first one can be used before the '.'. For instance,
299
+ the R concatenate function 'c', that concatenates two or more arguments can be part of
300
+ an expression as:
236
301
 
237
302
  ```{ruby expression_multiple_args}
238
- exp9 = :x.c(:y)
303
+ exp9 = R[:x].c(R[:y])
239
304
  puts exp9
240
305
  ```
306
+ Note that this gives an OO feeling to the code, as if we were saying 'x' concatenates 'y'. As a
307
+ side note, '.' notation can be used as the R pipe operator '%>%', but is more general than the
308
+ pipe.
241
309
 
242
310
  ## Evaluating an Expression
243
311
 
244
- Expressions can be evaluated by calling function 'eval' with a binding. A binding can be provided
245
- with a list:
312
+ Although we are mainly focusing on expressions to pass them to _dplyr_ functions, expressions
313
+ can be evaluated by calling function 'eval' with a binding.
314
+
315
+ A binding can be provided with a list or a data frame as shown below:
246
316
 
247
317
  ```{ruby eval_expression_list}
248
- exp = (:a + :b) * 2.0 + :c ** 2 / :z
318
+ exp = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
249
319
  puts exp.eval(R.list(a: 10, b: 20, c: 30, z: 40))
250
320
  ```
251
321
 
252
- ... with a data frame:
322
+ with a data frame:
253
323
 
254
324
  ```{ruby eval_expression_df}
255
325
  df = R.data__frame(
@@ -269,8 +339,8 @@ this post, we do not have enough space to write a complete manual on Galaaz
269
339
  (a short manual can be found at: https://www.rubydoc.info/gems/galaaz/0.4.9), so we will
270
340
  present only a few examples scripts using Galaaz.
271
341
 
272
- Basically, to call an R function from Ruby with Galaaz, one only needs to preceed the function
273
- with 'R.'. For instance, to create a vector in R, the 'c' function is used. From Galaaz, a
342
+ Basically, to call an R function from Ruby with Galaaz, one only needs to preced the function
343
+ with 'R.'. For instance, to create a vector in R, the 'c' function is used. In Galaaz, a
274
344
  vector can be created by using 'R.c':
275
345
 
276
346
  ```{ruby vector}
@@ -294,32 +364,77 @@ the expression $y = sin(45^\circ)$, which is $y = 0.850...$. In this case,
294
364
  we will use 'R.sin':
295
365
 
296
366
  ```{ruby eval_sin}
297
- exp10 = :y.assign R.sin(45)
367
+ exp10 = R[:y].assign R.sin(45)
298
368
  puts exp10
299
369
  ```
300
370
 
301
- # Filtering using expressions
371
+ # Data manipulation wiht _dplyr_
372
+
373
+ In this section we will give a brief tour _dplyr_'s usage in Galaaz and how to manipulate
374
+ data in Ruby with it. This section will follow [_dplyr_'s vignette](https://dplyr.tidyverse.org/articles/dplyr.html) that explores the nycflights13 data set. This dataset contains all 336776
375
+ flights that departed from New York City in 2013. The data comes from the US Bureau of
376
+ Transportation Statistics.
377
+
378
+ Let's start by taking a look at this dataset:
379
+
380
+ ```{ruby nycflights13}
381
+ R.library('nycflights13')
382
+ # check it's dimension
383
+ puts ~R[:flights].dim
384
+ # and the structure
385
+ ~R[:flights].str
386
+ ```
387
+
388
+ Now, let's use a first verb of _dplyr_: 'filter'. This verb, obviously, will filter the data
389
+ by the given expression. In the next block, we filter by columns 'month' and 'day'. The
390
+ first argument to the filter function is symbol ':flights'. A Ruby symbol, when given to
391
+ an R function will convert to the R variable of the same name, in this case 'flights', that
392
+ holds the nycflights13 data frame.
393
+
394
+ The second and third arguments are expressions that will be used by the filter function to
395
+ filter by columns, looking for entries in which the month and day are equal to 1.
396
+
397
+ ```{ruby filter}
398
+ puts R.filter(:flights, (R[:month].eq 1), (R[:day].eq 1))
399
+ ```
400
+
302
401
 
303
- Now that we know how to write expression and call R functions let's do some data manipulation in
304
- Galaaz. Let's first start by creating the same data frame that we created previously in section
305
- "Programming with dplyr":
402
+ ## Programming with _dplyr_: problems and how to solve them in Galaaz
403
+
404
+ In this section we look at the list of problems that Hadley describes in the "Programming with dplyr"
405
+ vignette and show how those problems are solved and coded with Galaaz. Readers interested in
406
+ how those problems are treated in _dplyr_ should read the vignette and use it as a comparison with
407
+ this blog.
408
+
409
+ ## Filtering using expressions
410
+
411
+ Now that we know how to write expressions and call R functions, let's do some data manipulation in
412
+ Galaaz. Let's first start by creating a data frame. In R, the 'data.frame' function creates a
413
+ data frame. In Ruby, writing 'data.frame' will not parse as a single object. To call R
414
+ functions that have a '.' in them, we need to substitute the '.' with '__'. So, method
415
+ 'data.frame' in R, is called in Galaaz as 'R.data\_\_frame':
306
416
 
307
417
  ```{ruby df}
308
418
  df = R.data__frame(x: (1..3), y: (3..1))
309
419
  puts df
310
420
  ```
311
- The 'filter' function can be called on this data frame either by using 'R.filter(df, ...)' or
312
- by using dot notation. We prefer to use dot notation as shown bellow. The argument to 'filter'
313
- in Galaaz should be an expression. Note that if we gave to filter a Ruby expression such as
421
+
422
+ _dplyr_ provides the 'filter' function, that filters data in a data brame. The 'filter'
423
+ function can be called on this data frame either by using 'R.filter(df, ...)' or
424
+ by using dot notation.
425
+
426
+ -------FIX---------
427
+
428
+ We prefer to use dot notation as shown below. The argument to 'filter' should be an
429
+ expression. Note that if we gave to filter a Ruby expression such as
314
430
  'x == 1', we would get an error, since there is no variable 'x' defined and if 'x' was a variable
315
431
  then 'x == 1' would either be 'true' or 'false'. Our goal is to filter our data frame returning
316
- all rows in which the 'x' value is equal to 1. To express this we want: ':x.eq 1', where :x will
432
+ all rows in which the 'x' value is equal to 1. To express this we want: 'R[:x].eq 1', where :x will
317
433
  be interpreted by filter as the 'x' column.
318
434
 
319
435
  ```{ruby filter_exp}
320
- puts df.filter(:x.eq 1)
436
+ puts df.filter(R[:x].eq 1)
321
437
  ```
322
-
323
438
  In R, and when coding with 'tidyverse', arguments to a function are usually not
324
439
  *referencially transparent*. That is, you can’t replace a value with a seemingly equivalent
325
440
  object that you’ve defined elsewhere. In other words, this code
@@ -331,16 +446,16 @@ filter(df, my_var == 1)
331
446
  Generates the following error: "object 'x' not found.
332
447
 
333
448
  However, in Galaaz, arguments are referencially transparent as can be seen by the
334
- code bellow. Note initally that 'my_var = :x' will not give the error "object 'x' not found"
449
+ code below. Note initially that 'my_var = R[:x]' will not give the error "object 'x' not found"
335
450
  since ':x' is treated as an expression and assigned to my\_var. Then when doing (my\_var.eq 1),
336
- my\_var is a variable that resolves to ':x' and it becomes equivalent to (:x.eq 1) which is
451
+ my\_var is a variable that resolves to ':x' and it becomes equivalent to (R[:x].eq 1) which is
337
452
  what we want.
338
453
 
339
454
  ```{ruby my_var}
340
- my_var = :x
455
+ my_var = R[:x]
341
456
  puts df.filter(my_var.eq 1)
342
457
  ```
343
- As stated by Hardley
458
+ As stated by Hadley
344
459
 
345
460
  > dplyr code is ambiguous. Depending on what variables are defined where,
346
461
  > filter(df, x == y) could be equivalent to any of:
@@ -352,9 +467,9 @@ df[x == df$y, ]
352
467
  df[x == y, ]
353
468
  ```
354
469
  In galaaz this ambiguity does not exist, filter(df, x.eq y) is not a valid expression as
355
- expressions are build with symbols. In doing filter(df, :x.eq y) we are looking for elements
470
+ expressions are build with symbols. In doing filter(df, R[:x].eq y) we are looking for elements
356
471
  of the 'x' column that are equal to a previously defined y variable. Finally in
357
- filter(df, :x.eq :y) we are looking for elements in which the 'x' column value is equal to
472
+ filter(df, R[:x].eq R[:y]) we are looking for elements in which the 'x' column value is equal to
358
473
  the 'y' column value. This can be seen in the following two chunks of code:
359
474
 
360
475
  ```{ruby disamb1}
@@ -362,15 +477,15 @@ y = 1
362
477
  x = 2
363
478
 
364
479
  # looking for values where the 'x' column is equal to the 'y' column
365
- puts df.filter(:x.eq :y)
480
+ puts df.filter(R[:x].eq R[:y])
366
481
  ```
367
482
 
368
483
  ```{ruby disamb2}
369
484
  # looking for values where the 'x' column is equal to the 'y' variable
370
485
  # in this case, the number 1
371
- puts df.filter(:x.eq y)
486
+ puts df.filter(R[:x].eq y)
372
487
  ```
373
- # Writing a function that applies to different data sets
488
+ ## Writing a function that applies to different data sets
374
489
 
375
490
  Let's suppose that we want to write a function that receives as the first argument a data frame
376
491
  and as second argument an expression that adds a column to the data frame that is equal to the
@@ -395,11 +510,12 @@ Unfortunately, in R, this function can fail silently if one of the variables isn
395
510
  in the data frame, but is present in the global environment. We will not go through here how
396
511
  to solve this problem in R.
397
512
 
398
- In Galaaz the method mutate_y bellow will work fine and will never fail silently.
513
+ In Galaaz the method mutate_y below will work fine and will never fail silently.
399
514
 
400
515
  ```{ruby mutate_y, warning=FALSE}
401
516
  def mutate_y(df)
402
- df.mutate(:y.assign :a + :x)
517
+ # Mutate column names are Ruby kwargs (y: …). Use .assign only for R `<-` expressions.
518
+ df.mutate(y: R[:a] + R[:x])
403
519
  end
404
520
  ```
405
521
  Here we create a data frame that has only one column named 'x':
@@ -410,18 +526,18 @@ puts df1
410
526
  ```
411
527
 
412
528
  Note that method mutate_y will fail independetly from the fact that variable 'a' is defined and
413
- in the scope of the method. Variable 'a' has no relationship with the symbol ':a' used in the
529
+ in the scope of the method. Variable 'a' has no relationship with the symbol `R[:a]` used in the
414
530
  definition of 'mutate\_y' above:
415
531
 
416
532
  ```{ruby call_mutate_y, warning = FALSE}
417
533
  a = 10
418
534
  mutate_y(df1)
419
535
  ```
420
- # Different expressions
536
+ ## Different expressions
421
537
 
422
- Let's move to the next problem as presented by Hardley where trying to write a function in R
538
+ Let's move to the next problem as presented by Hadley where trying to write a function in R
423
539
  that will receive two argumens, the first a variable and the second an expression is not trivial.
424
- Bellow we create a data frame and we want to write a function that groups data by a variable and
540
+ Below we create a data frame and we want to write a function that groups data by a variable and
425
541
  summarises it by an expression:
426
542
 
427
543
  ```{r diff_expr}
@@ -434,13 +550,13 @@ df <- data.frame(
434
550
  b = sample(5)
435
551
  )
436
552
 
437
- as.data.frame(df)
553
+ as.data.frame(df)
438
554
 
439
555
  d2 <- df %>%
440
556
  group_by(g1) %>%
441
557
  summarise(a = mean(a))
442
558
 
443
- as.data.frame(d2)
559
+ as.data.frame(d2)
444
560
 
445
561
  d2 <- df %>%
446
562
  group_by(g2) %>%
@@ -449,7 +565,7 @@ d2 <- df %>%
449
565
  as.data.frame(d2)
450
566
  ```
451
567
 
452
- As shown by Hardley, one might expect this function to do the trick:
568
+ As shown by Hadley, one might expect this function to do the trick:
453
569
 
454
570
  ```{r diff_exp_fnc}
455
571
  my_summarise <- function(df, group_var) {
@@ -464,40 +580,40 @@ my_summarise <- function(df, group_var) {
464
580
 
465
581
  In order to solve this problem, coding with dplyr requires the introduction of many new concepts
466
582
  and functions such as 'quo', 'quos', 'enquo', 'enquos', '!!' (bang bang), '!!!' (triple bang).
467
- Again, we'll leave to Hardley the explanation on how to use all those functions.
583
+ Again, we'll leave to Hadley the explanation on how to use all those functions.
468
584
 
469
585
  Now, let's try to implement the same function in galaaz. The next code block first prints the
470
- 'df' data frame define previously in R (to access an R variable from Galaaz, we use the tilda
586
+ 'df' data frame defined previously in R (to access an R variable from Galaaz, we use the tilde
471
587
  operator '~' applied to the R variable name as symbol, i.e., ':df'. We then create the
472
588
  'my_summarize' method and call it passing the R data frame and the group by variable ':g1':
473
589
 
474
590
  ```{ruby diff_exp_ruby_func}
475
- puts ~:df
591
+ puts ~R[:df]
476
592
  print "\n"
477
593
 
478
594
  def my_summarize(df, group_var)
479
595
  df.group_by(group_var).
480
- summarize(a: :a.mean)
596
+ summarize(a: R[:a].mean)
481
597
  end
482
598
 
483
- puts my_summarize(:df, :g1).as__data__frame
599
+ puts my_summarize(~R[:df], R[:g1])
484
600
  ```
485
601
  It works!!! Well, let's make sure this was not just some coincidence
486
602
 
487
603
  ```{ruby group_g2}
488
- puts my_summarize(:df, :g2).as__data__frame
604
+ puts my_summarize(~R[:df], R[:g2])
489
605
  ```
490
606
 
491
607
  Great, everything is fine! No magic, no new functions, no complexities, just normal, standard Ruby
492
608
  code. If you've ever done NSE in R, this certainly feels much safer and easy to implement.
493
609
 
494
- # Different input variables
610
+ ## Different input variables
495
611
 
496
612
  In the previous section we've managed to get rid of all NSE formulation for a simple example, but
497
613
  does this remain true for more complex examples, or will the Galaaz way prove inpractical for
498
614
  more complex code?
499
615
 
500
- In the next example Hardley proposes us to write a function that given an expression such as 'a'
616
+ In the next example Hadley proposes us to write a function that given an expression such as 'a'
501
617
  or 'a * b', calculates three summaries. What we want a function that does the same as these R
502
618
  statements:
503
619
 
@@ -526,16 +642,16 @@ def my_summarise2(df, expr)
526
642
  )
527
643
  end
528
644
 
529
- puts my_summarise2((~:df), :a)
530
- puts my_summarise2((~:df), :a * :b)
645
+ puts my_summarise2((~R[:df]), :a)
646
+ puts my_summarise2((~R[:df]), R[:a] * R[:b])
531
647
  ```
532
648
 
533
649
  Once again, there is no need to use any special theory or functions. The only point to be
534
650
  careful about is the use of 'E' to build expressions from functions 'mean', 'sum' and 'n'.
535
651
 
536
- # Different input and output variable
652
+ ## Different input and output variable
537
653
 
538
- Now the next challenge presented by Hardley is to vary the name of the output variables based on
654
+ Now the next challenge presented by Hadley is to vary the name of the output variables based on
539
655
  the received expression. So, if the input expression is 'a', we want our data frame columns to
540
656
  be named 'mean\_a' and 'sum\_a'. Now, if the input expression is 'b', columns
541
657
  should be named 'mean\_b' and 'sum\_b'.
@@ -561,7 +677,7 @@ mutate(df, mean_b = mean(b), sum_b = sum(b))
561
677
  #> 4 2 2 5 4 3 15
562
678
  #> # … with 1 more row
563
679
  ```
564
- In order to solve this problem in R, Hardley needs to introduce some more new functions and notations:
680
+ In order to solve this problem in R, Hadley needs to introduce some more new functions and notations:
565
681
  'quo_name' and the ':=' operator from package 'rlang'
566
682
 
567
683
  Here is our Ruby code:
@@ -575,8 +691,8 @@ def my_mutate(df, expr)
575
691
  sum_name => E.sum(expr))
576
692
  end
577
693
 
578
- puts my_mutate((~:df), :a)
579
- puts my_mutate((~:df), :b)
694
+ puts my_mutate((~R[:df]), :a)
695
+ puts my_mutate((~R[:df]), :b)
580
696
  ```
581
697
  It really seems that "Non Standard Evaluation" is actually quite standard in Galaaz! But, you
582
698
  might have noticed a small change in the way the arguments to the mutate method were called.
@@ -586,9 +702,9 @@ and variable mean\_name is not followed by ':' but by '=>'. This is standard Ru
586
702
 
587
703
  [explain....]
588
704
 
589
- # Capturing multiple variables
705
+ ## Capturing multiple variables
590
706
 
591
- Moving on with new complexities, Hardley proposes us to solve the problem in which the
707
+ Moving on with new complexities, Hadley proposes us to solve the problem in which the
592
708
  summarise function will receive any number of grouping variables.
593
709
 
594
710
  This again is quite standard Ruby. In order to receive an undefined number of paramenters
@@ -600,7 +716,7 @@ def my_summarise3(df, *group_vars)
600
716
  summarise(a: E.mean(:a))
601
717
  end
602
718
 
603
- puts my_summarise3((~:df), :g1, :g2).as__data__frame
719
+ puts my_summarise3((~R[:df]), :g1, :g2)
604
720
  ```
605
721
 
606
722
  # Why does R require NSE and Galaaz does not?
@@ -618,7 +734,7 @@ In Ruby, there is no lazy evaluation of parameters and 'a' is always a variable
618
734
  Variables assume their value as soon as they are used, so 'x = a' is immediately evaluate and
619
735
  variable 'x' will receive the value of variable 'a' as soon as the Ruby statement is executed.
620
736
  Ruby also provides the notion of a symbol; ':a' is a symbol and does not evaluate to anything.
621
- Galaaz uses Ruby symbols to build expressions that are not bound to anything: ':a.eq :b' is
737
+ Galaaz uses Ruby symbols to build expressions that are not bound to anything: 'R[:a].eq R[:b]' is
622
738
  clearly an expression and has no relationship whatsoever with the statment 'a = b'. By using
623
739
  symbols, variables and expressions all the possible ambiguities that are found in R are
624
740
  eliminated in Galaaz.
@@ -628,12 +744,12 @@ of input they are expecting, they might be expecting regular variables or they m
628
744
  expecting expressions and the R function will know how to deal with an input of the form
629
745
  'a = b', now for the Ruby developer it might not be immediately clear if it should call the
630
746
  function passing the value 'true' if variable 'a' is equal to variable 'b' or if it should
631
- call the function passing the expression ':a.eq :b'.
747
+ call the function passing the expression 'R[:a].eq R[:b]'.
632
748
 
633
749
 
634
750
  # Advanced dplyr features
635
751
 
636
- In the blog: Programming with dplyr by using dplyr (https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/) Iñaki Úcar shows surprise that some R users are trying to code in dplyr avoiding
752
+ In the blog: [Programming with dplyr by using dplyr](https://www.r-bloggers.com/programming-with-dplyr-by-using-dplyr/) Iñaki Úcar shows surprise that some R users are trying to code in dplyr avoiding
637
753
  the use of NSE. For instance he says:
638
754
 
639
755
  > Take the example of seplyr. It stands for standard evaluation dplyr, and enables us to
@@ -651,9 +767,9 @@ In the following examples, we show the use of functions 'group\_by\_at', 'summar
651
767
  features of characters in the Starwars movies:
652
768
 
653
769
  ```{ruby starwars}
654
- puts (~:starwars).head.as__data__frame
770
+ puts (~R[:starwars]).head
655
771
  ```
656
- The grouped_mean function bellow will receive a grouping variable and calculate summaries for
772
+ The grouped_mean function below will receive a grouping variable and calculate summaries for
657
773
  the value\_variables given:
658
774
 
659
775
  ```{r grouped_mean}
@@ -678,13 +794,23 @@ def grouped_mean(data, grouping_variables, value_variables)
678
794
  data.
679
795
  group_by_at(grouping_variables).
680
796
  mutate(count: E.n).
681
- summarise_at(E.c(value_variables, "count"), ~:mean, na__rm: true).
797
+ summarise_at(E.c(value_variables, "count"), R[:mean], na__rm: true).
682
798
  rename_at(value_variables, E.funs(E.paste0("mean_", value_variables)))
683
799
  end
684
800
 
685
- puts grouped_mean((~:starwars), "eye_color", E.c("mass", "birth_year")).as__data__frame
801
+ puts grouped_mean((~R[:starwars]), "eye_color", E.c("mass", "birth_year"))
686
802
  ```
687
803
 
804
+ # Further reading
805
+
806
+ * [JRuby](https://www.jruby.org/) — Ruby on the JVM (Galaaz 2.0)
807
+ * [How to make Beautiful Ruby Plots with Galaaz](https://medium.freecodecamp.org/how-to-make-beautiful-ruby-plots-with-galaaz-320848058857) (plots; narrative partly pre-2.0)
808
+ * [Ruby Plotting with Galaaz in GraalVM](https://towardsdatascience.com/ruby-plotting-with-galaaz-an-example-of-tightly-coupling-ruby-and-r-in-graalvm-520b69e21021) (older stack; ideas still useful)
809
+ * [How to do reproducible research in Ruby with gKnit](https://towardsdatascience.com/how-to-do-reproducible-research-in-ruby-with-gknit-c26d2684d64e)
810
+ * [R for Data Science](https://r4ds.had.co.nz/)
811
+ * [Advanced R](https://adv-r.hadley.nz/)
812
+ * Historical context: [GraalVM](https://www.graalvm.org/), [TruffleRuby](https://github.com/oracle/truffleruby), [FastR](https://github.com/oracle/fastr)
813
+
688
814
  # Conclusion
689
815
 
690
816
  Ruby and Galaaz provide a nice framework for developing code that uses R functions. Although R is