Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(bindings/ruby): support stat, and pass all blocking bdd test #1743

Merged
merged 2 commits into from
Mar 23, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions bindings/nodejs/tests/binding.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ Then('The blocking file {string} entry mode must be file', function (path) {
assert(meta.isFile())
})

Then('The blocking file {string} content length must be "{int}"', function (path, size) {
Then('The blocking file {string} content length must be {int}', function (path, size) {
let meta = this.op.statSync(path)
assert(meta.contentLength == size)
})
Expand All @@ -65,7 +65,7 @@ Then('The async file {string} entry mode must be file', async function (path) {
assert(meta.isFile())
})

Then('The async file {string} content length must be "{int}"', async function (path, size) {
Then('The async file {string} content length must be {int}', async function (path, size) {
let meta = await this.op.stat(path)
assert(meta.contentLength == size)
})
Expand Down
4 changes: 2 additions & 2 deletions bindings/python/tests/steps/binding.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def step_impl(context, filename):
def step_impl(context, filename):
assert context.op.stat(filename).mode.is_file()

@then('The blocking file "{filename}" content length must be "{size:d}"')
@then('The blocking file "{filename}" content length must be {size:d}')
def step_impl(context, filename, size):
assert context.op.stat(filename).content_length == size

Expand Down Expand Up @@ -65,7 +65,7 @@ async def step_impl(context, filename):
meta = await context.op.stat(filename)
assert meta.mode.is_file()

@then('The async file "{filename}" content length must be "{size:d}"')
@then('The async file "{filename}" content length must be {size:d}')
@async_run_until_complete
async def step_impl(context, filename, size):
meta = await context.op.stat(filename)
Expand Down
69 changes: 65 additions & 4 deletions bindings/ruby/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,54 @@ impl Operator {
.write(&path, bs.to_bytes())
.map_err(format_magnus_error)
}

/// Get current path's metadata **without cache** directly.
pub fn stat(&self, path: String) -> Result<Metadata> {
self.0
.stat(&path)
.map_err(format_magnus_error)
.map(Metadata)
}
}

#[magnus::wrap(class = "Metadata", free_immediately, size)]
pub struct Metadata(od::Metadata);

impl Metadata {
/// Content-Disposition of this object
pub fn content_disposition(&self) -> Option<&str> {
self.0.content_disposition()
}

/// Content length of this entry.
pub fn content_length(&self) -> u64 {
self.0.content_length()
}

/// Content MD5 of this entry.
pub fn content_md5(&self) -> Option<&str> {
self.0.content_md5()
}

/// Content Type of this entry.
pub fn content_type(&self) -> Option<&str> {
self.0.content_type()
}

/// ETag of this entry.
pub fn etag(&self) -> Option<&str> {
self.0.etag()
}

/// Returns `True` if this is a file.
pub fn is_file(&self) -> bool {
self.0.is_file()
}

/// Returns `True` if this is a directory.
pub fn is_dir(&self) -> bool {
self.0.is_dir()
}
}

fn format_magnus_error(err: od::Error) -> Error {
Expand All @@ -111,9 +159,22 @@ fn format_magnus_error(err: od::Error) -> Error {

#[magnus::init]
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))?;
let operator_class = define_class("Operator", class::object())?;
operator_class.define_singleton_method("new", function!(Operator::new, 2))?;
operator_class.define_method("read", method!(Operator::read, 1))?;
operator_class.define_method("write", method!(Operator::write, 2))?;
operator_class.define_method("stat", method!(Operator::stat, 1))?;

let metadata_class = define_class("Metadata", class::object())?;
metadata_class.define_method(
"content_disposition",
method!(Metadata::content_disposition, 0),
)?;
metadata_class.define_method("content_length", method!(Metadata::content_length, 0))?;
metadata_class.define_method("content_md5", method!(Metadata::content_md5, 0))?;
metadata_class.define_method("content_type", method!(Metadata::content_type, 0))?;
metadata_class.define_method("etag", method!(Metadata::etag, 0))?;
metadata_class.define_method("is_file", method!(Metadata::is_file, 0))?;
metadata_class.define_method("is_dir", method!(Metadata::is_dir, 0))?;
Ok(())
}
10 changes: 5 additions & 5 deletions bindings/ruby/tests/steps/binding.rb
Original file line number Diff line number Diff line change
Expand Up @@ -26,15 +26,15 @@
end

Then("The blocking file {string} should exist") do |path|
pending # Write code here that turns the phrase above into concrete actions
@op.stat(path)
end

Then("The blocking file {string} entry mode must be file") do |path|
pending # Write code here that turns the phrase above into concrete actions
@op.stat(path).is_file == true
end

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
Then("The blocking file {string} content length must be {int}") do |path, length|
@op.stat(path).content_length == length
end

Then("The blocking file {string} must have content {string}") do |path, content|
Expand All @@ -57,7 +57,7 @@
pending # Write code here that turns the phrase above into concrete actions
end

Then("The async file {string} content length must be {string}") do |path, length|
Then("The async file {string} content length must be {int}") do |path, length|
pending # Write code here that turns the phrase above into concrete actions
end

Expand Down
4 changes: 2 additions & 2 deletions bindings/tests/features/binding.feature
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,13 @@ Feature: OpenDAL Binding
When Blocking write path "test" with content "Hello, World!"
Then The blocking file "test" should exist
Then The blocking file "test" entry mode must be file
Then The blocking file "test" content length must be "13"
Then The blocking file "test" content length must be 13
Then The blocking file "test" must have content "Hello, World!"

Scenario: OpenDAL Async Operations
Given A new OpenDAL Async Operator
When Async write path "test" with content "Hello, World!"
Then The async file "test" should exist
Then The async file "test" entry mode must be file
Then The async file "test" content length must be "13"
Then The async file "test" content length must be 13
Then The async file "test" must have content "Hello, World!"