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,824 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'singleton'
|
|
4
|
+
require_relative '../new_bridge'
|
|
5
|
+
|
|
6
|
+
module R
|
|
7
|
+
# Phase 5.1 adapter: expose a minimal compatibility surface for legacy call sites
|
|
8
|
+
# that historically depended on ShadowBridge (now deprecated/obsolete).
|
|
9
|
+
# backed by NewBridge::SessionClient.
|
|
10
|
+
#
|
|
11
|
+
# Implemented compatibility methods:
|
|
12
|
+
# - eval_r(code)
|
|
13
|
+
# - eval_r_with_result("g2_v_x <- ...")
|
|
14
|
+
# - ready?
|
|
15
|
+
# - in_callback?
|
|
16
|
+
# - close
|
|
17
|
+
class NewBridgeAdapter
|
|
18
|
+
include Singleton
|
|
19
|
+
|
|
20
|
+
def initialize
|
|
21
|
+
@in_callback = false
|
|
22
|
+
@ready = false
|
|
23
|
+
source_path = ENV['GALAAZ_NEW_BRIDGE_SOURCE'] ||
|
|
24
|
+
File.expand_path('../../ext/new_bridge/galaaz_gatekeeper_phase1.cpp', __dir__)
|
|
25
|
+
@client = NewBridge::SessionClient.new(source_path: source_path)
|
|
26
|
+
@client.start(accept_timeout: 120)
|
|
27
|
+
|
|
28
|
+
# Compatibility with the legacy ShadowBridge setup:
|
|
29
|
+
# - `R.awt` / X11 for plotting (examples/sthda_ggplot).
|
|
30
|
+
# - `missing_arg()` for Ruby :all in `[` / tbl subset (R::Support.parse_arg).
|
|
31
|
+
# Use rlang::missing_arg when available: tibble/tidyselect reject the legacy
|
|
32
|
+
# quote(f(,0))[[2]] sentinel ("Subscript ... can't contain the empty string").
|
|
33
|
+
# The gatekeeper evaluates each REQ in a dedicated per-session env; globals are shared.
|
|
34
|
+
init_timeout = effective_bridge_timeout(timeout: nil)
|
|
35
|
+
@client.eval_r(
|
|
36
|
+
<<~RCODE,
|
|
37
|
+
({
|
|
38
|
+
assign('awt', function(...) { X11(...) }, envir = .GlobalEnv)
|
|
39
|
+
if (requireNamespace('rlang', quietly = TRUE)) {
|
|
40
|
+
assign('missing_arg', getExportedValue('rlang', 'missing_arg'), envir = .GlobalEnv)
|
|
41
|
+
} else {
|
|
42
|
+
assign('missing_arg', function() { quote(f(,0))[[2]] }, envir = .GlobalEnv)
|
|
43
|
+
}
|
|
44
|
+
# Build tidyselect-compatible range expressions from symbols, e.g. year:day.
|
|
45
|
+
if (!exists('range_helper', envir = .GlobalEnv, inherits = FALSE)) {
|
|
46
|
+
assign('range_helper', function(col_ini, col_end, remove = FALSE) {
|
|
47
|
+
ini <- substitute(col_ini)
|
|
48
|
+
fin <- substitute(col_end)
|
|
49
|
+
rng <- as.call(list(as.name(':'), ini, fin))
|
|
50
|
+
if (isTRUE(remove)) {
|
|
51
|
+
as.call(list(as.name('-'), rng))
|
|
52
|
+
} else {
|
|
53
|
+
rng
|
|
54
|
+
}
|
|
55
|
+
}, envir = .GlobalEnv)
|
|
56
|
+
}
|
|
57
|
+
if (!exists('up_to', envir = .GlobalEnv, inherits = FALSE)) {
|
|
58
|
+
assign('up_to', function(col_ini, col_end, remove = FALSE) {
|
|
59
|
+
range_helper(col_ini, col_end, remove = remove)
|
|
60
|
+
}, envir = .GlobalEnv)
|
|
61
|
+
}
|
|
62
|
+
# Legacy Galaaz: env_names(env) lists bindings (base R has no env_names).
|
|
63
|
+
if (!exists('env_names', envir = .GlobalEnv, inherits = FALSE)) {
|
|
64
|
+
assign('env_names', function(envir) {
|
|
65
|
+
if (missing(envir)) envir <- parent.frame()
|
|
66
|
+
ls(envir = envir, all.names = TRUE, sorted = TRUE)
|
|
67
|
+
}, envir = .GlobalEnv)
|
|
68
|
+
}
|
|
69
|
+
# Session-scoped environment helpers for transient bridge state.
|
|
70
|
+
if (!exists('galaaz_ensure_session_env', envir = .GlobalEnv, inherits = FALSE)) {
|
|
71
|
+
assign('galaaz_ensure_session_env', function(session_id) {
|
|
72
|
+
sid <- as.character(session_id)
|
|
73
|
+
# Primary path: reuse gatekeeper's per-session registry.
|
|
74
|
+
if (exists('.galaaz_sessions', envir = .GlobalEnv, inherits = FALSE)) {
|
|
75
|
+
sessions <- get('.galaaz_sessions', envir = .GlobalEnv, inherits = FALSE)
|
|
76
|
+
if (!is.list(sessions)) {
|
|
77
|
+
sessions <- list()
|
|
78
|
+
}
|
|
79
|
+
if (is.null(sessions[[sid]])) {
|
|
80
|
+
sessions[[sid]] <- new.env(parent = .GlobalEnv)
|
|
81
|
+
assign('.galaaz_sessions', sessions, envir = .GlobalEnv)
|
|
82
|
+
}
|
|
83
|
+
return(sessions[[sid]])
|
|
84
|
+
}
|
|
85
|
+
# Compatibility fallback if gatekeeper registry is unavailable.
|
|
86
|
+
nm <- paste0('galaaz_session_env_', gsub('[^A-Za-z0-9_]', '_', sid))
|
|
87
|
+
if (!exists(nm, envir = .GlobalEnv, inherits = FALSE)) {
|
|
88
|
+
assign(nm, new.env(parent = .GlobalEnv), envir = .GlobalEnv)
|
|
89
|
+
}
|
|
90
|
+
get(nm, envir = .GlobalEnv, inherits = FALSE)
|
|
91
|
+
}, envir = .GlobalEnv)
|
|
92
|
+
}
|
|
93
|
+
if (!exists('galaaz_assign_session', envir = .GlobalEnv, inherits = FALSE)) {
|
|
94
|
+
assign('galaaz_assign_session', function(session_id, key, value) {
|
|
95
|
+
en <- galaaz_ensure_session_env(session_id)
|
|
96
|
+
assign(as.character(key), value, envir = en)
|
|
97
|
+
invisible(NULL)
|
|
98
|
+
}, envir = .GlobalEnv)
|
|
99
|
+
}
|
|
100
|
+
if (!exists('galaaz_get_session', envir = .GlobalEnv, inherits = FALSE)) {
|
|
101
|
+
assign('galaaz_get_session', function(session_id, key) {
|
|
102
|
+
en <- galaaz_ensure_session_env(session_id)
|
|
103
|
+
get(as.character(key), envir = en, inherits = FALSE)
|
|
104
|
+
}, envir = .GlobalEnv)
|
|
105
|
+
}
|
|
106
|
+
if (!exists('galaaz_rm_session', envir = .GlobalEnv, inherits = FALSE)) {
|
|
107
|
+
assign('galaaz_rm_session', function(session_id, key) {
|
|
108
|
+
en <- galaaz_ensure_session_env(session_id)
|
|
109
|
+
rm(list = as.character(key), envir = en, inherits = FALSE)
|
|
110
|
+
invisible(NULL)
|
|
111
|
+
}, envir = .GlobalEnv)
|
|
112
|
+
}
|
|
113
|
+
0L
|
|
114
|
+
})
|
|
115
|
+
RCODE
|
|
116
|
+
session_id: current_session_id,
|
|
117
|
+
parent_id: callback_parent_id,
|
|
118
|
+
timeout: init_timeout
|
|
119
|
+
)
|
|
120
|
+
@ready = true
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def ready?
|
|
124
|
+
@ready
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def in_callback?
|
|
128
|
+
@in_callback
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
# Execute bridge operations within a specific NewBridge session_id.
|
|
132
|
+
# Scope is thread-local and restored after block execution.
|
|
133
|
+
def with_session(session_id)
|
|
134
|
+
old = Thread.current[:galaaz_new_bridge_session_id]
|
|
135
|
+
Thread.current[:galaaz_new_bridge_session_id] = session_id.to_s
|
|
136
|
+
yield
|
|
137
|
+
ensure
|
|
138
|
+
Thread.current[:galaaz_new_bridge_session_id] = old
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Minimal textual compatibility for existing call sites that expect
|
|
142
|
+
# "[1] <value>" style output for simple scalar evaluations.
|
|
143
|
+
def eval_r(code, timeout: nil)
|
|
144
|
+
effective_timeout = effective_bridge_timeout(timeout: timeout)
|
|
145
|
+
if ENV['GALAAZ_TIMEOUT_DEBUG']
|
|
146
|
+
STDERR.puts "[TIMEOUT_DEBUG] NewBridgeAdapter.eval_r timeout=#{effective_timeout}s explicit_timeout=#{timeout.inspect} env_bridge=#{ENV['GALAAZ_BRIDGE_TIMEOUT_SEC'].inspect}"
|
|
147
|
+
STDERR.flush
|
|
148
|
+
end
|
|
149
|
+
out = @client.eval_r(code, session_id: current_session_id, parent_id: callback_parent_id, timeout: effective_timeout)
|
|
150
|
+
format_scalar_print(out)
|
|
151
|
+
rescue NewBridge::SessionClient::RProcessError => e
|
|
152
|
+
# Compatibility fallback for side-effect-only evals:
|
|
153
|
+
# only retry when the error clearly matches phase1 scalar restrictions.
|
|
154
|
+
raise unless phase1_scalar_fallback_error?(e)
|
|
155
|
+
|
|
156
|
+
@client.eval_r("({ #{code}; 0L })", session_id: current_session_id, parent_id: callback_parent_id, timeout: effective_timeout)
|
|
157
|
+
''
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
# Async string eval: +block+ receives +NewBridge::EvalResult+; on success +#value+ is the same
|
|
161
|
+
# formatted string as +eval_r+ (no phase1 scalar fallback retry on async path).
|
|
162
|
+
#
|
|
163
|
+
# @param timeout [nil, Numeric] +nil+ means wait without Ruby-side limit; numeric starts a timer.
|
|
164
|
+
def eval_r_async(code, timeout: nil, &block)
|
|
165
|
+
raise ArgumentError, 'eval_r_async requires a block' unless block
|
|
166
|
+
|
|
167
|
+
@client.eval_r_async(code.to_s,
|
|
168
|
+
session_id: current_session_id,
|
|
169
|
+
parent_id: callback_parent_id,
|
|
170
|
+
timeout: timeout) do |raw|
|
|
171
|
+
mapped =
|
|
172
|
+
if raw.ok?
|
|
173
|
+
begin
|
|
174
|
+
NewBridge::EvalResult.success(format_scalar_print(raw.value))
|
|
175
|
+
rescue StandardError => e
|
|
176
|
+
NewBridge::EvalResult.failure(e)
|
|
177
|
+
end
|
|
178
|
+
else
|
|
179
|
+
raw
|
|
180
|
+
end
|
|
181
|
+
block.call(mapped)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# Async +eval_r_with_result+ payload; +block+ receives +NewBridge::EvalResult+ where success +#value+
|
|
186
|
+
# is a Hash +:envelope+, +:var_name+, +:r_expr+ for +R::Support.ruby_result_from_envelope+.
|
|
187
|
+
def eval_r_with_result_async(assignment_code, timeout: nil, &block)
|
|
188
|
+
raise ArgumentError, 'eval_r_with_result_async requires a block' unless block
|
|
189
|
+
|
|
190
|
+
code = "__G_EVAL_WITH_RESULT__#{assignment_code}"
|
|
191
|
+
@client.eval_r_async(code,
|
|
192
|
+
session_id: current_session_id,
|
|
193
|
+
parent_id: callback_parent_id,
|
|
194
|
+
timeout: timeout) do |raw|
|
|
195
|
+
if raw.ok?
|
|
196
|
+
begin
|
|
197
|
+
env = to_legacy_envelope(raw.value)
|
|
198
|
+
m = assignment_code.match(/\A(\S+)\s*<-\s*(.*)\z/m)
|
|
199
|
+
unless m
|
|
200
|
+
block.call(NewBridge::EvalResult.failure(StandardError.new("eval_r_with_result_async: bad assignment #{assignment_code.inspect}")))
|
|
201
|
+
next
|
|
202
|
+
end
|
|
203
|
+
vn = m[1]
|
|
204
|
+
rx = m[2].to_s.strip
|
|
205
|
+
block.call(NewBridge::EvalResult.success(envelope: env, var_name: vn, r_expr: rx))
|
|
206
|
+
rescue StandardError => e
|
|
207
|
+
block.call(NewBridge::EvalResult.failure(e))
|
|
208
|
+
end
|
|
209
|
+
else
|
|
210
|
+
block.call(raw)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
# Return the printed representation of an R object as a Ruby string.
|
|
216
|
+
def print_r(var_name)
|
|
217
|
+
parsed = @client.eval_r("paste(capture.output(print(#{var_name})), collapse='\\n')",
|
|
218
|
+
session_id: current_session_id,
|
|
219
|
+
parent_id: callback_parent_id,
|
|
220
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
221
|
+
if parsed['kind'].to_s == 'character'
|
|
222
|
+
unescape_scalar_character(parsed['value'].to_s)
|
|
223
|
+
else
|
|
224
|
+
parsed['value'].to_s
|
|
225
|
+
end
|
|
226
|
+
end
|
|
227
|
+
|
|
228
|
+
# Legacy-compatible envelope shape expected by existing bridge specs.
|
|
229
|
+
# Supports scalar assignments used by current migration subset.
|
|
230
|
+
def eval_r_with_result(assignment_code)
|
|
231
|
+
parsed = @client.eval_r("__G_EVAL_WITH_RESULT__#{assignment_code}",
|
|
232
|
+
session_id: current_session_id,
|
|
233
|
+
parent_id: callback_parent_id,
|
|
234
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
235
|
+
to_legacy_envelope(parsed)
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
# Multiple eval_r_with_result-style assignments in one REQ/RET (Phase 4). Fail-fast: first R error
|
|
239
|
+
# skips remaining ops. Transport still returns HTTP-like success with payload kind +batch_error+.
|
|
240
|
+
# @return [Array<Hash>] legacy envelopes in order
|
|
241
|
+
# @raise [R::BatchEvaluationError] on first failed op (+#failed_index+ is 0-based)
|
|
242
|
+
def batch_eval_r_with_result(assignment_codes)
|
|
243
|
+
codes = Array(assignment_codes).map(&:to_s)
|
|
244
|
+
raise ArgumentError, 'batch_eval_r_with_result requires at least one assignment' if codes.empty?
|
|
245
|
+
|
|
246
|
+
body = codes.join("\u001E")
|
|
247
|
+
parsed = @client.eval_r("__G_BATCH_EVAL_WITH_RESULT__#{body}",
|
|
248
|
+
session_id: current_session_id,
|
|
249
|
+
parent_id: callback_parent_id,
|
|
250
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
251
|
+
decode_batch_eval_payload(parsed)
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Single round-trip replacement for the two eval_r probes in
|
|
255
|
+
# R::Support.process_missing_dispatch (is_field + is_func).
|
|
256
|
+
# Gatekeeper: __G_DISPATCH_PROBE__|handle|name
|
|
257
|
+
def dispatch_probe(handle, name)
|
|
258
|
+
parsed = @client.eval_r("__G_DISPATCH_PROBE__|#{handle}|#{name}",
|
|
259
|
+
session_id: current_session_id,
|
|
260
|
+
parent_id: callback_parent_id,
|
|
261
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
262
|
+
unless parsed['kind'].to_s == 'dispatch_probe'
|
|
263
|
+
raise "dispatch_probe: unexpected payload #{parsed.inspect}"
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
{ is_field: parsed['is_field'], is_func: parsed['is_func'] }
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
# Ensure session-scoped environment exists and return its R env handle.
|
|
270
|
+
def ensure_session_env(session_id = current_session_id)
|
|
271
|
+
sid = session_id.to_s
|
|
272
|
+
@client.eval_r("({ galaaz_ensure_session_env(#{sid.inspect}); 0L })",
|
|
273
|
+
session_id: current_session_id,
|
|
274
|
+
parent_id: callback_parent_id,
|
|
275
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
276
|
+
nil
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Assign value expression into session environment.
|
|
280
|
+
# value_expr must be a valid R expression string.
|
|
281
|
+
def assign_session(session_id, key, value_expr)
|
|
282
|
+
sid = session_id.to_s
|
|
283
|
+
k = key.to_s
|
|
284
|
+
@client.eval_r("({ galaaz_assign_session(#{sid.inspect}, #{k.inspect}, { #{value_expr} }); 0L })",
|
|
285
|
+
session_id: current_session_id,
|
|
286
|
+
parent_id: callback_parent_id,
|
|
287
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
288
|
+
nil
|
|
289
|
+
end
|
|
290
|
+
|
|
291
|
+
# Get a value from session environment (parsed payload).
|
|
292
|
+
def get_session(session_id, key)
|
|
293
|
+
sid = session_id.to_s
|
|
294
|
+
k = key.to_s
|
|
295
|
+
@client.eval_r("galaaz_get_session(#{sid.inspect}, #{k.inspect})",
|
|
296
|
+
session_id: current_session_id,
|
|
297
|
+
parent_id: callback_parent_id,
|
|
298
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
299
|
+
end
|
|
300
|
+
|
|
301
|
+
# Remove a key from session environment.
|
|
302
|
+
def rm_session(session_id, key)
|
|
303
|
+
sid = session_id.to_s
|
|
304
|
+
k = key.to_s
|
|
305
|
+
@client.eval_r("({ galaaz_rm_session(#{sid.inspect}, #{k.inspect}); 0L })",
|
|
306
|
+
session_id: current_session_id,
|
|
307
|
+
parent_id: callback_parent_id,
|
|
308
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
309
|
+
nil
|
|
310
|
+
end
|
|
311
|
+
|
|
312
|
+
def effective_bridge_timeout(timeout: nil)
|
|
313
|
+
return timeout if timeout
|
|
314
|
+
|
|
315
|
+
raw = ENV['GALAAZ_BRIDGE_TIMEOUT_SEC']
|
|
316
|
+
return 60 if raw.nil?
|
|
317
|
+
|
|
318
|
+
s = raw.to_s.strip
|
|
319
|
+
return 60 if s.empty?
|
|
320
|
+
|
|
321
|
+
Integer(s)
|
|
322
|
+
rescue StandardError, ArgumentError
|
|
323
|
+
60
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
# Phase 5.3 callback stub registration for R::Support.parse_arg.
|
|
327
|
+
# Returns an R function string that forwards callback execution to Ruby
|
|
328
|
+
# using the NewBridge CALL/RET path.
|
|
329
|
+
def register_callback_proc_stub(proc_or_method)
|
|
330
|
+
callback_session_id = current_session_id
|
|
331
|
+
callback_wait_ms = begin
|
|
332
|
+
raw = ENV.fetch('GALAAZ_CALLBACK_TIMEOUT_MS', '120000').to_s.strip
|
|
333
|
+
v = Integer(raw)
|
|
334
|
+
v > 0 ? v : 120_000
|
|
335
|
+
rescue StandardError
|
|
336
|
+
120_000
|
|
337
|
+
end
|
|
338
|
+
if ENV['GALAAZ_TIMEOUT_DEBUG']
|
|
339
|
+
STDERR.puts "[TIMEOUT_DEBUG] NewBridgeAdapter.register_callback_proc_stub callback_wait_ms=#{callback_wait_ms} env_callback=#{ENV['GALAAZ_CALLBACK_TIMEOUT_MS'].inspect}"
|
|
340
|
+
STDERR.flush
|
|
341
|
+
end
|
|
342
|
+
# Stable R-safe fragment for namespacing callback result keys (session + call id).
|
|
343
|
+
sess_key = callback_session_id.to_s.gsub(/[^a-zA-Z0-9_]/, '_')
|
|
344
|
+
callback_call_id = @client.register_callback do |payload, call_id|
|
|
345
|
+
old = Thread.current[:galaaz_new_bridge_parent_id]
|
|
346
|
+
old_session = Thread.current[:galaaz_new_bridge_session_id]
|
|
347
|
+
Thread.current[:galaaz_new_bridge_parent_id] = call_id
|
|
348
|
+
Thread.current[:galaaz_new_bridge_session_id] = callback_session_id
|
|
349
|
+
@in_callback = true
|
|
350
|
+
begin
|
|
351
|
+
cb_args = callback_payload_to_r_objects(payload)
|
|
352
|
+
# Legacy arity-2 procs (phase 5.3 specs): (first R arg or nil, Ruby CALL envelope id).
|
|
353
|
+
# Knitr/RubyCallback use arity != 2 and receive call(*cb_args).
|
|
354
|
+
ar = proc_or_method.respond_to?(:arity) ? proc_or_method.arity : 0
|
|
355
|
+
raw = if ar == 2 && cb_args.size <= 1
|
|
356
|
+
proc_or_method.call(cb_args[0], call_id)
|
|
357
|
+
else
|
|
358
|
+
proc_or_method.call(*cb_args)
|
|
359
|
+
end
|
|
360
|
+
# Semantic return value: store in session env.
|
|
361
|
+
# Transport RET is ACK-only (SessionClient sends "1"); R stub reads env after CALL/RET.
|
|
362
|
+
slot_key = "r_#{sess_key}_#{call_id.gsub('-', '_')}"
|
|
363
|
+
rhs = raw.is_a?(String) ? raw : R::Support.parse_arg(raw)
|
|
364
|
+
assign_session(callback_session_id, slot_key, rhs)
|
|
365
|
+
# Semantic value is staged in session env; RET must be ACK-only (nil → transport "1").
|
|
366
|
+
nil
|
|
367
|
+
ensure
|
|
368
|
+
@in_callback = false
|
|
369
|
+
Thread.current[:galaaz_new_bridge_session_id] = old_session
|
|
370
|
+
Thread.current[:galaaz_new_bridge_parent_id] = old
|
|
371
|
+
end
|
|
372
|
+
end
|
|
373
|
+
|
|
374
|
+
# Each ... arg is assigned in session env under a temporary handle.
|
|
375
|
+
# Names must be g2_v + digits
|
|
376
|
+
# only — gatekeeper valid_bridge_handle_token rejects g2_v_cb_* (letters after g2_v), which
|
|
377
|
+
# breaks dispatch_probe when Ruby wraps the handle as R::Object.
|
|
378
|
+
"function(...) {
|
|
379
|
+
args <- list(...)
|
|
380
|
+
handles <- character(0)
|
|
381
|
+
if (length(args) > 0L) {
|
|
382
|
+
for (i in seq_along(args)) {
|
|
383
|
+
h <- paste0('g2_v', as.integer(stats::runif(1, 1e7, 9e7 - 1L)), sprintf('%04d', as.integer(i)))
|
|
384
|
+
galaaz_assign_session('#{callback_session_id}', h, args[[i]])
|
|
385
|
+
cls <- paste(class(args[[i]]), collapse = ' ')
|
|
386
|
+
handles <- c(handles, paste0(h, ':', cls))
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
payload <- paste(handles, collapse = '|')
|
|
390
|
+
gid <- '#{callback_call_id}'
|
|
391
|
+
galaaz_callback_call_phase3(gid, payload, #{callback_wait_ms})
|
|
392
|
+
sess <- '#{sess_key}'
|
|
393
|
+
nm <- paste0('r_', sess, '_', gsub('-', '_', gid))
|
|
394
|
+
sid <- '#{callback_session_id}'
|
|
395
|
+
if (exists(nm, envir = galaaz_ensure_session_env(sid), inherits = FALSE)) {
|
|
396
|
+
val <- galaaz_get_session(sid, nm)
|
|
397
|
+
galaaz_rm_session(sid, nm)
|
|
398
|
+
return(val)
|
|
399
|
+
}
|
|
400
|
+
stop('callback staged no semantic value in session env')
|
|
401
|
+
}"
|
|
402
|
+
end
|
|
403
|
+
|
|
404
|
+
def close
|
|
405
|
+
@client&.stop
|
|
406
|
+
@ready = false
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
# Structural unboxing helpers (Phase 5.5 hardening):
|
|
410
|
+
# Keep deep unboxing on explicit bridge reads instead of generic method-missing paths.
|
|
411
|
+
def unbox_list_length(var_name)
|
|
412
|
+
probe = probe_node_expr(var_name)
|
|
413
|
+
probe[:length].to_i
|
|
414
|
+
end
|
|
415
|
+
|
|
416
|
+
def unbox_list_element(var_name, one_based_index)
|
|
417
|
+
tmp = ::R::Support.generate_var_name
|
|
418
|
+
probe = probe_node_expr("#{var_name}[[#{one_based_index}]]", assign_to: tmp)
|
|
419
|
+
|
|
420
|
+
case probe[:kind]
|
|
421
|
+
when 'null'
|
|
422
|
+
nil
|
|
423
|
+
when 'list'
|
|
424
|
+
::R::Object.build(tmp, nil, r_class: 'list')
|
|
425
|
+
when 'scalar_integer'
|
|
426
|
+
probe[:value]
|
|
427
|
+
when 'scalar_double'
|
|
428
|
+
probe[:value]
|
|
429
|
+
when 'scalar_logical'
|
|
430
|
+
probe[:value]
|
|
431
|
+
when 'scalar_character'
|
|
432
|
+
v = probe[:value]
|
|
433
|
+
(v.is_a?(::String) && v =~ /^rb_obj_\d+$/) ? ::R::Support.get_ruby_object(v) : v
|
|
434
|
+
else
|
|
435
|
+
r_class = probe[:r_class].to_s.strip
|
|
436
|
+
return nil if r_class == 'NULL'
|
|
437
|
+
::R::Object.build(tmp, nil, r_class: r_class.empty? ? 'unknown' : r_class)
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
441
|
+
# Specialized bounded traversal for deep unboxing checks.
|
|
442
|
+
# Walks nested list structures in one bridge call and reports whether limits were exceeded.
|
|
443
|
+
# Returns:
|
|
444
|
+
# { status: :ok|:depth_limit|:node_limit, nodes: Integer, max_depth: Integer }
|
|
445
|
+
def unbox_walk(var_name, max_depth:, max_nodes:)
|
|
446
|
+
cmd = "__G_UNBOX_WALK__|#{var_name}|#{max_depth.to_i}|#{max_nodes.to_i}"
|
|
447
|
+
parsed = @client.eval_r(cmd, session_id: current_session_id, parent_id: callback_parent_id, timeout: effective_bridge_timeout(timeout: nil))
|
|
448
|
+
status =
|
|
449
|
+
case parsed['status'].to_s
|
|
450
|
+
when 'DEPTH' then :depth_limit
|
|
451
|
+
when 'NODE' then :node_limit
|
|
452
|
+
else :ok
|
|
453
|
+
end
|
|
454
|
+
{ status: status, nodes: parsed['nodes'].to_i, max_depth: parsed['max_depth'].to_i }
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
# Specialized one-call materialization for nested list/scalar/null trees.
|
|
458
|
+
# Returns:
|
|
459
|
+
# { status: :ok|:depth_limit|:node_limit|:unsupported, nodes:, max_depth:, value: }
|
|
460
|
+
def unbox_materialize(var_name, max_depth:, max_nodes:)
|
|
461
|
+
cmd = "__G_UNBOX_MATERIALIZE__|#{var_name}|#{max_depth.to_i}|#{max_nodes.to_i}"
|
|
462
|
+
parsed = @client.eval_r(cmd, session_id: current_session_id, parent_id: callback_parent_id, timeout: effective_bridge_timeout(timeout: nil))
|
|
463
|
+
status =
|
|
464
|
+
case parsed['status'].to_s
|
|
465
|
+
when 'DEPTH' then :depth_limit
|
|
466
|
+
when 'NODE' then :node_limit
|
|
467
|
+
when 'UNSUPPORTED' then :unsupported
|
|
468
|
+
else :ok
|
|
469
|
+
end
|
|
470
|
+
{ status: status, nodes: parsed['nodes'].to_i, max_depth: parsed['max_depth'].to_i, value: parsed['value'] }
|
|
471
|
+
end
|
|
472
|
+
|
|
473
|
+
# Unbox atomic vectors to Ruby Arrays.
|
|
474
|
+
# Primary path: gatekeeper `__G_PULL_VECTOR__` (one round-trip for full vector).
|
|
475
|
+
# Fallback: per-element scalar eval (complex types, older gatekeeper, errors).
|
|
476
|
+
def pull_vector(var_name)
|
|
477
|
+
begin
|
|
478
|
+
raw = eval_pull_vector_payload(var_name)
|
|
479
|
+
out = decode_pull_vector_bulk_payload(raw)
|
|
480
|
+
return out unless out.nil?
|
|
481
|
+
rescue NewBridge::SessionClient::RProcessError
|
|
482
|
+
# Unsupported SEXP type, unknown handle, or legacy binary without pull_vector.
|
|
483
|
+
end
|
|
484
|
+
pull_vector_elementwise(var_name)
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
# Indexed vector unboxing helpers expected by R::Vector#unboxed_get.
|
|
488
|
+
# offset is 0-based (Ruby index), R indexing is 1-based.
|
|
489
|
+
def pull_integer_vector(var_name, _total_size, offset = 0, chunk_size = nil)
|
|
490
|
+
chunk_size ||= 1
|
|
491
|
+
start_1 = offset + 1
|
|
492
|
+
begin
|
|
493
|
+
raw = eval_pull_vector_payload(var_name, slice_start_1based: start_1, slice_count: chunk_size)
|
|
494
|
+
out = decode_pull_vector_bulk_payload(raw, want_kind: 'integer_vector')
|
|
495
|
+
return out if out.is_a?(Array) && out.size == chunk_size
|
|
496
|
+
rescue NewBridge::SessionClient::RProcessError
|
|
497
|
+
end
|
|
498
|
+
pull_integer_vector_elementwise(var_name, offset, chunk_size)
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
def pull_double_vector(var_name, _total_size, offset = 0, chunk_size = nil)
|
|
502
|
+
chunk_size ||= 1
|
|
503
|
+
start_1 = offset + 1
|
|
504
|
+
begin
|
|
505
|
+
raw = eval_pull_vector_payload(var_name, slice_start_1based: start_1, slice_count: chunk_size)
|
|
506
|
+
out = decode_pull_vector_bulk_payload(raw, want_kind: 'double_vector')
|
|
507
|
+
return out if out.is_a?(Array) && out.size == chunk_size
|
|
508
|
+
rescue NewBridge::SessionClient::RProcessError
|
|
509
|
+
end
|
|
510
|
+
pull_double_vector_elementwise(var_name, offset, chunk_size)
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
# Push Ruby numeric array values into an R numeric vector.
|
|
514
|
+
# - ruby_array: Ruby Array of Numeric/nil (nil mapped to NA_real_)
|
|
515
|
+
# - var_name: target R variable handle/name
|
|
516
|
+
# - offset/total_size: when provided, writes a slice using 0-based offset
|
|
517
|
+
def push_double_vector(ruby_array, var_name, offset = nil, _total_size = nil)
|
|
518
|
+
values = Array(ruby_array)
|
|
519
|
+
return nil if values.empty?
|
|
520
|
+
|
|
521
|
+
serialized = values.map do |v|
|
|
522
|
+
if v.nil?
|
|
523
|
+
'NA_real_'
|
|
524
|
+
elsif v.is_a?(Numeric)
|
|
525
|
+
v.finite? ? v.to_f.to_s : 'NA_real_'
|
|
526
|
+
else
|
|
527
|
+
begin
|
|
528
|
+
Float(v).to_s
|
|
529
|
+
rescue StandardError
|
|
530
|
+
'NA_real_'
|
|
531
|
+
end
|
|
532
|
+
end
|
|
533
|
+
end.join(', ')
|
|
534
|
+
|
|
535
|
+
if offset
|
|
536
|
+
start_i = offset.to_i + 1
|
|
537
|
+
end_i = offset.to_i + values.length
|
|
538
|
+
@client.eval_r("({ #{var_name}[#{start_i}:#{end_i}] <- c(#{serialized}); 0L })",
|
|
539
|
+
session_id: current_session_id,
|
|
540
|
+
parent_id: callback_parent_id,
|
|
541
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
542
|
+
else
|
|
543
|
+
@client.eval_r("({ #{var_name} <- c(#{serialized}); 0L })",
|
|
544
|
+
session_id: current_session_id,
|
|
545
|
+
parent_id: callback_parent_id,
|
|
546
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
547
|
+
end
|
|
548
|
+
nil
|
|
549
|
+
end
|
|
550
|
+
|
|
551
|
+
# data.frame unboxing: Ruby hash { "colname" => [values...] }.
|
|
552
|
+
#
|
|
553
|
+
# Column-wise bulk path: assign each column to a temp `g2_v*` handle, then
|
|
554
|
+
# `pull_vector` (uses `__G_PULL_VECTOR__` when supported). Per-cell scalar
|
|
555
|
+
# evals are avoided for atomic columns; list / unsupported columns still
|
|
556
|
+
# fall back inside `pull_vector`.
|
|
557
|
+
def pull_dataframe(var_name)
|
|
558
|
+
t = effective_bridge_timeout(timeout: nil)
|
|
559
|
+
sid = current_session_id
|
|
560
|
+
pid = callback_parent_id
|
|
561
|
+
|
|
562
|
+
ncol = @client.eval_r("length(#{var_name})", session_id: sid, parent_id: pid, timeout: t)['value'].to_i
|
|
563
|
+
return {} if ncol <= 0
|
|
564
|
+
|
|
565
|
+
col_hash = {}
|
|
566
|
+
|
|
567
|
+
(1..ncol).each do |i|
|
|
568
|
+
col_name_parsed = @client.eval_r("names(#{var_name})[#{i}]", session_id: sid, parent_id: pid, timeout: t)
|
|
569
|
+
col_name = col_name_parsed['value']
|
|
570
|
+
col_name = col_name.to_s if col_name
|
|
571
|
+
|
|
572
|
+
tmp = ::R::Support.generate_var_name
|
|
573
|
+
@client.eval_r("({ #{tmp} <- #{var_name}[[#{i}]]; 0L })", session_id: sid, parent_id: pid, timeout: t)
|
|
574
|
+
col_hash[col_name] = pull_vector(tmp)
|
|
575
|
+
end
|
|
576
|
+
|
|
577
|
+
col_hash
|
|
578
|
+
end
|
|
579
|
+
|
|
580
|
+
private
|
|
581
|
+
|
|
582
|
+
# Decode CALL payload from register_callback_proc_stub R side (handle:class|...).
|
|
583
|
+
def callback_payload_to_r_objects(payload)
|
|
584
|
+
s = payload.to_s.strip
|
|
585
|
+
return [] if s.empty?
|
|
586
|
+
|
|
587
|
+
s.split('|').filter_map do |pair|
|
|
588
|
+
next if pair.empty?
|
|
589
|
+
|
|
590
|
+
handle, r_class = pair.split(':', 2)
|
|
591
|
+
R::Object.build(handle, nil, r_class: r_class)
|
|
592
|
+
end
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
def callback_parent_id
|
|
596
|
+
Thread.current[:galaaz_new_bridge_parent_id]
|
|
597
|
+
end
|
|
598
|
+
|
|
599
|
+
def current_session_id
|
|
600
|
+
Thread.current[:galaaz_new_bridge_session_id] || 'default'
|
|
601
|
+
end
|
|
602
|
+
|
|
603
|
+
def probe_node_expr(expr, assign_to: nil)
|
|
604
|
+
sep = "\u001F"
|
|
605
|
+
assign_line = assign_to ? "#{assign_to} <- (#{expr})" : nil
|
|
606
|
+
gk_obj_line = assign_to ? ".gk_obj <- #{assign_to}" : ".gk_obj <- (#{expr})"
|
|
607
|
+
r_code = <<~RCODE
|
|
608
|
+
({
|
|
609
|
+
#{assign_line}
|
|
610
|
+
#{gk_obj_line}
|
|
611
|
+
.gk_sep <- "#{sep}"
|
|
612
|
+
.gk_kind <- if (is.null(.gk_obj)) {
|
|
613
|
+
"null"
|
|
614
|
+
} else if (is.list(.gk_obj)) {
|
|
615
|
+
"list"
|
|
616
|
+
} else if (length(.gk_obj) == 1L && is.integer(.gk_obj)) {
|
|
617
|
+
"scalar_integer"
|
|
618
|
+
} else if (length(.gk_obj) == 1L && is.double(.gk_obj)) {
|
|
619
|
+
"scalar_double"
|
|
620
|
+
} else if (length(.gk_obj) == 1L && is.logical(.gk_obj)) {
|
|
621
|
+
"scalar_logical"
|
|
622
|
+
} else if (length(.gk_obj) == 1L && is.character(.gk_obj)) {
|
|
623
|
+
"scalar_character"
|
|
624
|
+
} else {
|
|
625
|
+
"other"
|
|
626
|
+
}
|
|
627
|
+
.gk_len <- length(.gk_obj)
|
|
628
|
+
.gk_cls <- paste(class(.gk_obj), collapse=" ")
|
|
629
|
+
.gk_val <- ""
|
|
630
|
+
if (.gk_kind == "scalar_integer") {
|
|
631
|
+
.gk_val <- if (is.na(.gk_obj[[1]])) "__NA__" else as.character(.gk_obj[[1]])
|
|
632
|
+
} else if (.gk_kind == "scalar_double") {
|
|
633
|
+
.gk_val <- if (is.na(.gk_obj[[1]])) "__NA__" else as.character(.gk_obj[[1]])
|
|
634
|
+
} else if (.gk_kind == "scalar_logical") {
|
|
635
|
+
.gk_val <- if (is.na(.gk_obj[[1]])) "__NA__" else if (.gk_obj[[1]]) "TRUE" else "FALSE"
|
|
636
|
+
} else if (.gk_kind == "scalar_character") {
|
|
637
|
+
.gk_val <- if (is.na(.gk_obj[[1]])) "__NA__" else as.character(.gk_obj[[1]])
|
|
638
|
+
}
|
|
639
|
+
paste(.gk_kind, as.character(.gk_len), .gk_cls, .gk_val, sep=.gk_sep)
|
|
640
|
+
})
|
|
641
|
+
RCODE
|
|
642
|
+
|
|
643
|
+
raw = @client.eval_r(r_code, session_id: current_session_id, parent_id: callback_parent_id, timeout: effective_bridge_timeout(timeout: nil))
|
|
644
|
+
token = raw['value'].to_s
|
|
645
|
+
parts = token.split(sep, 4)
|
|
646
|
+
kind = parts[0].to_s
|
|
647
|
+
len = parts[1].to_i
|
|
648
|
+
r_class = parts[2].to_s
|
|
649
|
+
raw_val = parts[3].to_s
|
|
650
|
+
value =
|
|
651
|
+
case kind
|
|
652
|
+
when 'scalar_integer'
|
|
653
|
+
raw_val == '__NA__' ? nil : raw_val.to_i
|
|
654
|
+
when 'scalar_double'
|
|
655
|
+
raw_val == '__NA__' ? nil : raw_val.to_f
|
|
656
|
+
when 'scalar_logical'
|
|
657
|
+
raw_val == '__NA__' ? nil : (raw_val == 'TRUE')
|
|
658
|
+
when 'scalar_character'
|
|
659
|
+
raw_val == '__NA__' ? nil : raw_val
|
|
660
|
+
else
|
|
661
|
+
nil
|
|
662
|
+
end
|
|
663
|
+
|
|
664
|
+
{ kind: kind, length: len, r_class: r_class, value: value }
|
|
665
|
+
end
|
|
666
|
+
|
|
667
|
+
def format_scalar_print(parsed)
|
|
668
|
+
kind = parsed['kind']
|
|
669
|
+
val = parsed['value']
|
|
670
|
+
case kind
|
|
671
|
+
when 'integer', 'double'
|
|
672
|
+
"[1] #{val.nil? ? 'NA' : val}"
|
|
673
|
+
when 'logical'
|
|
674
|
+
"[1] #{val.nil? ? 'NA' : (val ? 'TRUE' : 'FALSE')}"
|
|
675
|
+
when 'character'
|
|
676
|
+
"[1] \"#{unescape_scalar_character(val.to_s)}\""
|
|
677
|
+
else
|
|
678
|
+
parsed.to_s
|
|
679
|
+
end
|
|
680
|
+
end
|
|
681
|
+
|
|
682
|
+
def decode_batch_eval_payload(parsed)
|
|
683
|
+
raise "batch: expected Hash payload, got #{parsed.class}" unless parsed.is_a?(Hash)
|
|
684
|
+
|
|
685
|
+
case parsed['kind'].to_s
|
|
686
|
+
when 'batch_error'
|
|
687
|
+
idx = parsed['index']
|
|
688
|
+
idx = idx.to_i if idx && !idx.is_a?(Integer)
|
|
689
|
+
msg = parsed['message'].to_s
|
|
690
|
+
raise R::BatchEvaluationError.new(msg, idx)
|
|
691
|
+
when 'batch_eval'
|
|
692
|
+
Array(parsed['results']).map { |sub| to_legacy_envelope(sub) }
|
|
693
|
+
else
|
|
694
|
+
raise "batch: unknown payload kind #{parsed['kind'].inspect}"
|
|
695
|
+
end
|
|
696
|
+
end
|
|
697
|
+
|
|
698
|
+
def to_legacy_envelope(parsed)
|
|
699
|
+
ptype = parsed['type'].to_s
|
|
700
|
+
val = parsed['value']
|
|
701
|
+
case ptype
|
|
702
|
+
when 'scalar_integer'
|
|
703
|
+
{ type: :scalar_integer, value: val }
|
|
704
|
+
when 'scalar_double'
|
|
705
|
+
{ type: :scalar_double, value: val }
|
|
706
|
+
when 'scalar_logical'
|
|
707
|
+
{ type: :scalar_logical, value: val }
|
|
708
|
+
when 'scalar_character'
|
|
709
|
+
{ type: :scalar_character, value: val.nil? ? nil : unescape_scalar_character(val.to_s) }
|
|
710
|
+
when 'scalar_symbol'
|
|
711
|
+
{ type: :scalar_symbol, value: val.to_s }
|
|
712
|
+
when 'handle'
|
|
713
|
+
wt = parsed['wrapper_tag']
|
|
714
|
+
wt = nil if wt.nil? || wt.to_s.strip.empty?
|
|
715
|
+
{ type: :handle, handle: parsed['handle'].to_s, r_class: parsed['r_class'].to_s, wrapper_tag: wt&.to_s }
|
|
716
|
+
else
|
|
717
|
+
raise "Result protocol: unknown payload type #{parsed.inspect}"
|
|
718
|
+
end
|
|
719
|
+
end
|
|
720
|
+
|
|
721
|
+
def unescape_scalar_character(str)
|
|
722
|
+
str.to_s
|
|
723
|
+
.gsub(/\\n/, "\n")
|
|
724
|
+
.gsub(/\\"/, '"')
|
|
725
|
+
.gsub(/\\\\/, "\\")
|
|
726
|
+
end
|
|
727
|
+
|
|
728
|
+
# Gatekeeper bulk vector read: `__G_PULL_VECTOR__|handle` or slice `|start|count` (1-based start).
|
|
729
|
+
def eval_pull_vector_payload(var_name, slice_start_1based: nil, slice_count: nil)
|
|
730
|
+
cmd =
|
|
731
|
+
if slice_start_1based.nil?
|
|
732
|
+
"__G_PULL_VECTOR__|#{var_name}"
|
|
733
|
+
else
|
|
734
|
+
"__G_PULL_VECTOR__|#{var_name}|#{slice_start_1based.to_i}|#{slice_count.to_i}"
|
|
735
|
+
end
|
|
736
|
+
@client.eval_r(cmd,
|
|
737
|
+
session_id: current_session_id,
|
|
738
|
+
parent_id: callback_parent_id,
|
|
739
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
740
|
+
end
|
|
741
|
+
|
|
742
|
+
def vector_bulk_kind?(k)
|
|
743
|
+
%w[integer_vector double_vector logical_vector character_vector].include?(k.to_s)
|
|
744
|
+
end
|
|
745
|
+
|
|
746
|
+
# Returns Ruby Array or nil if +parsed+ is not a bulk vector payload.
|
|
747
|
+
def decode_pull_vector_bulk_payload(parsed, want_kind: nil)
|
|
748
|
+
return nil unless parsed.is_a?(Hash)
|
|
749
|
+
|
|
750
|
+
k = parsed['kind'].to_s
|
|
751
|
+
return nil unless vector_bulk_kind?(k)
|
|
752
|
+
return nil if want_kind && k != want_kind.to_s
|
|
753
|
+
|
|
754
|
+
vals = Array(parsed['values'])
|
|
755
|
+
case k
|
|
756
|
+
when 'integer_vector', 'double_vector'
|
|
757
|
+
vals
|
|
758
|
+
when 'logical_vector'
|
|
759
|
+
vals.map { |v| v.nil? ? R::NA : v }
|
|
760
|
+
when 'character_vector'
|
|
761
|
+
vals.map { |v| v.nil? ? nil : unescape_scalar_character(v.to_s) }
|
|
762
|
+
else
|
|
763
|
+
nil
|
|
764
|
+
end
|
|
765
|
+
end
|
|
766
|
+
|
|
767
|
+
def pull_vector_elementwise(var_name)
|
|
768
|
+
len = @client.eval_r("length(#{var_name})",
|
|
769
|
+
session_id: current_session_id,
|
|
770
|
+
parent_id: callback_parent_id,
|
|
771
|
+
timeout: effective_bridge_timeout(timeout: nil))['value'].to_i
|
|
772
|
+
return [] if len <= 0
|
|
773
|
+
|
|
774
|
+
(1..len).map do |i|
|
|
775
|
+
parsed = @client.eval_r("#{var_name}[[#{i}]]",
|
|
776
|
+
session_id: current_session_id,
|
|
777
|
+
parent_id: callback_parent_id,
|
|
778
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
779
|
+
case parsed['kind']
|
|
780
|
+
when 'integer', 'double', 'character'
|
|
781
|
+
parsed['kind'] == 'character' ? unescape_scalar_character(parsed['value'].to_s) : parsed['value']
|
|
782
|
+
when 'logical'
|
|
783
|
+
parsed['value'].nil? ? R::NA : parsed['value']
|
|
784
|
+
else
|
|
785
|
+
parsed['value']
|
|
786
|
+
end
|
|
787
|
+
end
|
|
788
|
+
end
|
|
789
|
+
|
|
790
|
+
def pull_integer_vector_elementwise(var_name, offset, chunk_size)
|
|
791
|
+
start_i = offset + 1
|
|
792
|
+
end_i = offset + chunk_size
|
|
793
|
+
(start_i..end_i).map do |i|
|
|
794
|
+
parsed = @client.eval_r("#{var_name}[[#{i}]]",
|
|
795
|
+
session_id: current_session_id,
|
|
796
|
+
parent_id: callback_parent_id,
|
|
797
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
798
|
+
parsed['value']
|
|
799
|
+
end
|
|
800
|
+
end
|
|
801
|
+
|
|
802
|
+
def pull_double_vector_elementwise(var_name, offset, chunk_size)
|
|
803
|
+
start_i = offset + 1
|
|
804
|
+
end_i = offset + chunk_size
|
|
805
|
+
(start_i..end_i).map do |i|
|
|
806
|
+
parsed = @client.eval_r("#{var_name}[[#{i}]]",
|
|
807
|
+
session_id: current_session_id,
|
|
808
|
+
parent_id: callback_parent_id,
|
|
809
|
+
timeout: effective_bridge_timeout(timeout: nil))
|
|
810
|
+
parsed['value']
|
|
811
|
+
end
|
|
812
|
+
end
|
|
813
|
+
|
|
814
|
+
def phase1_scalar_fallback_error?(error)
|
|
815
|
+
msg = error.message.to_s.strip
|
|
816
|
+
return true if msg =~ /\Aphase1 requires length-1 scalar\z/
|
|
817
|
+
return true if msg =~ /\Aunsupported type\z/
|
|
818
|
+
return true if msg =~ /payload_error\("phase1 requires length-1 scalar"\)/
|
|
819
|
+
return true if msg =~ /payload_error\("unsupported type"\)/
|
|
820
|
+
false
|
|
821
|
+
end
|
|
822
|
+
end
|
|
823
|
+
end
|
|
824
|
+
|