galaaz 2.0.0 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +43 -5
  3. data/README.md +200 -128
  4. data/Rakefile +17 -10
  5. data/bin/galaaz +10 -2
  6. data/bin/galaaz-jruby +3 -6
  7. data/bin/galaaz-ruby +16 -0
  8. data/bin/galaaz_jruby_env.inc.sh +19 -3
  9. data/bin/galaaz_ruby_env.inc.sh +38 -0
  10. data/bin/gbookdown +2 -3
  11. data/bin/gknit +2 -3
  12. data/bin/gstudio +4 -4
  13. data/bin/run_all_rspec +6 -5
  14. data/bin/run_example +10 -7
  15. data/bin/run_old_rspec +6 -5
  16. data/bin/run_rspec +9 -8
  17. data/bin/run_slow_rspec +6 -5
  18. data/blogs/R-on-Rails-Planning-Document.md +79 -112
  19. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/midwest_rb.png +0 -0
  20. data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/scatter_plot_rb.png +0 -0
  21. data/blogs/gknit/gknit_files/figure-gfm/bubble-1.png +0 -0
  22. data/blogs/gknit/gknit_files/figure-gfm/diverging_bar.png +0 -0
  23. data/blogs/manual/manual.Rmd +22 -19
  24. data/blogs/manual/manual.md +200 -128
  25. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/dose_len.png +0 -0
  26. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_delivery.png +0 -0
  27. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_dose.png +0 -0
  28. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color.png +0 -0
  29. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color2.png +0 -0
  30. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_decorations.png +0 -0
  31. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_jitter.png +0 -0
  32. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_points.png +0 -0
  33. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/final_box_plot.png +0 -0
  34. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/final_violin_plot.png +0 -0
  35. data/blogs/ruby_plot/ruby_plot_files/figure-gfm/violin_with_jitter.png +0 -0
  36. data/blogs/test/test.md +10 -0
  37. data/examples/50Plots_MasterList/ScatterPlot.rb +2 -1
  38. data/examples/50Plots_MasterList/scatter_plot.rb +1 -0
  39. data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +1 -0
  40. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +1 -0
  41. data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +1 -0
  42. data/examples/islr/all.rb +1 -0
  43. data/examples/islr/ch2.spec.rb +1 -0
  44. data/examples/islr/ch3.spec.rb +1 -0
  45. data/examples/islr/ch3_boston.rb +1 -0
  46. data/examples/islr/ch3_multiple_regression.rb +1 -0
  47. data/examples/islr/ch6.spec.rb +1 -0
  48. data/examples/islr/x_y_rnorm.jpg +0 -0
  49. data/examples/misc/ggplot.rb +2 -1
  50. data/examples/misc/moneyball.rb +1 -0
  51. data/examples/misc/subsetting.rb +1 -0
  52. data/examples/multithread_shards_to_r/shards_to_r.rb +1 -0
  53. data/examples/sthda_ggplot/all.rb +1 -0
  54. data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +1 -0
  55. data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +1 -0
  56. data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +1 -0
  57. data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +1 -0
  58. data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +1 -0
  59. data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +1 -0
  60. data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +1 -0
  61. data/examples/sthda_ggplot/one_variable_continuous/stat.rb +1 -0
  62. data/examples/sthda_ggplot/one_variable_discrete/bar.rb +1 -0
  63. data/examples/sthda_ggplot/qplots/box_violin_dot.rb +1 -0
  64. data/examples/sthda_ggplot/qplots/scatter_plots.rb +1 -0
  65. data/examples/sthda_ggplot/scatter_gg.rb +1 -0
  66. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +1 -0
  67. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +1 -0
  68. data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +1 -0
  69. data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +1 -0
  70. data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +1 -0
  71. data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +1 -0
  72. data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +1 -0
  73. data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +1 -0
  74. data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +1 -0
  75. data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +1 -0
  76. data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +1 -0
  77. data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +1 -0
  78. data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +1 -0
  79. data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +1 -0
  80. data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +1 -0
  81. data/lib/R_interface/r_arrow.rb +37 -0
  82. data/lib/R_interface/rvector.rb +15 -0
  83. data/lib/galaaz/arrow_ipc/java_arrow_backend.rb +250 -0
  84. data/lib/galaaz/arrow_ipc/red_arrow_backend.rb +126 -0
  85. data/lib/galaaz/arrow_ipc.rb +167 -0
  86. data/lib/galaaz/cli.rb +531 -0
  87. data/lib/galaaz.rb +6 -0
  88. data/lib/galaaz_jruby.rb +17 -2
  89. data/lib/galaaz_ruby.rb +34 -0
  90. data/lib/new_bridge/envelope.rb +2 -2
  91. data/new_bridge_specs/arrow_ipc_async_spec.rb +90 -0
  92. data/new_bridge_specs/arrow_ipc_export_async_spec.rb +68 -0
  93. data/r_requires/arrow.txt +3 -0
  94. data/r_requires/knit-extras.txt +4 -0
  95. data/r_requires/knit.txt +4 -0
  96. data/specs/arrow_ipc_export_spec.rb +62 -0
  97. data/specs/arrow_ipc_handoff_spec.rb +97 -0
  98. data/specs/gknit_include_engine_spec.rb +2 -2
  99. data/specs/gknit_install_timeout_report_spec.rb +2 -2
  100. data/specs/gknit_internal_error_report_spec.rb +2 -2
  101. data/specs/gknit_vector_map_output_spec.rb +2 -2
  102. data/version.rb +1 -1
  103. metadata +50 -13
@@ -0,0 +1,90 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Async synchronization for Stage B1 Arrow IPC handoff.
4
+ # Run: bin/run_all_rspec new_bridge_specs/arrow_ipc_async_spec.rb
5
+
6
+ require 'thread'
7
+ require 'galaaz'
8
+
9
+ RSpec.describe 'Arrow IPC async handoff' do
10
+ before(:all) do
11
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
12
+ skip 'Galaaz::ArrowIpc writer backend not available' unless Galaaz::ArrowIpc.available?
13
+ ok = R::Support.eval("requireNamespace('arrow', quietly=TRUE) && requireNamespace('dplyr', quietly=TRUE)")
14
+ skip 'R packages arrow/dplyr are not available' unless ok == true
15
+ @paths = []
16
+ end
17
+
18
+ after(:each) do
19
+ Array(@paths).each { |p| Galaaz::ArrowIpc.release(p) }
20
+ @paths = []
21
+ end
22
+
23
+ def track(path)
24
+ @paths << path
25
+ path
26
+ end
27
+
28
+ it 'happens-before: write+fsync then async open returns correct nrow' do
29
+ values = [1.0, 2.0, 3.0, 4.0]
30
+ path = track(Galaaz::ArrowIpc.write(value: values))
31
+
32
+ done = Queue.new
33
+ # Path-only over the bridge; R reads the IPC file.
34
+ R.eval_r_async("nrow(arrow::read_ipc_file(#{path.inspect}))", timeout: 30) do |result|
35
+ done.push(result)
36
+ end
37
+ r = done.pop
38
+ expect(r).to be_ok
39
+ expect(r.value).to match(/4/)
40
+ end
41
+
42
+ it 'async open then sync R reduction on the proxy' do
43
+ path = track(Galaaz::ArrowIpc.write(value: [10.0, 20.0, 30.0]))
44
+
45
+ done = Queue.new
46
+ R::Async.arrow___read_ipc_file(path, as_data_frame: false, timeout: 30) do |result|
47
+ done.push(result)
48
+ end
49
+ r = done.pop
50
+ expect(r).to be_ok
51
+ expect(r.value).to be_a(R::Object)
52
+
53
+ tbl = r.value
54
+ mean = R.mean(R.dplyr___pull(tbl, :value))
55
+ mean_v = mean.respond_to?(:>>) ? (mean >> 0) : mean
56
+ expect(mean_v).to eq(20.0)
57
+ end
58
+
59
+ it 'two concurrent handoffs do not cross-talk' do
60
+ path_a = track(Galaaz::ArrowIpc.write(tag: ['A'], n: [1]))
61
+ path_b = track(Galaaz::ArrowIpc.write(tag: ['B', 'B'], n: [2, 2]))
62
+
63
+ done = Queue.new
64
+ R.eval_r_async("nrow(arrow::read_ipc_file(#{path_a.inspect}))", timeout: 30) do |result|
65
+ done.push([:a, result])
66
+ end
67
+ R.eval_r_async("nrow(arrow::read_ipc_file(#{path_b.inspect}))", timeout: 30) do |result|
68
+ done.push([:b, result])
69
+ end
70
+
71
+ results = {}
72
+ 2.times do
73
+ key, res = done.pop
74
+ expect(res).to be_ok
75
+ results[key] = res.value
76
+ end
77
+ expect(results[:a]).to match(/1/)
78
+ expect(results[:b]).to match(/2/)
79
+ end
80
+
81
+ it 'missing path fails without hanging' do
82
+ done = Queue.new
83
+ missing = File.join(Galaaz::ArrowIpc.scratch_dir, 'galaaz_missing_async.arrow')
84
+ R.eval_r_async("arrow::read_ipc_file(#{missing.inspect})", timeout: 10) do |result|
85
+ done.push(result)
86
+ end
87
+ r = done.pop
88
+ expect(r).not_to be_ok
89
+ end
90
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Async synchronization for Stage B2 R→Ruby Arrow IPC export.
4
+ # Run: bin/run_all_rspec new_bridge_specs/arrow_ipc_export_async_spec.rb
5
+
6
+ require 'thread'
7
+ require 'galaaz'
8
+
9
+ RSpec.describe 'Arrow IPC export async (Stage B2)' do
10
+ before(:all) do
11
+ skip 'R not on PATH' unless system('command -v R >/dev/null 2>&1')
12
+ skip 'Galaaz::ArrowIpc backend not available' unless Galaaz::ArrowIpc.available?
13
+ ok = R::Support.eval("requireNamespace('arrow', quietly=TRUE)")
14
+ skip 'R package arrow is not available' unless ok == true
15
+ @paths = []
16
+ end
17
+
18
+ after(:each) do
19
+ Array(@paths).each { |p| Galaaz::ArrowIpc.release(p) }
20
+ @paths = []
21
+ end
22
+
23
+ def track(path)
24
+ @paths << path
25
+ path
26
+ end
27
+
28
+ it 'happens-before: async R write_ipc_file then Ruby read matches' do
29
+ in_path = track(Galaaz::ArrowIpc.write(n: [1, 2, 3]))
30
+ out_path = track(Galaaz::ArrowIpc.allocate_path)
31
+
32
+ done = Queue.new
33
+ R.eval_r_async(
34
+ "({ arrow::write_ipc_file(arrow::read_ipc_file(#{in_path.inspect}, as_data_frame=FALSE), #{out_path.inspect}, compression='uncompressed'); 1L })",
35
+ timeout: 30
36
+ ) { |result| done.push(result) }
37
+ r = done.pop
38
+ expect(r).to be_ok
39
+
40
+ cols = Galaaz::ArrowIpc.read(out_path)
41
+ expect(cols['n'].map(&:to_i)).to eq([1, 2, 3])
42
+ end
43
+
44
+ it 'two concurrent R exports do not cross-talk' do
45
+ in_a = track(Galaaz::ArrowIpc.write(tag: ['A']))
46
+ in_b = track(Galaaz::ArrowIpc.write(tag: ['B']))
47
+ out_a = track(Galaaz::ArrowIpc.allocate_path)
48
+ out_b = track(Galaaz::ArrowIpc.allocate_path)
49
+
50
+ done = Queue.new
51
+ R.eval_r_async(
52
+ "({ arrow::write_ipc_file(arrow::read_ipc_file(#{in_a.inspect}, as_data_frame=FALSE), #{out_a.inspect}, compression='uncompressed'); 1L })",
53
+ timeout: 30
54
+ ) { |res| done.push([:a, res]) }
55
+ R.eval_r_async(
56
+ "({ arrow::write_ipc_file(arrow::read_ipc_file(#{in_b.inspect}, as_data_frame=FALSE), #{out_b.inspect}, compression='uncompressed'); 1L })",
57
+ timeout: 30
58
+ ) { |res| done.push([:b, res]) }
59
+
60
+ 2.times do
61
+ _key, res = done.pop
62
+ expect(res).to be_ok
63
+ end
64
+
65
+ expect(Galaaz::ArrowIpc.read(out_a)['tag']).to eq(['A'])
66
+ expect(Galaaz::ArrowIpc.read(out_b)['tag']).to eq(['B'])
67
+ end
68
+ end
@@ -0,0 +1,3 @@
1
+ # CRAN packages for `galaaz add arrow`.
2
+ dplyr
3
+ arrow
@@ -0,0 +1,4 @@
1
+ # Best-effort CRAN extras for `galaaz add knit` (warn if missing).
2
+ ggplot2
3
+ kableExtra
4
+ RColorBrewer
@@ -0,0 +1,4 @@
1
+ # Hard CRAN set for `galaaz add knit` (must succeed).
2
+ dplyr
3
+ knitr
4
+ rmarkdown
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'galaaz'
4
+
5
+ describe 'Arrow IPC export (Stage B2)' do
6
+ before(:all) do
7
+ skip 'Galaaz::ArrowIpc backend not available' unless Galaaz::ArrowIpc.available?
8
+ ok = R::Support.eval("requireNamespace('arrow', quietly=TRUE) && requireNamespace('dplyr', quietly=TRUE)")
9
+ skip 'R packages arrow/dplyr are not available' unless ok == true
10
+ @paths = []
11
+ end
12
+
13
+ after(:each) do
14
+ Array(@paths).each { |p| Galaaz::ArrowIpc.release(p) }
15
+ @paths = []
16
+ end
17
+
18
+ def track(path)
19
+ @paths << path
20
+ path
21
+ end
22
+
23
+ it 'reads columns R wrote via write_ipc (R→Ruby)' do
24
+ in_path = track(Galaaz::ArrowIpc.write(value: [1.5, 2.5], grp: %w[a b]))
25
+ tbl = R::Arrow.open_ipc(in_path)
26
+ out_path = track(R::Arrow.write_ipc(tbl))
27
+ expect(File.exist?(out_path)).to be true
28
+
29
+ cols = Galaaz::ArrowIpc.read(out_path)
30
+ expect(cols['value']).to eq([1.5, 2.5])
31
+ expect(cols['grp']).to eq(%w[a b])
32
+
33
+ rows = Galaaz::ArrowIpc.read_batches(out_path)
34
+ expect(rows).to eq([{ value: 1.5, grp: 'a' }, { value: 2.5, grp: 'b' }])
35
+ end
36
+
37
+ it 'proves DB-style loop: Ruby ingest → R summarise → Ruby reads result table' do
38
+ in_path = track(Galaaz::ArrowIpc.write_batches([
39
+ { id: 1, grp: 'a', value: 10.0 },
40
+ { id: 2, grp: 'b', value: 20.5 },
41
+ { id: 3, grp: 'a', value: 30.0 }
42
+ ]))
43
+ tbl = R::Arrow.open_ipc(in_path)
44
+ grouped = R.dplyr___group_by(tbl, :grp)
45
+ summed = R.dplyr___summarise(grouped, total: E.sum(:value))
46
+ out_path = track(R::Arrow.write_ipc(summed))
47
+
48
+ rows = Galaaz::ArrowIpc.read_batches(out_path)
49
+ by_grp = rows.each_with_object({}) { |r, h| h[r[:grp].to_s] = r[:total].to_f }
50
+ expect(by_grp['a']).to eq(40.0)
51
+ expect(by_grp['b']).to eq(20.5)
52
+
53
+ Galaaz::ArrowIpc.release(out_path)
54
+ expect(File.exist?(out_path)).to be false
55
+ end
56
+
57
+ it 'raises when reading a missing IPC file' do
58
+ expect {
59
+ Galaaz::ArrowIpc.read('/tmp/galaaz_missing_b2.arrow')
60
+ }.to raise_error(ArgumentError, /not found/)
61
+ end
62
+ end
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'galaaz'
4
+
5
+ describe 'Arrow IPC handoff (Stage B1)' do
6
+ before(:all) do
7
+ skip 'Galaaz::ArrowIpc writer backend not available' unless Galaaz::ArrowIpc.available?
8
+ ok = R::Support.eval("requireNamespace('arrow', quietly=TRUE) && requireNamespace('dplyr', quietly=TRUE)")
9
+ skip 'R packages arrow/dplyr are not available' unless ok == true
10
+ @paths = []
11
+ end
12
+
13
+ after(:each) do
14
+ Array(@paths).each { |p| Galaaz::ArrowIpc.release(p) }
15
+ @paths = []
16
+ end
17
+
18
+ def track(path)
19
+ @paths << path
20
+ path
21
+ end
22
+
23
+ it 'round-trips a float64 column through open_ipc' do
24
+ values = [1.5, 2.5, -3.0, 0.0]
25
+ path = track(Galaaz::ArrowIpc.write(value: values))
26
+ expect(File.exist?(path)).to be true
27
+
28
+ tbl = R::Arrow.open_ipc(path)
29
+ expect(tbl.rclass.split(' ')).to include('Table')
30
+ expect((R.nrow(tbl) >> 0)).to eq(values.length)
31
+
32
+ collected = R.dplyr___collect(tbl)
33
+ col = collected[['value']]
34
+ got = (1..(col.length >> 0)).map do |i|
35
+ v = col[i]
36
+ v.respond_to?(:>>) ? (v >> 0) : v
37
+ end
38
+ expect(got).to eq(values)
39
+
40
+ Galaaz::ArrowIpc.release(path)
41
+ expect(File.exist?(path)).to be false
42
+ end
43
+
44
+ it 'round-trips multi-column id/grp/value via write_batches' do
45
+ rows = [
46
+ { id: 1, grp: 'a', value: 10.0 },
47
+ { id: 2, grp: 'b', value: 20.5 },
48
+ { id: 3, grp: 'a', value: 30.0 }
49
+ ]
50
+ path = track(Galaaz::ArrowIpc.write_batches(rows))
51
+ tbl = R::Arrow.open_ipc(path)
52
+
53
+ expect((R.nrow(tbl) >> 0)).to eq(3)
54
+ summed = R.dplyr___summarise(tbl, total: E.sum(:value))
55
+ out = R.dplyr___collect(summed)
56
+ total = out[['total']]
57
+ tot = total[1]
58
+ tot = tot.respond_to?(:>>) ? (tot >> 0) : tot
59
+ expect(tot).to eq(60.5)
60
+ end
61
+
62
+ it 'raises on missing R arrow package path for open_ipc with bad path' do
63
+ expect {
64
+ R::Arrow.open_ipc('/tmp/galaaz_missing_ipc_file_does_not_exist.arrow')
65
+ }.to raise_error(StandardError)
66
+ end
67
+
68
+ it 'raises when write is called without a usable backend message path' do
69
+ # available? already gated the suite; still check empty columns
70
+ expect { Galaaz::ArrowIpc.write({}) }.to raise_error(ArgumentError)
71
+ end
72
+
73
+ it 'optional timing smoke vs from_ruby_batches for N≈50k' do
74
+ n = 50_000
75
+ cols = {
76
+ id: (0...n).to_a,
77
+ grp: (0...n).map { |i| "g#{i % 5}" },
78
+ value: (0...n).map { |i| (i % 10) + 1.0 }
79
+ }
80
+
81
+ t0 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
82
+ path = track(Galaaz::ArrowIpc.write(cols))
83
+ tbl = R::Arrow.open_ipc(path)
84
+ ipc_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t0) * 1000.0
85
+ expect((R.nrow(tbl) >> 0)).to eq(n)
86
+
87
+ rows = (0...n).map { |i| { id: i, grp: "g#{i % 5}", value: (i % 10) + 1.0 } }
88
+ t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
89
+ tbl2 = R::Arrow.from_ruby_batches(rows)
90
+ batch_ms = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - t1) * 1000.0
91
+ expect((R.nrow(tbl2) >> 0)).to eq(n)
92
+
93
+ # Not a flaky perf gate — only ensure both paths produce a table.
94
+ expect(ipc_ms).to be > 0
95
+ expect(batch_ms).to be > 0
96
+ end
97
+ end
@@ -13,10 +13,10 @@ describe 'gknit include engine' do
13
13
  ].select { |dir| File.directory?(dir) }
14
14
  path = ENV.fetch('PATH', '')
15
15
  path = ([*extra, path].join(File::PATH_SEPARATOR)) unless extra.empty?
16
- {
16
+ ENV.to_h.merge(
17
17
  'JAVA_OPTS' => '--add-opens=java.base/java.nio=ALL-UNNAMED',
18
18
  'PATH' => path
19
- }
19
+ )
20
20
  end
21
21
 
22
22
  it 'loads include file code so constants are available in following ruby chunks' do
@@ -13,10 +13,10 @@ describe 'gknit install timeout reporting' do
13
13
  ].select { |dir| File.directory?(dir) }
14
14
  path = ENV.fetch('PATH', '')
15
15
  path = ([*extra, path].join(File::PATH_SEPARATOR)) unless extra.empty?
16
- {
16
+ ENV.to_h.merge(
17
17
  'JAVA_OPTS' => '--add-opens=java.base/java.nio=ALL-UNNAMED',
18
18
  'PATH' => path
19
- }
19
+ )
20
20
  end
21
21
 
22
22
  it 'continues processing and prints timeout in final report' do
@@ -13,10 +13,10 @@ describe 'gknit internal error report' do
13
13
  ].select { |dir| File.directory?(dir) }
14
14
  path = ENV.fetch('PATH', '')
15
15
  path = ([*extra, path].join(File::PATH_SEPARATOR)) unless extra.empty?
16
- {
16
+ ENV.to_h.merge(
17
17
  'JAVA_OPTS' => '--add-opens=java.base/java.nio=ALL-UNNAMED',
18
18
  'PATH' => path
19
- }
19
+ )
20
20
  end
21
21
 
22
22
  it 'prints chunk-scoped report only when internal errors are detected' do
@@ -13,10 +13,10 @@ describe 'gknit vector map output' do
13
13
  ].select { |dir| File.directory?(dir) }
14
14
  path = ENV.fetch('PATH', '')
15
15
  path = ([*extra, path].join(File::PATH_SEPARATOR)) unless extra.empty?
16
- {
16
+ ENV.to_h.merge(
17
17
  'JAVA_OPTS' => '--add-opens=java.base/java.nio=ALL-UNNAMED',
18
18
  'PATH' => path
19
- }
19
+ )
20
20
  end
21
21
 
22
22
  it 'renders vec.map in ruby chunks without missing bridge methods' do
data/version.rb CHANGED
@@ -1,2 +1,2 @@
1
1
  $gem_name = "galaaz"
2
- $version="2.0.0"
2
+ $version="2.1.1"
metadata CHANGED
@@ -1,13 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: galaaz
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 2.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rodrigo Botafogo
8
+ autorequire:
8
9
  bindir: bin
9
10
  cert_chain: []
10
- date: 2026-08-17 00:00:00.000000000 Z
11
+ date: 2026-09-04 00:00:00.000000000 Z
11
12
  dependencies:
12
13
  - !ruby/object:Gem::Dependency
13
14
  name: msgpack
@@ -66,27 +67,31 @@ dependencies:
66
67
  - !ruby/object:Gem::Version
67
68
  version: 6.1.2.1
68
69
  description: |
69
- Galaaz brings the full R ecosystem to Ruby developers. Galaaz 2.0 runs Ruby on JRuby and
70
- talks to standard GNU Rthe same R you use with CRAN and Bioconductor—in a separate
71
- process. A bridge handles requests, results, and typing so you can drive R from Ruby
72
- (for example calling R functions, loading packages, and working with R objects) without
73
- giving up multithreaded JRuby for application code.
70
+ Galaaz is R-on-Rails: R scientists keep GNU R (CRAN / Bioconductor) for statistics and
71
+ graphics, and use Ruby—often Railsto put that work on the web (HTTP, auth, jobs, HTML)
72
+ without rewriting analyses in another stack. Ruby developers also get full access to R
73
+ libraries through the same bridge.
74
+
75
+ Galaaz 2.0 talks to standard GNU R in a separate process. A bridge handles requests,
76
+ results, and typing so you can drive R from Ruby (calling R functions, loading packages,
77
+ and working with R objects). **JRuby** and **CRuby** are both supported for the same
78
+ NewBridge protocol (tested with JRuby 10.1.1.0 + Java 21, and CRuby 3.3).
74
79
 
75
80
  Like RinRuby, rpy2, or reticulate, Galaaz is a cross-language bridge; unlike embedding a
76
81
  second interpreter in one VM, using GNU R means compiled R packages and Bioconductor work
77
82
  as usual. Large tables can optionally flow through Apache Arrow on the R side when you use
78
83
  the helpers described in the project documentation.
79
84
 
80
- You need both JRuby and a working GNU R installation in PATH for the bridge to run.
85
+ You need JRuby or CRuby and a working GNU R installation in PATH for the bridge to run.
81
86
  Build the native gatekeeper after install with: make -C ext/new_bridge all
82
87
  email: rodrigo.a.botafogo@gmail.com
83
88
  executables:
84
89
  - galaaz
85
- - gbookdown
90
+ - gstudio
86
91
  - gknit
87
- - gknit-draft
92
+ - gbookdown
88
93
  - grun
89
- - gstudio
94
+ - gknit-draft
90
95
  extensions: []
91
96
  extra_rdoc_files: []
92
97
  files:
@@ -97,7 +102,9 @@ files:
97
102
  - bin/galaaz
98
103
  - bin/galaaz-bootstrap
99
104
  - bin/galaaz-jruby
105
+ - bin/galaaz-ruby
100
106
  - bin/galaaz_jruby_env.inc.sh
107
+ - bin/galaaz_ruby_env.inc.sh
101
108
  - bin/gbookdown
102
109
  - bin/gknit
103
110
  - bin/gknit-draft
@@ -120,6 +127,8 @@ files:
120
127
  - blogs/galaaz_ggplot/galaaz_ggplot.log
121
128
  - blogs/galaaz_ggplot/galaaz_ggplot.md
122
129
  - blogs/galaaz_ggplot/galaaz_ggplot.tex
130
+ - blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/midwest_rb.png
131
+ - blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/scatter_plot_rb.png
123
132
  - blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/midwest_rb.png
124
133
  - blogs/galaaz_ggplot/galaaz_ggplot_files/figure-html/scatter_plot_rb.png
125
134
  - blogs/galaaz_ggplot/galaaz_ggplot_files/figure-markdown_github/midwest_rb.png
@@ -128,6 +137,8 @@ files:
128
137
  - blogs/galaaz_ggplot/midwest_external_png
129
138
  - blogs/gknit/gknit.Rmd
130
139
  - blogs/gknit/gknit.md
140
+ - blogs/gknit/gknit_files/figure-gfm/bubble-1.png
141
+ - blogs/gknit/gknit_files/figure-gfm/diverging_bar.png
131
142
  - blogs/gknit/gknit_files/figure-html/bubble-1.png
132
143
  - blogs/gknit/gknit_files/figure-html/diverging_bar.png
133
144
  - blogs/gknit/lst.rds
@@ -157,6 +168,17 @@ files:
157
168
  - blogs/ruby_plot/ruby_plot.log
158
169
  - blogs/ruby_plot/ruby_plot.md
159
170
  - blogs/ruby_plot/ruby_plot.tex
171
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/dose_len.png
172
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_delivery.png
173
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_dose.png
174
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color.png
175
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color2.png
176
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_decorations.png
177
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_jitter.png
178
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_points.png
179
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/final_box_plot.png
180
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/final_violin_plot.png
181
+ - blogs/ruby_plot/ruby_plot_files/figure-gfm/violin_with_jitter.png
160
182
  - blogs/ruby_plot/ruby_plot_files/figure-html/dose_len.png
161
183
  - blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_delivery.png
162
184
  - blogs/ruby_plot/ruby_plot_files/figure-html/facet_by_dose.png
@@ -180,6 +202,7 @@ files:
180
202
  - blogs/ruby_plot/ruby_plot_files/figure-latex/final_violin_plot.png
181
203
  - blogs/ruby_plot/ruby_plot_files/figure-latex/violin_with_jitter.png
182
204
  - blogs/test/test.Rmd
205
+ - blogs/test/test.md
183
206
  - examples/50Plots_MasterList/Images/midwest-scatterplot.PNG
184
207
  - examples/50Plots_MasterList/ScatterPlot.rb
185
208
  - examples/50Plots_MasterList/scatter_plot.rb
@@ -314,7 +337,12 @@ files:
314
337
  - lib/R_interface/runary_operators.rb
315
338
  - lib/R_interface/rvector.rb
316
339
  - lib/galaaz.rb
340
+ - lib/galaaz/arrow_ipc.rb
341
+ - lib/galaaz/arrow_ipc/java_arrow_backend.rb
342
+ - lib/galaaz/arrow_ipc/red_arrow_backend.rb
343
+ - lib/galaaz/cli.rb
317
344
  - lib/galaaz_jruby.rb
345
+ - lib/galaaz_ruby.rb
318
346
  - lib/gknit.rb
319
347
  - lib/gknit/diagnostics.rb
320
348
  - lib/gknit/draft.rb
@@ -333,6 +361,8 @@ files:
333
361
  - lib/new_bridge/tcp_framed.rb
334
362
  - lib/util/exec_ruby.rb
335
363
  - lib/util/inline_file.rb
364
+ - new_bridge_specs/arrow_ipc_async_spec.rb
365
+ - new_bridge_specs/arrow_ipc_export_async_spec.rb
336
366
  - new_bridge_specs/benchmark_phase5_5_unboxing_spec.rb
337
367
  - new_bridge_specs/eval_r_async_spec.rb
338
368
  - new_bridge_specs/integration_phase5_1_concurrent_spec.rb
@@ -359,10 +389,15 @@ files:
359
389
  - new_bridge_specs/phase4_2_hardening_spec.rb
360
390
  - new_bridge_specs/phase4_3_r_instance_manager_spec.rb
361
391
  - new_bridge_specs/phase4_nested_callbacks_spec.rb
392
+ - r_requires/arrow.txt
362
393
  - r_requires/ggplot.rb
394
+ - r_requires/knit-extras.txt
395
+ - r_requires/knit.txt
363
396
  - r_requires/knitr.rb
364
397
  - specs/all.rb
365
398
  - specs/arrow_from_ruby_batches_spec.rb
399
+ - specs/arrow_ipc_export_spec.rb
400
+ - specs/arrow_ipc_handoff_spec.rb
366
401
  - specs/arrow_semantics_spec.rb
367
402
  - specs/bridge_concurrent_spec.rb
368
403
  - specs/bridge_nested_spec.rb
@@ -450,6 +485,7 @@ metadata:
450
485
  documentation_uri: https://rbotafogo.github.io/galaaz/
451
486
  changelog_uri: https://github.com/rbotafogo/galaaz/blob/galaaz2_0/CHANGELOG.md
452
487
  yard.run: yri
488
+ post_install_message:
453
489
  rdoc_options: []
454
490
  require_paths:
455
491
  - lib
@@ -464,7 +500,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
464
500
  - !ruby/object:Gem::Version
465
501
  version: '0'
466
502
  requirements: []
467
- rubygems_version: 4.0.3
503
+ rubygems_version: 3.5.22
504
+ signing_key:
468
505
  specification_version: 4
469
- summary: Tightly coupling Ruby and R
506
+ summary: 'R-on-Rails: tightly couple Ruby and GNU R for data science on the web'
470
507
  test_files: []