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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -0
- data/LICENSE +0 -0
- data/README.md +1360 -636
- data/Rakefile +61 -41
- data/bin/galaaz-bootstrap +137 -0
- data/bin/galaaz-jruby +14 -0
- data/bin/galaaz_jruby_env.inc.sh +6 -0
- data/bin/gbookdown +64 -0
- data/bin/gknit +84 -13
- data/bin/gknit-draft.rb +0 -0
- data/bin/gstudio +5 -3
- data/bin/gstudio_irb.rb +0 -0
- data/bin/gstudio_pry.rb +0 -0
- data/bin/install-tinytex +6 -0
- data/bin/run_all_rspec +43 -0
- data/bin/run_example +14 -0
- data/bin/run_old_rspec +19 -0
- data/bin/run_rspec +23 -0
- data/bin/run_rspec_subset +38 -0
- data/bin/run_slow_rspec +19 -0
- data/blogs/R-on-Rails-Planning-Document.md +940 -0
- data/blogs/README.md +100 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.Rmd +38 -66
- data/blogs/galaaz_ggplot/galaaz_ggplot.log +754 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot.md +115 -155
- data/blogs/galaaz_ggplot/galaaz_ggplot.tex +607 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/scatter_plot_rb.png +0 -0
- data/blogs/galaaz_ggplot/midwest.Rmd +3 -3
- data/blogs/galaaz_ggplot/midwest_external_png +0 -0
- data/blogs/gknit/gknit.Rmd +47 -52
- data/blogs/gknit/gknit.md +1430 -0
- data/blogs/gknit/gknit_files/figure-html/bubble-1.png +0 -0
- data/blogs/gknit/gknit_files/figure-html/diverging_bar.png +0 -0
- data/blogs/gknit/lst.rds +0 -0
- data/blogs/gknit/model.rb +1 -1
- data/blogs/gknit/stats.bib +0 -0
- data/blogs/manual/include_model_local_repro.Rmd +14 -0
- data/blogs/manual/include_model_local_repro.md +75 -0
- data/blogs/manual/lst.rds +0 -0
- data/blogs/manual/manual.Rmd +852 -239
- data/blogs/manual/manual.log +1786 -0
- data/blogs/manual/manual.md +1360 -636
- data/blogs/manual/manual.tex +1883 -1161
- data/blogs/manual/manual_files/figure-html/bubble-1.png +0 -0
- data/blogs/manual/manual_files/figure-html/diverging_bar.png +0 -0
- data/blogs/manual/manual_files/figure-latex/bubble-1.png +0 -0
- data/blogs/manual/model.rb +1 -1
- data/blogs/nse_dplyr/nse_dplyr.Rmd +84 -111
- data/blogs/nse_dplyr/nse_dplyr.log +928 -0
- data/blogs/nse_dplyr/nse_dplyr.md +198 -229
- data/blogs/oh_my/not_so.rb +0 -0
- data/blogs/oh_my/oh_my.Rmd +1234 -25
- data/blogs/oh_my/oh_my.log +804 -0
- data/blogs/oh_my/oh_my.md +1663 -86
- data/blogs/oh_my/oh_my.tex +821 -0
- data/blogs/oh_my/old.Rmd +15 -14
- data/blogs/ruby_plot/ruby_plot.Rmd +58 -82
- data/blogs/ruby_plot/ruby_plot.log +885 -0
- data/blogs/ruby_plot/ruby_plot.md +71 -102
- data/blogs/ruby_plot/ruby_plot.tex +940 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-html/violin_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png +0 -0
- data/blogs/test/test.Rmd +14 -0
- data/examples/50Plots_MasterList/Images/midwest-scatterplot.PNG +0 -0
- data/examples/50Plots_MasterList/ScatterPlot.rb +0 -0
- data/examples/50Plots_MasterList/scatter_plot.rb +0 -0
- data/examples/Bibliography/master.bib +0 -0
- data/examples/Bibliography/stats.bib +0 -0
- data/examples/R/calc.R +0 -0
- data/examples/R/java_interop.R +0 -0
- data/examples/bioconductor_deseq2_airway/Documentation/DESeq2-airway-walkthrough.md +56 -0
- data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +53 -0
- data/examples/bioconductor_deseq2_airway/bench_r_three_same_process.R +34 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +33 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +34 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_minimal.R +30 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_pipeline_for_bench.R +36 -0
- data/examples/islr/all.rb +13 -0
- data/examples/islr/ch2.spec.rb +37 -7
- data/examples/islr/ch3.spec.rb +11 -2
- data/examples/islr/ch3_boston.rb +27 -0
- data/examples/islr/ch3_multiple_regression.rb +0 -0
- data/examples/islr/ch6.spec.rb +24 -1
- data/examples/islr/x_y_rnorm.jpg +0 -0
- data/examples/latex_templates/Test-acm_article/acm_proc_article-sp.cls +0 -0
- data/examples/latex_templates/Test-acm_article/sigproc.bib +0 -0
- data/examples/latex_templates/Test-acs_article/acs-Test-acs_article.bib +0 -0
- data/examples/latex_templates/Test-acs_article/acs-my_output.bib +0 -0
- data/examples/latex_templates/Test-aea_article/BibFile.bib +0 -0
- data/examples/latex_templates/Test-aea_article/Test-aea_article.Rmd +0 -0
- data/examples/latex_templates/Test-aea_article/references.bib +0 -0
- data/examples/latex_templates/Test-amq_article/Test-amq_article.Rmd +0 -0
- data/examples/latex_templates/Test-amq_article/Test-amq_article.pdfsync +0 -0
- data/examples/latex_templates/Test-ieee_article/IEEEtran.bst +0 -0
- data/examples/latex_templates/Test-ieee_article/mybibfile.bib +0 -0
- data/examples/latex_templates/Test-rjournal_article/RJournal.sty +0 -0
- data/examples/latex_templates/Test-rjournal_article/RJreferences.bib +0 -0
- data/examples/latex_templates/Test-rjournal_article/Test-rjournal_article.Rmd +0 -0
- data/examples/misc/baseball.csv +0 -0
- data/examples/misc/ggplot.rb +3 -2
- data/examples/misc/moneyball.rb +0 -0
- data/examples/misc/subsetting.rb +0 -0
- data/examples/multithread_shards_to_r/shards_to_r.rb +67 -0
- data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.Rmd +0 -0
- data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.Rmd +0 -0
- data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.Rmd +0 -0
- data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.Rmd +0 -0
- data/examples/rmarkdown/svm-rmarkdown-syllabus-example/attend-grade-relationships.csv +0 -0
- data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.Rmd +0 -0
- data/examples/rmarkdown/svm-xaringan-example/svm-xaringan-example.Rmd +0 -0
- data/examples/sthda_ggplot/README.md +0 -0
- data/examples/sthda_ggplot/RUN.md +41 -0
- data/examples/sthda_ggplot/all.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +2 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +0 -0
- data/examples/sthda_ggplot/one_variable_continuous/stat.rb +0 -0
- data/examples/sthda_ggplot/one_variable_discrete/bar.rb +0 -0
- data/examples/sthda_ggplot/qplots/box_violin_dot.rb +0 -0
- data/examples/sthda_ggplot/qplots/scatter_plots.rb +0 -0
- data/examples/sthda_ggplot/scatter_gg.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +0 -0
- data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +4 -3
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +0 -0
- data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +0 -0
- data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +0 -0
- data/ext/new_bridge/Makefile +46 -0
- data/ext/new_bridge/galaaz_gatekeeper_phase0.cpp +12 -0
- data/ext/new_bridge/galaaz_gatekeeper_phase1.cpp +1639 -0
- data/lib/R_interface/galaaz_device.R +20 -0
- data/lib/R_interface/include_engine.R +109 -0
- data/lib/R_interface/new_bridge_adapter.rb +824 -0
- data/lib/R_interface/r.rb +177 -25
- data/lib/R_interface/r_arrow.rb +113 -0
- data/lib/R_interface/r_libs.R +3 -3
- data/lib/R_interface/r_methods.rb +13 -126
- data/lib/R_interface/r_module_s.rb +0 -0
- data/lib/R_interface/rbinary_operators.rb +20 -2
- data/lib/R_interface/rclosure.rb +5 -1
- data/lib/R_interface/rdata_frame.rb +34 -70
- data/lib/R_interface/rdevice.rb +125 -0
- data/lib/R_interface/rdevices.R +0 -0
- data/lib/R_interface/renvironment.rb +10 -4
- data/lib/R_interface/rexpression.rb +5 -1
- data/lib/R_interface/rindexed_object.rb +41 -13
- data/lib/R_interface/rlanguage.rb +20 -62
- data/lib/R_interface/rlist.rb +115 -25
- data/lib/R_interface/rlogical_operators.rb +0 -0
- data/lib/R_interface/rmatrix.rb +2 -11
- data/lib/R_interface/rmd_indexed_object.rb +5 -1
- data/lib/R_interface/robject.rb +348 -290
- data/lib/R_interface/rpkg.rb +0 -0
- data/lib/R_interface/rsupport.rb +609 -328
- data/lib/R_interface/rsupport_scope.rb +2 -1
- data/lib/R_interface/rsymbol.rb +50 -0
- data/lib/R_interface/ruby_callback.rb +2 -3
- data/lib/R_interface/ruby_extensions.rb +225 -175
- data/lib/R_interface/runary_operators.rb +0 -0
- data/lib/R_interface/rvector.rb +147 -31
- data/lib/galaaz.rb +0 -0
- data/lib/galaaz_jruby.rb +22 -0
- data/lib/gknit/diagnostics.rb +50 -0
- data/lib/gknit/draft.rb +23 -17
- data/lib/gknit/include_engine.rb +15 -7
- data/lib/gknit/knitr_engine.rb +223 -74
- data/lib/gknit/rb_engine.rb +3 -3
- data/lib/gknit/ruby_engine.rb +0 -0
- data/lib/gknit.rb +1 -0
- data/lib/new_bridge/bootstrap/windows_bootstrap.rb +285 -0
- data/lib/new_bridge/envelope.rb +51 -0
- data/lib/new_bridge/eval_result.rb +26 -0
- data/lib/new_bridge/framing.rb +39 -0
- data/lib/new_bridge/instance_pool_client.rb +38 -0
- data/lib/new_bridge/r_instance_manager.rb +404 -0
- data/lib/new_bridge/session_client.rb +530 -0
- data/lib/new_bridge/tcp_framed.rb +44 -0
- data/lib/new_bridge.rb +9 -0
- data/lib/util/exec_ruby.rb +95 -20
- data/lib/util/inline_file.rb +35 -30
- data/new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb +96 -0
- data/new_bridge_specs/eval_r_async_spec.rb +113 -0
- data/new_bridge_specs/integration_phase5_1_concurrent_spec.rb +50 -0
- data/new_bridge_specs/integration_phase5_1_eval_spec.rb +16 -0
- data/new_bridge_specs/integration_phase5_1_r_api_spec.rb +25 -0
- data/new_bridge_specs/integration_phase5_1_smoke_spec.rb +31 -0
- data/new_bridge_specs/integration_phase5_2_dataframe_unboxing_spec.rb +19 -0
- data/new_bridge_specs/integration_phase5_2_handle_eval_unboxing_spec.rb +25 -0
- data/new_bridge_specs/integration_phase5_3_callback_args_spec.rb +28 -0
- data/new_bridge_specs/integration_phase5_3_callback_error_spec.rb +22 -0
- data/new_bridge_specs/integration_phase5_3_callback_timeout_spec.rb +28 -0
- data/new_bridge_specs/integration_phase5_3_callbacks_smoke_spec.rb +22 -0
- data/new_bridge_specs/integration_phase5_3_edge_cases_spec.rb +52 -0
- data/new_bridge_specs/integration_phase5_3_nested_spec.rb +30 -0
- data/new_bridge_specs/integration_phase5_4_concurrent_sessions_spec.rb +53 -0
- data/new_bridge_specs/integration_phase5_4_nested_session_callbacks_spec.rb +49 -0
- data/new_bridge_specs/integration_phase5_4_session_routing_spec.rb +38 -0
- data/new_bridge_specs/integration_phase5_5_stress_concurrency_spec.rb +52 -0
- data/new_bridge_specs/integration_phase5_5_unbox_walk_spec.rb +46 -0
- data/new_bridge_specs/phase0_protocol_spec.rb +96 -0
- data/new_bridge_specs/phase1_req_ret_spec.rb +66 -0
- data/new_bridge_specs/phase2_multi_instance_spec.rb +67 -0
- data/new_bridge_specs/phase3_callbacks_spec.rb +71 -0
- data/new_bridge_specs/phase4_2_hardening_spec.rb +252 -0
- data/new_bridge_specs/phase4_3_r_instance_manager_spec.rb +85 -0
- data/new_bridge_specs/phase4_nested_callbacks_spec.rb +123 -0
- data/r_requires/ggplot.rb +0 -0
- data/r_requires/knitr.rb +0 -0
- data/specs/all.rb +15 -11
- data/specs/arrow_from_ruby_batches_spec.rb +50 -0
- data/specs/arrow_semantics_spec.rb +64 -0
- data/specs/bridge_concurrent_spec.rb +46 -0
- data/specs/bridge_nested_spec.rb +25 -0
- data/specs/dataframe_semantics_spec.rb +122 -0
- data/specs/dataframe_single_index_logical_filter_spec.rb +21 -0
- data/specs/dispatch_probe_cache_spec.rb +38 -0
- data/specs/dispatch_probe_error_class_fallback_spec.rb +20 -0
- data/specs/dispatch_probe_fallback_spec.rb +18 -0
- data/specs/environment_semantics_spec.rb +89 -0
- data/specs/field_access_spec.rb +31 -0
- data/specs/figures/bg.jpeg +0 -0
- data/specs/figures/bg.png +0 -0
- data/specs/figures/bg.svg +168 -57
- data/specs/figures/dose_len.png +0 -0
- data/specs/figures/no_args.jpeg +0 -0
- data/specs/figures/no_args.png +0 -0
- data/specs/figures/no_args.svg +168 -57
- data/specs/figures/width_height.jpeg +0 -0
- data/specs/figures/width_height.png +0 -0
- data/specs/figures/width_height_units1.jpeg +0 -0
- data/specs/figures/width_height_units1.png +0 -0
- data/specs/figures/width_height_units2.jpeg +0 -0
- data/specs/figures/width_height_units2.png +0 -0
- data/specs/formula_semantics_spec.rb +81 -0
- data/specs/galaaz_util_exec_ruby_spec.rb +85 -0
- data/specs/galaaz_util_inline_file_spec.rb +54 -0
- data/specs/gknit_cli_option_permutation_spec.rb +24 -0
- data/specs/gknit_include_engine_spec.rb +72 -0
- data/specs/gknit_install_timeout_report_spec.rb +69 -0
- data/specs/gknit_internal_error_report_spec.rb +57 -0
- data/specs/gknit_vector_map_output_spec.rb +59 -0
- data/specs/globalenv_guardrail_spec.rb +52 -0
- data/specs/language_expression_semantics_spec.rb +145 -0
- data/specs/list_semantics_spec.rb +111 -0
- data/specs/new_bridge_bulk_dataframe_transfer_spec.rb +44 -0
- data/specs/new_bridge_bulk_vector_transfer_spec.rb +73 -0
- data/specs/new_bridge_callback_timeout_spec.rb +69 -0
- data/specs/new_bridge_eval_r_fallback_spec.rb +55 -0
- data/specs/nil_null_spec.rb +42 -0
- data/specs/object_build_phase2_spec.rb +53 -0
- data/specs/phase1_callback_bridge_spec.rb +84 -0
- data/specs/phase2_gknit_generic_rendering_guardrail_spec.rb +46 -0
- data/specs/phase2_gknit_no_raw_code_leakage_spec.rb +43 -0
- data/specs/phase3_gknit_generic_graphics_capture_spec.rb +71 -0
- data/specs/plot_device_semantics_spec.rb +28 -0
- data/specs/plot_snapshot_semantics_spec.rb +58 -0
- data/specs/protocol_result_spec.rb +236 -0
- data/specs/r_batch_fail_fast_spec.rb +47 -0
- data/specs/r_bridge_bootstrap_spec.rb +11 -0
- data/specs/r_devices.spec.rb +1 -1
- data/specs/r_eval.spec.rb +16 -18
- data/specs/r_function.spec.rb +1 -1
- data/specs/r_instance_manager_spec.rb +285 -0
- data/specs/r_list_apply.spec.rb +15 -15
- data/specs/r_matrix.spec.rb +0 -0
- data/specs/r_nse.spec.rb +5 -5
- data/specs/r_object_send_dispatch_spec.rb +13 -0
- data/specs/r_vector_comparator_spec.rb +8 -0
- data/specs/r_vector_creation.spec.rb +0 -0
- data/specs/r_vector_functions.spec.rb +0 -0
- data/specs/r_vector_object.spec.rb +0 -0
- data/specs/r_vector_operators.spec.rb +0 -0
- data/specs/r_vector_structured_scalar_reads_spec.rb +35 -0
- data/specs/r_vector_subsetting.spec.rb +0 -0
- data/specs/range_helper_spec.rb +21 -0
- data/specs/rsupport_scope_spec.rb +28 -0
- data/specs/rsupport_var_name_thread_safety_spec.rb +24 -0
- data/specs/scalar_character_spec.rb +44 -0
- data/specs/scoped_symbol_dsl_refinement_spec.rb +40 -0
- data/specs/session_env_bridge_spec.rb +25 -0
- data/specs/simplecov_bootstrap_spec.rb +10 -0
- data/specs/spec_helper.rb +10 -0
- data/specs/tmp.rb +0 -0
- data/specs/unboxing_recursion_regression_spec.rb +30 -0
- data/specs/unboxing_spec.rb +49 -0
- data/specs/verify_callbacks.rb +42 -0
- data/sty/galaaz.sty +0 -0
- data/version.rb +1 -1
- metadata +194 -64
- data/blogs/galaaz_ggplot/galaaz_ggplot.html +0 -520
- data/blogs/galaaz_ggplot/galaaz_ggplot.pdf +0 -0
- data/blogs/galaaz_ggplot/midwest.html +0 -188
- data/blogs/gknit/gknit.html +0 -2266
- data/blogs/gknit/gknit.pdf +0 -0
- data/blogs/manual/manual.html +0 -4638
- data/blogs/manual/manual.pdf +0 -0
- data/blogs/manual/manual_files/figure-latex/diverging_bar.pdf +0 -0
- data/blogs/nse_dplyr/nse_dplyr.html +0 -878
- data/blogs/nse_dplyr/nse_dplyr.pdf +0 -0
- data/blogs/oh_my/oh_my.html +0 -568
- data/blogs/ruby_plot/ruby_plot.html +0 -544
- data/blogs/ruby_plot/ruby_plot.pdf +0 -0
- data/examples/latex_templates/Test-acs_article/Test-acs_article.pdf +0 -0
- data/examples/latex_templates/Test-aea_article/Test-aea_article.pdf +0 -0
- data/examples/latex_templates/Test-amq_article/Test-amq_article.pdf +0 -0
- data/examples/latex_templates/Test-amq_article/pics/Figure2.pdf +0 -0
- data/examples/latex_templates/Test-asa_article/Test-asa_article.pdf +0 -0
- data/examples/latex_templates/Test-ieee_article/Test-ieee_article.pdf +0 -0
- data/examples/latex_templates/Test-rjournal_article/RJwrapper.pdf +0 -0
- data/examples/latex_templates/Test-springer_article/Test-springer_article.pdf +0 -0
- data/examples/rmarkdown/svm-rmarkdown-anon-ms-example/svm-rmarkdown-anon-ms-example.pdf +0 -0
- data/examples/rmarkdown/svm-rmarkdown-article-example/svm-rmarkdown-article-example.pdf +0 -0
- data/examples/rmarkdown/svm-rmarkdown-beamer-example/svm-rmarkdown-beamer-example.pdf +0 -0
- data/examples/rmarkdown/svm-rmarkdown-cv/svm-rmarkdown-cv.pdf +0 -0
- data/examples/rmarkdown/svm-rmarkdown-syllabus-example/svm-rmarkdown-syllabus-example.pdf +0 -0
- data/specs/r_dataframe.spec.rb +0 -379
- data/specs/r_environment.spec.rb +0 -140
- data/specs/r_formula.spec.rb +0 -232
- data/specs/r_language.spec.rb +0 -112
- data/specs/r_list.spec.rb +0 -293
- data/specs/r_plots.spec.rb +0 -72
- data/specs/ruby_expression.spec.rb +0 -316
|
@@ -0,0 +1,404 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'open3'
|
|
4
|
+
require_relative 'session_client'
|
|
5
|
+
|
|
6
|
+
module NewBridge
|
|
7
|
+
# Phase 4.3 (local): Manage a dynamic set of R instances.
|
|
8
|
+
#
|
|
9
|
+
# This is the first slice of the planned production-grade instance manager:
|
|
10
|
+
# - spawn local R processes on demand
|
|
11
|
+
# - evaluate code via the spawned SessionClient instances
|
|
12
|
+
# - stop one or all instances
|
|
13
|
+
#
|
|
14
|
+
# Container provisioning and multi-version orchestration are deferred.
|
|
15
|
+
class RInstanceManager
|
|
16
|
+
class Error < StandardError; end
|
|
17
|
+
|
|
18
|
+
attr_reader :default_instance_id, :preferred_bridge_host
|
|
19
|
+
|
|
20
|
+
def initialize(source_path:, host: '127.0.0.1', default_r_cmd: 'R', session_client_class: SessionClient, out: $stdout, docker_access_checker: nil)
|
|
21
|
+
@source_path = File.expand_path(source_path)
|
|
22
|
+
@host = host
|
|
23
|
+
@default_r_cmd = default_r_cmd
|
|
24
|
+
@session_client_class = session_client_class
|
|
25
|
+
@out = out
|
|
26
|
+
@docker_access_checker = docker_access_checker
|
|
27
|
+
@clients = {} # instance_id => SessionClient
|
|
28
|
+
@meta = {} # instance_id => { provider:, runtime:, version:, r_cmd:, status:, image: }
|
|
29
|
+
@default_instance_id = nil
|
|
30
|
+
@preferred_bridge_host = nil
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
# Spawn a new local R gatekeeper process.
|
|
34
|
+
#
|
|
35
|
+
# @param instance_id [String]
|
|
36
|
+
# @param r_cmd [String] R executable (or full path to it)
|
|
37
|
+
# @param version [String, nil] semantic/version label for routing (e.g., "4.3.3")
|
|
38
|
+
# @return [SessionClient]
|
|
39
|
+
def spawn_local(instance_id:, r_cmd: @default_r_cmd, version: nil)
|
|
40
|
+
raise ArgumentError, "instance already exists: #{instance_id}" if @clients.key?(instance_id)
|
|
41
|
+
|
|
42
|
+
@out.puts("[RInstanceManager] starting local instance #{instance_id} version=#{version || 'n/a'}")
|
|
43
|
+
c = @session_client_class.new(source_path: @source_path, host: @host, r_cmd: r_cmd)
|
|
44
|
+
c.start
|
|
45
|
+
@clients[instance_id] = c
|
|
46
|
+
@meta[instance_id] = {
|
|
47
|
+
provider: 'local',
|
|
48
|
+
runtime: 'local',
|
|
49
|
+
version: version,
|
|
50
|
+
r_cmd: r_cmd,
|
|
51
|
+
status: :healthy
|
|
52
|
+
}
|
|
53
|
+
@default_instance_id ||= instance_id
|
|
54
|
+
c
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# Spawn R in a container image.
|
|
58
|
+
#
|
|
59
|
+
# Notes:
|
|
60
|
+
# - This uses Docker and assumes the image can execute `R` with Rcpp available.
|
|
61
|
+
# - We mount the project root into /workspace and source the gatekeeper from that path.
|
|
62
|
+
def spawn_container(instance_id:, image:, version:, container_name: nil, r_exec: 'R', accept_timeout: 30,
|
|
63
|
+
bridge_host: nil, bridge_hosts: nil, relearn_bridge_host: false)
|
|
64
|
+
raise ArgumentError, "instance already exists: #{instance_id}" if @clients.key?(instance_id)
|
|
65
|
+
ensure_docker_daemon_access!
|
|
66
|
+
|
|
67
|
+
source_dir = File.dirname(@source_path)
|
|
68
|
+
project_root = File.expand_path('../..', source_dir)
|
|
69
|
+
runtime_source = "/workspace/ext/new_bridge/#{File.basename(@source_path)}"
|
|
70
|
+
base_name = container_name || "galaaz-#{instance_id}"
|
|
71
|
+
host_candidates = if bridge_host
|
|
72
|
+
[bridge_host]
|
|
73
|
+
elsif bridge_hosts
|
|
74
|
+
bridge_hosts
|
|
75
|
+
else
|
|
76
|
+
bridge_host_candidates(relearn: relearn_bridge_host)
|
|
77
|
+
end
|
|
78
|
+
@out.puts("[RInstanceManager] starting container instance #{instance_id} image=#{image} version=#{version}")
|
|
79
|
+
@out.puts("[RInstanceManager] bridge host candidates: #{host_candidates.join(', ')}")
|
|
80
|
+
|
|
81
|
+
c = nil
|
|
82
|
+
last_error = nil
|
|
83
|
+
selected_name = nil
|
|
84
|
+
selected_host = nil
|
|
85
|
+
selected_launch = nil
|
|
86
|
+
|
|
87
|
+
host_candidates.each_with_index do |bridge_host, idx|
|
|
88
|
+
name = "#{base_name}-#{idx}"
|
|
89
|
+
@out.puts("[RInstanceManager] trying bridge host #{bridge_host} (attempt #{idx + 1}/#{host_candidates.size})")
|
|
90
|
+
launch = [
|
|
91
|
+
'docker', 'run',
|
|
92
|
+
'--name', name,
|
|
93
|
+
'--add-host', 'host.docker.internal:host-gateway',
|
|
94
|
+
'-v', "#{project_root}:/workspace",
|
|
95
|
+
image, r_exec
|
|
96
|
+
]
|
|
97
|
+
|
|
98
|
+
c = @session_client_class.new(
|
|
99
|
+
source_path: @source_path,
|
|
100
|
+
runtime_source_path: runtime_source,
|
|
101
|
+
host: '0.0.0.0',
|
|
102
|
+
bridge_host: bridge_host,
|
|
103
|
+
r_cmd: launch
|
|
104
|
+
)
|
|
105
|
+
begin
|
|
106
|
+
c.start(accept_timeout: accept_timeout)
|
|
107
|
+
selected_name = name
|
|
108
|
+
selected_host = bridge_host
|
|
109
|
+
selected_launch = launch
|
|
110
|
+
@out.puts("[RInstanceManager] container instance #{instance_id} connected via #{bridge_host}")
|
|
111
|
+
break
|
|
112
|
+
rescue StandardError => e
|
|
113
|
+
last_error = e
|
|
114
|
+
logs = docker_logs(name, tail: 120)
|
|
115
|
+
@out.puts("[RInstanceManager] bridge host #{bridge_host} failed: #{e.message}")
|
|
116
|
+
if bridge_host == @preferred_bridge_host
|
|
117
|
+
@out.puts("[RInstanceManager] cached bridge host failed, trying fallback candidates...")
|
|
118
|
+
end
|
|
119
|
+
@out.puts(logs) unless logs.nil? || logs.empty?
|
|
120
|
+
docker_rm_force(name)
|
|
121
|
+
c = nil
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
if c.nil?
|
|
126
|
+
raise Error, "container runtime start failed instance=#{instance_id} image=#{image}: #{last_error&.message}"
|
|
127
|
+
end
|
|
128
|
+
if selected_host && selected_host != @preferred_bridge_host
|
|
129
|
+
@preferred_bridge_host = selected_host
|
|
130
|
+
@out.puts("[RInstanceManager] learned preferred bridge host: #{@preferred_bridge_host}")
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
@clients[instance_id] = c
|
|
134
|
+
@meta[instance_id] = {
|
|
135
|
+
provider: 'docker',
|
|
136
|
+
runtime: 'container',
|
|
137
|
+
version: version,
|
|
138
|
+
image: image,
|
|
139
|
+
bridge_host: selected_host,
|
|
140
|
+
container_name: selected_name,
|
|
141
|
+
r_cmd: selected_launch,
|
|
142
|
+
status: :healthy
|
|
143
|
+
}
|
|
144
|
+
@default_instance_id ||= instance_id
|
|
145
|
+
c
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Unified spawn API.
|
|
149
|
+
# runtime: 'local' or 'container'
|
|
150
|
+
def spawn(instance_id:, runtime:, version:, r_cmd: @default_r_cmd, image: nil, container_name: nil, accept_timeout: 30,
|
|
151
|
+
bridge_host: nil, bridge_hosts: nil, relearn_bridge_host: false)
|
|
152
|
+
case runtime.to_s
|
|
153
|
+
when 'local'
|
|
154
|
+
spawn_local(instance_id: instance_id, r_cmd: r_cmd, version: version)
|
|
155
|
+
when 'container'
|
|
156
|
+
raise ArgumentError, 'image is required for container runtime' if image.nil? || image.empty?
|
|
157
|
+
|
|
158
|
+
spawn_container(
|
|
159
|
+
instance_id: instance_id,
|
|
160
|
+
image: image,
|
|
161
|
+
version: version,
|
|
162
|
+
container_name: container_name,
|
|
163
|
+
accept_timeout: accept_timeout,
|
|
164
|
+
bridge_host: bridge_host,
|
|
165
|
+
bridge_hosts: bridge_hosts,
|
|
166
|
+
relearn_bridge_host: relearn_bridge_host
|
|
167
|
+
)
|
|
168
|
+
else
|
|
169
|
+
raise ArgumentError, "unsupported runtime=#{runtime} (expected 'local' or 'container')"
|
|
170
|
+
end
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def instance_ids
|
|
174
|
+
@clients.keys
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Lightweight metadata view suitable for management UIs and tests.
|
|
178
|
+
# Example:
|
|
179
|
+
# [{ id: "a", provider: "local", version: "4.3.3", status: :healthy, r_cmd: "R" }]
|
|
180
|
+
def instances
|
|
181
|
+
@clients.keys.map do |id|
|
|
182
|
+
m = @meta.fetch(id, {})
|
|
183
|
+
{
|
|
184
|
+
id: id,
|
|
185
|
+
provider: m[:provider] || 'local',
|
|
186
|
+
runtime: m[:runtime] || 'local',
|
|
187
|
+
version: m[:version],
|
|
188
|
+
status: m[:status] || :healthy,
|
|
189
|
+
r_cmd: m[:r_cmd],
|
|
190
|
+
image: m[:image],
|
|
191
|
+
container_name: m[:container_name],
|
|
192
|
+
default: (id == @default_instance_id)
|
|
193
|
+
}
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
def eval_r(code, session_id:, instance_id:, parent_id: nil, timeout: 60)
|
|
198
|
+
c = @clients.fetch(instance_id)
|
|
199
|
+
c.eval_r(code, session_id: session_id, instance_id: instance_id, parent_id: parent_id, timeout: timeout)
|
|
200
|
+
rescue StandardError => e
|
|
201
|
+
raise unless infrastructure_retryable_error?(e)
|
|
202
|
+
raise unless @clients.key?(instance_id)
|
|
203
|
+
|
|
204
|
+
@out.puts("[RInstanceManager] runtime failure on instance=#{instance_id}: #{e.class}: #{e.message}")
|
|
205
|
+
@out.puts("[RInstanceManager] attempting one restart+retry for instance=#{instance_id}")
|
|
206
|
+
restart_instance(instance_id)
|
|
207
|
+
c2 = @clients.fetch(instance_id)
|
|
208
|
+
c2.eval_r(code, session_id: session_id, instance_id: instance_id, parent_id: parent_id, timeout: timeout)
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
# Route to an instance by version label.
|
|
212
|
+
# If multiple instances share a version, first match is used (deterministic by insertion order).
|
|
213
|
+
def eval_with_version(code, version:, session_id: 'default', timeout: 60)
|
|
214
|
+
entry = @meta.find { |_id, m| m[:version] == version }
|
|
215
|
+
raise KeyError, "no instance for version=#{version}" unless entry
|
|
216
|
+
|
|
217
|
+
instance_id, = entry
|
|
218
|
+
eval_r(code, session_id: session_id, instance_id: instance_id, timeout: timeout)
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
# Run the same code once per distinct version.
|
|
222
|
+
# Returns a map keyed by version label.
|
|
223
|
+
def eval_all_versions(code, session_id: 'default', timeout: 60)
|
|
224
|
+
by_version = {}
|
|
225
|
+
@meta.each do |id, m|
|
|
226
|
+
v = m[:version]
|
|
227
|
+
next if v.nil? || by_version.key?(v)
|
|
228
|
+
|
|
229
|
+
by_version[v] = eval_r(code, session_id: session_id, instance_id: id, timeout: timeout)
|
|
230
|
+
end
|
|
231
|
+
by_version
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
def set_default_instance(instance_id)
|
|
235
|
+
raise KeyError, "unknown instance_id=#{instance_id}" unless @clients.key?(instance_id)
|
|
236
|
+
|
|
237
|
+
@default_instance_id = instance_id
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# Stop one instance or all instances.
|
|
241
|
+
# - keep_default: when stopping all, leaves default instance alive.
|
|
242
|
+
# - force_container: when stopping container instances, force-remove docker container.
|
|
243
|
+
def stop(instance_id = nil, keep_default: false, force_container: false)
|
|
244
|
+
if instance_id
|
|
245
|
+
c = @clients.delete(instance_id)
|
|
246
|
+
c&.stop
|
|
247
|
+
m = @meta.delete(instance_id)
|
|
248
|
+
cleanup_container(m, force: force_container)
|
|
249
|
+
@default_instance_id = @clients.keys.first if @default_instance_id == instance_id
|
|
250
|
+
return self
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
ids = @clients.keys
|
|
254
|
+
ids.each do |id|
|
|
255
|
+
next if keep_default && id == @default_instance_id
|
|
256
|
+
|
|
257
|
+
c = @clients.delete(id)
|
|
258
|
+
c&.stop
|
|
259
|
+
m = @meta.delete(id)
|
|
260
|
+
cleanup_container(m, force: force_container)
|
|
261
|
+
end
|
|
262
|
+
|
|
263
|
+
if @clients.empty?
|
|
264
|
+
@default_instance_id = nil
|
|
265
|
+
elsif @default_instance_id.nil? || !@clients.key?(@default_instance_id)
|
|
266
|
+
@default_instance_id = @clients.keys.first
|
|
267
|
+
end
|
|
268
|
+
self
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
def stop_all(keep_default: false, force_container: false)
|
|
272
|
+
stop(nil, keep_default: keep_default, force_container: force_container)
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
# Explicitly force-kill a container-backed runtime instance.
|
|
276
|
+
# Useful when user wants to ensure no container stays alive after a versioned run.
|
|
277
|
+
def kill_container(instance_id)
|
|
278
|
+
m = @meta.fetch(instance_id)
|
|
279
|
+
raise ArgumentError, "instance #{instance_id} is not container runtime" unless m[:runtime] == 'container'
|
|
280
|
+
|
|
281
|
+
stop(instance_id, force_container: true)
|
|
282
|
+
end
|
|
283
|
+
|
|
284
|
+
private
|
|
285
|
+
|
|
286
|
+
def restart_instance(instance_id)
|
|
287
|
+
m = @meta.fetch(instance_id)
|
|
288
|
+
stop(instance_id, force_container: true)
|
|
289
|
+
case m[:runtime]
|
|
290
|
+
when 'container'
|
|
291
|
+
spawn_container(
|
|
292
|
+
instance_id: instance_id,
|
|
293
|
+
image: m[:image],
|
|
294
|
+
version: m[:version],
|
|
295
|
+
container_name: m[:container_name],
|
|
296
|
+
accept_timeout: 30,
|
|
297
|
+
bridge_host: m[:bridge_host]
|
|
298
|
+
)
|
|
299
|
+
else
|
|
300
|
+
spawn_local(instance_id: instance_id, r_cmd: m[:r_cmd] || @default_r_cmd, version: m[:version])
|
|
301
|
+
end
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
def infrastructure_retryable_error?(e)
|
|
305
|
+
return true if e.is_a?(Timeout::Error)
|
|
306
|
+
return true if e.is_a?(Errno::EPIPE) || e.is_a?(Errno::ECONNRESET) || e.is_a?(IOError)
|
|
307
|
+
return true if e.is_a?(NewBridge::SessionClient::TimeoutError)
|
|
308
|
+
return false unless e.is_a?(NewBridge::SessionClient::RProcessError)
|
|
309
|
+
|
|
310
|
+
msg = e.message.to_s.downcase
|
|
311
|
+
return false if msg.include?('evaluation error') || msg.include?('parse error')
|
|
312
|
+
msg.include?('connection closed') || msg.include?('failed to accept runtime connection')
|
|
313
|
+
end
|
|
314
|
+
|
|
315
|
+
def cleanup_container(meta, force:)
|
|
316
|
+
return unless meta && meta[:runtime] == 'container'
|
|
317
|
+
return unless force
|
|
318
|
+
|
|
319
|
+
name = meta[:container_name]
|
|
320
|
+
docker_rm_force(name)
|
|
321
|
+
end
|
|
322
|
+
|
|
323
|
+
def docker_rm_force(name)
|
|
324
|
+
return if name.nil? || name.empty?
|
|
325
|
+
|
|
326
|
+
Open3.capture3('docker', 'rm', '-f', name)
|
|
327
|
+
rescue StandardError
|
|
328
|
+
nil
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def docker_logs(container_name, tail: 80)
|
|
332
|
+
out, err, st = Open3.capture3('docker', 'logs', '--tail', tail.to_s, container_name)
|
|
333
|
+
return out if st.success?
|
|
334
|
+
|
|
335
|
+
err.to_s
|
|
336
|
+
rescue StandardError
|
|
337
|
+
''
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
# Hostnames/IPs the container should try when dialing back to JRuby.
|
|
341
|
+
#
|
|
342
|
+
# On WSL2 + Docker Desktop, +host.docker.internal+ / host-gateway points at the
|
|
343
|
+
# Desktop VM, not the WSL distro where JRuby listens — so prefer the WSL eth0 IP
|
|
344
|
+
# first. Elsewhere, prefer +host.docker.internal+ and keep the local IP as fallback.
|
|
345
|
+
def bridge_host_candidates(relearn: false)
|
|
346
|
+
wsl_ip = local_wsl_ip
|
|
347
|
+
wsl_ip = nil if wsl_ip.nil? || wsl_ip.empty?
|
|
348
|
+
|
|
349
|
+
cands = if running_in_wsl?
|
|
350
|
+
[wsl_ip, 'host.docker.internal'].compact
|
|
351
|
+
else
|
|
352
|
+
['host.docker.internal', wsl_ip].compact
|
|
353
|
+
end
|
|
354
|
+
|
|
355
|
+
if !relearn && @preferred_bridge_host
|
|
356
|
+
([@preferred_bridge_host] + cands).uniq
|
|
357
|
+
else
|
|
358
|
+
cands.uniq
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def running_in_wsl?
|
|
363
|
+
return true unless ENV['WSL_DISTRO_NAME'].to_s.empty?
|
|
364
|
+
return true unless ENV['WSL_INTEROP'].to_s.empty?
|
|
365
|
+
|
|
366
|
+
ver = File.exist?('/proc/version') ? File.read('/proc/version') : ''
|
|
367
|
+
!!(ver =~ /microsoft|wsl/i)
|
|
368
|
+
rescue StandardError
|
|
369
|
+
false
|
|
370
|
+
end
|
|
371
|
+
|
|
372
|
+
def local_wsl_ip
|
|
373
|
+
out, _err, st = Open3.capture3('bash', '-lc', "hostname -I | awk '{print $1}'")
|
|
374
|
+
return nil unless st.success?
|
|
375
|
+
|
|
376
|
+
out.to_s.strip
|
|
377
|
+
rescue StandardError
|
|
378
|
+
nil
|
|
379
|
+
end
|
|
380
|
+
|
|
381
|
+
def ensure_docker_daemon_access!
|
|
382
|
+
if @docker_access_checker
|
|
383
|
+
ok, err = @docker_access_checker.call
|
|
384
|
+
return if ok
|
|
385
|
+
|
|
386
|
+
msg = +'docker daemon is not accessible'
|
|
387
|
+
msg << ": #{err}" unless err.to_s.strip.empty?
|
|
388
|
+
msg << '. Try: `newgrp docker` (or reopen WSL terminal) and verify `docker info`.'
|
|
389
|
+
raise Error, msg
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
_out, err, st = Open3.capture3('docker', 'info')
|
|
393
|
+
return if st.success?
|
|
394
|
+
|
|
395
|
+
msg = +'docker daemon is not accessible'
|
|
396
|
+
unless err.to_s.strip.empty?
|
|
397
|
+
msg << ": #{err.to_s.strip}"
|
|
398
|
+
end
|
|
399
|
+
msg << '. Try: `newgrp docker` (or reopen WSL terminal) and verify `docker info`.'
|
|
400
|
+
raise Error, msg
|
|
401
|
+
end
|
|
402
|
+
end
|
|
403
|
+
end
|
|
404
|
+
|