From 0d8b23fb3401171f33c2f299335418abff4df606 Mon Sep 17 00:00:00 2001 From: Francis Murillo Date: Sat, 20 Mar 2021 10:51:53 +0800 Subject: [PATCH] Migrate Ruby bindings from helix to rutie --- .github/workflows/ruby_build.yml | 10 +-- Cargo.lock | 78 ++++++++++++++--------- ruby/Cargo.toml | 4 +- ruby/Gemfile | 4 +- ruby/Rakefile | 10 +-- ruby/lib/deltalake.rb | 8 ++- ruby/lib/deltalake/version.rb | 5 ++ ruby/spec/deltalake_spec.rb | 12 ++++ ruby/src/lib.rs | 102 +++++++++++++++++++++++-------- 9 files changed, 162 insertions(+), 71 deletions(-) create mode 100644 ruby/lib/deltalake/version.rb diff --git a/.github/workflows/ruby_build.yml b/.github/workflows/ruby_build.yml index b82a48b95b..bb3bdd6d55 100644 --- a/.github/workflows/ruby_build.yml +++ b/.github/workflows/ruby_build.yml @@ -17,15 +17,15 @@ jobs: - name: Cache Rust build uses: actions/cache@v1.0.1 with: - path: target/debug/build - key: ruby-${{ runner.OS }}-target-build-${{ hashFiles('**/Cargo.lock') }} + path: target/release/build + key: ruby-${{ runner.OS }}-target-release-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ruby-${{ runner.OS }}-target-build- - name: Cache Rust incremental build uses: actions/cache@v1.0.1 with: - path: target/debug/incremental - key: ruby-${{ runner.OS }}-target-incremental-${{ hashFiles('**/Cargo.lock') }} + path: target/release/incremental + key: ruby-${{ runner.OS }}-target-release-incremental-${{ hashFiles('**/Cargo.lock') }} restore-keys: | ruby-${{ runner.OS }}-target-incremental- - name: Install minimal stable with clippy and rustfmt @@ -34,6 +34,8 @@ jobs: profile: default toolchain: stable override: true + - name: Build Release for Ruby + run: cargo build --release - name: 'Set up Ruby' uses: actions/setup-ruby@v1 - name: 'Install Ruby Dependencies' diff --git a/Cargo.lock b/Cargo.lock index 9b4f8b6a58..089575286c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -73,6 +73,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "ansi_term" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a9bb7ec0cf484c551830a7ce27bd20d67eac647e1befb56b0be4ee39a55d2" +dependencies = [ + "winapi", +] + [[package]] name = "anyhow" version = "1.0.38" @@ -351,7 +360,7 @@ version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" dependencies = [ - "ansi_term", + "ansi_term 0.11.0", "atty", "bitflags", "strsim 0.8.0", @@ -514,12 +523,6 @@ dependencies = [ "subtle", ] -[[package]] -name = "cstr-macro" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db53fddba18cdd35477a7213a3ef6acfbfa333c31b42ce019e544c4a1420a06f" - [[package]] name = "csv" version = "1.1.6" @@ -609,6 +612,7 @@ dependencies = [ "libc", "log", "parquet", + "pretty_assertions", "regex", "reqwest", "rusoto_core", @@ -643,10 +647,17 @@ name = "deltalake-ruby" version = "0.1.0" dependencies = [ "deltalake", - "helix", + "lazy_static", + "rutie", "tokio", ] +[[package]] +name = "diff" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e25ea47919b1560c4e3b7fe0aaab9becf5b84a10325ddf7db0f0ba5e1026499" + [[package]] name = "digest" version = "0.9.0" @@ -1019,17 +1030,6 @@ dependencies = [ "unicode-segmentation", ] -[[package]] -name = "helix" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "49a017e3e798ad9386e0a0584e66fd6c04a80ccc1242eb8f689c62ce6f408240" -dependencies = [ - "cstr-macro", - "libc", - "libcruby-sys", -] - [[package]] name = "hermit-abi" version = "0.1.18" @@ -1284,15 +1284,6 @@ version = "0.2.88" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "03b07a082330a35e43f63177cc01689da34fbffa0105e1246cf0311472cac73a" -[[package]] -name = "libcruby-sys" -version = "0.7.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fef6028cdce0c8d55676fd1d66bb810facef8cade0dd71d28511d375e84da4c0" -dependencies = [ - "libc", -] - [[package]] name = "lock_api" version = "0.4.2" @@ -1636,6 +1627,15 @@ version = "2.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "afb2e1c3ee07430c2cf76151675e583e0f19985fa6efae47d6848a3e2c824f85" +[[package]] +name = "output_vt100" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53cdc5b785b7a58c5aad8216b3dfa114df64b0b06ae6e1501cef91df2fbdf8f9" +dependencies = [ + "winapi", +] + [[package]] name = "parking_lot" version = "0.11.1" @@ -1764,6 +1764,18 @@ version = "0.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ac74c624d6b2d21f425f752262f42188365d7b8ff1aff74c82e45136510a4857" +[[package]] +name = "pretty_assertions" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f297542c27a7df8d45de2b0e620308ab883ad232d06c14b76ac3e144bda50184" +dependencies = [ + "ansi_term 0.12.1", + "ctor", + "diff", + "output_vt100", +] + [[package]] name = "prettytable-rs" version = "0.8.0" @@ -2251,6 +2263,16 @@ dependencies = [ "winapi", ] +[[package]] +name = "rutie" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678217ed742ca819057a79c0146703d1278afbb38896eb0283c410a6cab7c28c" +dependencies = [ + "lazy_static", + "libc", +] + [[package]] name = "ryu" version = "1.0.5" diff --git a/ruby/Cargo.toml b/ruby/Cargo.toml index f2c71d857e..32f229a727 100644 --- a/ruby/Cargo.toml +++ b/ruby/Cargo.toml @@ -4,11 +4,11 @@ version = "0.1.0" authors = ["R Tyler Croy "] [lib] - crate-type = ["cdylib"] [dependencies] -helix = "*" +lazy_static = "1" +rutie = "0.8.2" tokio = { version = "1", features = ["rt-multi-thread"] } [dependencies.deltalake] diff --git a/ruby/Gemfile b/ruby/Gemfile index b6701dd74a..b2a0948b62 100644 --- a/ruby/Gemfile +++ b/ruby/Gemfile @@ -1,7 +1,9 @@ +# frozen_string_literal: true + source 'https://rubygems.org' -gem 'helix_runtime' gem 'colorize' +gem 'rutie', '~> 0.0.3' group :development do gem 'rake', '~> 12.0' diff --git a/ruby/Rakefile b/ruby/Rakefile index 26d9f69af4..6d02871eac 100644 --- a/ruby/Rakefile +++ b/ruby/Rakefile @@ -1,17 +1,13 @@ +# frozen_string_literal: true + require 'bundler/setup' -require 'helix_runtime/build_task' require 'rspec/core/rake_task' # For Windows $stdout.sync = true -HelixRuntime::BuildTask.new do |t| - t.build_root = File.expand_path("../", __dir__) -end - RSpec::Core::RakeTask.new(:spec) do |t| t.verbose = false end -task :spec => :build -task :default => :spec +task default: :spec diff --git a/ruby/lib/deltalake.rb b/ruby/lib/deltalake.rb index 3ea9601cf2..ceee57dc8a 100644 --- a/ruby/lib/deltalake.rb +++ b/ruby/lib/deltalake.rb @@ -1,7 +1,11 @@ -require 'helix_runtime' -require 'deltalake-ruby/native' +# frozen_string_literal: true + +require 'deltalake/version' +require 'rutie' module Deltalake + Rutie.new(:deltalake_ruby, lib_path: '../../target/release').init 'Init_table', __dir__ + def self.open_table(table_path) Table.new(table_path) end diff --git a/ruby/lib/deltalake/version.rb b/ruby/lib/deltalake/version.rb new file mode 100644 index 0000000000..f9765e5aa2 --- /dev/null +++ b/ruby/lib/deltalake/version.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +module Deltalake + VERSION = '0.1.0' +end diff --git a/ruby/spec/deltalake_spec.rb b/ruby/spec/deltalake_spec.rb index 5688bda0a6..771d82ceae 100644 --- a/ruby/spec/deltalake_spec.rb +++ b/ruby/spec/deltalake_spec.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require 'spec_helper' require 'deltalake' @@ -17,6 +19,16 @@ it { should be_instance_of Array } its(:size) { should eq(5) } + + it { + should contain_exactly( + 'part-00000-2befed33-c358-4768-a43c-3eda0d2a499d-c000.snappy.parquet', + 'part-00000-c1777d7d-89d9-4790-b38a-6ee7e24456b1-c000.snappy.parquet', + 'part-00007-3a0e4727-de0d-41b6-81ef-5223cf40f025-c000.snappy.parquet', + 'part-00001-7891c33d-cedc-47c3-88a6-abcfb049d3b4-c000.snappy.parquet', + 'part-00004-315835fe-fb44-4562-98f6-5e6cfa3ae45d-c000.snappy.parquet' + ) + } end end end diff --git a/ruby/src/lib.rs b/ruby/src/lib.rs index 7bbf33da49..46fa30b477 100644 --- a/ruby/src/lib.rs +++ b/ruby/src/lib.rs @@ -1,43 +1,91 @@ #![recursion_limit = "1024"] -#[macro_use] -extern crate helix; extern crate deltalake; +#[macro_use] +extern crate lazy_static; + +#[macro_use] +extern crate rutie; + use deltalake::DeltaTable; +use rutie::{AnyObject, Array, Class, Integer, Object, RString}; use std::sync::Arc; -ruby! { - class Table { - struct { - table_path: String, - actual: Arc, - } +pub struct TableData { + table_path: String, + actual: Arc, +} - def initialize(helix, table_path: String) { - println!("initializing with {}", table_path); +impl TableData { + fn new(table_path: String) -> Self { + println!("initializing with {}", table_path); - let rt = tokio::runtime::Runtime::new().unwrap(); - let table = rt.block_on(deltalake::open_table(&table_path)).unwrap(); - let actual = Arc::new(table); + let rt = tokio::runtime::Runtime::new().unwrap(); + let table = rt.block_on(deltalake::open_table(&table_path)).unwrap(); + let actual = Arc::new(table); - Table { - helix, - table_path, - actual, - } - } + Self { table_path, actual } + } - def table_path(&self) -> String { - self.table_path.clone() - } + fn table_path(&self) -> &str { + &self.table_path + } - def version(&self) -> i64 { - self.actual.version - } + fn version(&self) -> i64 { + self.actual.version + } - def files(&self) -> Vec { - self.actual.get_files().to_vec() + fn files(&self) -> &[String] { + self.actual.get_files().as_slice() + } +} + +wrappable_struct!(TableData, TableDataWrapper, TABLE_DATA_WRAPPER); + +class!(Table); + +methods!( + Table, + rtself, + fn ruby_table_new(table_path: RString) -> AnyObject { + let table_data = TableData::new(table_path.unwrap().to_string()); + + Class::from_existing("Table").wrap_data(table_data, &*TABLE_DATA_WRAPPER) + }, + fn ruby_table_path() -> RString { + let table_path = rtself.get_data(&*TABLE_DATA_WRAPPER).table_path(); + + RString::new_utf8(table_path) + }, + fn ruby_version() -> Integer { + let version = rtself.get_data(&*TABLE_DATA_WRAPPER).version(); + + Integer::new(version) + }, + fn ruby_files() -> Array { + let files = rtself.get_data(&*TABLE_DATA_WRAPPER).files(); + + let mut array = Array::with_capacity(files.len()); + + for file in files { + array.push(RString::new_utf8(file)); } + + array } +); + +#[allow(non_snake_case)] +#[no_mangle] +pub extern "C" fn Init_table() { + let data_class = Class::from_existing("Object"); + + Class::new("Table", Some(&data_class)).define(|klass| { + klass.def_self("new", ruby_table_new); + + klass.def("table_path", ruby_table_path); + klass.def("version", ruby_version); + klass.def("files", ruby_files); + }); }