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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +43 -5
- data/README.md +200 -128
- data/Rakefile +17 -10
- data/bin/galaaz +10 -2
- data/bin/galaaz-jruby +3 -6
- data/bin/galaaz-ruby +16 -0
- data/bin/galaaz_jruby_env.inc.sh +19 -3
- data/bin/galaaz_ruby_env.inc.sh +38 -0
- data/bin/gbookdown +2 -3
- data/bin/gknit +2 -3
- data/bin/gstudio +4 -4
- data/bin/run_all_rspec +6 -5
- data/bin/run_example +10 -7
- data/bin/run_old_rspec +6 -5
- data/bin/run_rspec +9 -8
- data/bin/run_slow_rspec +6 -5
- data/blogs/R-on-Rails-Planning-Document.md +79 -112
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/midwest_rb.png +0 -0
- data/blogs/galaaz_ggplot/galaaz_ggplot_files/figure-gfm/scatter_plot_rb.png +0 -0
- data/blogs/gknit/gknit_files/figure-gfm/bubble-1.png +0 -0
- data/blogs/gknit/gknit_files/figure-gfm/diverging_bar.png +0 -0
- data/blogs/manual/manual.Rmd +22 -19
- data/blogs/manual/manual.md +200 -128
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/dose_len.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_delivery.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facet_by_dose.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_by_delivery_color2.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_decorations.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_jitter.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/facets_with_points.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/final_box_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/final_violin_plot.png +0 -0
- data/blogs/ruby_plot/ruby_plot_files/figure-gfm/violin_with_jitter.png +0 -0
- data/blogs/test/test.md +10 -0
- data/examples/50Plots_MasterList/ScatterPlot.rb +2 -1
- data/examples/50Plots_MasterList/scatter_plot.rb +1 -0
- data/examples/bioconductor_deseq2_airway/bench_galaaz_three_same_process.rb +1 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz.rb +1 -0
- data/examples/bioconductor_deseq2_airway/deseq2_airway_galaaz_optimized.rb +1 -0
- data/examples/islr/all.rb +1 -0
- data/examples/islr/ch2.spec.rb +1 -0
- data/examples/islr/ch3.spec.rb +1 -0
- data/examples/islr/ch3_boston.rb +1 -0
- data/examples/islr/ch3_multiple_regression.rb +1 -0
- data/examples/islr/ch6.spec.rb +1 -0
- data/examples/islr/x_y_rnorm.jpg +0 -0
- data/examples/misc/ggplot.rb +2 -1
- data/examples/misc/moneyball.rb +1 -0
- data/examples/misc/subsetting.rb +1 -0
- data/examples/multithread_shards_to_r/shards_to_r.rb +1 -0
- data/examples/sthda_ggplot/all.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/density_gg.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_area.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_density.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_dotplot.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_freqpoly.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/geom_histogram.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/histogram_density.rb +1 -0
- data/examples/sthda_ggplot/one_variable_continuous/stat.rb +1 -0
- data/examples/sthda_ggplot/one_variable_discrete/bar.rb +1 -0
- data/examples/sthda_ggplot/qplots/box_violin_dot.rb +1 -0
- data/examples/sthda_ggplot/qplots/scatter_plots.rb +1 -0
- data/examples/sthda_ggplot/scatter_gg.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_bin2d.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_density2d.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_bivariate/geom_hex.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_point.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/geom_smooth.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_cont/misc.rb +1 -0
- data/examples/sthda_ggplot/two_variables_cont_function/geom_area.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_bar.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_boxplot.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_dotplot.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_jitter.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_line.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_cont/geom_violin.rb +1 -0
- data/examples/sthda_ggplot/two_variables_disc_disc/geom_jitter.rb +1 -0
- data/examples/sthda_ggplot/two_variables_error/geom_crossbar.rb +1 -0
- data/lib/R_interface/r_arrow.rb +37 -0
- data/lib/R_interface/rvector.rb +15 -0
- data/lib/galaaz/arrow_ipc/java_arrow_backend.rb +250 -0
- data/lib/galaaz/arrow_ipc/red_arrow_backend.rb +126 -0
- data/lib/galaaz/arrow_ipc.rb +167 -0
- data/lib/galaaz/cli.rb +531 -0
- data/lib/galaaz.rb +6 -0
- data/lib/galaaz_jruby.rb +17 -2
- data/lib/galaaz_ruby.rb +34 -0
- data/lib/new_bridge/envelope.rb +2 -2
- data/new_bridge_specs/arrow_ipc_async_spec.rb +90 -0
- data/new_bridge_specs/arrow_ipc_export_async_spec.rb +68 -0
- data/r_requires/arrow.txt +3 -0
- data/r_requires/knit-extras.txt +4 -0
- data/r_requires/knit.txt +4 -0
- data/specs/arrow_ipc_export_spec.rb +62 -0
- data/specs/arrow_ipc_handoff_spec.rb +97 -0
- data/specs/gknit_include_engine_spec.rb +2 -2
- data/specs/gknit_install_timeout_report_spec.rb +2 -2
- data/specs/gknit_internal_error_report_spec.rb +2 -2
- data/specs/gknit_vector_map_output_spec.rb +2 -2
- data/version.rb +1 -1
- 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
|
data/r_requires/knit.txt
ADDED
|
@@ -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.
|
|
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.
|
|
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-
|
|
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
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
70
|
+
Galaaz is R-on-Rails: R scientists keep GNU R (CRAN / Bioconductor) for statistics and
|
|
71
|
+
graphics, and use Ruby—often Rails—to 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
|
|
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
|
-
-
|
|
90
|
+
- gstudio
|
|
86
91
|
- gknit
|
|
87
|
-
-
|
|
92
|
+
- gbookdown
|
|
88
93
|
- grun
|
|
89
|
-
-
|
|
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:
|
|
503
|
+
rubygems_version: 3.5.22
|
|
504
|
+
signing_key:
|
|
468
505
|
specification_version: 4
|
|
469
|
-
summary:
|
|
506
|
+
summary: 'R-on-Rails: tightly couple Ruby and GNU R for data science on the web'
|
|
470
507
|
test_files: []
|