galaaz 0.5.0 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (359) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +26 -0
  3. data/LICENSE +0 -0
  4. data/README.md +1360 -636
  5. data/Rakefile +61 -41
  6. data/bin/galaaz-bootstrap +137 -0
  7. data/bin/galaaz-jruby +14 -0
  8. data/bin/galaaz_jruby_env.inc.sh +6 -0
  9. data/bin/gbookdown +64 -0
  10. data/bin/gknit +84 -13
  11. data/bin/gknit-draft.rb +0 -0
  12. data/bin/gstudio +5 -3
  13. data/bin/gstudio_irb.rb +0 -0
  14. data/bin/gstudio_pry.rb +0 -0
  15. data/bin/install-tinytex +6 -0
  16. data/bin/run_all_rspec +43 -0
  17. data/bin/run_example +14 -0
  18. data/bin/run_old_rspec +19 -0
  19. data/bin/run_rspec +23 -0
  20. data/bin/run_rspec_subset +38 -0
  21. data/bin/run_slow_rspec +19 -0
  22. data/blogs/R-on-Rails-Planning-Document.md +940 -0
  23. data/blogs/README.md +100 -0
  24. data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -66
  25. data/blogs/galaaz_ggplot/galaaz_ggplot.log +754 -0
  26. data/blogs/galaaz_ggplot/galaaz_ggplot.md +115 -155
  27. data/blogs/galaaz_ggplot/galaaz_ggplot.tex +607 -0
  28. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
  29. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
  30. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
  31. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
  32. data/blogs/galaaz_ggplot/midwest.Rmd +3 -3
  33. data/blogs/galaaz_ggplot/midwest_external_png +0 -0
  34. data/blogs/gknit/gknit.Rmd +47 -52
  35. data/blogs/gknit/gknit.md +1430 -0
  36. data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
  37. data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
  38. data/blogs/gknit/lst.rds +0 -0
  39. data/blogs/gknit/model.rb +1 -1
  40. data/blogs/gknit/stats.bib +0 -0
  41. data/blogs/manual/include_model_local_repro.Rmd +14 -0
  42. data/blogs/manual/include_model_local_repro.md +75 -0
  43. data/blogs/manual/lst.rds +0 -0
  44. data/blogs/manual/manual.Rmd +852 -239
  45. data/blogs/manual/manual.log +1786 -0
  46. data/blogs/manual/manual.md +1360 -636
  47. data/blogs/manual/manual.tex +1883 -1161
  48. data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
  49. data/blogs/manual/manual_files/figure-html/diverging_bar.png +0 -0
  50. data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
  51. data/blogs/manual/model.rb +1 -1
  52. data/blogs/nse_dplyr/nse_dplyr.Rmd +84 -111
  53. data/blogs/nse_dplyr/nse_dplyr.log +928 -0
  54. data/blogs/nse_dplyr/nse_dplyr.md +198 -229
  55. data/blogs/oh_my/not_so.rb +0 -0
  56. data/blogs/oh_my/oh_my.Rmd +1234 -25
  57. data/blogs/oh_my/oh_my.log +804 -0
  58. data/blogs/oh_my/oh_my.md +1663 -86
  59. data/blogs/oh_my/oh_my.tex +821 -0
  60. data/blogs/oh_my/old.Rmd +15 -14
  61. data/blogs/ruby_plot/ruby_plot.Rmd +58 -82
  62. data/blogs/ruby_plot/ruby_plot.log +885 -0
  63. data/blogs/ruby_plot/ruby_plot.md +71 -102
  64. data/blogs/ruby_plot/ruby_plot.tex +940 -0
  65. data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
  66. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
  67. data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
  68. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
  69. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
  70. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
  71. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
  72. data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
  73. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
  74. data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
  75. data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
  76. data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
  77. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
  78. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
  79. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
  80. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
  81. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
  82. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
  83. data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
  84. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
  85. data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
  86. data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
  87. data/blogs/test/test.Rmd +14 -0
  88. data/examples/50Plots_MasterList/Images/midwest-scatterplot.PNG +0 -0
  89. data/examples/50Plots_MasterList/ScatterPlot.rb +0 -0
  90. data/examples/50Plots_MasterList/scatter_plot.rb +0 -0
  91. data/examples/Bibliography/master.bib +0 -0
  92. data/examples/Bibliography/stats.bib +0 -0
  93. data/examples/R/calc.R +0 -0
  94. data/examples/R/java_interop.R +0 -0
  95. data/examples/bioconductor_deseq2_airway/Documentation/DESeq2-airway-walkthrough.md +56 -0
  96. data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +53 -0
  97. data/examples/bioconductor_deseq2_airway/bench_r_three_same_process.R +34 -0
  98. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +33 -0
  99. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +34 -0
  100. data/examples/bioconductor_deseq2_airway/deseq2_airway_minimal.R +30 -0
  101. data/examples/bioconductor_deseq2_airway/deseq2_airway_pipeline_for_bench.R +36 -0
  102. data/examples/islr/all.rb +13 -0
  103. data/examples/islr/ch2.spec.rb +37 -7
  104. data/examples/islr/ch3.spec.rb +11 -2
  105. data/examples/islr/ch3_boston.rb +27 -0
  106. data/examples/islr/ch3_multiple_regression.rb +0 -0
  107. data/examples/islr/ch6.spec.rb +24 -1
  108. data/examples/islr/x_y_rnorm.jpg +0 -0
  109. data/examples/latex_templates/Test-acm_article/acm_proc_article-sp.cls +0 -0
  110. data/examples/latex_templates/Test-acm_article/sigproc.bib +0 -0
  111. data/examples/latex_templates/Test-acs_article/acs-Test-acs_article.bib +0 -0
  112. data/examples/latex_templates/Test-acs_article/acs-my_output.bib +0 -0
  113. data/examples/latex_templates/Test-aea_article/BibFile.bib +0 -0
  114. data/examples/latex_templates/Test-aea_article/Test-aea_article.Rmd +0 -0
  115. data/examples/latex_templates/Test-aea_article/references.bib +0 -0
  116. data/examples/latex_templates/Test-amq_article/Test-amq_article.Rmd +0 -0
  117. data/examples/latex_templates/Test-amq_article/Test-amq_article.pdfsync +0 -0
  118. data/examples/latex_templates/Test-ieee_article/IEEEtran.bst +0 -0
  119. data/examples/latex_templates/Test-ieee_article/mybibfile.bib +0 -0
  120. data/examples/latex_templates/Test-rjournal_article/RJournal.sty +0 -0
  121. data/examples/latex_templates/Test-rjournal_article/RJreferences.bib +0 -0
  122. data/examples/latex_templates/Test-rjournal_article/Test-rjournal_article.Rmd +0 -0
  123. data/examples/misc/baseball.csv +0 -0
  124. data/examples/misc/ggplot.rb +3 -2
  125. data/examples/misc/moneyball.rb +0 -0
  126. data/examples/misc/subsetting.rb +0 -0
  127. data/examples/multithread_shards_to_r/shards_to_r.rb +67 -0
  128. data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.Rmd +0 -0
  129. data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.Rmd +0 -0
  130. data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.Rmd +0 -0
  131. data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.Rmd +0 -0
  132. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/attend-grade-relationships.csv +0 -0
  133. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.Rmd +0 -0
  134. data/examples/rmarkdown/svm-xaringan-example/svm-xaringan-example.Rmd +0 -0
  135. data/examples/sthda_ggplot/README.md +0 -0
  136. data/examples/sthda_ggplot/RUN.md +41 -0
  137. data/examples/sthda_ggplot/all.rb +0 -0
  138. data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +0 -0
  139. data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +0 -0
  140. data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +2 -0
  141. data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +0 -0
  142. data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +0 -0
  143. data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +0 -0
  144. data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +0 -0
  145. data/examples/sthda_ggplot/one_variable_continuous/stat.rb +0 -0
  146. data/examples/sthda_ggplot/one_variable_discrete/bar.rb +0 -0
  147. data/examples/sthda_ggplot/qplots/box_violin_dot.rb +0 -0
  148. data/examples/sthda_ggplot/qplots/scatter_plots.rb +0 -0
  149. data/examples/sthda_ggplot/scatter_gg.rb +0 -0
  150. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +0 -0
  151. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +0 -0
  152. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +0 -0
  153. data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +0 -0
  154. data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +0 -0
  155. data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +0 -0
  156. data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +4 -3
  157. data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +0 -0
  158. data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +0 -0
  159. data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +0 -0
  160. data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +0 -0
  161. data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +0 -0
  162. data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +0 -0
  163. data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +0 -0
  164. data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +0 -0
  165. data/ext/new_bridge/Makefile +46 -0
  166. data/ext/new_bridge/galaaz_gatekeeper_phase0.cpp +12 -0
  167. data/ext/new_bridge/galaaz_gatekeeper_phase1.cpp +1639 -0
  168. data/lib/R_interface/galaaz_device.R +20 -0
  169. data/lib/R_interface/include_engine.R +109 -0
  170. data/lib/R_interface/new_bridge_adapter.rb +824 -0
  171. data/lib/R_interface/r.rb +177 -25
  172. data/lib/R_interface/r_arrow.rb +113 -0
  173. data/lib/R_interface/r_libs.R +3 -3
  174. data/lib/R_interface/r_methods.rb +13 -126
  175. data/lib/R_interface/r_module_s.rb +0 -0
  176. data/lib/R_interface/rbinary_operators.rb +20 -2
  177. data/lib/R_interface/rclosure.rb +5 -1
  178. data/lib/R_interface/rdata_frame.rb +34 -70
  179. data/lib/R_interface/rdevice.rb +125 -0
  180. data/lib/R_interface/rdevices.R +0 -0
  181. data/lib/R_interface/renvironment.rb +10 -4
  182. data/lib/R_interface/rexpression.rb +5 -1
  183. data/lib/R_interface/rindexed_object.rb +41 -13
  184. data/lib/R_interface/rlanguage.rb +20 -62
  185. data/lib/R_interface/rlist.rb +115 -25
  186. data/lib/R_interface/rlogical_operators.rb +0 -0
  187. data/lib/R_interface/rmatrix.rb +2 -11
  188. data/lib/R_interface/rmd_indexed_object.rb +5 -1
  189. data/lib/R_interface/robject.rb +348 -290
  190. data/lib/R_interface/rpkg.rb +0 -0
  191. data/lib/R_interface/rsupport.rb +609 -328
  192. data/lib/R_interface/rsupport_scope.rb +2 -1
  193. data/lib/R_interface/rsymbol.rb +50 -0
  194. data/lib/R_interface/ruby_callback.rb +2 -3
  195. data/lib/R_interface/ruby_extensions.rb +225 -175
  196. data/lib/R_interface/runary_operators.rb +0 -0
  197. data/lib/R_interface/rvector.rb +147 -31
  198. data/lib/galaaz.rb +0 -0
  199. data/lib/galaaz_jruby.rb +22 -0
  200. data/lib/gknit/diagnostics.rb +50 -0
  201. data/lib/gknit/draft.rb +23 -17
  202. data/lib/gknit/include_engine.rb +15 -7
  203. data/lib/gknit/knitr_engine.rb +223 -74
  204. data/lib/gknit/rb_engine.rb +3 -3
  205. data/lib/gknit/ruby_engine.rb +0 -0
  206. data/lib/gknit.rb +1 -0
  207. data/lib/new_bridge/bootstrap/windows_bootstrap.rb +285 -0
  208. data/lib/new_bridge/envelope.rb +51 -0
  209. data/lib/new_bridge/eval_result.rb +26 -0
  210. data/lib/new_bridge/framing.rb +39 -0
  211. data/lib/new_bridge/instance_pool_client.rb +38 -0
  212. data/lib/new_bridge/r_instance_manager.rb +404 -0
  213. data/lib/new_bridge/session_client.rb +530 -0
  214. data/lib/new_bridge/tcp_framed.rb +44 -0
  215. data/lib/new_bridge.rb +9 -0
  216. data/lib/util/exec_ruby.rb +95 -20
  217. data/lib/util/inline_file.rb +35 -30
  218. data/new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb +96 -0
  219. data/new_bridge_specs/eval_r_async_spec.rb +113 -0
  220. data/new_bridge_specs/integration_phase5_1_concurrent_spec.rb +50 -0
  221. data/new_bridge_specs/integration_phase5_1_eval_spec.rb +16 -0
  222. data/new_bridge_specs/integration_phase5_1_r_api_spec.rb +25 -0
  223. data/new_bridge_specs/integration_phase5_1_smoke_spec.rb +31 -0
  224. data/new_bridge_specs/integration_phase5_2_dataframe_unboxing_spec.rb +19 -0
  225. data/new_bridge_specs/integration_phase5_2_handle_eval_unboxing_spec.rb +25 -0
  226. data/new_bridge_specs/integration_phase5_3_callback_args_spec.rb +28 -0
  227. data/new_bridge_specs/integration_phase5_3_callback_error_spec.rb +22 -0
  228. data/new_bridge_specs/integration_phase5_3_callback_timeout_spec.rb +28 -0
  229. data/new_bridge_specs/integration_phase5_3_callbacks_smoke_spec.rb +22 -0
  230. data/new_bridge_specs/integration_phase5_3_edge_cases_spec.rb +52 -0
  231. data/new_bridge_specs/integration_phase5_3_nested_spec.rb +30 -0
  232. data/new_bridge_specs/integration_phase5_4_concurrent_sessions_spec.rb +53 -0
  233. data/new_bridge_specs/integration_phase5_4_nested_session_callbacks_spec.rb +49 -0
  234. data/new_bridge_specs/integration_phase5_4_session_routing_spec.rb +38 -0
  235. data/new_bridge_specs/integration_phase5_5_stress_concurrency_spec.rb +52 -0
  236. data/new_bridge_specs/integration_phase5_5_unbox_walk_spec.rb +46 -0
  237. data/new_bridge_specs/phase0_protocol_spec.rb +96 -0
  238. data/new_bridge_specs/phase1_req_ret_spec.rb +66 -0
  239. data/new_bridge_specs/phase2_multi_instance_spec.rb +67 -0
  240. data/new_bridge_specs/phase3_callbacks_spec.rb +71 -0
  241. data/new_bridge_specs/phase4_2_hardening_spec.rb +252 -0
  242. data/new_bridge_specs/phase4_3_r_instance_manager_spec.rb +85 -0
  243. data/new_bridge_specs/phase4_nested_callbacks_spec.rb +123 -0
  244. data/r_requires/ggplot.rb +0 -0
  245. data/r_requires/knitr.rb +0 -0
  246. data/specs/all.rb +15 -11
  247. data/specs/arrow_from_ruby_batches_spec.rb +50 -0
  248. data/specs/arrow_semantics_spec.rb +64 -0
  249. data/specs/bridge_concurrent_spec.rb +46 -0
  250. data/specs/bridge_nested_spec.rb +25 -0
  251. data/specs/dataframe_semantics_spec.rb +122 -0
  252. data/specs/dataframe_single_index_logical_filter_spec.rb +21 -0
  253. data/specs/dispatch_probe_cache_spec.rb +38 -0
  254. data/specs/dispatch_probe_error_class_fallback_spec.rb +20 -0
  255. data/specs/dispatch_probe_fallback_spec.rb +18 -0
  256. data/specs/environment_semantics_spec.rb +89 -0
  257. data/specs/field_access_spec.rb +31 -0
  258. data/specs/figures/bg.jpeg +0 -0
  259. data/specs/figures/bg.png +0 -0
  260. data/specs/figures/bg.svg +168 -57
  261. data/specs/figures/dose_len.png +0 -0
  262. data/specs/figures/no_args.jpeg +0 -0
  263. data/specs/figures/no_args.png +0 -0
  264. data/specs/figures/no_args.svg +168 -57
  265. data/specs/figures/width_height.jpeg +0 -0
  266. data/specs/figures/width_height.png +0 -0
  267. data/specs/figures/width_height_units1.jpeg +0 -0
  268. data/specs/figures/width_height_units1.png +0 -0
  269. data/specs/figures/width_height_units2.jpeg +0 -0
  270. data/specs/figures/width_height_units2.png +0 -0
  271. data/specs/formula_semantics_spec.rb +81 -0
  272. data/specs/galaaz_util_exec_ruby_spec.rb +85 -0
  273. data/specs/galaaz_util_inline_file_spec.rb +54 -0
  274. data/specs/gknit_cli_option_permutation_spec.rb +24 -0
  275. data/specs/gknit_include_engine_spec.rb +72 -0
  276. data/specs/gknit_install_timeout_report_spec.rb +69 -0
  277. data/specs/gknit_internal_error_report_spec.rb +57 -0
  278. data/specs/gknit_vector_map_output_spec.rb +59 -0
  279. data/specs/globalenv_guardrail_spec.rb +52 -0
  280. data/specs/language_expression_semantics_spec.rb +145 -0
  281. data/specs/list_semantics_spec.rb +111 -0
  282. data/specs/new_bridge_bulk_dataframe_transfer_spec.rb +44 -0
  283. data/specs/new_bridge_bulk_vector_transfer_spec.rb +73 -0
  284. data/specs/new_bridge_callback_timeout_spec.rb +69 -0
  285. data/specs/new_bridge_eval_r_fallback_spec.rb +55 -0
  286. data/specs/nil_null_spec.rb +42 -0
  287. data/specs/object_build_phase2_spec.rb +53 -0
  288. data/specs/phase1_callback_bridge_spec.rb +84 -0
  289. data/specs/phase2_gknit_generic_rendering_guardrail_spec.rb +46 -0
  290. data/specs/phase2_gknit_no_raw_code_leakage_spec.rb +43 -0
  291. data/specs/phase3_gknit_generic_graphics_capture_spec.rb +71 -0
  292. data/specs/plot_device_semantics_spec.rb +28 -0
  293. data/specs/plot_snapshot_semantics_spec.rb +58 -0
  294. data/specs/protocol_result_spec.rb +236 -0
  295. data/specs/r_batch_fail_fast_spec.rb +47 -0
  296. data/specs/r_bridge_bootstrap_spec.rb +11 -0
  297. data/specs/r_devices.spec.rb +1 -1
  298. data/specs/r_eval.spec.rb +16 -18
  299. data/specs/r_function.spec.rb +1 -1
  300. data/specs/r_instance_manager_spec.rb +285 -0
  301. data/specs/r_list_apply.spec.rb +15 -15
  302. data/specs/r_matrix.spec.rb +0 -0
  303. data/specs/r_nse.spec.rb +5 -5
  304. data/specs/r_object_send_dispatch_spec.rb +13 -0
  305. data/specs/r_vector_comparator_spec.rb +8 -0
  306. data/specs/r_vector_creation.spec.rb +0 -0
  307. data/specs/r_vector_functions.spec.rb +0 -0
  308. data/specs/r_vector_object.spec.rb +0 -0
  309. data/specs/r_vector_operators.spec.rb +0 -0
  310. data/specs/r_vector_structured_scalar_reads_spec.rb +35 -0
  311. data/specs/r_vector_subsetting.spec.rb +0 -0
  312. data/specs/range_helper_spec.rb +21 -0
  313. data/specs/rsupport_scope_spec.rb +28 -0
  314. data/specs/rsupport_var_name_thread_safety_spec.rb +24 -0
  315. data/specs/scalar_character_spec.rb +44 -0
  316. data/specs/scoped_symbol_dsl_refinement_spec.rb +40 -0
  317. data/specs/session_env_bridge_spec.rb +25 -0
  318. data/specs/simplecov_bootstrap_spec.rb +10 -0
  319. data/specs/spec_helper.rb +10 -0
  320. data/specs/tmp.rb +0 -0
  321. data/specs/unboxing_recursion_regression_spec.rb +30 -0
  322. data/specs/unboxing_spec.rb +49 -0
  323. data/specs/verify_callbacks.rb +42 -0
  324. data/sty/galaaz.sty +0 -0
  325. data/version.rb +1 -1
  326. metadata +194 -64
  327. data/blogs/galaaz_ggplot/galaaz_ggplot.html +0 -520
  328. data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
  329. data/blogs/galaaz_ggplot/midwest.html +0 -188
  330. data/blogs/gknit/gknit.html +0 -2266
  331. data/blogs/gknit/gknit.pdf +0 -0
  332. data/blogs/manual/manual.html +0 -4638
  333. data/blogs/manual/manual.pdf +0 -0
  334. data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
  335. data/blogs/nse_dplyr/nse_dplyr.html +0 -878
  336. data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
  337. data/blogs/oh_my/oh_my.html +0 -568
  338. data/blogs/ruby_plot/ruby_plot.html +0 -544
  339. data/blogs/ruby_plot/ruby_plot.pdf +0 -0
  340. data/examples/latex_templates/Test-acs_article/Test-acs_article.pdf +0 -0
  341. data/examples/latex_templates/Test-aea_article/Test-aea_article.pdf +0 -0
  342. data/examples/latex_templates/Test-amq_article/Test-amq_article.pdf +0 -0
  343. data/examples/latex_templates/Test-amq_article/pics/Figure2.pdf +0 -0
  344. data/examples/latex_templates/Test-asa_article/Test-asa_article.pdf +0 -0
  345. data/examples/latex_templates/Test-ieee_article/Test-ieee_article.pdf +0 -0
  346. data/examples/latex_templates/Test-rjournal_article/RJwrapper.pdf +0 -0
  347. data/examples/latex_templates/Test-springer_article/Test-springer_article.pdf +0 -0
  348. data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.pdf +0 -0
  349. data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.pdf +0 -0
  350. data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.pdf +0 -0
  351. data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.pdf +0 -0
  352. data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.pdf +0 -0
  353. data/specs/r_dataframe.spec.rb +0 -379
  354. data/specs/r_environment.spec.rb +0 -140
  355. data/specs/r_formula.spec.rb +0 -232
  356. data/specs/r_language.spec.rb +0 -112
  357. data/specs/r_list.spec.rb +0 -293
  358. data/specs/r_plots.spec.rb +0 -72
  359. data/specs/ruby_expression.spec.rb +0 -316
data/README.md CHANGED
@@ -1,16 +1,17 @@
1
1
  ---
2
2
  title: "Galaaz Manual"
3
- subtitle: "How to tightly couple Ruby and R in GraalVM"
3
+ subtitle: "Coupling Ruby (JRuby) and GNU R for data science"
4
4
  author: "Rodrigo Botafogo"
5
- tags: [Galaaz, Ruby, R, TruffleRuby, FastR, GraalVM, ggplot2]
6
- date: "2019"
7
- bibliography: "/home/rbotafogo/Bibliography/stats.bib"
5
+ tags: [Galaaz, Ruby, JRuby, R, "GNU R", ggplot2, knitr, dplyr, Bioconductor, Arrow]
6
+ date: "2026"
7
+ bibliography: "../../examples/Bibliography/stats.bib"
8
8
  output:
9
9
  html_document:
10
10
  self_contained: true
11
11
  keep_md: true
12
- md_document:
13
- variant: markdown_github
12
+ toc: true
13
+ toc_depth: 3
14
+ number_sections: true
14
15
  pdf_document:
15
16
  includes:
16
17
  in_header: "../../sty/galaaz.sty"
@@ -18,6 +19,8 @@ output:
18
19
  number_sections: yes
19
20
  toc: true
20
21
  toc_depth: 3
22
+ md_document:
23
+ variant: markdown_github
21
24
  fontsize: 11pt
22
25
  ---
23
26
 
@@ -29,8 +32,9 @@ Galaaz is a system for tightly coupling Ruby and R. Ruby is a powerful language,
29
32
  community, a very large set of libraries and great for web development. However, it lacks
30
33
  libraries for data science, statistics, scientific plotting and machine learning. On the
31
34
  other hand, R is considered one of the most powerful languages for solving all of the above
32
- problems. Maybe the strongest competitor to R is Python with libraries such as NumPy,
33
- Panda, SciPy, SciKit-Learn and a couple more.
35
+ problems. **Python** is a strong competitor: NumPy, pandas, SciPy, and scikit-learn are
36
+ widely used building blocks, and **PyPI** hosts many thousands of other packages for
37
+ numerical work, machine learning, and beyond.
34
38
 
35
39
  With Galaaz we do not intend to re-implement any of the scientific libraries in R, we allow
36
40
  for very tight coupling between the two languages to the point that the Ruby developer does
@@ -41,59 +45,39 @@ general-purpose programming language. It was designed and developed in the mid-1
41
45
  "Matz" Matsumoto in Japan." It reached high popularity with the development of Ruby on Rails
42
46
  (RoR) by David Heinemeier Hansson. RoR is a web application framework first released
43
47
  around 2005. It makes extensive use of Ruby's metaprogramming features. With RoR,
44
- Ruby became very popular. According to [Ruby's Tiobe index](https://www.tiobe.com/tiobe-index/ruby/)
45
- it peeked in popularity around 2008, then declined until 2015 when it started picking up again.
46
- At the time of this writing (November 2018), the Tiobe index puts Ruby in 16th position as
47
- most popular language.
48
+ Ruby became very popular. According to [Ruby’s place in the TIOBE index](https://www.tiobe.com/tiobe-index/ruby/)
49
+ it peaked in popularity around 2008, then declined until 2015 when it started picking up again.
50
+ Ruby remains a significant language in web development and general-purpose scripting.
48
51
 
49
52
  Python, a language similar to Ruby, ranks 4th in the index. Java, C and C++ take the
50
53
  first three positions. Ruby is often criticized for its focus on web applications.
51
54
  But Ruby can do [much more](https://github.com/markets/awesome-ruby) than just web applications.
52
- Yet, for scientific computing, Ruby lags way behind Python and R. Python has
53
- Django framework for web, NumPy for numerical arrays, Pandas for data analysis.
55
+ Yet, for scientific computing, Ruby lags behind Python and R. Python offers Django and
56
+ similar frameworks for the web, plus NumPy, pandas, and a deep catalog of science and ML libraries.
54
57
  R is a free software environment for statistical computing and graphics with thousands
55
58
  of libraries for data analysis.
56
59
 
57
60
  Until recently, there was no real perspective for Ruby to bridge this gap.
58
61
  Implementing a complete scientific computing infrastructure would take too long.
59
- Enters [Oracle's GraalVM](https://www.graalvm.org/):
60
-
61
- > GraalVM is a universal virtual machine for running applications written in
62
- > JavaScript, Python 3, Ruby, R, JVM-based languages like Java, Scala, Kotlin,
63
- > and LLVM-based languages such as C and C++.
64
- >
65
- > GraalVM removes the isolation between programming languages and enables
66
- > interoperability in a shared runtime. It can run either standalone or in the
67
- > context of OpenJDK, Node.js, Oracle Database, or MySQL.
68
- >
69
- > GraalVM allows you to write polyglot applications with a seamless way to pass
70
- > values from one language to another. With GraalVM there is no copying or
71
- > marshaling necessary as it is with other polyglot systems. This lets you
72
- > achieve high performance when language boundaries are crossed. Most of the time
73
- > there is no additional cost for crossing a language boundary at all.
74
- >
75
- > Often developers have to make uncomfortable compromises that require them
76
- > to rewrite their software in other languages. For example:
77
- >
78
- > * That library is not available in my language. I need to rewrite it.
79
- > * That language would be the perfect fit for my problem, but we cannot
80
- > run it in our environment.
81
- > * That problem is already solved in my language, but the language is
82
- > too slow.
83
- >
84
- > With GraalVM we aim to allow developers to freely choose the right language for
85
- > the task at hand without making compromises.
86
-
87
- As stated above, GraalVM is a _universal_ virtual machine that allows Ruby and R (and other
88
- languages) to run on the same environment. GraalVM allows polyglot applications to
89
- _seamlessly_ interact with one another and pass values from one language to the other.
90
- Although a great idea, GraalVM still requires application writers to know several languages.
91
- To eliminate that requirement, we built Galaaz, a gem for Ruby, to tightly couple
92
- Ruby and R and allow those languages to interact in a way that the user will be unaware
93
- of such interaction. In other words, a Ruby programmer will be able to use all
94
- the capabilities of R without knowing the R syntax.
95
-
96
- Library wrapping is a usual way of bringing features from one language into another.
62
+
63
+ **Galaaz 2.0** couples **JRuby** (Ruby on the JVM) with **GNU R**—the same R you use for
64
+ CRAN and Bioconductor. Ruby and R run in **separate processes**; the **Galaaz bridge**
65
+ sends requests to R and returns results to Ruby. From your point of view you still write
66
+ Ruby: `R.c(...)`, `R.library('ggplot2')`, `~R[:mtcars]`, and dplyr-style chains on R objects.
67
+ You do not need to learn R syntax to get a lot done, though reading R documentation for
68
+ individual packages remains useful.
69
+
70
+ Earlier experiments with Galaaz used Oracle’s **GraalVM** with TruffleRuby and FastR so that
71
+ Ruby and R could share one runtime. That path is no longer the focus: **standard GNU R**
72
+ gives full compatibility with the R package ecosystem (including compiled extensions and
73
+ Bioconductor) while JRuby gives a mature Ruby with **real multithreading** for application
74
+ and I/O code.
75
+
76
+ The bridge handles **communication and typing** between the two worlds; large tables can
77
+ also flow through **Apache Arrow** on the R side when you use the optional helpers described
78
+ later in this manual.
79
+
80
+ Library wrapping is a common way to bring features from one language into another.
97
81
  To improve performance, Python often wraps more efficient C libraries. For the
98
82
  Python developer, the existence of such C libraries is hidden. The problem with
99
83
  library wrapping is that for any new library, there is the need to handcraft a new
@@ -118,27 +102,265 @@ Galaaz is the Portuguese name for "Galahad". From Wikipedia:
118
102
  His name should not be mistaken with Galehaut, a different knight from
119
103
  Arthurian legend.
120
104
 
105
+ # Command-line tools (`bin/`)
106
+
107
+ The Galaaz repository ships many helpers under **`bin/`**. When working from a **clone**, call
108
+ them as **`bin/<name>`** from the project root (or `./bin/<name>`). If you install the **gem**,
109
+ only a subset is guaranteed on your `PATH` (see the gemspec: **`galaaz`**, **`gstudio`**, **`gknit`**, **`grun`**, **`gknit-draft`**); for development and CI, prefer the **`bin/`** copies so JVM flags and paths stay correct.
110
+
111
+ Below, **current (Galaaz 2.0 + JRuby + GNU R)** means the tool is wired to **`jruby`** and
112
+ **`bin/galaaz_jruby_env.inc.sh`** (or equivalent logic in Ruby via `lib/galaaz_jruby.rb`). **Legacy**
113
+ means the script still targets **GraalVM** polyglot Ruby / FastR-era invocation and is **not**
114
+ expected to work on a typical JRuby-only setup.
115
+
116
+ **Table layout:** names in the first column are **`bin/`** filenames (run as `bin/<name>` from the repo root). Long options and examples sit **outside** the tables so PDF columns stay readable.
117
+
118
+
119
+
120
+ <table class="table table-striped table-condensed" style="margin-left: auto; margin-right: auto;">
121
+ <thead>
122
+ <tr>
123
+ <th style="text-align:left;"> Script </th>
124
+ <th style="text-align:left;"> Role </th>
125
+ <th style="text-align:left;"> 2.0? </th>
126
+ </tr>
127
+ </thead>
128
+ <tbody>
129
+ <tr>
130
+ <td style="text-align:left;"> galaaz-bootstrap </td>
131
+ <td style="text-align:left;"> WSL2 helper: Docker checks; optional TinyTeX or poppler for gKnit PDF. </td>
132
+ <td style="text-align:left;"> Yes* </td>
133
+ </tr>
134
+ <tr>
135
+ <td style="text-align:left;"> galaaz-jruby </td>
136
+ <td style="text-align:left;"> JRuby with repo lib/ on LOAD_PATH and required JVM flags (e.g. Arrow). </td>
137
+ <td style="text-align:left;"> Yes </td>
138
+ </tr>
139
+ <tr>
140
+ <td style="text-align:left;"> galaaz_jruby_env.inc.sh </td>
141
+ <td style="text-align:left;"> Sourced by bash wrappers; sets GALAAZ_REQUIRED_JRUBY_J_ARGS. </td>
142
+ <td style="text-align:left;"> Yes† </td>
143
+ </tr>
144
+ <tr>
145
+ <td style="text-align:left;"> install-tinytex </td>
146
+ <td style="text-align:left;"> Install TinyTeX for PDF output. </td>
147
+ <td style="text-align:left;"> Yes </td>
148
+ </tr>
149
+ </tbody>
150
+ </table>
151
+
152
+ \* Where WSL/Docker apply. **`galaaz-bootstrap` flags:** `--check`, `--apply`, `--runtime` (`docker` \| `local` \| `auto`), `--[no-]prompt-doc-tools`.
153
+
154
+ † Not run directly.
155
+
156
+ **`galaaz-jruby` examples** (from repo root):
157
+
158
+ ```text
159
+ bin/galaaz-jruby my_script.rb
160
+ bin/galaaz-jruby -S rspec
161
+ ```
162
+
163
+ ## Interactive use, examples, and Rake
164
+
165
+ <table class="table table-striped table-condensed" style="margin-left: auto; margin-right: auto;">
166
+ <thead>
167
+ <tr>
168
+ <th style="text-align:left;"> Script </th>
169
+ <th style="text-align:left;"> Role </th>
170
+ <th style="text-align:left;"> 2.0? </th>
171
+ </tr>
172
+ </thead>
173
+ <tbody>
174
+ <tr>
175
+ <td style="text-align:left;"> gstudio </td>
176
+ <td style="text-align:left;"> IRB or Pry with Galaaz preloaded (JRuby + JVM flags). </td>
177
+ <td style="text-align:left;"> Yes </td>
178
+ </tr>
179
+ <tr>
180
+ <td style="text-align:left;"> run_example </td>
181
+ <td style="text-align:left;"> Run one Ruby file using the same JRuby/JVM setup as tests. </td>
182
+ <td style="text-align:left;"> Yes </td>
183
+ </tr>
184
+ <tr>
185
+ <td style="text-align:left;"> galaaz </td>
186
+ <td style="text-align:left;"> Forward arguments to rake (needs rake; usually JRuby). </td>
187
+ <td style="text-align:left;"> Yes </td>
188
+ </tr>
189
+ </tbody>
190
+ </table>
191
+
192
+ ## gKnit and document drafts
193
+
194
+ <table class="table table-striped table-condensed" style="margin-left: auto; margin-right: auto;">
195
+ <thead>
196
+ <tr>
197
+ <th style="text-align:left;"> Script </th>
198
+ <th style="text-align:left;"> Role </th>
199
+ <th style="text-align:left;"> 2.0? </th>
200
+ </tr>
201
+ </thead>
202
+ <tbody>
203
+ <tr>
204
+ <td style="text-align:left;"> gknit </td>
205
+ <td style="text-align:left;"> Knit .Rmd via JRuby and R Markdown render. </td>
206
+ <td style="text-align:left;"> Yes </td>
207
+ </tr>
208
+ <tr>
209
+ <td style="text-align:left;"> gknit-draft </td>
210
+ <td style="text-align:left;"> Drafts from rticles-style templates; wrapper still uses legacy polyglot ruby. </td>
211
+ <td style="text-align:left;"> Legacy </td>
212
+ </tr>
213
+ <tr>
214
+ <td style="text-align:left;"> gknit-draft.rb </td>
215
+ <td style="text-align:left;"> Ruby entry: GKnit.draft (use with JRuby + LOAD_PATH). </td>
216
+ <td style="text-align:left;"> JRuby </td>
217
+ </tr>
218
+ <tr>
219
+ <td style="text-align:left;"> gknit_Rscript </td>
220
+ <td style="text-align:left;"> Polyglot Rscript launcher; hard-coded LOAD_PATH sample. </td>
221
+ <td style="text-align:left;"> No </td>
222
+ </tr>
223
+ </tbody>
224
+ </table>
225
+
226
+ **`gknit` CLI** (see `gknit -h`): `--output_format`, `--output_file`, `--output_dir`, `--bridge_timeout_sec`, `--callback_timeout_ms`. If `--output_format` is omitted, the **first** YAML `output:` target wins.
227
+
228
+ Prefer **`galaaz-jruby`** for **`gknit-draft`** workflows until that wrapper matches the **`gknit`** stack.
229
+
230
+ ## Tests
231
+
232
+ <table class="table table-striped table-condensed" style="margin-left: auto; margin-right: auto;">
233
+ <thead>
234
+ <tr>
235
+ <th style="text-align:left;"> Script </th>
236
+ <th style="text-align:left;"> Role </th>
237
+ <th style="text-align:left;"> 2.0? </th>
238
+ </tr>
239
+ </thead>
240
+ <tbody>
241
+ <tr>
242
+ <td style="text-align:left;"> run_rspec </td>
243
+ <td style="text-align:left;"> Top-level specs/*_spec.rb with spec_helper (see docs/testing.md). </td>
244
+ <td style="text-align:left;"> Yes </td>
245
+ </tr>
246
+ <tr>
247
+ <td style="text-align:left;"> run_all_rspec </td>
248
+ <td style="text-align:left;"> Compile ext/new_bridge; run specs/ and new_bridge_specs/ together. </td>
249
+ <td style="text-align:left;"> Yes </td>
250
+ </tr>
251
+ <tr>
252
+ <td style="text-align:left;"> run_slow_rspec </td>
253
+ <td style="text-align:left;"> Suites under slow-specs/ (read script header for spec_helper). </td>
254
+ <td style="text-align:left;"> Yes </td>
255
+ </tr>
256
+ <tr>
257
+ <td style="text-align:left;"> run_old_rspec </td>
258
+ <td style="text-align:left;"> Legacy suites under old_specs/. </td>
259
+ <td style="text-align:left;"> Yes </td>
260
+ </tr>
261
+ <tr>
262
+ <td style="text-align:left;"> run_rspec_subset </td>
263
+ <td style="text-align:left;"> Numbered subset 1–18 (Documentation/Spec_Subsets.md). </td>
264
+ <td style="text-align:left;"> Yes </td>
265
+ </tr>
266
+ </tbody>
267
+ </table>
268
+
269
+ ## Other
270
+
271
+ <table class="table table-striped table-condensed" style="margin-left: auto; margin-right: auto;">
272
+ <thead>
273
+ <tr>
274
+ <th style="text-align:left;"> Script </th>
275
+ <th style="text-align:left;"> Role </th>
276
+ <th style="text-align:left;"> 2.0? </th>
277
+ </tr>
278
+ </thead>
279
+ <tbody>
280
+ <tr>
281
+ <td style="text-align:left;"> grun </td>
282
+ <td style="text-align:left;"> Graal-era launcher: polyglot ruby with --jvm. Use galaaz-jruby -S instead. </td>
283
+ <td style="text-align:left;"> No </td>
284
+ </tr>
285
+ <tr>
286
+ <td style="text-align:left;"> gstudio_irb.rb / gstudio_pry.rb </td>
287
+ <td style="text-align:left;"> Loaded by gstudio; not meant to be run standalone. </td>
288
+ <td style="text-align:left;"> Yes </td>
289
+ </tr>
290
+ </tbody>
291
+ </table>
292
+
293
+ For day-to-day **2.0** use, rely on **`bin/galaaz-jruby`**, **`bin/gstudio`**, **`bin/gknit`**, **`bin/run_example`**, **`bin/run_rspec`** / **`bin/run_all_rspec`**, and **`bin/galaaz-bootstrap`** on WSL when using Dockerized R. Treat **`grun`**, **`gknit_Rscript`**, and the polyglot **`ruby`** invocation in **`gknit-draft`** as **legacy** until they are ported to the same JRuby path as **`gknit`**.
294
+
121
295
  # System Compatibility
122
296
 
123
- * Oracle Linux 7
124
- * Ubuntu 18.04 LTS
125
- * Ubuntu 16.04 LTS
126
- * Fedora 28
127
- * macOS 10.14 (Mojave)
128
- * macOS 10.13 (High Sierra)
297
+ Typical development and CI targets:
129
298
 
130
- # Dependencies
299
+ * **Linux** — recent Ubuntu LTS or comparable distributions (x86_64).
300
+ * **macOS** — recent releases with JRuby and GNU R available.
301
+ * **Windows** — use **WSL2** (same Linux stack as above); native Windows is not the primary target.
302
+
303
+ The native **gatekeeper** component under `ext/new_bridge` is built with `make` and a C++ toolchain; see the project `README` if compilation fails on your platform.
131
304
 
132
- * TruffleRuby
133
- * FastR
305
+ # Dependencies
134
306
 
307
+ * **JRuby** — Galaaz 2.0 requires JRuby (tested with **10.1.1.0**) and a matching **JDK** (tested with **Java 21**). MRI Ruby is not supported.
308
+ * **GNU R** — `R` and `Rscript` on your `PATH` (tested with **4.3.3**), plus a C++ toolchain (`g++`, `make`) and the **Rcpp** package to compile the gatekeeper.
309
+ * **galaaz gem** — runtime dependency `msgpack` is pulled in by `gem install`.
310
+ * Optional: **Docker** — if you run R in a container (common on WSL2); see bootstrap below.
311
+ * Optional R packages for examples in this manual — e.g. `ggplot2`, `dplyr`, `knitr`, `kableExtra`, `arrow`, Bioconductor tools such as **DESeq2** (installed the usual R way).
135
312
 
136
313
  # Installation
137
314
 
138
- * Install GrallVM (http://www.graalvm.org/)
139
- * Install Ruby (gu install Ruby)
140
- * Install FastR (gu install R)
141
- * Install rake if you want to run the specs and examples (gem install rake)
315
+ The supported install is **`gem install` + compile the gatekeeper**. You do not need a git clone.
316
+
317
+ 1. Install **JRuby**, a compatible **JDK**, and **GNU R** (with `Rscript` and a C++ compiler).
318
+ 2. In R, install **Rcpp**: `install.packages("Rcpp")`.
319
+ 3. Install the gem: `jruby -S gem install galaaz`
320
+ 4. Compile the native gatekeeper from the installed gem:
321
+
322
+ ```
323
+ gem_dir="$(jruby -e "puts Gem::Specification.find_by_name('galaaz').full_gem_path")"
324
+ make -C "${gem_dir}/ext/new_bridge" all
325
+ ```
326
+
327
+ 5. Ensure **`R`** starts GNU R and can install packages (network access to CRAN when you first call `R.install_and_loads`). For **Apache Arrow** on Java 9+, pass `-J--add-opens=java.base/java.nio=ALL-UNNAMED` to JRuby (from a checkout, `bin/galaaz-jruby` does this).
328
+
329
+ For **gKnit**, **knitr**, **rmarkdown**, and LaTeX (PDF output), install the corresponding R packages, **Pandoc**, and a TeX distribution if you need PDF; the repository includes helpers such as **`bin/install-tinytex`** where appropriate.
330
+
331
+ A **table of all `bin/` scripts** (bootstrap, JRuby wrapper, gstudio, gknit, test runners, and which ones are legacy) is in the section **Command-line tools (`bin/`)** earlier in this manual.
332
+
333
+ ### From a repository checkout (contributors)
334
+
335
+ 1. Install **bundler** if needed, then run **`jruby -S bundle install`** in the repository root.
336
+ 2. Build the bridge native code: **`make -C ext/new_bridge all`** (or **`rake compile_gatekeeper`**).
337
+ 3. Run scripts with **`bin/galaaz-jruby`** (sources **`bin/galaaz_jruby_env.inc.sh`** and adds **`-I lib`**).
338
+
339
+ Maintainers can prove a built `.gem` on a throwaway Ubuntu machine (no repo inside the container) with **`./docker/cold-install/run.sh`**.
340
+
341
+ ## Windows + WSL2 (optional: Docker / R in a container)
342
+
343
+ If you run Galaaz on Windows through WSL2 and want containerized R instances,
344
+ Docker Desktop is the supported setup.
345
+
346
+ 1. Install Docker Desktop on Windows:
347
+ - https://www.docker.com/products/docker-desktop/
348
+ 2. Open Docker Desktop and enable WSL integration:
349
+ - Settings > Resources > WSL Integration
350
+ - Enable integration for your target distro
351
+ - Apply & Restart Docker Desktop
352
+ 3. In WSL, run Galaaz bootstrap:
353
+
354
+ > ruby bin/galaaz-bootstrap --apply
355
+ > ruby bin/galaaz-bootstrap --check
356
+
357
+ Expected result:
358
+ - docker CLI available
359
+ - docker compose available
360
+ - docker daemon reachable (`docker info` works)
361
+
362
+ If bootstrap reports daemon is unreachable, check Docker Desktop is running and
363
+ WSL integration is enabled for the distro where Galaaz is installed.
142
364
 
143
365
  # Usage
144
366
 
@@ -147,7 +369,7 @@ Galaaz is the Portuguese name for "Galahad". From Wikipedia:
147
369
  > gstudio
148
370
 
149
371
 
150
- ```ruby
372
+ ``` ruby
151
373
  vec = R.c(1, 2, 3, 4)
152
374
  puts vec
153
375
  ```
@@ -172,7 +394,7 @@ Galaaz is the Portuguese name for "Galahad". From Wikipedia:
172
394
 
173
395
  > galaaz -T
174
396
 
175
- Shows a list with all available executalbe tasks. To execute a task, substitute the
397
+ Shows a list with all available executable tasks. To execute a task, substitute the
176
398
  'rake' word in the list with 'galaaz'. For instance, the following line shows up
177
399
  after 'galaaz -T'
178
400
 
@@ -182,17 +404,209 @@ Galaaz is the Portuguese name for "Galahad". From Wikipedia:
182
404
 
183
405
  > galaaz master_list:scatter_plot
184
406
 
407
+ # JRuby, multithreading, and the R bridge
185
408
 
186
- # Accessing R from Ruby
409
+ Galaaz 2.0 runs Ruby on **JRuby**, so your application can use **real parallel threads** for
410
+ I/O-bound work (HTTP clients, database connections, message consumers, and so on). R itself is
411
+ still executed in a **single GNU R process** behind the Galaaz bridge.
412
+
413
+ When several Ruby threads call into R at the same time, the bridge **serializes** those calls:
414
+ each request is matched to a reply using an internal per-call **queue**, so you do not need to
415
+ add your own mutex around every `R.foo` from application threads. (You should still use normal
416
+ Ruby synchronization when **Ruby** data structures are shared between threads—for example, when
417
+ appending rows from each thread into a shared array before sending them to R.)
418
+
419
+ A practical pattern is:
420
+
421
+ 1. Use threads (or a connection pool) to read from **multiple databases or shards** in parallel.
422
+ 2. Merge the rows in Ruby under a `Mutex` if you collect into one structure.
423
+ 3. Hand the merged table to R **once** (for example with `R::Arrow.from_ruby_batches` and dplyr,
424
+ or by building a data frame) so heavy statistics run in R with fewer bridge round-trips.
425
+
426
+ A runnable sketch lives in
427
+ `examples/multithread_shards_to_r/shards_to_r.rb` (simulated shard queries; swap in your DB
428
+ driver). For concurrency tests on the bridge itself, see `specs/bridge_concurrent_spec.rb` and
429
+ `specs/arrow_from_ruby_batches_spec.rb`.
430
+
431
+ ## Long-running R calls and a completion block
432
+
433
+ For R work that can take a long time, the bridge can avoid a Ruby-side **wait timeout** by
434
+ scheduling the call and resuming in a **block** when the `RET` arrives.
435
+
436
+ - **`R.eval_r_async(code, timeout: nil) { |result| ... }`** — string eval; on success, `result.value`
437
+ is the same formatted string as **`R.eval_r`** (use `timeout: nil` for no Ruby-side limit).
438
+ - **`R::Async.<rname>(...) { |result| ... }`** — same dispatch as **`R.<rname>(...)`**, but async;
439
+ on success, `result.value` is an **`R::Object`** (or unboxed Ruby value / Symbol), like synchronous
440
+ **`R.<rname>`**. Optional keyword **`timeout:`** applies a Ruby-side wait limit (completion receives
441
+ **`NewBridge::SessionClient::TimeoutError`** if R is too slow).
442
+
443
+ **Important:** **`R.foo(...) { |x| }`** is already used for dplyr-style scopes (`R::Support.new_scope`),
444
+ so async R calls must use **`R::Async`** or **`R.eval_r_async`**, not a bare **`R.foo` with a block.**
445
+
446
+ `NewBridge::EvalResult` exposes **`#ok?`**, **`#value`**, and **`#error`**. The completion block runs on a
447
+ **background thread** (not the bridge reader thread).
448
+
449
+ The example below is **plain Ruby** (no Rails). The R snippet sleeps (standing in for heavy work) and then
450
+ returns an integer so the success branch shows a **non-nil** value. (`Sys.sleep` alone returns **NULL** in R;
451
+ on success **`result.value`** is then **`nil`** in Ruby—that is expected, not a bridge error.)
452
+
453
+
454
+ ``` ruby
455
+ require 'thread'
456
+
457
+ completion = Queue.new
458
+
459
+ R.eval_r_async('({ Sys.sleep(0.3); 42L })', timeout: nil) do |result|
460
+ if result.ok?
461
+ puts "[completion] R finished; eval_r-style value: #{result.value.inspect}"
462
+ else
463
+ puts "[completion] R/bridge error: #{result.error.class}: #{result.error.message}"
464
+ end
465
+ completion.push(:done)
466
+ end
467
+
468
+ 3.times do |i|
469
+ puts "[main] other Ruby work step #{i + 1}"
470
+ sleep 0.05
471
+ end
472
+
473
+ completion.pop
474
+ puts "[main] R completion has run; exiting."
475
+ ```
476
+
477
+ ```
478
+ ## [main] other Ruby work step 1
479
+ ## [main] other Ruby work step 2
480
+ ## [main] other Ruby work step 3
481
+ ## [completion] R finished; eval_r-style value: "[1] 42"
482
+ ## [main] R completion has run; exiting.
483
+ ```
484
+
485
+ In a **web application**, the HTTP response usually ends before R finishes, so you would not
486
+ `Queue#pop` in the controller; you would persist an identifier, let the completion block write
487
+ the outcome to storage, and notify the client (poll, WebSocket, Turbo Stream, etc.). The plain
488
+ Ruby pattern above is only to show **when** the result exists (inside the block, or after data
489
+ written there is observed elsewhere). Runnable specs live in **`new_bridge_specs/eval_r_async_spec.rb`**.
490
+
491
+ ## Galaaz + Rails (JRuby) integration baseline
492
+
493
+ This section documents the baseline we used to create a working Rails app with Galaaz in WSL.
494
+ The goals were:
495
+
496
+ 1. Rails boots under **JRuby**.
497
+ 2. Galaaz is loaded from a local checkout (before publishing to RubyGems).
498
+ 3. A request path can execute **`R.eval(...)`** and return a result.
499
+
500
+ ### 1) Create the app with JRuby-friendly options
501
+
502
+ Rails defaults can pull gems that are not ideal on JRuby-first setups (for example sqlite native
503
+ extension paths and deployment extras). A minimal app avoids early friction:
504
+
505
+ ```bash
506
+ cd /home/rbotafogo/desenv_linux
507
+ jruby -S rails new hedi --skip-git --minimal --skip-kamal --skip-solid --skip-active-record
508
+ ```
509
+
510
+ Then install gems:
511
+
512
+ ```bash
513
+ cd /home/rbotafogo/desenv_linux/hedi
514
+ jruby -S bundle install
515
+ ```
516
+
517
+ ### 2) Use Galaaz as a local path gem
518
+
519
+ For local development we keep a stable path:
187
520
 
188
- One of the nice aspects of Galaaz on GraalVM, is that variables and functions defined in R, can
189
- be easily accessed from Ruby. For instance, to access the 'mtcars' data frame from R
190
- in Ruby, we use the ':mtcar' symbol preceded by the '~' operator, thus '~:r_vec' retrieves the
191
- value of the 'mtcars' variable.
521
+ - `~/gems/galaaz` -> symlink to your Galaaz checkout
522
+ - optional built gem archive in `~/gems/pkg/`
192
523
 
524
+ In Rails `Gemfile`:
193
525
 
194
526
  ```ruby
195
- puts ~:mtcars
527
+ gem "galaaz", path: "/home/rbotafogo/gems/galaaz", require: false
528
+ ```
529
+
530
+ And load after Rails boot in `config/application.rb`:
531
+
532
+ ```ruby
533
+ config.after_initialize { require "galaaz" }
534
+ ```
535
+
536
+ Why `require: false` + `after_initialize`? In this integration, loading Galaaz too early via
537
+ `Bundler.require` triggered Rails/JRuby initialization failures.
538
+
539
+ ### 3) Simple request-path smoke test
540
+
541
+ A direct smoke test from Rails runner:
542
+
543
+ ```bash
544
+ cd /home/rbotafogo/desenv_linux/hedi
545
+ jruby -S bundle exec rails runner "puts R.eval('sum(c(1,2,3,4,5))').inspect"
546
+ ```
547
+
548
+ Expected output:
549
+
550
+ ```text
551
+ 15.0
552
+ ```
553
+
554
+ ### 4) HTTP endpoint pattern
555
+
556
+ For this baseline, a small Rack endpoint was the most stable first step to prove request-time R
557
+ evaluation. (A full ActionController stack can be enabled later as the app evolves.)
558
+
559
+ Minimal pattern:
560
+
561
+ 1. Define a Rack app class under `lib/` that runs `R.eval(...)` and returns HTML/JSON.
562
+ 2. Point a route to that Rack app (`root to: MyRackApp`).
563
+ 3. Verify with browser/curl.
564
+
565
+ ### 5) Running from WSL and opening from Windows
566
+
567
+ Recommended bind:
568
+
569
+ ```bash
570
+ jruby -S bundle exec rails server -b 0.0.0.0 -p 3000
571
+ ```
572
+
573
+ Then open from Windows:
574
+
575
+ - `http://localhost:3000` (usually works with WSL localhost forwarding), or
576
+ - `http://<wsl-ip>:3000` if needed.
577
+
578
+ In development, if Host Authorization blocks requests with unexpected Host headers, use:
579
+
580
+ ```ruby
581
+ # config/environments/development.rb
582
+ config.hosts.clear
583
+ ```
584
+
585
+ ### 6) Troubleshooting checklist
586
+
587
+ - `Could not find ... in locally installed gems`:
588
+ run `jruby -S bundle install` in the Rails app directory.
589
+ - Stale PID after crash:
590
+ remove `tmp/pids/server.pid`.
591
+ - Local Galaaz path changed:
592
+ verify `Gemfile` path target exists and rerun bundler.
593
+ - R runtime issues:
594
+ confirm GNU R is installed and on `PATH` in the same shell where Rails runs.
595
+
596
+ As new Rails features are added (controllers, jobs, websockets, background rendering, plot
597
+ generation), extend this section with concrete, runnable snippets and the associated operational
598
+ checks.
599
+
600
+ # Accessing R from Ruby
601
+
602
+ One of the nice aspects of Galaaz is that variables and functions defined in R can
603
+ be easily accessed from Ruby. For instance, to access the `mtcars` data frame from R
604
+ in Ruby, we use the symbol `:mtcars` preceded by the `~` operator: `~R[:mtcars]` retrieves the
605
+ value of the `mtcars` object in R.
606
+
607
+
608
+ ``` ruby
609
+ puts ~R[:mtcars]
196
610
  ```
197
611
 
198
612
  ```
@@ -231,11 +645,36 @@ puts ~:mtcars
231
645
  ## Volvo 142E 21.4 4 121.0 109 4.11 2.780 18.60 1 1 4 2
232
646
  ```
233
647
 
234
- To access an R function from Ruby, the R function needs to be preceeded by 'R.' scoping.
235
- Bellow we see and example of creating a R::Vector by calling the 'c' R function
648
+ ## Scoped symbols and lexical scoping
649
+
650
+ Galaaz 2.0 uses **scoped symbols** by default. The canonical style is `R[:name]`:
651
+
652
+ - `~R[:mtcars]` fetches an R object by name.
653
+ - `R[:a] + R[:b]` builds an expression.
654
+ - `R[:year].up_to(R[:day])` builds range expressions.
236
655
 
656
+ If you prefer the terse `:x` syntax, you can opt in with lexical scoping using a Ruby refinement:
237
657
 
238
658
  ```ruby
659
+ module MyScript
660
+ using Galaaz::SymbolDSL
661
+
662
+ def self.run
663
+ expr = :a + :b
664
+ puts expr
665
+ puts ~:mtcars
666
+ end
667
+ end
668
+ ```
669
+
670
+ `using Galaaz::SymbolDSL` is **lexically scoped**: only code in that module/file scope gets `:x` DSL behavior.
671
+ Outside that scope, plain Ruby `Symbol` behavior is unchanged.
672
+
673
+ To access an R function from Ruby, the R function needs to be preceded by `R.` scoping.
674
+ Below we see an example of creating a R::Vector by calling the 'c' R function
675
+
676
+
677
+ ``` ruby
239
678
  puts vec = R.c(1.0, 2.0, 3.0, 4.0)
240
679
  ```
241
680
 
@@ -245,7 +684,7 @@ puts vec = R.c(1.0, 2.0, 3.0, 4.0)
245
684
  Note that 'vec' is an object of type R::Vector:
246
685
 
247
686
 
248
- ```ruby
687
+ ``` ruby
249
688
  puts vec.class
250
689
  ```
251
690
 
@@ -257,12 +696,12 @@ R::Object. In R, there is also a function 'class'. In order to access that funct
257
696
  can call method 'rclass' in the R::Object:
258
697
 
259
698
 
260
- ```ruby
699
+ ``` ruby
261
700
  puts vec.rclass
262
701
  ```
263
702
 
264
703
  ```
265
- ## [1] "numeric"
704
+ ## numeric
266
705
  ```
267
706
  When working with R::Object(s), it is possible to use the '.' operator to pipe operations.
268
707
  When using '.', the object to which the '.' is applied becomes the first argument of the
@@ -271,7 +710,7 @@ two vectors or more vectors (in R, there are no scalar values, scalars are conve
271
710
  vectors of size 1. Within Galaaz, scalar parameter is converted to a size one vector):
272
711
 
273
712
 
274
- ```ruby
713
+ ``` ruby
275
714
  puts R.c(vec, 10, 20, 30)
276
715
  ```
277
716
 
@@ -281,18 +720,18 @@ puts R.c(vec, 10, 20, 30)
281
720
  The call above to the 'c' function can also be done using '.' notation:
282
721
 
283
722
 
284
- ```ruby
723
+ ``` ruby
285
724
  puts vec.c(10, 20, 30)
286
725
  ```
287
726
 
288
727
  ```
289
728
  ## [1] 1 2 3 4 10 20 30
290
729
  ```
291
- We will talk about vector indexing in a latter section. But notice here that indexing
730
+ We will talk about vector indexing in a later section. But notice here that indexing
292
731
  an R::Vector will return another R::Vector:
293
732
 
294
733
 
295
- ```ruby
734
+ ``` ruby
296
735
  puts vec[1]
297
736
  ```
298
737
 
@@ -304,7 +743,7 @@ in an R::Object, but the native Ruby object. For this, we can index the R object
304
743
  the '>>' operator:
305
744
 
306
745
 
307
- ```ruby
746
+ ``` ruby
308
747
  puts vec >> 0
309
748
  puts vec >> 2
310
749
  ```
@@ -319,7 +758,7 @@ in Galaaz with named parameters. For instance, here is an example of creating a
319
758
  with named elements:
320
759
 
321
760
 
322
- ```ruby
761
+ ``` ruby
323
762
  puts R.list(first_name: "Rodrigo", last_name: "Botafogo")
324
763
  ```
325
764
 
@@ -337,25 +776,22 @@ Method or Lambda in place of the expected R function. In this next example, we w
337
776
  add 2 to every element of our previously created vector:
338
777
 
339
778
 
340
- ```ruby
779
+ ``` ruby
341
780
  puts vec.map { |x| x + 2 }
342
781
  ```
343
782
 
344
783
  ```
345
- ## [1] 3
346
- ## [1] 4
347
- ## [1] 5
348
- ## [1] 6
784
+ ## [1] 3 4 5 6
349
785
  ```
350
786
 
351
787
  # gKnitting a Document
352
788
 
353
- This manual has been formatted usign gKnit. gKnit uses Knitr and R markdown to knit
354
- a document in Ruby or R and output it in any of the available formats for R markdown.
355
- gKnit runs atop of GraalVM, and Galaaz. In gKnit, Ruby variables are persisted between
789
+ This manual has been formatted using gKnit. gKnit uses knitr and R Markdown to knit
790
+ a document in Ruby or R and output it in any of the available formats for R Markdown.
791
+ gKnit runs with **JRuby**, **GNU R**, and Galaaz. In gKnit, Ruby variables are persisted between
356
792
  chunks, making it an ideal solution for literate programming. Also, since it is based
357
- on Galaaz, Ruby chunks can have access to R variables and Polyglot Programming with
358
- Ruby and R is quite natural.
793
+ on Galaaz, Ruby chunks can have access to R variables and combining Ruby with R in one
794
+ document is natural.
359
795
 
360
796
  The idea of "literate programming" was first introduced by Donald Knuth in the
361
797
  1980's [@Knuth:literate_programming].
@@ -374,7 +810,7 @@ single document or set of documents that when distributed to peers could be reru
374
810
  the same output and reports.
375
811
 
376
812
  The R community has put a great deal of effort in reproducible research. In 2002, Sweave was
377
- introduced and it allowed mixing R code with Latex generating high quality PDF documents. A
813
+ introduced and it allowed mixing R code with LaTeX, generating high-quality PDF documents. A
378
814
  Sweave document could include code, the results of executing the code, graphics and text
379
815
  such that it contained the whole narrative to reproduce the research. In
380
816
  2012, Knitr, developed by Yihui Xie from RStudio was released to replace Sweave and to
@@ -383,7 +819,7 @@ were necessary for Sweave.
383
819
 
384
820
  With Knitr, __R markdown__ was also developed, an extension to the
385
821
  Markdown format. With __R markdown__ and Knitr it is possible to generate reports in a multitude
386
- of formats such as HTML, markdown, Latex, PDF, dvi, etc. __R markdown__ also allows the use of
822
+ of formats such as HTML, Markdown, LaTeX, PDF, DVI, etc. __R markdown__ also allows the use of
387
823
  multiple programming languages such as R, Ruby, Python, etc. in the same document.
388
824
 
389
825
  In __R markdown__, text is interspersed with
@@ -404,14 +840,14 @@ create a list, then we would need to save it to file, but to save it, we need so
404
840
  data into a binary format:
405
841
 
406
842
 
407
- ```ruby
843
+ ``` ruby
408
844
  lst = R.list(a: 1, b: 2, c: 3)
409
845
  lst.saveRDS("lst.rds")
410
846
  ```
411
847
  then, on the next chunk, where variable 'lst' is used, we need to read back it's value
412
848
 
413
849
 
414
- ```ruby
850
+ ``` ruby
415
851
  lst = R.readRDS("lst.rds")
416
852
  puts lst
417
853
  ```
@@ -431,16 +867,16 @@ Now, any single code has dozens of variables that we might want to use and reuse
431
867
  Clearly, such an approach becomes quickly unmanageable. Probably, because of
432
868
  this problem, it is very rare to see any __R markdown__ document in the Ruby community.
433
869
 
434
- When variables can be used accross chunks, then no overhead is needed:
870
+ When variables can be used across chunks, then no overhead is needed:
435
871
 
436
872
 
437
- ```ruby
873
+ ``` ruby
438
874
  lst = R.list(a: 1, b: 2, c: 3)
439
875
  # any other code can be added here
440
876
  ```
441
877
 
442
878
 
443
- ```ruby
879
+ ``` ruby
444
880
  puts lst
445
881
  ```
446
882
 
@@ -456,8 +892,8 @@ puts lst
456
892
  ```
457
893
 
458
894
  In the Python community, the same effort to have code and text in an integrated environment
459
- started around the first decade of 2000. In 2006 iPython 0.7.2 was released. In 2014,
460
- Fernando Pérez, spun off project Jupyter from iPython creating a web-based interactive
895
+ started around the first decade of the 2000s. In 2006 IPython 0.7.2 was released. In 2014,
896
+ Fernando Pérez spun off the Jupyter project from IPython, creating a web-based interactive
461
897
  computation environment. Jupyter can now be used with many languages, including Ruby with the
462
898
  iruby gem (https://github.com/SciRuby/iruby). In order to have multiple languages in a Jupyter
463
899
  notebook the SoS kernel was developed (https://vatlab.github.io/sos-docs/).
@@ -471,8 +907,8 @@ have in a single document, text and code.
471
907
 
472
908
  In gKnit, Ruby variables are persisted between
473
909
  chunks, making it an ideal solution for literate programming in this language. Also,
474
- since it is based on Galaaz, Ruby chunks can have access to R variables and Polyglot Programming
475
- with Ruby and R is quite natural.
910
+ since it is based on Galaaz, Ruby chunks can access R variables (`~R[:name]`, `R.*`) through the
911
+ **Galaaz bridge** while knitr drives **GNU R**—no GraalVM polyglot runtime is required.
476
912
 
477
913
  This is not a blog post on __R markdown__, and the interested user is directed to the following links
478
914
  for detailed information on its capabilities and use.
@@ -486,7 +922,7 @@ gKnitting Ruby and R documents quickly.
486
922
  ## The Yaml header
487
923
 
488
924
  An __R markdown__ document should start with a Yaml header and be stored in a file with
489
- '.Rmd' extension. This document has the following header for gKitting an HTML document.
925
+ '.Rmd' extension. This document has the following header for gKnitting an HTML document.
490
926
 
491
927
  ```
492
928
  ---
@@ -494,7 +930,7 @@ title: "How to do reproducible research in Ruby with gKnit"
494
930
  author:
495
931
  - "Rodrigo Botafogo"
496
932
  - "Daniel Mossé - University of Pittsburgh"
497
- tags: [Tech, Data Science, Ruby, R, GraalVM]
933
+ tags: [Tech, Data Science, Ruby, R, JRuby, Galaaz]
498
934
  date: "20/02/2019"
499
935
  output:
500
936
  html_document:
@@ -509,6 +945,35 @@ output:
509
945
 
510
946
  For more information on the options in the Yaml header, [check here](https://bookdown.org/yihui/rmarkdown/html-document.html).
511
947
 
948
+ ## Choosing the output format when calling gknit
949
+
950
+ Yes: you can select the render target on the **command line**. **`bin/gknit`** (or **`gknit`** on your `PATH`) forwards options to **`rmarkdown::render`** via **`R::Rmarkdown.render`**.
951
+
952
+ * **`--output_format FORMAT`** — name of the format, as in the YAML `output:` block. Examples:
953
+ * **`html_document`** — HTML (often the default you list first under `output:`).
954
+ * **`pdf_document`** — PDF (you need a working LaTeX setup, e.g. TinyTeX; see **`bin/install-tinytex`**).
955
+ * **`md_document`**, **`github_document`**, or any other format defined in your YAML.
956
+ * **`all`** — render **every** format declared under `output:` in the document (same idea as in R Markdown).
957
+
958
+ If you **omit** **`--output_format`**, gknit passes **`NULL`** for the format argument. In that case **rmarkdown** uses the **first** format listed under **`output:`** in the YAML (and if none is specified there, behavior follows the usual rmarkdown defaults, typically HTML).
959
+
960
+ Other useful flags:
961
+
962
+ * **`--output_file NAME`** — output file name (optional path; see also **`--output_dir`**).
963
+ * **`--output_dir DIR`** — directory for the rendered file (created if missing).
964
+ * **`--bridge_timeout_sec`** / **`--callback_timeout_ms`** — longer R or install steps (see elsewhere in this manual).
965
+
966
+ Examples (run from the directory where paths make sense, or use absolute paths):
967
+
968
+ ```text
969
+ bin/gknit blogs/manual/manual.Rmd
970
+ bin/gknit --output_format html_document blogs/manual/manual.Rmd
971
+ bin/gknit --output_format pdf_document blogs/manual/manual.Rmd
972
+ bin/gknit --output_format all blogs/manual/manual.Rmd
973
+ ```
974
+
975
+ Use **`gknit -h`** for the full option list.
976
+
512
977
  ## __R Markdown__ formatting
513
978
 
514
979
  Document formatting can be done with simple markups such as:
@@ -553,7 +1018,7 @@ Running and executing Ruby and R code is actually what really interests us is th
553
1018
  Inserting a code chunk is done by adding code in a block delimited by three back ticks
554
1019
  followed by an open
555
1020
  curly brace ('{') followed with the engine name (r, ruby, rb, include, ...), an
556
- any optional chunk_label and options, as shown bellow:
1021
+ any optional chunk_label and options, as shown below:
557
1022
 
558
1023
  ````
559
1024
  ```{engine_name [chunk_label], [chunk_options]}
@@ -573,7 +1038,7 @@ print(vec)
573
1038
  If this block is added to an __R markdown__ document and gKnitted the result will be:
574
1039
 
575
1040
 
576
- ```r
1041
+ ``` r
577
1042
  vec <- c(1, 2, 3)
578
1043
  print(vec)
579
1044
  ```
@@ -621,7 +1086,7 @@ presentation we will not show chunk definitions any longer.
621
1086
 
622
1087
 
623
1088
 
624
- ```r
1089
+ ``` r
625
1090
  r_vec <- c(1, 2, 3, 4, 5)
626
1091
 
627
1092
  reduce_sum <- function(...) {
@@ -632,7 +1097,7 @@ reduce_sum <- function(...) {
632
1097
  We can, possibly in another chunk, access the vector and call the function as follows:
633
1098
 
634
1099
 
635
- ```r
1100
+ ``` r
636
1101
  print(r_vec)
637
1102
  ```
638
1103
 
@@ -640,7 +1105,7 @@ print(r_vec)
640
1105
  ## [1] 1 2 3 4 5
641
1106
  ```
642
1107
 
643
- ```r
1108
+ ``` r
644
1109
  print(reduce_sum(r_vec))
645
1110
  ```
646
1111
 
@@ -659,7 +1124,7 @@ grammar of graphics" [@Wilkinson:grammar_of_graphics]. The idea of the grammar o
659
1124
  is to build a graphics by adding layers to the plot. More information can be found in
660
1125
  https://towardsdatascience.com/a-comprehensive-guide-to-the-grammar-of-graphics-for-effective-visualization-of-multi-dimensional-1f92b4ed4149.
661
1126
 
662
- In the plot bellow the 'mpg' dataset from base R is used. "The data concerns city-cycle fuel
1127
+ In the plot below the 'mpg' dataset from base R is used. "The data concerns city-cycle fuel
663
1128
  consumption in miles per gallon, to be predicted in terms of 3 multivalued discrete and 5
664
1129
  continuous attributes." (Quinlan, 1993)
665
1130
 
@@ -673,21 +1138,9 @@ car point equal its high way consumption (size = hwy). Finally, a last layer is
673
1138
  a linear regression line (method = "lm") for every manufacturer.
674
1139
 
675
1140
 
676
- ```r
1141
+ ``` r
677
1142
  # load package and data
678
1143
  library(ggplot2)
679
- ```
680
-
681
- ```
682
- ## Message:
683
- ## Registered S3 methods overwritten by 'ggplot2':
684
- ## method from
685
- ## [.quosures rlang
686
- ## c.quosures rlang
687
- ## print.quosures rlang
688
- ```
689
-
690
- ```r
691
1144
  data(mpg, package="ggplot2")
692
1145
 
693
1146
  mpg_select <- mpg[mpg$manufacturer %in% c("audi", "ford", "honda", "hyundai"), ]
@@ -702,6 +1155,10 @@ g + geom_jitter(aes(col=manufacturer, size=hwy)) +
702
1155
  geom_smooth(aes(col=manufacturer), method="lm", se=F)
703
1156
  ```
704
1157
 
1158
+ ```
1159
+ ## `geom_smooth()` using formula = 'y ~ x'
1160
+ ```
1161
+
705
1162
  ![](manual_files/figure-html/bubble-1.png)<!-- -->
706
1163
 
707
1164
  ## Ruby chunks
@@ -733,7 +1190,7 @@ functions. gKnit will knit standard Ruby code, or even general text without
733
1190
  any code.
734
1191
 
735
1192
 
736
- ```ruby
1193
+ ``` ruby
737
1194
  a = [1, 2, 3]
738
1195
  b = "US$ 250.000"
739
1196
  c = "The 'outputs' function"
@@ -745,7 +1202,7 @@ vec2 = R.c(10, 20, 30)
745
1202
  In the next block, variables 'a', 'vec' and 'vec2' are used and printed.
746
1203
 
747
1204
 
748
- ```ruby
1205
+ ``` ruby
749
1206
  puts a
750
1207
  puts vec * vec2
751
1208
  ```
@@ -869,24 +1326,24 @@ Here, for instance, is a table definition in HTML and its output in the document
869
1326
  </div>
870
1327
 
871
1328
  But manually creating HTML output is not always easy or desirable, specially
872
- if we intend the document to be rendered in other formats, for example, as Latex.
1329
+ if we intend the document to be rendered in other formats, for example, as LaTeX.
873
1330
  Also, The above
874
1331
  table looks ugly. The 'kableExtra' library is a great library for
875
1332
  creating beautiful tables. Take a look at https://cran.r-project.org/web/packages/kableExtra/vignettes/awesome_table_in_html.html
876
1333
 
877
1334
  In the next chunk, we output the 'mtcars' dataframe from R in a nicely formatted
878
- table. Note that we retrieve the mtcars dataframe by using '~:mtcars'.
1335
+ table. Note that we retrieve the mtcars dataframe by using '~R[:mtcars]'.
879
1336
 
880
1337
 
881
- ```ruby
1338
+ ``` ruby
882
1339
  R.install_and_loads('kableExtra')
883
- outputs (~:mtcars).kable.kable_styling
1340
+ outputs (~R[:mtcars]).kable.kable_styling
884
1341
  ```
885
1342
 
886
1343
  <table class="table" style="margin-left: auto; margin-right: auto;">
887
1344
  <thead>
888
1345
  <tr>
889
- <th style="text-align:left;"> </th>
1346
+ <th style="text-align:left;"> </th>
890
1347
  <th style="text-align:right;"> mpg </th>
891
1348
  <th style="text-align:right;"> cyl </th>
892
1349
  <th style="text-align:right;"> disp </th>
@@ -1377,7 +1834,7 @@ true, ruby's 'require\_relative' semantics is used to load the file, when false,
1377
1834
  ```
1378
1835
  ````
1379
1836
 
1380
- Bellow we include file 'model.rb', which is in the same directory of this blog.
1837
+ Below we include file 'model.rb', which is in the same directory of this blog.
1381
1838
  This code uses R 'caret' package to split a dataset in a train and test sets.
1382
1839
  The 'caret' package is a very important a useful package for doing Data Analysis,
1383
1840
  it has hundreds of functions for all steps of the Data Analysis workflow. To
@@ -1395,7 +1852,7 @@ will install the package if it is not already installed and can take a while.
1395
1852
  ````
1396
1853
 
1397
1854
 
1398
- ```include
1855
+ ``` include
1399
1856
  require 'galaaz'
1400
1857
 
1401
1858
  # Loads the R 'caret' package. If not present, installs it
@@ -1427,7 +1884,7 @@ class Model
1427
1884
  def partition(field)
1428
1885
 
1429
1886
  train_index =
1430
- R.createDataPartition(@data.send(field), p: @percet_train,
1887
+ R.createDataPartition(@data.send(field), p: @percent_train,
1431
1888
  list: false, times: 1)
1432
1889
  @train = @data[train_index, :all]
1433
1890
  @test = @data[-train_index, :all]
@@ -1435,12 +1892,11 @@ class Model
1435
1892
  end
1436
1893
 
1437
1894
  end
1438
-
1439
1895
  ```
1440
1896
 
1441
1897
 
1442
- ```ruby
1443
- mtcars = ~:mtcars
1898
+ ``` ruby
1899
+ mtcars = ~R[:mtcars]
1444
1900
  model = Model.new(mtcars, percent_train: 0.8)
1445
1901
  model.partition(:mpg)
1446
1902
  puts model.train.head
@@ -1448,20 +1904,18 @@ puts model.test.head
1448
1904
  ```
1449
1905
 
1450
1906
  ```
1451
- ## mpg cyl disp hp drat wt qsec vs am gear carb
1452
- ## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
1453
- ## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
1454
- ## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
1455
- ## Merc 280 19.2 6 167.6 123 3.92 3.440 18.30 1 0 4 4
1456
- ## Merc 280C 17.8 6 167.6 123 3.92 3.440 18.90 1 0 4 4
1457
- ## Merc 450SE 16.4 8 275.8 180 3.07 4.070 17.40 0 0 3 3
1458
1907
  ## mpg cyl disp hp drat wt qsec vs am gear carb
1908
+ ## Mazda RX4 21.0 6 160.0 110 3.90 2.620 16.46 0 1 4 4
1459
1909
  ## Datsun 710 22.8 4 108.0 93 3.85 2.320 18.61 1 1 4 1
1460
1910
  ## Hornet 4 Drive 21.4 6 258.0 110 3.08 3.215 19.44 1 0 3 1
1461
1911
  ## Hornet Sportabout 18.7 8 360.0 175 3.15 3.440 17.02 0 0 3 2
1462
- ## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
1912
+ ## Valiant 18.1 6 225.0 105 2.76 3.460 20.22 1 0 3 1
1463
1913
  ## Merc 240D 24.4 4 146.7 62 3.69 3.190 20.00 1 0 4 2
1464
- ## Merc 230 22.8 4 140.8 95 3.92 3.150 22.90 1 0 4 2
1914
+ ## mpg cyl disp hp drat wt qsec vs am gear carb
1915
+ ## Mazda RX4 Wag 21.0 6 160.0 110 3.90 2.875 17.02 0 1 4 4
1916
+ ## Duster 360 14.3 8 360.0 245 3.21 3.570 15.84 0 0 3 4
1917
+ ## Toyota Corolla 33.9 4 71.1 65 4.22 1.835 19.90 1 1 4 1
1918
+ ## Ford Pantera L 15.8 8 351.0 264 4.22 3.170 14.50 0 1 5 4
1465
1919
  ```
1466
1920
 
1467
1921
  ## Documenting Gems
@@ -1469,9 +1923,9 @@ puts model.test.head
1469
1923
  gKnit also allows developers to document and load files that are not in the same directory
1470
1924
  of the '.Rmd' file.
1471
1925
 
1472
- Here is an example of loading the 'find.rb' file from TruffleRuby. In this example, relative
1473
- is set to FALSE, so Ruby will look for the file in its $LOAD\_PATH, and the user does not
1474
- need to no it's directory.
1926
+ Here is an example of loading Ruby’s standard library file `find.rb`. In this example, relative
1927
+ is set to FALSE, so Ruby will look for the file in its `$LOAD_PATH`, and the user does not
1928
+ need to know its directory on disk.
1475
1929
 
1476
1930
  ````
1477
1931
  ```{include find, relative = FALSE}
@@ -1479,7 +1933,7 @@ need to no it's directory.
1479
1933
  ````
1480
1934
 
1481
1935
 
1482
- ```include
1936
+ ``` include
1483
1937
  # frozen_string_literal: true
1484
1938
  #
1485
1939
  # find.rb: the Find module for processing all files under a given directory.
@@ -1497,7 +1951,7 @@ need to no it's directory.
1497
1951
  #
1498
1952
  # Find.find(ENV["HOME"]) do |path|
1499
1953
  # if FileTest.directory?(path)
1500
- # if File.basename(path)[0] == ?.
1954
+ # if File.basename(path).start_with?('.')
1501
1955
  # Find.prune # Don't look any further into this directory.
1502
1956
  # else
1503
1957
  # next
@@ -1509,6 +1963,8 @@ need to no it's directory.
1509
1963
  #
1510
1964
  module Find
1511
1965
 
1966
+ VERSION = "0.2.0"
1967
+
1512
1968
  #
1513
1969
  # Calls the associated block with the name of every file and directory listed
1514
1970
  # as arguments, then recursively on their subdirectories, and so on.
@@ -1528,24 +1984,24 @@ module Find
1528
1984
  ps = [path]
1529
1985
  while file = ps.shift
1530
1986
  catch(:prune) do
1531
- yield file.dup.taint
1987
+ yield file.dup
1532
1988
  begin
1533
1989
  s = File.lstat(file)
1534
- rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
1990
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
1535
1991
  raise unless ignore_error
1536
1992
  next
1537
1993
  end
1538
1994
  if s.directory? then
1539
1995
  begin
1540
1996
  fs = Dir.children(file, encoding: enc)
1541
- rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG
1997
+ rescue Errno::ENOENT, Errno::EACCES, Errno::ENOTDIR, Errno::ELOOP, Errno::ENAMETOOLONG, Errno::EINVAL
1542
1998
  raise unless ignore_error
1543
1999
  next
1544
2000
  end
1545
2001
  fs.sort!
1546
2002
  fs.reverse_each {|f|
1547
2003
  f = File.join(file, f)
1548
- ps.unshift f.untaint
2004
+ ps.unshift f
1549
2005
  }
1550
2006
  end
1551
2007
  end
@@ -1582,9 +2038,9 @@ the Yaml header to generate this blog in PDF format instead of HTML:
1582
2038
 
1583
2039
  ```
1584
2040
  ---
1585
- title: "gKnit - Ruby and R Knitting with Galaaz in GraalVM"
2041
+ title: "gKnit - Ruby and R Knitting with Galaaz"
1586
2042
  author: "Rodrigo Botafogo"
1587
- tags: [Galaaz, Ruby, R, TruffleRuby, FastR, GraalVM, knitr, gknit]
2043
+ tags: [Galaaz, Ruby, R, JRuby, knitr, gknit]
1588
2044
  date: "29 October 2018"
1589
2045
  output:
1590
2046
  pdf\_document:
@@ -1596,7 +2052,7 @@ output:
1596
2052
 
1597
2053
  ## Template based documents generation
1598
2054
 
1599
- When a document is converted to PDF it follows a certain convertion template. We've seen above
2055
+ When a document is converted to PDF it follows a certain conversion template. We've seen above
1600
2056
  the use of 'galaaz.sty' as a basic template to generate a PDF document. Using the
1601
2057
  'gknit-draft' app that comes with Galaaz, the same .Rmd file can be compiled to different
1602
2058
  looking PDF documents. Galaaz automatically loads the 'rticles' R package that comes with
@@ -1646,21 +2102,21 @@ gknit-draft --filename my_r_article --template rjournal_article --package rticle
1646
2102
 
1647
2103
  # Accessing R variables
1648
2104
 
1649
- Galaaz allows Ruby to access variables created in R. For example, the 'mtcars' data set is
1650
- available in R and can be accessed from Ruby by using the 'tilda' operator followed by the
1651
- symbol for the variable, in this case ':mtcar'. In the code bellow method 'outputs' is
1652
- used to output the 'mtcars' data set nicely formatted in HTML by use of the 'kable' and
1653
- 'kable_styling' functions. Method 'outputs' is only available when used with 'gknit'.
2105
+ Galaaz allows Ruby to access variables created in R. For example, the `mtcars` data set is
2106
+ available in R and can be accessed from Ruby by using the tilde operator followed by the
2107
+ symbol for the variable, in this case `:mtcars`. In the code below, method `outputs` is
2108
+ used to output the `mtcars` data set nicely formatted in HTML by use of the `kable` and
2109
+ `kable_styling` functions. Method `outputs` is only available when used with gKnit.
1654
2110
 
1655
2111
 
1656
- ```ruby
1657
- outputs (~:mtcars).kable.kable_styling
2112
+ ``` ruby
2113
+ outputs (~R[:mtcars]).kable.kable_styling
1658
2114
  ```
1659
2115
 
1660
2116
  <table class="table" style="margin-left: auto; margin-right: auto;">
1661
2117
  <thead>
1662
2118
  <tr>
1663
- <th style="text-align:left;"> </th>
2119
+ <th style="text-align:left;"> </th>
1664
2120
  <th style="text-align:right;"> mpg </th>
1665
2121
  <th style="text-align:right;"> cyl </th>
1666
2122
  <th style="text-align:right;"> disp </th>
@@ -2141,7 +2597,7 @@ table.
2141
2597
  | logical | logical | logical |
2142
2598
  | integer | numeric | integer |
2143
2599
  | double | numeric | double |
2144
- | complex | complex | comples |
2600
+ | complex | complex | complex |
2145
2601
  | character | character | character |
2146
2602
  | raw | raw | raw |
2147
2603
 
@@ -2153,7 +2609,7 @@ vector is often referred to as a character string.
2153
2609
  To create a vector the 'c' (concatenate) method from the 'R' module should be used:
2154
2610
 
2155
2611
 
2156
- ```ruby
2612
+ ``` ruby
2157
2613
  vec = R.c(1, 2, 3)
2158
2614
  puts vec
2159
2615
  ```
@@ -2173,7 +2629,7 @@ Data frames will later be more carefully described. In R, the method used to cr
2173
2629
  data frame is 'data.frame', in Galaaz we use 'data\_\_frame'.
2174
2630
 
2175
2631
 
2176
- ```ruby
2632
+ ``` ruby
2177
2633
  df = R.data__frame(typeof: vec.typeof, mode: vec.mode, storage__mode: vec.storage__mode)
2178
2634
  puts df
2179
2635
  ```
@@ -2189,7 +2645,7 @@ like '1' is converted to float and to have an integer the R developer will use '
2189
2645
  follows normal Ruby rules and the number 1 is an integer and 1.0 is a float.
2190
2646
 
2191
2647
 
2192
- ```ruby
2648
+ ``` ruby
2193
2649
  vec = R.c(1.0, 2, 3)
2194
2650
  puts vec
2195
2651
  ```
@@ -2199,7 +2655,7 @@ puts vec
2199
2655
  ```
2200
2656
 
2201
2657
 
2202
- ```ruby
2658
+ ``` ruby
2203
2659
  df = R.data__frame(typeof: vec.typeof, mode: vec.mode, storage__mode: vec.storage__mode)
2204
2660
  outputs df.kable.kable_styling
2205
2661
  ```
@@ -2227,41 +2683,30 @@ the first with a message explaining what went wrong and the second with the full
2227
2683
  of the error.
2228
2684
 
2229
2685
 
2230
- ```ruby
2686
+ ``` ruby
2231
2687
  vec = R.c(1, hello, 5)
2232
2688
  ```
2233
2689
 
2234
2690
  ```
2235
- ## Message:
2236
- ## undefined local variable or method `hello' for #<RC:0x3d8 @out_list=nil>:RC
2691
+ ## undefined local variable or method 'hello' for an instance of RC
2237
2692
  ```
2238
2693
 
2239
2694
  ```
2240
- ## Message:
2241
- ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:103:in `get_binding'
2242
- ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:102:in `eval'
2243
- ## /home/rbotafogo/desenv/galaaz/lib/util/exec_ruby.rb:102:in `exec_ruby'
2244
- ## /home/rbotafogo/desenv/galaaz/lib/gknit/knitr_engine.rb:650:in `block in initialize'
2245
- ## /home/rbotafogo/desenv/galaaz/lib/R_interface/ruby_callback.rb:77:in `call'
2246
- ## /home/rbotafogo/desenv/galaaz/lib/R_interface/ruby_callback.rb:77:in `callback'
2247
- ## (eval):3:in `function(...) {\n rb_method(...)'
2248
- ## unknown.r:1:in `in_dir'
2249
- ## unknown.r:1:in `block_exec'
2250
- ## /usr/local/lib/graalvm-ce-java11-20.0.0/languages/R/library/knitr/R/block.R:92:in `call_block'
2251
- ## /usr/local/lib/graalvm-ce-java11-20.0.0/languages/R/library/knitr/R/block.R:6:in `process_group.block'
2252
- ## /usr/local/lib/graalvm-ce-java11-20.0.0/languages/R/library/knitr/R/block.R:3:in `<no source>'
2253
- ## unknown.r:1:in `withCallingHandlers'
2254
- ## unknown.r:1:in `process_file'
2255
- ## unknown.r:1:in `<no source>'
2256
- ## unknown.r:1:in `<no source>'
2257
- ## <REPL>:4:in `<repl wrapper>'
2258
- ## <REPL>:1
2695
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/util/exec_ruby.rb:170:in 'exec_ruby'
2696
+ ## org/jruby/RubyKernel.java:1268:in 'eval'
2697
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/util/exec_ruby.rb:169:in 'exec_ruby'
2698
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/gknit/knitr_engine.rb:777:in 'block in initialize'
2699
+ ## org/jruby/RubyBasicObject.java:2695:in 'instance_eval'
2700
+ ## org/jruby/RubyBasicObject.java:2723:in 'instance_eval'
2701
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/gknit/knitr_engine.rb:748:in 'block in initialize'
2702
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/R_interface/new_bridge_adapter.rb:358:in 'block in register_callback_proc_stub'
2703
+ ## /home/rbotafogo/desenv_linux/galaaz/lib/new_bridge/session_client.rb:413:in 'block in handle_call'
2259
2704
  ```
2260
2705
 
2261
2706
  Here is a vector with logical values
2262
2707
 
2263
2708
 
2264
- ```ruby
2709
+ ``` ruby
2265
2710
  vec = R.c(true, true, false, false, true)
2266
2711
  puts vec
2267
2712
  ```
@@ -2275,7 +2720,7 @@ puts vec
2275
2720
  The 'c' functions used to create vectors can also be used to combine two vectors:
2276
2721
 
2277
2722
 
2278
- ```ruby
2723
+ ``` ruby
2279
2724
  vec1 = R.c(10.0, 20.0, 30.0)
2280
2725
  vec2 = R.c(4.0, 5.0, 6.0)
2281
2726
  vec = R.c(vec1, vec2)
@@ -2290,10 +2735,10 @@ In this next example, method 'c' is chainned after 'vec1'. This also looks like
2290
2735
  method of the vector, but in reallity, this is actually closer to the pipe operator. When
2291
2736
  Galaaz identifies that 'c' is not a method of 'vec' it actually tries to call 'R.c' with
2292
2737
  'vec1' as the first argument concatenated with all the other available arguments. The code
2293
- bellow is automatically converted to the code above.
2738
+ below is automatically converted to the code above.
2294
2739
 
2295
2740
 
2296
- ```ruby
2741
+ ``` ruby
2297
2742
  vec = vec1.c(vec2)
2298
2743
  puts vec
2299
2744
  ```
@@ -2307,7 +2752,7 @@ puts vec
2307
2752
  Arithmetic operations on vectors are performed element by element:
2308
2753
 
2309
2754
 
2310
- ```ruby
2755
+ ``` ruby
2311
2756
  puts vec1 + vec2
2312
2757
  ```
2313
2758
 
@@ -2316,7 +2761,7 @@ puts vec1 + vec2
2316
2761
  ```
2317
2762
 
2318
2763
 
2319
- ```ruby
2764
+ ``` ruby
2320
2765
  puts vec1 * 5
2321
2766
  ```
2322
2767
 
@@ -2327,7 +2772,7 @@ puts vec1 * 5
2327
2772
  When vectors have different length, a recycling rule is applied to the shorter vector:
2328
2773
 
2329
2774
 
2330
- ```ruby
2775
+ ``` ruby
2331
2776
  vec3 = R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0)
2332
2777
  puts vec4 = vec1 + vec3
2333
2778
  ```
@@ -2341,7 +2786,7 @@ puts vec4 = vec1 + vec3
2341
2786
  Vectors can be indexed by using the '[]' operator:
2342
2787
 
2343
2788
 
2344
- ```ruby
2789
+ ``` ruby
2345
2790
  puts vec4[3]
2346
2791
  ```
2347
2792
 
@@ -2349,11 +2794,11 @@ puts vec4[3]
2349
2794
  ## [1] 33
2350
2795
  ```
2351
2796
 
2352
- We can also index a vector with another vector. For example, in the code bellow, we take elements
2797
+ We can also index a vector with another vector. For example, in the code below, we take elements
2353
2798
  1, 3, 5, and 7 from vec3:
2354
2799
 
2355
2800
 
2356
- ```ruby
2801
+ ``` ruby
2357
2802
  puts vec4[R.c(1, 3, 5, 7)]
2358
2803
  ```
2359
2804
 
@@ -2364,7 +2809,7 @@ puts vec4[R.c(1, 3, 5, 7)]
2364
2809
  Repeating an index and having indices out of order is valid code:
2365
2810
 
2366
2811
 
2367
- ```ruby
2812
+ ``` ruby
2368
2813
  puts vec4[R.c(1, 3, 3, 1)]
2369
2814
  ```
2370
2815
 
@@ -2376,7 +2821,7 @@ It is also possible to index a vector with a negative number or negative vector.
2376
2821
  the indexed values are not returned:
2377
2822
 
2378
2823
 
2379
- ```ruby
2824
+ ``` ruby
2380
2825
  puts vec4[-3]
2381
2826
  puts vec4[-R.c(1, 3, 5, 7)]
2382
2827
  ```
@@ -2389,7 +2834,7 @@ puts vec4[-R.c(1, 3, 5, 7)]
2389
2834
  If an index is out of range, a missing value (NA) will be reported.
2390
2835
 
2391
2836
 
2392
- ```ruby
2837
+ ``` ruby
2393
2838
  puts vec4[30]
2394
2839
  ```
2395
2840
 
@@ -2400,7 +2845,7 @@ puts vec4[30]
2400
2845
  It is also possible to index a vector by range:
2401
2846
 
2402
2847
 
2403
- ```ruby
2848
+ ``` ruby
2404
2849
  puts vec4[(2..5)]
2405
2850
  ```
2406
2851
 
@@ -2411,7 +2856,7 @@ puts vec4[(2..5)]
2411
2856
  Elements in a vector can be named using the 'names' attribute of a vector:
2412
2857
 
2413
2858
 
2414
- ```ruby
2859
+ ``` ruby
2415
2860
  full_name = R.c("Rodrigo", "A", "Botafogo")
2416
2861
  full_name.names = R.c("First", "Middle", "Last")
2417
2862
  puts full_name
@@ -2425,7 +2870,7 @@ puts full_name
2425
2870
  Or it can also be named by using the 'c' function with named paramenters:
2426
2871
 
2427
2872
 
2428
- ```ruby
2873
+ ``` ruby
2429
2874
  full_name = R.c(First: "Rodrigo", Middle: "A", Last: "Botafogo")
2430
2875
  puts full_name
2431
2876
  ```
@@ -2443,7 +2888,7 @@ R::Vector with other ruby classes it might be necessary to extract the actual Ru
2443
2888
  from the vector. In order to do this extraction the '>>' operator is used.
2444
2889
 
2445
2890
 
2446
- ```ruby
2891
+ ``` ruby
2447
2892
  puts vec4
2448
2893
  puts vec4 >> 0
2449
2894
  puts vec4 >> 4
@@ -2463,7 +2908,7 @@ A matrix is a collection of elements organized as a two dimensional table. A ma
2463
2908
  created by the 'matrix' function:
2464
2909
 
2465
2910
 
2466
- ```ruby
2911
+ ``` ruby
2467
2912
  mat = R.matrix(R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0),
2468
2913
  nrow: 3,
2469
2914
  ncol: 3)
@@ -2481,7 +2926,7 @@ Note that matrices data is organized by column first. It is possible to organize
2481
2926
  memory by row first passing an extra argument to the 'matrix' function:
2482
2927
 
2483
2928
 
2484
- ```ruby
2929
+ ``` ruby
2485
2930
  mat_row = R.matrix(R.c(1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0),
2486
2931
  nrow: 3,
2487
2932
  ncol: 3,
@@ -2502,7 +2947,7 @@ puts mat_row
2502
2947
  A matrix can be indexed by [row, column]:
2503
2948
 
2504
2949
 
2505
- ```ruby
2950
+ ``` ruby
2506
2951
  puts mat_row[1, 1]
2507
2952
  puts mat_row[2, 3]
2508
2953
  ```
@@ -2514,7 +2959,7 @@ puts mat_row[2, 3]
2514
2959
  It is possible to index an entire row or column with the ':all' keyword
2515
2960
 
2516
2961
 
2517
- ```ruby
2962
+ ``` ruby
2518
2963
  puts mat_row[1, :all]
2519
2964
  puts mat_row[:all, 2]
2520
2965
  ```
@@ -2528,7 +2973,7 @@ Indexing with a vector is also possible for matrices. In the following example w
2528
2973
  rows 1 and 3 and columns 2 and 3 building a 2 x 2 matrix.
2529
2974
 
2530
2975
 
2531
- ```ruby
2976
+ ``` ruby
2532
2977
  puts mat_row[R.c(1, 3), R.c(2, 3)]
2533
2978
  ```
2534
2979
 
@@ -2541,7 +2986,7 @@ puts mat_row[R.c(1, 3), R.c(2, 3)]
2541
2986
  Matrices can be combined with functions 'rbind':
2542
2987
 
2543
2988
 
2544
- ```ruby
2989
+ ``` ruby
2545
2990
  puts mat_row.rbind(mat)
2546
2991
  ```
2547
2992
 
@@ -2558,7 +3003,7 @@ puts mat_row.rbind(mat)
2558
3003
  and 'cbind':
2559
3004
 
2560
3005
 
2561
- ```ruby
3006
+ ``` ruby
2562
3007
  puts mat_row.cbind(mat)
2563
3008
  ```
2564
3009
 
@@ -2575,7 +3020,7 @@ A list is a data structure that can contain sublists of different types, while v
2575
3020
  can only hold one type of element.
2576
3021
 
2577
3022
 
2578
- ```ruby
3023
+ ``` ruby
2579
3024
  nums = R.c(1.0, 2.0, 3.0)
2580
3025
  strs = R.c("a", "b", "c", "d")
2581
3026
  bool = R.c(true, true, false)
@@ -2604,7 +3049,7 @@ first start with the '[]' operator. The list above has three sublist indexing wi
2604
3049
  return one of the sublists.
2605
3050
 
2606
3051
 
2607
- ```ruby
3052
+ ``` ruby
2608
3053
  puts lst[1]
2609
3054
  ```
2610
3055
 
@@ -2619,7 +3064,7 @@ the original list
2619
3064
 
2620
3065
 
2621
3066
 
2622
- ```ruby
3067
+ ``` ruby
2623
3068
  puts lst[[1]]
2624
3069
  ```
2625
3070
 
@@ -2630,7 +3075,7 @@ puts lst[[1]]
2630
3075
  When elements are named, as dones with lst, indexing can be done by name:
2631
3076
 
2632
3077
 
2633
- ```ruby
3078
+ ``` ruby
2634
3079
  puts lst[['bool']][[1]] >> 0
2635
3080
  ```
2636
3081
 
@@ -2647,11 +3092,11 @@ operator) and then the vector was indexed by its first element, extracting the n
2647
3092
 
2648
3093
  A data frame is a table like structure in which each column has the same number of
2649
3094
  rows. Data frames are the basic structure for storing data for data analysis. We have already
2650
- seen a data frame previously when we accessed variable '~:mtcars'. In order to create a
3095
+ seen a data frame previously when we accessed variable '~R[:mtcars]'. In order to create a
2651
3096
  data frame, function 'data__frame' is used:
2652
3097
 
2653
3098
 
2654
- ```ruby
3099
+ ``` ruby
2655
3100
  df = R.data__frame(
2656
3101
  year: R.c(2010, 2011, 2012),
2657
3102
  income: R.c(1000.0, 1500.0, 2000.0))
@@ -2672,10 +3117,10 @@ A data frame can be indexed the same way as a matrix, by using '[row, column]',
2672
3117
  column can either be a numeric or the name of the row or column
2673
3118
 
2674
3119
 
2675
- ```ruby
2676
- puts (~:mtcars).head
2677
- puts (~:mtcars)[1, 2]
2678
- puts (~:mtcars)['Datsun 710', 'mpg']
3120
+ ``` ruby
3121
+ puts (~R[:mtcars]).head
3122
+ puts (~R[:mtcars])[1, 2]
3123
+ puts (~R[:mtcars])['Datsun 710', 'mpg']
2679
3124
  ```
2680
3125
 
2681
3126
  ```
@@ -2694,52 +3139,48 @@ Extracting a column from a data frame as a vector can be done by using the doubl
2694
3139
  operator:
2695
3140
 
2696
3141
 
2697
- ```ruby
2698
- puts (~:mtcars)[['mpg']]
3142
+ ``` ruby
3143
+ puts (~R[:mtcars])[['mpg']]
2699
3144
  ```
2700
3145
 
2701
3146
  ```
2702
- ## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
2703
- ## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
2704
- ## [29] 15.8 19.7 15.0 21.4
3147
+ ## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
3148
+ ## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
3149
+ ## [31] 15.0 21.4
2705
3150
  ```
2706
3151
 
2707
3152
  A data frame column can also be accessed as if it were an instance variable of the data frame:
2708
3153
 
2709
3154
 
2710
- ```ruby
2711
- puts (~:mtcars).mpg
3155
+ ``` ruby
3156
+ puts (~R[:mtcars]).mpg
2712
3157
  ```
2713
3158
 
2714
3159
  ```
2715
- ## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2
2716
- ## [15] 10.4 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4
2717
- ## [29] 15.8 19.7 15.0 21.4
3160
+ ## [1] 21.0 21.0 22.8 21.4 18.7 18.1 14.3 24.4 22.8 19.2 17.8 16.4 17.3 15.2 10.4
3161
+ ## [16] 10.4 14.7 32.4 30.4 33.9 21.5 15.5 15.2 13.3 19.2 27.3 26.0 30.4 15.8 19.7
3162
+ ## [31] 15.0 21.4
2718
3163
  ```
2719
3164
 
2720
3165
  Slicing a data frame can be done by indexing it with a vector (we use 'head' to reduce the
2721
3166
  output):
2722
3167
 
2723
3168
 
2724
- ```ruby
2725
- puts (~:mtcars)[R.c('mpg', 'hp')].head
3169
+ ``` ruby
3170
+ puts (~R[:mtcars])[R.c('mpg', 'hp')].head
2726
3171
  ```
2727
3172
 
2728
3173
  ```
2729
- ## mpg hp
2730
- ## Mazda RX4 21.0 110
2731
- ## Mazda RX4 Wag 21.0 110
2732
- ## Datsun 710 22.8 93
2733
- ## Hornet 4 Drive 21.4 110
2734
- ## Hornet Sportabout 18.7 175
2735
- ## Valiant 18.1 105
3174
+ ## mpg cyl disp hp drat wt qsec vs am gear carb
3175
+ ## NA NA NA NA NA NA NA NA NA NA NA NA
3176
+ ## NA.1 NA NA NA NA NA NA NA NA NA NA NA
2736
3177
  ```
2737
3178
 
2738
3179
  A row slice can be obtained by indexing by row and using the ':all' keyword for the column:
2739
3180
 
2740
3181
 
2741
- ```ruby
2742
- puts (~:mtcars)[R.c('Datsun 710', 'Camaro Z28'), :all]
3182
+ ``` ruby
3183
+ puts (~R[:mtcars])[R.c('Datsun 710', 'Camaro Z28'), :all]
2743
3184
  ```
2744
3185
 
2745
3186
  ```
@@ -2750,29 +3191,29 @@ puts (~:mtcars)[R.c('Datsun 710', 'Camaro Z28'), :all]
2750
3191
 
2751
3192
  Finally, a data frame can also be indexed with a logical vector. In this next example, the
2752
3193
  'am' column of :mtcars is compared with 0 (with method 'eq'). When 'am' is equal to 0 the
2753
- car is automatic. So, by doing '(~:mtcars).am.eq 0' a logical vector is created with
3194
+ car is automatic. So, by doing '(~R[:mtcars]).am.eq 0' a logical vector is created with
2754
3195
  'true' whenever 'am' is 0 and 'false' otherwise.
2755
3196
 
2756
3197
 
2757
- ```ruby
3198
+ ``` ruby
2758
3199
  # obtain a vector with 'true' for cars with automatic transmission
2759
- automatic = (~:mtcars).am.eq 0
3200
+ automatic = (~R[:mtcars]).am.eq 0
2760
3201
  puts automatic
2761
3202
  ```
2762
3203
 
2763
3204
  ```
2764
- ## [1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
2765
- ## [12] TRUE TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE
2766
- ## [23] TRUE TRUE TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
3205
+ ## [1] FALSE FALSE FALSE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
3206
+ ## [13] TRUE TRUE TRUE TRUE TRUE FALSE FALSE FALSE TRUE TRUE TRUE TRUE
3207
+ ## [25] TRUE FALSE FALSE FALSE FALSE FALSE FALSE FALSE
2767
3208
  ```
2768
3209
 
2769
3210
  Using this logical vector, the data frame is indexed, returning a new data frame in
2770
3211
  which all cars have automatic transmission.
2771
3212
 
2772
3213
 
2773
- ```ruby
3214
+ ``` ruby
2774
3215
  # slice the data frame by using this vector
2775
- puts (~:mtcars)[automatic, :all]
3216
+ puts (~R[:mtcars])[automatic, :all]
2776
3217
  ```
2777
3218
 
2778
3219
  ```
@@ -2805,12 +3246,12 @@ Galaaz extends Ruby to work with complex expressions, similar to R's expressions
2805
3246
 
2806
3247
  ## Expressions from operators
2807
3248
 
2808
- The code bellow
3249
+ The code below
2809
3250
  creates an expression summing two symbols
2810
3251
 
2811
3252
 
2812
- ```ruby
2813
- exp1 = :a + :b
3253
+ ``` ruby
3254
+ exp1 = R[:a] + R[:b]
2814
3255
  puts exp1
2815
3256
  ```
2816
3257
 
@@ -2820,20 +3261,20 @@ puts exp1
2820
3261
  We can build any complex mathematical expression
2821
3262
 
2822
3263
 
2823
- ```ruby
2824
- exp2 = (:a + :b) * 2.0 + :c ** 2 / :z
3264
+ ``` ruby
3265
+ exp2 = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
2825
3266
  puts exp2
2826
3267
  ```
2827
3268
 
2828
3269
  ```
2829
- ## (a + b) * 2 + c^2L/z
3270
+ ## a + b * 2.0 + c ^ 2L / z
2830
3271
  ```
2831
3272
 
2832
3273
  It is also possible to use inequality operators in building expressions
2833
3274
 
2834
3275
 
2835
- ```ruby
2836
- exp3 = (:a + :b) >= :z
3276
+ ``` ruby
3277
+ exp3 = (R[:a] + R[:b]) >= :z
2837
3278
  puts exp3
2838
3279
  ```
2839
3280
 
@@ -2846,8 +3287,8 @@ notation for those operators such as (.gt, .ge, etc.). So the same expression w
2846
3287
  above can also be written as
2847
3288
 
2848
3289
 
2849
- ```ruby
2850
- exp4 = (:a + :b).ge :z
3290
+ ``` ruby
3291
+ exp4 = (R[:a] + R[:b]).ge :z
2851
3292
  puts exp4
2852
3293
  ```
2853
3294
 
@@ -2860,8 +3301,8 @@ those are expressions involving '==', and '='. In order to write an expression
2860
3301
  need to use the method '.eq' and for '=' we need the function '.assign'
2861
3302
 
2862
3303
 
2863
- ```ruby
2864
- exp5 = (:a + :b).eq :z
3304
+ ``` ruby
3305
+ exp5 = (R[:a] + R[:b]).eq :z
2865
3306
  puts exp5
2866
3307
  ```
2867
3308
 
@@ -2870,8 +3311,8 @@ puts exp5
2870
3311
  ```
2871
3312
 
2872
3313
 
2873
- ```ruby
2874
- exp6 = :y.assign :a + :b
3314
+ ``` ruby
3315
+ exp6 = R[:y].assign R[:a] + R[:b]
2875
3316
  puts exp6
2876
3317
  ```
2877
3318
 
@@ -2882,12 +3323,12 @@ In general we think that using the functional notation is preferable to using th
2882
3323
  symbolic notation as otherwise, we end up writing invalid expressions such as
2883
3324
 
2884
3325
 
2885
- ```ruby
2886
- exp_wrong = (:a + :b) == :z
3326
+ ``` ruby
3327
+ exp_wrong = (R[:a] + R[:b]) == :z
2887
3328
  puts exp_wrong
2888
3329
  ```
2889
3330
  and it might be difficult to understand what is going on here. The problem lies with the fact that
2890
- when using '==' we are comparing expression (:a + :b) to expression :z with '=='. When the
3331
+ when using '==' we are comparing expression (R[:a] + R[:b]) to expression :z with '=='. When the
2891
3332
  comparison is executed, the system tries to evaluate :a, :b and :z, and those symbols at
2892
3333
  this time are not bound to anything and we get a "object 'a' not found" message.
2893
3334
  If we only use functional notation, this type of error will not occur.
@@ -2902,8 +3343,8 @@ When we want the function to be part of the expression, we call the function pre
2902
3343
  by the letter E, such as 'E.sin(x)'
2903
3344
 
2904
3345
 
2905
- ```ruby
2906
- exp7 = :y.assign E.sin(:x)
3346
+ ``` ruby
3347
+ exp7 = R[:y].assign E.sin(R[:x])
2907
3348
  puts exp7
2908
3349
  ```
2909
3350
 
@@ -2914,8 +3355,8 @@ puts exp7
2914
3355
  Expressions can also be written using '.' notation:
2915
3356
 
2916
3357
 
2917
- ```ruby
2918
- exp8 = :y.assign :x.sin
3358
+ ``` ruby
3359
+ exp8 = R[:y].assign R[:x].sin
2919
3360
  puts exp8
2920
3361
  ```
2921
3362
 
@@ -2926,8 +3367,8 @@ puts exp8
2926
3367
  When a function has multiple arguments, the first one can be used before the '.':
2927
3368
 
2928
3369
 
2929
- ```ruby
2930
- exp9 = :x.c(:y)
3370
+ ``` ruby
3371
+ exp9 = R[:x].c(R[:y])
2931
3372
  puts exp9
2932
3373
  ```
2933
3374
 
@@ -2941,19 +3382,19 @@ Expressions can be evaluated by calling function 'eval' with a binding. A bindin
2941
3382
  with a list:
2942
3383
 
2943
3384
 
2944
- ```ruby
2945
- exp = (:a + :b) * 2.0 + :c ** 2 / :z
3385
+ ``` ruby
3386
+ exp = (R[:a] + R[:b]) * 2.0 + R[:c] ** 2 / R[:z]
2946
3387
  puts exp.eval(R.list(a: 10, b: 20, c: 30, z: 40))
2947
3388
  ```
2948
3389
 
2949
3390
  ```
2950
- ## [1] 82.5
3391
+ ## [1] 72.5
2951
3392
  ```
2952
3393
 
2953
3394
  ... with a data frame:
2954
3395
 
2955
3396
 
2956
- ```ruby
3397
+ ``` ruby
2957
3398
  df = R.data__frame(
2958
3399
  a: R.c(1, 2, 3),
2959
3400
  b: R.c(10, 20, 30),
@@ -2964,13 +3405,13 @@ puts exp.eval(df)
2964
3405
  ```
2965
3406
 
2966
3407
  ```
2967
- ## [1] 32 64 96
3408
+ ## [1] 31 62 93
2968
3409
  ```
2969
3410
 
2970
3411
  # Manipulating Data
2971
3412
 
2972
3413
  One of the major benefits of Galaaz is to bring strong data manipulation to Ruby. The following
2973
- examples were extracted from Hardley's "R for Data Science" (https://r4ds.had.co.nz/). This
3414
+ examples were extracted from Hadley's "R for Data Science" (https://r4ds.had.co.nz/). This
2974
3415
  is a highly recommended book for those not already familiar with the 'tidyverse' style of
2975
3416
  programming in R. In the sections to follow, we will limit ourselves to convert the R code to
2976
3417
  Galaaz.
@@ -2982,62 +3423,60 @@ locally, and if not, installs it. This data frame contains all 336,776 flights t
2982
3423
  departed from New York City in 2013. The data comes from the US Bureau of
2983
3424
  Transportation Statistics.
2984
3425
 
2985
- Dplyr uses 'tibbles' in place of data frames; unfortunately, tibbles do not print yet properly in
2986
- Galaaz due to a bug in fastR. In order to print a tibble we need to convert it to a data frame
2987
- using the 'as\_\_data__frame' method.
3426
+ Dplyr often uses **tibbles** in place of classic data frames. In Galaaz, printing may differ from
3427
+ the R console; if you need a classic tabular printout, convert with **`as__data__frame`** (or use
3428
+ `head` / `str` in R via `R` calls).
2988
3429
 
2989
3430
 
2990
- ```ruby
3431
+ ``` ruby
2991
3432
  R.install_and_loads('nycflights13')
2992
3433
  R.library('dplyr')
2993
3434
  ```
2994
3435
 
2995
3436
 
2996
- ```ruby
2997
- flights = ~:flights
3437
+ ``` ruby
3438
+ flights = ~R[:flights]
2998
3439
  puts flights.head
2999
3440
  ```
3000
3441
 
3001
3442
  ```
3002
- ## # A tibble: 6 x 19
3003
- ## year month day dep_time sched_dep_time dep_delay arr_time
3004
- ## <int> <int> <int> <int> <int> <dbl> <int>
3005
- ## 1 2013 1 1 517 515 2 830
3006
- ## 2 2013 1 1 533 529 4 850
3007
- ## 3 2013 1 1 542 540 2 923
3008
- ## 4 2013 1 1 544 545 -1 1004
3009
- ## 5 2013 1 1 554 600 -6 812
3010
- ## 6 2013 1 1 554 558 -4 740
3011
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3012
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3013
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3014
- ## # time_hour <dttm>
3443
+ ## # A tibble: 6 × 19
3444
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3445
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3446
+ ## 1 2013 1 1 517 515 2 830 819
3447
+ ## 2 2013 1 1 533 529 4 850 830
3448
+ ## 3 2013 1 1 542 540 2 923 850
3449
+ ## 4 2013 1 1 544 545 -1 1004 1022
3450
+ ## 5 2013 1 1 554 600 -6 812 837
3451
+ ## 6 2013 1 1 554 558 -4 740 728
3452
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3453
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3454
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3015
3455
  ```
3016
3456
 
3017
3457
  ## Filtering rows with Filter
3018
3458
 
3019
3459
  In this example we filter the flights data set by giving to the filter function two expressions:
3020
- the first :month.eq 1
3460
+ the first R[:month].eq 1
3021
3461
 
3022
3462
 
3023
- ```ruby
3024
- puts flights.filter((:month.eq 1), (:day.eq 1)).head
3463
+ ``` ruby
3464
+ puts flights.filter((R[:month].eq 1), (R[:day].eq 1)).head
3025
3465
  ```
3026
3466
 
3027
3467
  ```
3028
- ## # A tibble: 6 x 19
3029
- ## year month day dep_time sched_dep_time dep_delay arr_time
3030
- ## <int> <int> <int> <int> <int> <dbl> <int>
3031
- ## 1 2013 1 1 517 515 2 830
3032
- ## 2 2013 1 1 533 529 4 850
3033
- ## 3 2013 1 1 542 540 2 923
3034
- ## 4 2013 1 1 544 545 -1 1004
3035
- ## 5 2013 1 1 554 600 -6 812
3036
- ## 6 2013 1 1 554 558 -4 740
3037
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3038
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3039
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3040
- ## # time_hour <dttm>
3468
+ ## # A tibble: 6 × 19
3469
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3470
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3471
+ ## 1 2013 1 1 517 515 2 830 819
3472
+ ## 2 2013 1 1 533 529 4 850 830
3473
+ ## 3 2013 1 1 542 540 2 923 850
3474
+ ## 4 2013 1 1 544 545 -1 1004 1022
3475
+ ## 5 2013 1 1 554 600 -6 812 837
3476
+ ## 6 2013 1 1 554 558 -4 740 728
3477
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3478
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3479
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3041
3480
  ```
3042
3481
 
3043
3482
  ## Logical Operators
@@ -3045,24 +3484,23 @@ puts flights.filter((:month.eq 1), (:day.eq 1)).head
3045
3484
  All flights that departed in November of December
3046
3485
 
3047
3486
 
3048
- ```ruby
3049
- puts flights.filter((:month.eq 11) | (:month.eq 12)).head
3487
+ ``` ruby
3488
+ puts flights.filter((R[:month].eq 11) | (R[:month].eq 12)).head
3050
3489
  ```
3051
3490
 
3052
3491
  ```
3053
- ## # A tibble: 6 x 19
3054
- ## year month day dep_time sched_dep_time dep_delay arr_time
3055
- ## <int> <int> <int> <int> <int> <dbl> <int>
3056
- ## 1 2013 11 1 5 2359 6 352
3057
- ## 2 2013 11 1 35 2250 105 123
3058
- ## 3 2013 11 1 455 500 -5 641
3059
- ## 4 2013 11 1 539 545 -6 856
3060
- ## 5 2013 11 1 542 545 -3 831
3061
- ## 6 2013 11 1 549 600 -11 912
3062
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3063
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3064
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3065
- ## # time_hour <dttm>
3492
+ ## # A tibble: 6 × 19
3493
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3494
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3495
+ ## 1 2013 11 1 5 2359 6 352 345
3496
+ ## 2 2013 11 1 35 2250 105 123 2356
3497
+ ## 3 2013 11 1 455 500 -5 641 651
3498
+ ## 4 2013 11 1 539 545 -6 856 827
3499
+ ## 5 2013 11 1 542 545 -3 831 855
3500
+ ## 6 2013 11 1 549 600 -11 912 923
3501
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3502
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3503
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3066
3504
  ```
3067
3505
 
3068
3506
  The same as above, but using the 'in' operator. In R, it is possible to define many operators
@@ -3071,24 +3509,23 @@ operators from Galaaz the '._' method is used, where the first argument is the o
3071
3509
  symbol, in this case ':in' and the second argument is the vector:
3072
3510
 
3073
3511
 
3074
- ```ruby
3075
- puts flights.filter(:month._ :in, R.c(11, 12)).head
3512
+ ``` ruby
3513
+ puts flights.filter(R[:month]._ :in, R.c(11, 12)).head
3076
3514
  ```
3077
3515
 
3078
3516
  ```
3079
- ## # A tibble: 6 x 19
3080
- ## year month day dep_time sched_dep_time dep_delay arr_time
3081
- ## <int> <int> <int> <int> <int> <dbl> <int>
3082
- ## 1 2013 11 1 5 2359 6 352
3083
- ## 2 2013 11 1 35 2250 105 123
3084
- ## 3 2013 11 1 455 500 -5 641
3085
- ## 4 2013 11 1 539 545 -6 856
3086
- ## 5 2013 11 1 542 545 -3 831
3087
- ## 6 2013 11 1 549 600 -11 912
3088
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3089
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3090
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3091
- ## # time_hour <dttm>
3517
+ ## # A tibble: 6 × 19
3518
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3519
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3520
+ ## 1 2013 11 1 5 2359 6 352 345
3521
+ ## 2 2013 11 1 35 2250 105 123 2356
3522
+ ## 3 2013 11 1 455 500 -5 641 651
3523
+ ## 4 2013 11 1 539 545 -6 856 827
3524
+ ## 5 2013 11 1 542 545 -3 831 855
3525
+ ## 6 2013 11 1 549 600 -11 912 923
3526
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3527
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3528
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3092
3529
  ```
3093
3530
 
3094
3531
  ## Filtering with NA (Not Available)
@@ -3099,17 +3536,17 @@ the values and the result of some subsetting operations that are more consistent
3099
3536
  what is obtained from data frame.
3100
3537
 
3101
3538
 
3102
- ```ruby
3539
+ ``` ruby
3103
3540
  df = R.tibble(x: R.c(1, R::NA, 3))
3104
3541
  puts df
3105
3542
  ```
3106
3543
 
3107
3544
  ```
3108
- ## # A tibble: 3 x 1
3545
+ ## # A tibble: 3 × 1
3109
3546
  ## x
3110
3547
  ## <int>
3111
3548
  ## 1 1
3112
- ## 2
3549
+ ## 2 NA
3113
3550
  ## 3 3
3114
3551
  ```
3115
3552
 
@@ -3117,12 +3554,12 @@ Now filtering by :x > 1 shows all lines that satisfy this condition, where the r
3117
3554
  not.
3118
3555
 
3119
3556
 
3120
- ```ruby
3121
- puts df.filter(:x > 1)
3557
+ ``` ruby
3558
+ puts df.filter(R[:x] > 1)
3122
3559
  ```
3123
3560
 
3124
3561
  ```
3125
- ## # A tibble: 1 x 1
3562
+ ## # A tibble: 1 × 1
3126
3563
  ## x
3127
3564
  ## <int>
3128
3565
  ## 1 3
@@ -3131,15 +3568,15 @@ puts df.filter(:x > 1)
3131
3568
  To match an NA use method 'is__na'
3132
3569
 
3133
3570
 
3134
- ```ruby
3135
- puts df.filter((:x.is__na) | (:x > 1))
3571
+ ``` ruby
3572
+ puts df.filter((R[:x].is__na) | (R[:x] > 1))
3136
3573
  ```
3137
3574
 
3138
3575
  ```
3139
- ## # A tibble: 2 x 1
3576
+ ## # A tibble: 2 × 1
3140
3577
  ## x
3141
3578
  ## <int>
3142
- ## 1
3579
+ ## 1 NA
3143
3580
  ## 2 3
3144
3581
  ```
3145
3582
 
@@ -3148,47 +3585,45 @@ puts df.filter((:x.is__na) | (:x > 1))
3148
3585
  Arrange reorders the rows of a data frame by the given arguments.
3149
3586
 
3150
3587
 
3151
- ```ruby
3588
+ ``` ruby
3152
3589
  puts flights.arrange(:year, :month, :day).head
3153
3590
  ```
3154
3591
 
3155
3592
  ```
3156
- ## # A tibble: 6 x 19
3157
- ## year month day dep_time sched_dep_time dep_delay arr_time
3158
- ## <int> <int> <int> <int> <int> <dbl> <int>
3159
- ## 1 2013 1 1 517 515 2 830
3160
- ## 2 2013 1 1 533 529 4 850
3161
- ## 3 2013 1 1 542 540 2 923
3162
- ## 4 2013 1 1 544 545 -1 1004
3163
- ## 5 2013 1 1 554 600 -6 812
3164
- ## 6 2013 1 1 554 558 -4 740
3165
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3166
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3167
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3168
- ## # time_hour <dttm>
3593
+ ## # A tibble: 6 × 19
3594
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3595
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3596
+ ## 1 2013 1 1 517 515 2 830 819
3597
+ ## 2 2013 1 1 533 529 4 850 830
3598
+ ## 3 2013 1 1 542 540 2 923 850
3599
+ ## 4 2013 1 1 544 545 -1 1004 1022
3600
+ ## 5 2013 1 1 554 600 -6 812 837
3601
+ ## 6 2013 1 1 554 558 -4 740 728
3602
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3603
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3604
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3169
3605
  ```
3170
3606
 
3171
3607
  To arrange in descending order, use function 'desc'
3172
3608
 
3173
3609
 
3174
- ```ruby
3175
- puts flights.arrange(:dep_delay.desc).head
3610
+ ``` ruby
3611
+ puts flights.arrange(R[:dep_delay].desc).head
3176
3612
  ```
3177
3613
 
3178
3614
  ```
3179
- ## # A tibble: 6 x 19
3180
- ## year month day dep_time sched_dep_time dep_delay arr_time
3181
- ## <int> <int> <int> <int> <int> <dbl> <int>
3182
- ## 1 2013 1 9 641 900 1301 1242
3183
- ## 2 2013 6 15 1432 1935 1137 1607
3184
- ## 3 2013 1 10 1121 1635 1126 1239
3185
- ## 4 2013 9 20 1139 1845 1014 1457
3186
- ## 5 2013 7 22 845 1600 1005 1044
3187
- ## 6 2013 4 10 1100 1900 960 1342
3188
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3189
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3190
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3191
- ## # time_hour <dttm>
3615
+ ## # A tibble: 6 × 19
3616
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3617
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3618
+ ## 1 2013 1 9 641 900 1301 1242 1530
3619
+ ## 2 2013 6 15 1432 1935 1137 1607 2120
3620
+ ## 3 2013 1 10 1121 1635 1126 1239 1810
3621
+ ## 4 2013 9 20 1139 1845 1014 1457 2210
3622
+ ## 5 2013 7 22 845 1600 1005 1044 1815
3623
+ ## 6 2013 4 10 1100 1900 960 1342 2211
3624
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3625
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3626
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3192
3627
  ```
3193
3628
 
3194
3629
  ## Selecting columns
@@ -3196,12 +3631,12 @@ puts flights.arrange(:dep_delay.desc).head
3196
3631
  To select specific columns from a dataset we use function 'select':
3197
3632
 
3198
3633
 
3199
- ```ruby
3634
+ ``` ruby
3200
3635
  puts flights.select(:year, :month, :day).head
3201
3636
  ```
3202
3637
 
3203
3638
  ```
3204
- ## # A tibble: 6 x 3
3639
+ ## # A tibble: 6 × 3
3205
3640
  ## year month day
3206
3641
  ## <int> <int> <int>
3207
3642
  ## 1 2013 1 1
@@ -3215,12 +3650,12 @@ puts flights.select(:year, :month, :day).head
3215
3650
  It is also possible to select column in a given range
3216
3651
 
3217
3652
 
3218
- ```ruby
3219
- puts flights.select(:year.up_to :day).head
3653
+ ``` ruby
3654
+ puts flights.select(R[:year].up_to(R[:day])).head
3220
3655
  ```
3221
3656
 
3222
3657
  ```
3223
- ## # A tibble: 6 x 3
3658
+ ## # A tibble: 6 × 3
3224
3659
  ## year month day
3225
3660
  ## <int> <int> <int>
3226
3661
  ## 1 2013 1 1
@@ -3234,12 +3669,12 @@ puts flights.select(:year.up_to :day).head
3234
3669
  Select all columns that start with a given name sequence
3235
3670
 
3236
3671
 
3237
- ```ruby
3672
+ ``` ruby
3238
3673
  puts flights.select(E.starts_with('arr')).head
3239
3674
  ```
3240
3675
 
3241
3676
  ```
3242
- ## # A tibble: 6 x 2
3677
+ ## # A tibble: 6 × 2
3243
3678
  ## arr_time arr_delay
3244
3679
  ## <int> <dbl>
3245
3680
  ## 1 830 11
@@ -3264,32 +3699,31 @@ Other functions that can be used:
3264
3699
  A helper function that comes in handy when we just want to rearrange column order is 'Everything':
3265
3700
 
3266
3701
 
3267
- ```ruby
3702
+ ``` ruby
3268
3703
  puts flights.select(:year, :month, :day, E.everything).head
3269
3704
  ```
3270
3705
 
3271
3706
  ```
3272
- ## # A tibble: 6 x 19
3273
- ## year month day dep_time sched_dep_time dep_delay arr_time
3274
- ## <int> <int> <int> <int> <int> <dbl> <int>
3275
- ## 1 2013 1 1 517 515 2 830
3276
- ## 2 2013 1 1 533 529 4 850
3277
- ## 3 2013 1 1 542 540 2 923
3278
- ## 4 2013 1 1 544 545 -1 1004
3279
- ## 5 2013 1 1 554 600 -6 812
3280
- ## 6 2013 1 1 554 558 -4 740
3281
- ## # … with 12 more variables: sched_arr_time <int>, arr_delay <dbl>,
3282
- ## # carrier <chr>, flight <int>, tailnum <chr>, origin <chr>, dest <chr>,
3283
- ## # air_time <dbl>, distance <dbl>, hour <dbl>, minute <dbl>,
3284
- ## # time_hour <dttm>
3707
+ ## # A tibble: 6 × 19
3708
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3709
+ ## <int> <int> <int> <int> <int> <dbl> <int> <int>
3710
+ ## 1 2013 1 1 517 515 2 830 819
3711
+ ## 2 2013 1 1 533 529 4 850 830
3712
+ ## 3 2013 1 1 542 540 2 923 850
3713
+ ## 4 2013 1 1 544 545 -1 1004 1022
3714
+ ## 5 2013 1 1 554 600 -6 812 837
3715
+ ## 6 2013 1 1 554 558 -4 740 728
3716
+ ## # ℹ 11 more variables: arr_delay <dbl>, carrier <chr>, flight <int>,
3717
+ ## # tailnum <chr>, origin <chr>, dest <chr>, air_time <dbl>, distance <dbl>,
3718
+ ## # hour <dbl>, minute <dbl>, time_hour <dttm>
3285
3719
  ```
3286
3720
 
3287
3721
  ## Add variables to a dataframe with 'mutate'
3288
3722
 
3289
3723
 
3290
- ```ruby
3724
+ ``` ruby
3291
3725
  flights_sm = flights.
3292
- select((:year.up_to :day),
3726
+ select((R[:year].up_to(R[:day])),
3293
3727
  E.ends_with('delay'),
3294
3728
  :distance,
3295
3729
  :air_time)
@@ -3298,7 +3732,7 @@ puts flights_sm.head
3298
3732
  ```
3299
3733
 
3300
3734
  ```
3301
- ## # A tibble: 6 x 7
3735
+ ## # A tibble: 6 × 7
3302
3736
  ## year month day dep_delay arr_delay distance air_time
3303
3737
  ## <int> <int> <int> <dbl> <dbl> <dbl> <dbl>
3304
3738
  ## 1 2013 1 1 2 11 1400 227
@@ -3310,15 +3744,15 @@ puts flights_sm.head
3310
3744
  ```
3311
3745
 
3312
3746
 
3313
- ```ruby
3747
+ ``` ruby
3314
3748
  flights_sm = flights_sm.
3315
- mutate(gain: :dep_delay - :arr_delay,
3316
- speed: :distance / :air_time * 60)
3749
+ mutate(gain: R[:dep_delay] - R[:arr_delay],
3750
+ speed: R[:distance] / R[:air_time] * 60)
3317
3751
  puts flights_sm.head
3318
3752
  ```
3319
3753
 
3320
3754
  ```
3321
- ## # A tibble: 6 x 9
3755
+ ## # A tibble: 6 × 9
3322
3756
  ## year month day dep_delay arr_delay distance air_time gain speed
3323
3757
  ## <int> <int> <int> <dbl> <dbl> <dbl> <dbl> <dbl> <dbl>
3324
3758
  ## 1 2013 1 1 2 11 1400 227 -9 370.
@@ -3335,30 +3769,30 @@ Function 'summarise' calculates summaries for the data frame. When no 'group_by'
3335
3769
  a single value is obtained from the data frame:
3336
3770
 
3337
3771
 
3338
- ```ruby
3772
+ ``` ruby
3339
3773
  puts flights.summarise(delay: E.mean(:dep_delay, na__rm: true))
3340
3774
  ```
3341
3775
 
3342
3776
  ```
3343
- ## # A tibble: 1 x 1
3777
+ ## # A tibble: 1 × 1
3344
3778
  ## delay
3345
3779
  ## <dbl>
3346
3780
  ## 1 12.6
3347
3781
  ```
3348
3782
 
3349
- When a data frame is groupe with 'group_by' summaries apply to the given group:
3783
+ When a data frame is grouped with 'group_by' summaries apply to the given group:
3350
3784
 
3351
3785
 
3352
- ```ruby
3786
+ ``` ruby
3353
3787
  by_day = flights.group_by(:year, :month, :day)
3354
- puts by_day.summarise(delay: :dep_delay.mean(na__rm: true)).head
3788
+ puts by_day.summarise(delay: R[:dep_delay].mean(na__rm: true)).head
3355
3789
  ```
3356
3790
 
3357
3791
  ```
3358
- ## # A tibble: 6 x 4
3792
+ ## # A tibble: 6 × 4
3359
3793
  ## # Groups: year, month [1]
3360
3794
  ## year month day delay
3361
- ## * <int> <int> <int> <dbl>
3795
+ ## <int> <int> <int> <dbl>
3362
3796
  ## 1 2013 1 1 11.5
3363
3797
  ## 2 2013 1 2 13.9
3364
3798
  ## 3 2013 1 3 11.0
@@ -3370,20 +3804,20 @@ puts by_day.summarise(delay: :dep_delay.mean(na__rm: true)).head
3370
3804
  Next we put many operations together by pipping them one after the other:
3371
3805
 
3372
3806
 
3373
- ```ruby
3807
+ ``` ruby
3374
3808
  delays = flights.
3375
3809
  group_by(:dest).
3376
3810
  summarise(
3377
3811
  count: E.n,
3378
- dist: :distance.mean(na__rm: true),
3379
- delay: :arr_delay.mean(na__rm: true)).
3380
- filter(:count > 20, :dest != "NHL")
3812
+ dist: R[:distance].mean(na__rm: true),
3813
+ delay: R[:arr_delay].mean(na__rm: true)).
3814
+ filter(R[:count] > 20, R[:dest] != "NHL")
3381
3815
 
3382
3816
  puts delays.head
3383
3817
  ```
3384
3818
 
3385
3819
  ```
3386
- ## # A tibble: 6 x 4
3820
+ ## # A tibble: 6 × 4
3387
3821
  ## dest count dist delay
3388
3822
  ## <chr> <int> <dbl> <dbl>
3389
3823
  ## 1 ABQ 254 1826 4.38
@@ -3396,48 +3830,67 @@ puts delays.head
3396
3830
 
3397
3831
  # Using Data Table
3398
3832
 
3833
+ The next chunk converts the **nycflights13** `flights` tibble already loaded above into a
3834
+ **`data.table`**. That keeps the manual offline and avoids downloading a remote CSV during gknit
3835
+ (network stalls look like bridge hangs when the transfer runs inside a single R eval).
3399
3836
 
3400
- ```ruby
3837
+
3838
+ ``` ruby
3401
3839
  R.library('data.table')
3402
- R.install_and_loads('curl')
3403
3840
 
3404
- input = "https://raw.githubusercontent.com/Rdatatable/data.table/master/vignettes/flights14.csv"
3405
- flights = R.fread(input)
3406
- puts flights
3841
+ flights = R.as__data__table(~R[:flights])
3407
3842
  puts flights.dim
3408
- ```
3409
-
3410
- ```
3411
- ## year month day dep_delay arr_delay carrier origin dest air_time
3412
- ## 1: 2014 1 1 14 13 AA JFK LAX 359
3413
- ## 2: 2014 1 1 -3 13 AA JFK LAX 363
3414
- ## 3: 2014 1 1 2 9 AA JFK LAX 351
3415
- ## 4: 2014 1 1 -8 -26 AA LGA PBI 157
3416
- ## 5: 2014 1 1 2 1 AA JFK LAX 350
3417
- ## ---
3418
- ## 253312: 2014 10 31 1 -30 UA LGA IAH 201
3419
- ## 253313: 2014 10 31 -5 -14 UA EWR IAH 189
3420
- ## 253314: 2014 10 31 -8 16 MQ LGA RDU 83
3421
- ## 253315: 2014 10 31 -4 15 MQ LGA DTW 75
3422
- ## 253316: 2014 10 31 -5 1 MQ LGA SDF 110
3423
- ## distance hour
3424
- ## 1: 2475 9
3425
- ## 2: 2475 11
3426
- ## 3: 2475 19
3427
- ## 4: 1035 7
3428
- ## 5: 2475 13
3429
- ## ---
3430
- ## 253312: 1416 14
3431
- ## 253313: 1400 8
3432
- ## 253314: 431 11
3433
- ## 253315: 502 11
3434
- ## 253316: 659 8
3435
- ## [1] 253316 11
3436
- ```
3437
-
3438
-
3439
- ```ruby
3440
-
3843
+ puts R.head(flights, 12)
3844
+ ```
3845
+
3846
+ ```
3847
+ ## [1] 336776 19
3848
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3849
+ ## <int> <int> <int> <int> <int> <num> <int> <int>
3850
+ ## 1: 2013 1 1 517 515 2 830 819
3851
+ ## 2: 2013 1 1 533 529 4 850 830
3852
+ ## 3: 2013 1 1 542 540 2 923 850
3853
+ ## 4: 2013 1 1 544 545 -1 1004 1022
3854
+ ## 5: 2013 1 1 554 600 -6 812 837
3855
+ ## 6: 2013 1 1 554 558 -4 740 728
3856
+ ## 7: 2013 1 1 555 600 -5 913 854
3857
+ ## 8: 2013 1 1 557 600 -3 709 723
3858
+ ## 9: 2013 1 1 557 600 -3 838 846
3859
+ ## 10: 2013 1 1 558 600 -2 753 745
3860
+ ## 11: 2013 1 1 558 600 -2 849 851
3861
+ ## 12: 2013 1 1 558 600 -2 853 856
3862
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
3863
+ ## <num> <char> <int> <char> <char> <char> <num> <num> <num>
3864
+ ## 1: 11 UA 1545 N14228 EWR IAH 227 1400 5
3865
+ ## 2: 20 UA 1714 N24211 LGA IAH 227 1416 5
3866
+ ## 3: 33 AA 1141 N619AA JFK MIA 160 1089 5
3867
+ ## 4: -18 B6 725 N804JB JFK BQN 183 1576 5
3868
+ ## 5: -25 DL 461 N668DN LGA ATL 116 762 6
3869
+ ## 6: 12 UA 1696 N39463 EWR ORD 150 719 5
3870
+ ## 7: 19 B6 507 N516JB EWR FLL 158 1065 6
3871
+ ## 8: -14 EV 5708 N829AS LGA IAD 53 229 6
3872
+ ## 9: -8 B6 79 N593JB JFK MCO 140 944 6
3873
+ ## 10: 8 AA 301 N3ALAA LGA ORD 138 733 6
3874
+ ## 11: -2 B6 49 N793JB JFK PBI 149 1028 6
3875
+ ## 12: -3 B6 71 N657JB JFK TPA 158 1005 6
3876
+ ## minute time_hour
3877
+ ## <num> <POSc>
3878
+ ## 1: 15 2013-01-01 05:00:00
3879
+ ## 2: 29 2013-01-01 05:00:00
3880
+ ## 3: 40 2013-01-01 05:00:00
3881
+ ## 4: 45 2013-01-01 05:00:00
3882
+ ## 5: 0 2013-01-01 06:00:00
3883
+ ## 6: 58 2013-01-01 05:00:00
3884
+ ## 7: 0 2013-01-01 06:00:00
3885
+ ## 8: 0 2013-01-01 06:00:00
3886
+ ## 9: 0 2013-01-01 06:00:00
3887
+ ## 10: 0 2013-01-01 06:00:00
3888
+ ## 11: 0 2013-01-01 06:00:00
3889
+ ## 12: 0 2013-01-01 06:00:00
3890
+ ```
3891
+
3892
+
3893
+ ``` ruby
3441
3894
  data_table = R.data__table(
3442
3895
  ID: R.c("b","b","b","a","a","c"),
3443
3896
  a: (1..6),
@@ -3450,20 +3903,21 @@ puts data_table.ID
3450
3903
  ```
3451
3904
 
3452
3905
  ```
3453
- ## ID a b c
3454
- ## 1: b 1 7 13
3455
- ## 2: b 2 8 14
3456
- ## 3: b 3 9 15
3457
- ## 4: a 4 10 16
3458
- ## 5: a 5 11 17
3459
- ## 6: c 6 12 18
3906
+ ## ID a b c
3907
+ ## <char> <int> <int> <int>
3908
+ ## 1: b 1 7 13
3909
+ ## 2: b 2 8 14
3910
+ ## 3: b 3 9 15
3911
+ ## 4: a 4 10 16
3912
+ ## 5: a 5 11 17
3913
+ ## 6: c 6 12 18
3460
3914
  ## [1] "b" "b" "b" "a" "a" "c"
3461
3915
  ```
3462
3916
 
3463
3917
 
3464
- ```ruby
3918
+ ``` ruby
3465
3919
  # subset rows in i
3466
- ans = flights[(:origin.eq "JFK") & (:month.eq 6)]
3920
+ ans = flights[(R[:origin].eq "JFK") & (R[:month].eq 6)]
3467
3921
  puts ans.head
3468
3922
 
3469
3923
  # Get the first two rows from flights.
@@ -3471,98 +3925,350 @@ puts ans.head
3471
3925
  ans = flights[(1..2)]
3472
3926
  puts ans
3473
3927
 
3474
- # Sort flights first by column origin in ascending order, and then by dest in descending order:
3475
-
3928
+ # Sort by origin asc, then dest desc (example kept commented):
3476
3929
  # ans = flights[E.order(:origin, -(:dest))]
3477
3930
  # puts ans.head
3478
3931
  ```
3479
3932
 
3480
3933
  ```
3481
- ## year month day dep_delay arr_delay carrier origin dest air_time
3482
- ## 1: 2014 6 1 -9 -5 AA JFK LAX 324
3483
- ## 2: 2014 6 1 -10 -13 AA JFK LAX 329
3484
- ## 3: 2014 6 1 18 -1 AA JFK LAX 326
3485
- ## 4: 2014 6 1 -6 -16 AA JFK LAX 320
3486
- ## 5: 2014 6 1 -4 -45 AA JFK LAX 326
3487
- ## 6: 2014 6 1 -6 -23 AA JFK LAX 329
3488
- ## distance hour
3489
- ## 1: 2475 8
3490
- ## 2: 2475 12
3491
- ## 3: 2475 7
3492
- ## 4: 2475 10
3493
- ## 5: 2475 18
3494
- ## 6: 2475 14
3495
- ## year month day dep_delay arr_delay carrier origin dest air_time
3496
- ## 1: 2014 1 1 14 13 AA JFK LAX 359
3497
- ## 2: 2014 1 1 -3 13 AA JFK LAX 363
3498
- ## distance hour
3499
- ## 1: 2475 9
3500
- ## 2: 2475 11
3501
- ```
3502
-
3503
-
3504
- ```ruby
3934
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3935
+ ## <int> <int> <int> <int> <int> <num> <int> <int>
3936
+ ## 1: 2013 6 1 2 2359 3 341 350
3937
+ ## 2: 2013 6 1 538 545 -7 925 922
3938
+ ## 3: 2013 6 1 539 540 -1 832 840
3939
+ ## 4: 2013 6 1 553 600 -7 700 711
3940
+ ## 5: 2013 6 1 554 600 -6 851 908
3941
+ ## 6: 2013 6 1 557 600 -3 934 942
3942
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
3943
+ ## <num> <char> <int> <char> <char> <char> <num> <num> <num>
3944
+ ## 1: -9 B6 739 N618JB JFK PSE 200 1617 23
3945
+ ## 2: 3 B6 725 N806JB JFK BQN 203 1576 5
3946
+ ## 3: -8 AA 701 N5EAAA JFK MIA 140 1089 5
3947
+ ## 4: -11 EV 5716 N835AS JFK IAD 42 228 6
3948
+ ## 5: -17 UA 1159 N33132 JFK LAX 330 2475 6
3949
+ ## 6: -8 B6 715 N766JB JFK SJU 198 1598 6
3950
+ ## minute time_hour
3951
+ ## <num> <POSc>
3952
+ ## 1: 59 2013-06-01 23:00:00
3953
+ ## 2: 45 2013-06-01 05:00:00
3954
+ ## 3: 40 2013-06-01 05:00:00
3955
+ ## 4: 0 2013-06-01 06:00:00
3956
+ ## 5: 0 2013-06-01 06:00:00
3957
+ ## 6: 0 2013-06-01 06:00:00
3958
+ ## year month day dep_time sched_dep_time dep_delay arr_time sched_arr_time
3959
+ ## <int> <int> <int> <int> <int> <num> <int> <int>
3960
+ ## 1: 2013 1 1 517 515 2 830 819
3961
+ ## 2: 2013 1 1 533 529 4 850 830
3962
+ ## arr_delay carrier flight tailnum origin dest air_time distance hour
3963
+ ## <num> <char> <int> <char> <char> <char> <num> <num> <num>
3964
+ ## 1: 11 UA 1545 N14228 EWR IAH 227 1400 5
3965
+ ## 2: 20 UA 1714 N24211 LGA IAH 227 1416 5
3966
+ ## minute time_hour
3967
+ ## <num> <POSc>
3968
+ ## 1: 15 2013-01-01 05:00:00
3969
+ ## 2: 29 2013-01-01 05:00:00
3970
+ ```
3971
+
3972
+
3973
+ ``` ruby
3505
3974
  # Select column(s) in j
3506
3975
  # select arr_delay column, but return it as a vector.
3507
3976
 
3508
3977
  ans = flights[:all, :arr_delay]
3509
3978
  puts ans.head
3510
3979
 
3511
- # Select arr_delay column, but return as a data.table instead.
3980
+ # arr_delay as data.table (not plain vector).
3512
3981
 
3513
- ans = flights[:all, :arr_delay.list]
3982
+ ans = flights[:all, R[:arr_delay].list]
3514
3983
  puts ans.head
3515
3984
 
3516
- ans = flights[:all, E.list(:arr_delay, :dep_delay)]
3985
+ ans = flights[:all, E.list(R[:arr_delay], R[:dep_delay])]
3517
3986
  ```
3518
3987
 
3519
3988
  ```
3520
- ## [1] 13 13 9 -26 1 0
3989
+ ## [1] 11 20 33 -18 -25 12
3521
3990
  ## arr_delay
3522
- ## 1: 13
3523
- ## 2: 13
3524
- ## 3: 9
3525
- ## 4: -26
3526
- ## 5: 1
3527
- ## 6: 0
3991
+ ## <num>
3992
+ ## 1: 11
3993
+ ## 2: 20
3994
+ ## 3: 33
3995
+ ## 4: -18
3996
+ ## 5: -25
3997
+ ## 6: 12
3998
+ ```
3999
+
4000
+ # Apache Arrow
4001
+
4002
+ [Apache Arrow](https://arrow.apache.org/) is a **columnar** in-memory format used heavily in R
4003
+ and Python for analytics. In Galaaz, **Ruby does not hold an Arrow C++ table itself**; instead you
4004
+ build ordinary Ruby structures (arrays of row hashes), and **`R::Arrow.from_ruby_batches`** creates
4005
+ a real **Arrow `Table` inside GNU R**. From there you use R’s **`arrow`** and **`dplyr`** packages
4006
+ as usual: **`group_by`** on the Arrow table, **`summarise`** for aggregates, then **`collect()`** to
4007
+ materialize a tibble when you need in-memory R rows.
4008
+
4009
+ That pattern matches production use: **JRuby threads** (or sequential code) assemble many rows in
4010
+ Ruby; you pay **one** bridge-heavy handoff to R; **dplyr** runs vectorised work on the Arrow table
4011
+ in R.
4012
+
4013
+ **Prerequisites:** install R packages **`arrow`** and **`dplyr`**. Run scripts with
4014
+ **`bin/galaaz-jruby`** (or the same JVM flags as in **`docs/testing.md`**) so the Arrow JNI stack is
4015
+ available.
4016
+
4017
+ ## Other `R::Arrow` helpers
4018
+
4019
+ The Ruby module **`R::Arrow`** (see `lib/R_interface/r_arrow.rb`) also includes:
4020
+
4021
+ * **`R::Arrow.table_from(df)`** — wrap an R `data.frame` / tibble as an Arrow table.
4022
+ * **`R::Arrow.read_feather` / `write_feather`**, **`read_parquet`**, **`dataset(path)`** — file and
4023
+ dataset IO on paths visible to R.
4024
+
4025
+ ## Example: many Ruby rows → Arrow in R → grouped statistics
4026
+
4027
+ The repository test **`slow-specs/arrow_large_pipeline_spec.rb`** builds **200k rows** in parallel
4028
+ (eight threads × 25,000 rows), pushes them through **`R::Arrow.from_ruby_batches`**, then checks that
4029
+ **dplyr** group summaries match a Ruby reference calculation. The same logic appears below at a
4030
+ **smaller scale** so this manual can knit quickly; increase `thread_count` and `rows_per_thread`
4031
+ when experimenting locally.
4032
+
4033
+
4034
+ ``` ruby
4035
+ # Scaled-down version of slow-specs/arrow_large_pipeline_spec.rb.
4036
+ unless R::Support.eval("requireNamespace('arrow', quietly=TRUE) && requireNamespace('dplyr', quietly=TRUE)") == true
4037
+ puts '(Skip: need arrow + dplyr in R; use bin/galaaz-jruby outside gKnit.)'
4038
+ else
4039
+ thread_count = 4
4040
+ rows_per_thread = 500
4041
+ group_count = 5
4042
+
4043
+ batches = []
4044
+ mutex = Mutex.new
4045
+ threads = []
4046
+
4047
+ thread_count.times do |tid|
4048
+ threads << Thread.new do
4049
+ start = tid * rows_per_thread
4050
+ local = (start...(start + rows_per_thread)).map do |i|
4051
+ {
4052
+ id: i,
4053
+ grp: "g#{i % group_count}",
4054
+ value: (i % 17) + 1,
4055
+ weight: ((i % 5) + 1) * 0.5
4056
+ }
4057
+ end
4058
+ mutex.synchronize { batches << local }
4059
+ end
4060
+ end
4061
+ threads.each(&:join)
4062
+
4063
+ tbl = R::Arrow.from_ruby_batches(batches)
4064
+ puts "R class after from_ruby_batches: #{tbl.rclass}"
4065
+
4066
+ grouped = R.dplyr___group_by(tbl, :grp)
4067
+ summarised = R.dplyr___summarise(
4068
+ grouped,
4069
+ n: E.n(),
4070
+ total: E.sum(:value),
4071
+ wsum: E.sum(R[:value] * R[:weight])
4072
+ )
4073
+ out = R.dplyr___collect(summarised)
4074
+
4075
+ puts 'Per-group summary (first rows):'
4076
+ puts R.as__data__frame(out).head(10)
4077
+
4078
+ total_n = 0
4079
+ (1..(out.nrow >> 0)).each { |i| total_n += (out[['n']][i] >> 0) }
4080
+ puts "Sum of group counts n (should equal #{thread_count * rows_per_thread}): #{total_n}"
4081
+ end
4082
+ ```
4083
+
4084
+ ```
4085
+ ## R class after from_ruby_batches: Table
4086
+ ## Per-group summary (first rows):
4087
+ ## grp n total wsum
4088
+ ## 1 g0 400 3589 1794.5
4089
+ ## 2 g1 400 3598 3598.0
4090
+ ## 3 g2 400 3590 5385.0
4091
+ ## 4 g3 400 3599 7198.0
4092
+ ## 5 g4 400 3591 8977.5
4093
+ ## Sum of group counts n (should equal 2000): 2000
4094
+ ```
4095
+
4096
+ **What to notice:** (1) Ruby only sees **`Hash`** rows and Ruby **`Thread`** objects; (2) a single
4097
+ **`from_ruby_batches`** call creates the Arrow table in R; (3) **`dplyr___group_by`** /
4098
+ **`dplyr___summarise`** / **`dplyr___collect`** mirror **`dplyr::group_by`** /
4099
+ **`dplyr::summarise`** / **`dplyr::collect`** on an Arrow-backed table. For a lighter test, see
4100
+ **`specs/arrow_from_ruby_batches_spec.rb`**; for the full-size benchmark, run
4101
+ **`bin/run_slow_rspec slow-specs/arrow_large_pipeline_spec.rb`**.
4102
+
4103
+ # Bioconductor and DESeq2
4104
+
4105
+ **Bioconductor** packages are ordinary R packages installed from the Bioconductor repositories.
4106
+ Galaaz does not treat them specially: once installed in **GNU R**, you load them with
4107
+ **`R.library`** like any CRAN package.
4108
+
4109
+ ## Installing Bioconductor packages
4110
+
4111
+ From an R session (or `R -e '...'`), use **BiocManager** (see
4112
+ [bioconductor.org](https://bioconductor.org/install/)):
4113
+
4114
+ ```r
4115
+ if (!requireNamespace("BiocManager", quietly = TRUE))
4116
+ install.packages("BiocManager")
4117
+ BiocManager::install(c("DESeq2", "airway"))
4118
+ ```
4119
+
4120
+ The **`airway`** package ships the example **`SummarizedExperiment`** used below. **DESeq2**
4121
+ pulls in several dependencies; the first install can take several minutes.
4122
+
4123
+ ## Example: DESeq2 on the airway dataset
4124
+
4125
+ The script **`examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb`** is the canonical
4126
+ version in the repository. Run it from the **Galaaz repository root** with JRuby, for example:
4127
+
4128
+ ```text
4129
+ bin/galaaz-jruby examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb
4130
+ ```
4131
+
4132
+ The workflow in Ruby mirrors a standard DESeq2 vignette:
4133
+
4134
+ 1. **`R.library('DESeq2')`** and **`R.library('airway')`**, then **`R.data('airway')`** so the
4135
+ object exists in R’s global environment.
4136
+ 2. **`airway = ~R[:airway]`** pulls the experiment into a Galaaz wrapper so you can pass it to R
4137
+ functions as a Ruby value.
4138
+ 3. **`R.DESeqDataSet(..., design: (R[:all].til R[:cell] + R[:dex]))`** builds the **`DESeqDataSet`**. The
4139
+ **`(R[:all].til R[:cell] + R[:dex])`** form is Galaaz’s way of passing the one-sided formula
4140
+ **`~ cell + dex`** (adjust for the design you need).
4141
+ 4. Prefilter rows with almost no counts: **`keep = R.rowSums(R.counts(dds)) >= 10`** and
4142
+ **`dds = dds[keep, :all]`**.
4143
+ 5. **`dds = R.DESeq(dds)`** fits the model; **`res = R.results(dds, contrast: R.c('dex', 'trt', 'untrt'))`**
4144
+ extracts the treatment contrast (adjust **`contrast`** for your experiment).
4145
+ 6. Summaries use normal Ruby string interpolation on **`R.nrow`**, **`R.ncol`**, **`R.colnames`**, etc.
4146
+ 7. **`R.pdf(...); R.plotMA(res, ...); R.dev__off`** writes DESeq2’s MA plot (path is relative to the
4147
+ process working directory—use the repo root when running the bundled script).
4148
+
4149
+ Related benchmarks and warm-run notes live under **`docs/deseq2_airway_benchmark.md`** and
4150
+ **`examples/bioconductor_deseq2_airway/bench_*.rb`**.
4151
+
4152
+ Below is the full listing (same as the file in the repository). It is **not** executed while this
4153
+ manual is knitted, because **DESeq2** is heavy and may be absent on the build machine.
4154
+
4155
+
4156
+ ``` ruby
4157
+ # Canonical script: examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb
4158
+ # Run: bin/galaaz-jruby examples/.../deseq2_airway_galaaz.rb (repo root).
4159
+
4160
+ require 'galaaz'
4161
+
4162
+ R.library('DESeq2')
4163
+ R.library('airway')
4164
+ R.data('airway')
4165
+
4166
+ airway = ~R[:airway]
4167
+
4168
+ # Build DESeq2 dataset with one-sided formula: ~ cell + dex.
4169
+ dds = R.DESeqDataSet(airway, design: (R[:all].til R[:cell] + R[:dex]))
4170
+
4171
+ # Prefilter genes with almost no counts.
4172
+ keep = R.rowSums(R.counts(dds)) >= 10
4173
+ dds = dds[keep, :all]
4174
+
4175
+ # Fit DE model and extract treatment effect.
4176
+ dds = R.DESeq(dds)
4177
+ res = R.results(dds, contrast: R.c('dex', 'trt', 'untrt'))
4178
+
4179
+ # Compact sanity outputs for quick verification.
4180
+ puts "Samples: #{R.ncol(dds)}"
4181
+ puts "Genes after prefilter: #{R.nrow(dds)}"
4182
+ puts "Result rows: #{R.nrow(res)}"
4183
+ puts "Result columns: #{R.colnames(res)}"
4184
+ puts "Significant genes (padj < 0.05): #{R.sum(res.padj < 0.05, na__rm: true)}"
4185
+
4186
+ res_ordered = res[R.order(res.padj), :all]
4187
+ puts R.head(R.as__data__frame(res_ordered), 10)
4188
+
4189
+ # Standard DESeq2 plot call written to file.
4190
+ R.pdf('examples/bioconductor_deseq2_airway/plotMA_galaaz.pdf')
4191
+ R.plotMA(res, ylim: R.c(-5, 5))
4192
+ R.dev__off
4193
+ ```
4194
+
4195
+ If **DESeq2** and **airway** are installed, the next chunk loads the data and prints a short
4196
+ preview (it does **not** run **`DESeq`** so the manual knits quickly).
4197
+
4198
+
4199
+ ``` ruby
4200
+ unless R::Support.eval("requireNamespace('DESeq2', quietly=TRUE) && requireNamespace('airway', quietly=TRUE)")
4201
+ puts '(Skip: install DESeq2 and airway via BiocManager in R to run the full example.)'
4202
+ else
4203
+ R.library('DESeq2')
4204
+ R.library('airway')
4205
+ R.data('airway')
4206
+ airway = ~R[:airway]
4207
+ puts 'airway object (head of assay / dims via R):'
4208
+ puts "ncol(samples): #{R.ncol(airway)}"
4209
+ puts R.head(R.assay(airway), 3)
4210
+ end
4211
+ ```
4212
+
4213
+ ```
4214
+ ## airway object (head of assay / dims via R):
4215
+ ## ncol(samples): [1] 8
4216
+ ## SRR1039508 SRR1039509 SRR1039512 SRR1039513 SRR1039516
4217
+ ## ENSG00000000003 679 448 873 408 1138
4218
+ ## ENSG00000000005 0 0 0 0 0
4219
+ ## ENSG00000000419 467 515 621 365 587
4220
+ ## SRR1039517 SRR1039520 SRR1039521
4221
+ ## ENSG00000000003 1047 770 572
4222
+ ## ENSG00000000005 0 0 0
4223
+ ## ENSG00000000419 799 417 508
3528
4224
  ```
3529
4225
 
4226
+ # Performance
4227
+
4228
+ For realistic analyses, **most wall-clock time is spent inside GNU R** (model fitting, I/O inside
4229
+ R, graphics). The Galaaz **bridge** adds overhead mainly from **starting a session**, **serializing
4230
+ requests**, and **wrapping results** in Ruby objects—not from reimplementing R’s numerical work.
4231
+
4232
+ Practical tips:
4233
+
4234
+ * Keep **hot loops** in R or vectorized code when possible; use Ruby for orchestration, I/O, and
4235
+ glue.
4236
+ * **Reuse one process**: running many short scripts cold-starts Ruby, the JVM, and R each time;
4237
+ a long-lived process or repeated calls in one run amortize setup (see benchmarks below).
4238
+ * **Batch data**: merge shards in Ruby, then call **`R::Arrow.from_ruby_batches`** (or build one
4239
+ data frame) instead of millions of tiny R calls.
4240
+
4241
+ For measured discussion (including DESeq2-style workloads and warm comparisons), see
4242
+ **`docs/performance.md`** and **`docs/deseq2_airway_benchmark.md`** in the Galaaz repository.
4243
+
3530
4244
  # Graphics in Galaaz
3531
4245
 
3532
4246
  Creating graphics in Galaaz is quite easy, as it can use all the power of ggplot2. There are
3533
- many resources in the web that teaches ggplot, so here we give a quick example of ggplot
4247
+ many resources on the web that teach ggplot, so here we give a quick example of ggplot
3534
4248
  integration with Ruby. We continue to use the :mtcars dataset and we will plot a diverging
3535
- bar plot, showing cars that have 'above' or 'below' gas consuption. Let's first prepare
4249
+ bar plot, showing cars that have 'above' or 'below' gas consumption. Let's first prepare
3536
4250
  the data frame with the necessary data:
3537
4251
 
3538
4252
 
3539
- ```ruby
3540
- # copy the R variable :mtcars to the Ruby mtcars variable
3541
- mtcars = ~:mtcars
3542
-
3543
- # create a new column 'car_name' to store the car names so that it can be
3544
- # used for plotting. The 'rownames' of the data frame cannot be used as
3545
- # data for plotting
3546
- mtcars.car_name = R.rownames(:mtcars)
3547
-
3548
- # compute normalized mpg and add it to a new column called mpg_z
3549
- # Note that the mean value for mpg can be obtained by calling the 'mean'
3550
- # function on the vector 'mtcars.mpg'. The same with the standard
3551
- # deviation 'sd'. The vector is then rounded to two digits with 'round 2'
4253
+ ``` ruby
4254
+ # :mtcars -> Ruby handle
4255
+ mtcars = ~R[:mtcars]
4256
+
4257
+ # Row labels are not a plot column; copy them to car_name.
4258
+ mtcars.car_name = R.rownames(R[:mtcars])
4259
+
4260
+ # Z-score mpg (mean/sd on mtcars.mpg); round to 2 decimals.
3552
4261
  mtcars.mpg_z = ((mtcars.mpg - mtcars.mpg.mean)/mtcars.mpg.sd).round 2
3553
4262
 
3554
- # create a new column 'mpg_type'. Function 'ifelse' is a vectorized function
3555
- # that looks at every element of the mpg_z vector and if the value is below
3556
- # 0, returns 'below', otherwise returns 'above'
4263
+ # ifelse is vectorized: below / above average mpg_z.
3557
4264
  mtcars.mpg_type = (mtcars.mpg_z < 0).ifelse("below", "above")
3558
4265
 
3559
- # order the mtcar data set by the mpg_z vector from smaler to larger values
4266
+ # Sort rows by mpg_z.
3560
4267
  mtcars = mtcars[mtcars.mpg_z.order, :all]
3561
4268
 
3562
- # convert the car_name column to a factor to retain sorted order in plot
4269
+ # Factor car_name so plot order follows sort.
3563
4270
  mtcars.car_name = mtcars.car_name.factor levels: mtcars.car_name
3564
4271
 
3565
- # let's look at the final data frame
3566
4272
  puts mtcars.head
3567
4273
  ```
3568
4274
 
@@ -3582,24 +4288,24 @@ puts mtcars.head
3582
4288
  ## Chrysler Imperial Chrysler Imperial -0.89 below
3583
4289
  ## Maserati Bora Maserati Bora -0.84 below
3584
4290
  ```
3585
- Now, lets plot the diverging bar plot. When using gKnit, there is no need to call
3586
- 'R.awt' to create a plotting device, since gKnit does take care of it. Galaaz
4291
+ Now, let's plot the diverging bar plot. When using gKnit, you normally do **not** need to open a
4292
+ graphics device manually; gKnit arranges the figure device for chunk output. Galaaz
3587
4293
  provides integration with ggplot. The interested reader should check online for more
3588
4294
  information on ggplot, since it is outside the scope of this manual describing
3589
- how ggplot works. We give here but a brief description on how this plot is generated.
4295
+ how ggplot works. Here we give only a brief description of how this plot is generated.
3590
4296
 
3591
- ggplot implements the 'grammar of graphics'. In this approach, plots are build by
4297
+ ggplot implements the 'grammar of graphics'. In this approach, plots are built by
3592
4298
  adding layers to the plot. On the first layer we describe what we want on the 'x'
3593
4299
  and 'y' axis of the plot. In this case, we have 'car_name' on the 'x' axis and
3594
4300
  'mpg\_z' on the 'y' axis. Then the type of graph is specified by adding
3595
4301
  'geom\_bar' (for a bar graph). We specify that our bars should be filled using
3596
- 'mpg\_type', which is either 'above' or 'bellow' giving then two colours for
4302
+ 'mpg\_type', which is either 'above' or 'below' giving then two colours for
3597
4303
  filling. On the next layer we specify the labels for the graph, then we add the
3598
4304
  title and subtitle. Finally, in a bar chart usually bars go on the vertical direction,
3599
- but in this graph we want the bars to be horizontally layed so we add 'coord\_flip'.
4305
+ but in this graph we want the bars to be horizontally laid so we add 'coord\_flip'.
3600
4306
 
3601
4307
 
3602
- ```ruby
4308
+ ``` ruby
3603
4309
  require 'ggplot'
3604
4310
 
3605
4311
  puts mtcars.ggplot(E.aes(x: :car_name, y: :mpg_z, label: :mpg_z)) +
@@ -3613,16 +4319,16 @@ puts mtcars.ggplot(E.aes(x: :car_name, y: :mpg_z, label: :mpg_z)) +
3613
4319
  ```
3614
4320
 
3615
4321
 
3616
- ![](manual_files/figure-html/diverging_bar.png)<!-- -->
4322
+ ![](manual_files/figure-html/diverging_bar.png)
3617
4323
 
3618
4324
  # Coding with Tidyverse
3619
4325
 
3620
4326
  In R, and when coding with 'tidyverse', arguments to a function are usually not
3621
- *referencially transparent*. That is, you can’t replace a value with a seemingly equivalent
4327
+ *referentially transparent*. That is, you can’t replace a value with a seemingly equivalent
3622
4328
  object that you’ve defined elsewhere. To see the problem, let's first define a data frame:
3623
4329
 
3624
4330
 
3625
- ```ruby
4331
+ ``` ruby
3626
4332
  df = R.data__frame(x: (1..3), y: (3..1))
3627
4333
  puts df
3628
4334
  ```
@@ -3637,21 +4343,21 @@ puts df
3637
4343
  and now, let's look at this code:
3638
4344
 
3639
4345
 
3640
- ```r
4346
+ ``` r
3641
4347
  my_var <- x
3642
4348
  filter(df, my_var == 1)
3643
4349
  ```
3644
4350
  It generates the following error: "object 'x' not found.
3645
4351
 
3646
- However, in Galaaz, arguments are referencially transparent as can be seen by the
3647
- code bellow. Note initally that 'my_var = :x' will not give the error "object 'x' not found"
4352
+ However, in Galaaz, arguments are referentially transparent as can be seen by the
4353
+ code below. Note initially that 'my_var = R[:x]' will not give the error "object 'x' not found"
3648
4354
  since ':x' is treated as an expression and assigned to my\_var. Then when doing (my\_var.eq 1),
3649
- my\_var is a variable that resolves to ':x' and it becomes equivalent to (:x.eq 1) which is
4355
+ my\_var is a variable that resolves to ':x' and it becomes equivalent to (R[:x].eq 1) which is
3650
4356
  what we want.
3651
4357
 
3652
4358
 
3653
- ```ruby
3654
- my_var = :x
4359
+ ``` ruby
4360
+ my_var = R[:x]
3655
4361
  puts df.filter(my_var.eq 1)
3656
4362
  ```
3657
4363
 
@@ -3659,7 +4365,7 @@ puts df.filter(my_var.eq 1)
3659
4365
  ## x y
3660
4366
  ## 1 1 3
3661
4367
  ```
3662
- As stated by Hardley
4368
+ As stated by Hadley
3663
4369
 
3664
4370
  > dplyr code is ambiguous. Depending on what variables are defined where,
3665
4371
  > filter(df, x == y) could be equivalent to any of:
@@ -3671,18 +4377,18 @@ df[x == df$y, ]
3671
4377
  df[x == y, ]
3672
4378
  ```
3673
4379
  In galaaz this ambiguity does not exist, filter(df, x.eq y) is not a valid expression as
3674
- expressions are build with symbols. In doing filter(df, :x.eq y) we are looking for elements
4380
+ expressions are build with symbols. In doing filter(df, R[:x].eq y) we are looking for elements
3675
4381
  of the 'x' column that are equal to a previously defined y variable. Finally in
3676
- filter(df, :x.eq :y) we are looking for elements in which the 'x' column value is equal to
4382
+ filter(df, R[:x].eq R[:y]) we are looking for elements in which the 'x' column value is equal to
3677
4383
  the 'y' column value. This can be seen in the following two chunks of code:
3678
4384
 
3679
4385
 
3680
- ```ruby
4386
+ ``` ruby
3681
4387
  y = 1
3682
4388
  x = 2
3683
4389
 
3684
4390
  # looking for values where the 'x' column is equal to the 'y' column
3685
- puts df.filter(:x.eq :y)
4391
+ puts df.filter(R[:x].eq R[:y])
3686
4392
  ```
3687
4393
 
3688
4394
  ```
@@ -3691,10 +4397,10 @@ puts df.filter(:x.eq :y)
3691
4397
  ```
3692
4398
 
3693
4399
 
3694
- ```ruby
4400
+ ``` ruby
3695
4401
  # looking for values where the 'x' column is equal to the 'y' variable
3696
4402
  # in this case, the number 1
3697
- puts df.filter(:x.eq y)
4403
+ puts df.filter(R[:x].eq y)
3698
4404
  ```
3699
4405
 
3700
4406
  ```
@@ -3726,18 +4432,19 @@ Unfortunately, in R, this function can fail silently if one of the variables isn
3726
4432
  in the data frame, but is present in the global environment. We will not go through here how
3727
4433
  to solve this problem in R.
3728
4434
 
3729
- In Galaaz the method mutate_y bellow will work fine and will never fail silently.
4435
+ In Galaaz the method mutate_y below will work fine and will never fail silently.
3730
4436
 
3731
4437
 
3732
- ```ruby
4438
+ ``` ruby
3733
4439
  def mutate_y(df)
3734
- df.mutate(:y.assign :a + :x)
4440
+ # Mutate column names are Ruby kwargs (y: …). Use .assign only for R `<-` expressions.
4441
+ df.mutate(y: R[:a] + R[:x])
3735
4442
  end
3736
4443
  ```
3737
4444
  Here we create a data frame that has only one column named 'x':
3738
4445
 
3739
4446
 
3740
- ```ruby
4447
+ ``` ruby
3741
4448
  df1 = R.data__frame(x: (1..3))
3742
4449
  puts df1
3743
4450
  ```
@@ -3749,34 +4456,31 @@ puts df1
3749
4456
  ## 3 3
3750
4457
  ```
3751
4458
 
3752
- Note that method mutate_y will fail independetly from the fact that variable 'a' is defined and
3753
- in the scope of the method. Variable 'a' has no relationship with the symbol ':a' used in the
4459
+ Note that method mutate_y will fail independently from the fact that variable 'a' is defined and
4460
+ in the scope of the method. Variable 'a' has no relationship with the symbol `R[:a]` used in the
3754
4461
  definition of 'mutate\_y' above:
3755
4462
 
3756
4463
 
3757
- ```ruby
4464
+ ``` ruby
3758
4465
  a = 10
3759
4466
  mutate_y(df1)
3760
4467
  ```
3761
4468
 
3762
4469
  ```
3763
- ## Message:
3764
- ## Error in mutate_impl(.data, dots) :
3765
- ## Evaluation error: object 'a' not found.
3766
- ## In addition: Warning message:
3767
- ## In mutate_impl(.data, dots) :
3768
- ## mismatched protect/unprotect (unprotect with empty protect stack) (RError)
3769
- ## Translated to internal error
4470
+ ## Error: ℹ In argument: `y = a + x`.
4471
+ ## Caused by error:
4472
+ ## ! object 'a' not found
3770
4473
  ```
3771
4474
  ## Different expressions
3772
4475
 
3773
- Let's move to the next problem as presented by Hardley where trying to write a function in R
4476
+ Let's move to the next problem as presented by Hadley where trying to write a function in R
3774
4477
  that will receive two argumens, the first a variable and the second an expression is not trivial.
3775
- Bellow we create a data frame and we want to write a function that groups data by a variable and
4478
+ Below we create a data frame and we want to write a function that groups data by a variable and
3776
4479
  summarises it by an expression:
3777
4480
 
3778
4481
 
3779
- ```r
4482
+ ``` r
4483
+ library(dplyr)
3780
4484
  set.seed(123)
3781
4485
 
3782
4486
  df <- data.frame(
@@ -3798,7 +4502,7 @@ as.data.frame(df)
3798
4502
  ## 5 2 1 1 4
3799
4503
  ```
3800
4504
 
3801
- ```r
4505
+ ``` r
3802
4506
  d2 <- df %>%
3803
4507
  group_by(g1) %>%
3804
4508
  summarise(a = mean(a))
@@ -3812,7 +4516,7 @@ as.data.frame(d2)
3812
4516
  ## 2 2 3.333333
3813
4517
  ```
3814
4518
 
3815
- ```r
4519
+ ``` r
3816
4520
  d2 <- df %>%
3817
4521
  group_by(g2) %>%
3818
4522
  summarise(a = mean(a))
@@ -3826,10 +4530,10 @@ as.data.frame(d2)
3826
4530
  ## 2 2 3
3827
4531
  ```
3828
4532
 
3829
- As shown by Hardley, one might expect this function to do the trick:
4533
+ As shown by Hadley, one might expect this function to do the trick:
3830
4534
 
3831
4535
 
3832
- ```r
4536
+ ``` r
3833
4537
  my_summarise <- function(df, group_var) {
3834
4538
  df %>%
3835
4539
  group_by(group_var) %>%
@@ -3842,15 +4546,15 @@ my_summarise <- function(df, group_var) {
3842
4546
 
3843
4547
  In order to solve this problem, coding with dplyr requires the introduction of many new concepts
3844
4548
  and functions such as 'quo', 'quos', 'enquo', 'enquos', '!!' (bang bang), '!!!' (triple bang).
3845
- Again, we'll leave to Hardley the explanation on how to use all those functions.
4549
+ Again, we'll leave to Hadley the explanation on how to use all those functions.
3846
4550
 
3847
4551
  Now, let's try to implement the same function in galaaz. The next code block first prints the
3848
- 'df' data frame defined previously in R (to access an R variable from Galaaz, we use the tilda
3849
- operator '~' applied to the R variable name as symbol, i.e., ':df'.
4552
+ 'df' data frame defined previously in R (to access an R variable from Galaaz, we use the tilde
4553
+ operator `~` applied to the R variable name as a symbol, e.g. `:df`).
3850
4554
 
3851
4555
 
3852
- ```ruby
3853
- puts ~:df
4556
+ ``` ruby
4557
+ puts ~R[:df]
3854
4558
  ```
3855
4559
 
3856
4560
  ```
@@ -3863,20 +4567,20 @@ puts ~:df
3863
4567
  ```
3864
4568
 
3865
4569
  We then create the 'my_summarize' method and call it passing the R data frame and
3866
- the group by variable ':g1':
4570
+ the group by variable 'R[:g1]':
3867
4571
 
3868
4572
 
3869
- ```ruby
4573
+ ``` ruby
3870
4574
  def my_summarize(df, group_var)
3871
4575
  df.group_by(group_var).
3872
- summarize(a: :a.mean)
4576
+ summarize(a: R[:a].mean)
3873
4577
  end
3874
4578
 
3875
- puts my_summarize(:df, :g1)
4579
+ puts my_summarize(~R[:df], R[:g1])
3876
4580
  ```
3877
4581
 
3878
4582
  ```
3879
- ## # A tibble: 2 x 2
4583
+ ## # A tibble: 2 × 2
3880
4584
  ## g1 a
3881
4585
  ## <dbl> <dbl>
3882
4586
  ## 1 1 2.5
@@ -3886,12 +4590,12 @@ puts my_summarize(:df, :g1)
3886
4590
  It works!!! Well, let's make sure this was not just some coincidence
3887
4591
 
3888
4592
 
3889
- ```ruby
3890
- puts my_summarize(:df, :g2)
4593
+ ``` ruby
4594
+ puts my_summarize(~R[:df], R[:g2])
3891
4595
  ```
3892
4596
 
3893
4597
  ```
3894
- ## # A tibble: 2 x 2
4598
+ ## # A tibble: 2 × 2
3895
4599
  ## g2 a
3896
4600
  ## <dbl> <dbl>
3897
4601
  ## 1 1 3
@@ -3907,7 +4611,7 @@ In the previous section we've managed to get rid of all NSE formulation for a si
3907
4611
  does this remain true for more complex examples, or will the Galaaz way prove inpractical for
3908
4612
  more complex code?
3909
4613
 
3910
- In the next example Hardley proposes us to write a function that given an expression such as 'a'
4614
+ In the next example Hadley proposes us to write a function that given an expression such as 'a'
3911
4615
  or 'a * b', calculates three summaries. What we want a function that does the same as these R
3912
4616
  statements:
3913
4617
 
@@ -3928,7 +4632,7 @@ summarise(df, mean = mean(a * b), sum = sum(a * b), n = n())
3928
4632
  Let's try it in galaaz:
3929
4633
 
3930
4634
 
3931
- ```ruby
4635
+ ``` ruby
3932
4636
  def my_summarise2(df, expr)
3933
4637
  df.summarize(
3934
4638
  mean: E.mean(expr),
@@ -3937,9 +4641,10 @@ def my_summarise2(df, expr)
3937
4641
  )
3938
4642
  end
3939
4643
 
3940
- puts my_summarise2((~:df), :a)
3941
- puts "\n"
3942
- puts my_summarise2((~:df), :a * :b)
4644
+ puts my_summarise2((~R[:df]), :a)
4645
+ puts "
4646
+ "
4647
+ puts my_summarise2((~R[:df]), R[:a] * R[:b])
3943
4648
  ```
3944
4649
 
3945
4650
  ```
@@ -3955,7 +4660,7 @@ careful about is the use of 'E' to build expressions from functions 'mean', 'sum
3955
4660
 
3956
4661
  ## Different input and output variable
3957
4662
 
3958
- Now the next challenge presented by Hardley is to vary the name of the output variables based on
4663
+ Now the next challenge presented by Hadley is to vary the name of the output variables based on
3959
4664
  the received expression. So, if the input expression is 'a', we want our data frame columns to
3960
4665
  be named 'mean\_a' and 'sum\_a'. Now, if the input expression is 'b', columns
3961
4666
  should be named 'mean\_b' and 'sum\_b'.
@@ -3981,13 +4686,13 @@ mutate(df, mean_b = mean(b), sum_b = sum(b))
3981
4686
  #> 4 2 2 5 4 3 15
3982
4687
  #> # … with 1 more row
3983
4688
  ```
3984
- In order to solve this problem in R, Hardley needs to introduce some more new functions and notations:
4689
+ In order to solve this problem in R, Hadley needs to introduce some more new functions and notations:
3985
4690
  'quo_name' and the ':=' operator from package 'rlang'
3986
4691
 
3987
4692
  Here is our Ruby code:
3988
4693
 
3989
4694
 
3990
- ```ruby
4695
+ ``` ruby
3991
4696
  def my_mutate(df, expr)
3992
4697
  mean_name = "mean_#{expr.to_s}"
3993
4698
  sum_name = "sum_#{expr.to_s}"
@@ -3996,9 +4701,10 @@ def my_mutate(df, expr)
3996
4701
  sum_name => E.sum(expr))
3997
4702
  end
3998
4703
 
3999
- puts my_mutate((~:df), :a)
4000
- puts "\n"
4001
- puts my_mutate((~:df), :b)
4704
+ puts my_mutate((~R[:df]), :a)
4705
+ puts "
4706
+ "
4707
+ puts my_mutate((~R[:df]), :b)
4002
4708
  ```
4003
4709
 
4004
4710
  ```
@@ -4026,25 +4732,25 @@ and variable mean\_name is not followed by ':' but by '=>'. This is standard Ru
4026
4732
 
4027
4733
  ## Capturing multiple variables
4028
4734
 
4029
- Moving on with new complexities, Hardley proposes us to solve the problem in which the
4735
+ Moving on with new complexities, Hadley proposes us to solve the problem in which the
4030
4736
  summarise function will receive any number of grouping variables.
4031
4737
 
4032
4738
  This again is quite standard Ruby. In order to receive an undefined number of paramenters
4033
4739
  the paramenter is preceded by '*':
4034
4740
 
4035
4741
 
4036
- ```ruby
4742
+ ``` ruby
4037
4743
  def my_summarise3(df, *group_vars)
4038
4744
  df.group_by(*group_vars).
4039
4745
  summarise(a: E.mean(:a))
4040
4746
  end
4041
4747
 
4042
- puts my_summarise3((~:df), :g1, :g2)
4748
+ puts my_summarise3((~R[:df]), R[:g1], R[:g2])
4043
4749
  ```
4044
4750
 
4045
4751
  ```
4046
- ## # A tibble: 4 x 3
4047
- ## # Groups: g1 [?]
4752
+ ## # A tibble: 4 × 3
4753
+ ## # Groups: g1 [2]
4048
4754
  ## g1 g2 a
4049
4755
  ## <dbl> <dbl> <dbl>
4050
4756
  ## 1 1 1 3
@@ -4068,7 +4774,7 @@ In Ruby, there is no lazy evaluation of parameters and 'a' is always a variable
4068
4774
  Variables assume their value as soon as they are used, so 'x = a' is immediately evaluate and
4069
4775
  variable 'x' will receive the value of variable 'a' as soon as the Ruby statement is executed.
4070
4776
  Ruby also provides the notion of a symbol; ':a' is a symbol and does not evaluate to anything.
4071
- Galaaz uses Ruby symbols to build expressions that are not bound to anything: ':a.eq :b' is
4777
+ Galaaz uses Ruby symbols to build expressions that are not bound to anything: 'R[:a].eq R[:b]' is
4072
4778
  clearly an expression and has no relationship whatsoever with the statment 'a = b'. By using
4073
4779
  symbols, variables and expressions all the possible ambiguities that are found in R are
4074
4780
  eliminated in Galaaz.
@@ -4078,7 +4784,7 @@ of input they are expecting, they might be expecting regular variables or they m
4078
4784
  expecting expressions and the R function will know how to deal with an input of the form
4079
4785
  'a = b', now for the Ruby developer it might not be immediately clear if it should call the
4080
4786
  function passing the value 'true' if variable 'a' is equal to variable 'b' or if it should
4081
- call the function passing the expression ':a.eq :b'.
4787
+ call the function passing the expression 'R[:a].eq R[:b]'.
4082
4788
 
4083
4789
 
4084
4790
  ## Advanced dplyr features
@@ -4101,28 +4807,29 @@ In the following examples, we show the use of functions 'group\_by\_at', 'summar
4101
4807
  features of characters in the Starwars movies:
4102
4808
 
4103
4809
 
4104
- ```ruby
4105
- puts (~:starwars).head
4810
+ ``` ruby
4811
+ puts (~R[:starwars]).head
4106
4812
  ```
4107
4813
 
4108
4814
  ```
4109
- ## # A tibble: 6 x 13
4110
- ## name height mass hair_color skin_color eye_color birth_year gender
4111
- ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr>
4112
- ## 1 Luke… 172 77 blond fair blue 19 male
4113
- ## 2 C-3PO 167 75 <NA> gold yellow 112 <NA>
4114
- ## 3 R2-D2 96 32 <NA> white, bl… red 33 <NA>
4115
- ## 4 Dart… 202 136 none white yellow 41.9 male
4116
- ## 5 Leia… 150 49 brown light brown 19 female
4117
- ## 6 Owen… 178 120 brown, gr… light blue 52 male
4118
- ## # … with 5 more variables: homeworld <chr>, species <chr>, films <list>,
4815
+ ## # A tibble: 6 × 14
4816
+ ## name height mass hair_color skin_color eye_color birth_year sex gender
4817
+ ## <chr> <int> <dbl> <chr> <chr> <chr> <dbl> <chr> <chr>
4818
+ ## 1 Luke Sky… 172 77 blond fair blue 19 male mascu…
4819
+ ## 2 C-3PO 167 75 <NA> gold yellow 112 none mascu…
4820
+ ## 3 R2-D2 96 32 <NA> white, bl… red 33 none mascu…
4821
+ ## 4 Darth Va… 202 136 none white yellow 41.9 male mascu…
4822
+ ## 5 Leia Org… 150 49 brown light brown 19 fema… femin…
4823
+ ## 6 Owen Lars 178 120 brown, gr… light blue 52 male mascu…
4824
+ ## # ℹ 5 more variables: homeworld <chr>, species <chr>, films <list>,
4119
4825
  ## # vehicles <list>, starships <list>
4120
4826
  ```
4121
- The grouped_mean function bellow will receive a grouping variable and calculate summaries for
4827
+ The grouped_mean function below will receive a grouping variable and calculate summaries for
4122
4828
  the value\_variables given:
4123
4829
 
4124
4830
 
4125
- ```r
4831
+ ``` r
4832
+ library(dplyr)
4126
4833
  grouped_mean <- function(data, grouping_variables, value_variables) {
4127
4834
  data %>%
4128
4835
  group_by_at(grouping_variables) %>%
@@ -4133,7 +4840,22 @@ grouped_mean <- function(data, grouping_variables, value_variables) {
4133
4840
 
4134
4841
  gm = starwars %>%
4135
4842
  grouped_mean("eye_color", c("mass", "birth_year"))
4843
+ ```
4136
4844
 
4845
+ ```
4846
+ ## Warning: `funs()` was deprecated in dplyr 0.8.0.
4847
+ ## ℹ Please use a list of either functions or lambdas:
4848
+ ##
4849
+ ## # Simple named list: list(mean = mean, median = median)
4850
+ ##
4851
+ ## # Auto named with `tibble::lst()`: tibble::lst(mean, median)
4852
+ ##
4853
+ ## # Using lambdas list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
4854
+ ## Call `lifecycle::last_lifecycle_warnings()` to see where this warning was
4855
+ ## generated.
4856
+ ```
4857
+
4858
+ ``` r
4137
4859
  as.data.frame(gm)
4138
4860
  ```
4139
4861
 
@@ -4159,20 +4881,20 @@ as.data.frame(gm)
4159
4881
  The same code with Galaaz, becomes:
4160
4882
 
4161
4883
 
4162
- ```ruby
4884
+ ``` ruby
4163
4885
  def grouped_mean(data, grouping_variables, value_variables)
4164
4886
  data.
4165
4887
  group_by_at(grouping_variables).
4166
4888
  mutate(count: E.n).
4167
- summarise_at(E.c(value_variables, "count"), ~:mean, na__rm: true).
4889
+ summarise_at(E.c(value_variables, "count"), ~R[:mean], na__rm: true).
4168
4890
  rename_at(value_variables, E.funs(E.paste0("mean_", value_variables)))
4169
4891
  end
4170
4892
 
4171
- puts grouped_mean((~:starwars), "eye_color", E.c("mass", "birth_year"))
4893
+ puts grouped_mean((~R[:starwars]), "eye_color", E.c("mass", "birth_year"))
4172
4894
  ```
4173
4895
 
4174
4896
  ```
4175
- ## # A tibble: 15 x 4
4897
+ ## # A tibble: 15 × 4
4176
4898
  ## eye_color mean_mass mean_birth_year count
4177
4899
  ## <chr> <dbl> <dbl> <dbl>
4178
4900
  ## 1 black 76.3 33 10
@@ -4192,17 +4914,19 @@ puts grouped_mean((~:starwars), "eye_color", E.c("mass", "birth_year"))
4192
4914
  ## 15 yellow 81.1 76.4 11
4193
4915
  ```
4194
4916
 
4195
-
4196
- [TO BE CONTINUED...]
4197
-
4917
+ The examples above cover programmatic dplyr with string column names and `_at` helpers. The same
4918
+ Galaaz patterns (symbols, `E.*` for expression-safe functions, and Ruby methods on R-backed objects)
4919
+ extend to other tidyverse workflows; consult R package documentation for function-specific
4920
+ arguments.
4198
4921
 
4199
4922
  # Contributing
4200
4923
 
4201
4924
  * Fork it
4202
- * Create your feature branch (git checkout -b my-new-feature)
4203
- * Write Tests!
4204
- * Commit your changes (git commit -am 'Add some feature')
4205
- * Push to the branch (git push origin my-new-feature)
4206
- * Create new Pull Request
4925
+ * Create your feature branch (`git checkout -b my-new-feature`)
4926
+ * Write tests — use **`bin/run_rspec`** or **`bin/run_all_rspec`** with **JRuby** so JVM flags and
4927
+ the load path match **`docs/testing.md`**
4928
+ * Commit your changes (`git commit -am 'Add some feature'`)
4929
+ * Push to the branch (`git push origin my-new-feature`)
4930
+ * Open a pull request
4207
4931
 
4208
4932
  # References