You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@opendal.apache.org by xu...@apache.org on 2023/03/23 16:00:25 UTC
[incubator-opendal] branch main updated: feat(bindings/ruby): support read and write (#1734)
This is an automated email from the ASF dual-hosted git repository.
xuanwo pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/incubator-opendal.git
The following commit(s) were added to refs/heads/main by this push:
new 14cbb0f1 feat(bindings/ruby): support read and write (#1734)
14cbb0f1 is described below
commit 14cbb0f187cfc42ad0626d767628075e67afad44
Author: Chojan Shang <ps...@apache.org>
AuthorDate: Fri Mar 24 00:00:19 2023 +0800
feat(bindings/ruby): support read and write (#1734)
* feat(bindings/ruby): support read and write
Signed-off-by: Chojan Shang <ps...@outlook.com>
* chore(bindings/ruby): make bdd more clear
Signed-off-by: Chojan Shang <ps...@outlook.com>
* refactor(bindings/ruby): use string to replace u8 array
Signed-off-by: Chojan Shang <ps...@outlook.com>
* chore(bindings/ruby): remove hello_opendal
Signed-off-by: Chojan Shang <ps...@outlook.com>
* fix(bindings/ruby): revert to u8 array
Signed-off-by: Chojan Shang <ps...@outlook.com>
* fix(bindings/ruby): try to use RString
Signed-off-by: Chojan Shang <ps...@outlook.com>
---------
Signed-off-by: Chojan Shang <ps...@outlook.com>
---
Cargo.lock | 1 +
bindings/ruby/Cargo.toml | 2 +-
bindings/ruby/Gemfile | 3 -
bindings/ruby/README.md | 2 +-
bindings/ruby/lib/opendal.rb | 2 +-
bindings/ruby/src/lib.rs | 103 ++++++++++++++++++++++++++++++++---
bindings/ruby/tests/opendal_test.rb | 24 --------
bindings/ruby/tests/steps/binding.rb | 28 +++++-----
bindings/ruby/tests/test_helper.rb | 23 --------
9 files changed, 115 insertions(+), 73 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index 0fb64c49..0cdbdbc1 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1784,6 +1784,7 @@ version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f3fda351681130b40996b3e40592565b5e44ef1a677c45ea3768ed223b5918a5"
dependencies = [
+ "bytes",
"magnus-macros",
"rb-sys",
"rb-sys-env",
diff --git a/bindings/ruby/Cargo.toml b/bindings/ruby/Cargo.toml
index 63d7a762..99f3b677 100644
--- a/bindings/ruby/Cargo.toml
+++ b/bindings/ruby/Cargo.toml
@@ -32,4 +32,4 @@ name = "opendal_ruby"
[dependencies]
opendal = { version = "0.30", path = "../../core" }
-magnus = "0.5"
\ No newline at end of file
+magnus = { version = "0.5" , features = ["bytes-crate"] }
\ No newline at end of file
diff --git a/bindings/ruby/Gemfile b/bindings/ruby/Gemfile
index 096e4143..60d03032 100644
--- a/bindings/ruby/Gemfile
+++ b/bindings/ruby/Gemfile
@@ -24,9 +24,6 @@ gemspec
gem "rake", "~> 13.0"
-gem "minitest", "~> 5.10"
-gem "minitest-reporters", "~> 1.1"
gem "cucumber", "~> 8.0"
-gem "color_pound_spec_reporter", "~> 0.0.6"
gem "standard", "~> 1.3"
diff --git a/bindings/ruby/README.md b/bindings/ruby/README.md
index 15db8fb2..50561bfa 100644
--- a/bindings/ruby/README.md
+++ b/bindings/ruby/README.md
@@ -7,7 +7,7 @@ This crate intends to build a native ruby binding.
Install gems:
```shell
-bundle install
+bundle
```
Build bindings:
diff --git a/bindings/ruby/lib/opendal.rb b/bindings/ruby/lib/opendal.rb
index 0e477faa..28bd9813 100644
--- a/bindings/ruby/lib/opendal.rb
+++ b/bindings/ruby/lib/opendal.rb
@@ -17,5 +17,5 @@
# frozen_string_literal: true
-require "opendal_ruby/version"
+require_relative "opendal_ruby/version"
require_relative "opendal_ruby/opendal_ruby"
diff --git a/bindings/ruby/src/lib.rs b/bindings/ruby/src/lib.rs
index e3f1c3a1..59ee073e 100644
--- a/bindings/ruby/src/lib.rs
+++ b/bindings/ruby/src/lib.rs
@@ -15,16 +15,105 @@
// specific language governing permissions and limitations
// under the License.
-use magnus::{define_global_function, function, Error};
-use opendal::{services::Memory, Operator};
+use std::{collections::HashMap, str::FromStr};
-fn hello_opendal() {
- let op = Operator::new(Memory::default()).unwrap().finish();
- println!("{op:?}")
+use magnus::{
+ class, define_class, error::Result, exception, function, method, prelude::*, Error, RString,
+};
+use opendal as od;
+
+fn build_operator(scheme: od::Scheme, map: HashMap<String, String>) -> Result<od::Operator> {
+ use od::services::*;
+
+ let op = match scheme {
+ od::Scheme::Azblob => od::Operator::from_map::<Azblob>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Azdfs => od::Operator::from_map::<Azdfs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Fs => od::Operator::from_map::<Fs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Gcs => od::Operator::from_map::<Gcs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Ghac => od::Operator::from_map::<Ghac>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Http => od::Operator::from_map::<Http>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Ipmfs => od::Operator::from_map::<Ipmfs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Memory => od::Operator::from_map::<Memory>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Obs => od::Operator::from_map::<Obs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Oss => od::Operator::from_map::<Oss>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::S3 => od::Operator::from_map::<S3>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Webdav => od::Operator::from_map::<Webdav>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ od::Scheme::Webhdfs => od::Operator::from_map::<Webhdfs>(map)
+ .map_err(format_magnus_error)?
+ .finish(),
+ _ => {
+ return Err(format_magnus_error(od::Error::new(
+ od::ErrorKind::Unexpected,
+ "not supported scheme",
+ )))
+ }
+ };
+
+ Ok(op)
+}
+
+#[magnus::wrap(class = "Operator", free_immediately, size)]
+#[derive(Clone, Debug)]
+pub struct Operator(od::BlockingOperator);
+
+impl Operator {
+ pub fn new(scheme: String, options: Option<HashMap<String, String>>) -> Result<Self> {
+ let scheme = od::Scheme::from_str(&scheme)
+ .map_err(|err| {
+ od::Error::new(od::ErrorKind::Unexpected, "unsupported scheme").set_source(err)
+ })
+ .map_err(format_magnus_error)?;
+ let options = options.unwrap_or_default();
+ Ok(Operator(build_operator(scheme, options)?.blocking()))
+ }
+
+ /// Read the whole path into string.
+ pub fn read(&self, path: String) -> Result<RString> {
+ let bytes = self.0.read(&path).map_err(format_magnus_error)?;
+ Ok(RString::from_slice(&bytes))
+ }
+
+ /// Write string into given path.
+ pub fn write(&self, path: String, bs: RString) -> Result<()> {
+ self.0
+ .write(&path, bs.to_bytes())
+ .map_err(format_magnus_error)
+ }
+}
+
+fn format_magnus_error(err: od::Error) -> Error {
+ Error::new(exception::runtime_error(), err.to_string())
}
#[magnus::init]
-fn init() -> Result<(), Error> {
- define_global_function("hello_opendal", function!(hello_opendal, 0));
+fn init() -> Result<()> {
+ let class = define_class("Operator", class::object())?;
+ class.define_singleton_method("new", function!(Operator::new, 2))?;
+ class.define_method("read", method!(Operator::read, 1))?;
+ class.define_method("write", method!(Operator::write, 2))?;
Ok(())
}
diff --git a/bindings/ruby/tests/opendal_test.rb b/bindings/ruby/tests/opendal_test.rb
deleted file mode 100644
index 1b5c2ac6..00000000
--- a/bindings/ruby/tests/opendal_test.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-require_relative "test_helper"
-
-class OpenDALTest < Minitest::Test
- def test_hello_opendal
- hello_opendal
- end
-end
diff --git a/bindings/ruby/tests/steps/binding.rb b/bindings/ruby/tests/steps/binding.rb
index adaa886e..d4498625 100644
--- a/bindings/ruby/tests/steps/binding.rb
+++ b/bindings/ruby/tests/steps/binding.rb
@@ -15,50 +15,52 @@
# specific language governing permissions and limitations
# under the License.
+require_relative "../../lib/opendal"
+
Given("A new OpenDAL Blocking Operator") do
- pending # Write code here that turns the phrase above into concrete actions
+ @op = Operator.new("memory", nil)
end
-When("Blocking write path {string} with content {string}") do |string, string2|
- pending # Write code here that turns the phrase above into concrete actions
+When("Blocking write path {string} with content {string}") do |path, content|
+ @op.write(path, content)
end
-Then("The blocking file {string} should exist") do |string|
+Then("The blocking file {string} should exist") do |path|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The blocking file {string} entry mode must be file") do |string|
+Then("The blocking file {string} entry mode must be file") do |path|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The blocking file {string} content length must be {string}") do |string, string2|
+Then("The blocking file {string} content length must be {string}") do |path, length|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The blocking file {string} must have content {string}") do |string, string2|
- pending # Write code here that turns the phrase above into concrete actions
+Then("The blocking file {string} must have content {string}") do |path, content|
+ @op.read(path) == content
end
Given("A new OpenDAL Async Operator") do
pending # Write code here that turns the phrase above into concrete actions
end
-When("Async write path {string} with content {string}") do |string, string2|
+When("Async write path {string} with content {string}") do |path, content|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The async file {string} should exist") do |string|
+Then("The async file {string} should exist") do |path|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The async file {string} entry mode must be file") do |string|
+Then("The async file {string} entry mode must be file") do |path|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The async file {string} content length must be {string}") do |string, string2|
+Then("The async file {string} content length must be {string}") do |path, length|
pending # Write code here that turns the phrase above into concrete actions
end
-Then("The async file {string} must have content {string}") do |string, string2|
+Then("The async file {string} must have content {string}") do |path, content|
pending # Write code here that turns the phrase above into concrete actions
end
diff --git a/bindings/ruby/tests/test_helper.rb b/bindings/ruby/tests/test_helper.rb
deleted file mode 100644
index 63a525f7..00000000
--- a/bindings/ruby/tests/test_helper.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-# Licensed to the Apache Software Foundation (ASF) under one
-# or more contributor license agreements. See the NOTICE file
-# distributed with this work for additional information
-# regarding copyright ownership. The ASF licenses this file
-# to you under the Apache License, Version 2.0 (the
-# "License"); you may not use this file except in compliance
-# with the License. You may obtain a copy of the License at
-#
-# http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing,
-# software distributed under the License is distributed on an
-# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
-# KIND, either express or implied. See the License for the
-# specific language governing permissions and limitations
-# under the License.
-
-$LOAD_PATH.unshift File.expand_path("../../lib", __FILE__)
-require_relative "../lib/opendal"
-
-require "minitest/autorun"
-require "color_pound_spec_reporter"
-Minitest::Reporters.use! [ColorPoundSpecReporter.new]