From 73f08d4510b5f142b908c97ecb4bb6644aeda266 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 09:17:18 +0000 Subject: [PATCH] Refactor filesystem path operations using new helpers Co-authored-by: logbie <1138960+logbie@users.noreply.github.com> --- src/stdlib/filesystem.rs | 83 +++++++++++++--------------------------- src/stdlib/helpers.rs | 49 ++++++++++++++++++++++++ test_helpers.rs | 3 ++ 3 files changed, 78 insertions(+), 57 deletions(-) create mode 100644 test_helpers.rs diff --git a/src/stdlib/filesystem.rs b/src/stdlib/filesystem.rs index ad7d5561..da41299b 100644 --- a/src/stdlib/filesystem.rs +++ b/src/stdlib/filesystem.rs @@ -1,4 +1,6 @@ -use super::helpers::{check_arg_count, check_arg_range, expect_text}; +use super::helpers::{ + check_arg_count, check_arg_range, expect_text, unary_path_bool_op, unary_path_string_op, +}; use crate::interpreter::error::RuntimeError; use crate::interpreter::value::Value; use std::cell::RefCell; @@ -123,31 +125,23 @@ pub fn native_path_join(args: Vec) -> Result { } pub fn native_path_basename(args: Vec) -> Result { - check_arg_count("path_basename", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - let basename = path - .file_name() - .and_then(|name| name.to_str()) - .unwrap_or(""); - - Ok(Value::Text(Arc::from(basename))) + unary_path_string_op("path_basename", args, |path| { + Arc::from( + path.file_name() + .and_then(|name| name.to_str()) + .unwrap_or(""), + ) + }) } pub fn native_path_dirname(args: Vec) -> Result { - check_arg_count("path_dirname", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - let dirname = path - .parent() - .and_then(|parent| parent.to_str()) - .unwrap_or(""); - - Ok(Value::Text(Arc::from(dirname))) + unary_path_string_op("path_dirname", args, |path| { + Arc::from( + path.parent() + .and_then(|parent| parent.to_str()) + .unwrap_or(""), + ) + }) } pub fn native_makedirs(args: Vec) -> Result { @@ -211,30 +205,15 @@ pub fn native_file_mtime(args: Vec) -> Result { } pub fn native_path_exists(args: Vec) -> Result { - check_arg_count("path_exists", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - Ok(Value::Bool(path.exists())) + unary_path_bool_op("path_exists", args, |path| path.exists()) } pub fn native_is_file(args: Vec) -> Result { - check_arg_count("is_file", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - Ok(Value::Bool(path.is_file())) + unary_path_bool_op("is_file", args, |path| path.is_file()) } pub fn native_is_dir(args: Vec) -> Result { - check_arg_count("is_dir", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - Ok(Value::Bool(path.is_dir())) + unary_path_bool_op("is_dir", args, |path| path.is_dir()) } pub fn native_count_lines(args: Vec) -> Result { @@ -281,25 +260,15 @@ pub fn native_count_lines(args: Vec) -> Result { } pub fn native_path_extension(args: Vec) -> Result { - check_arg_count("path_extension", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - let extension = path.extension().and_then(|ext| ext.to_str()).unwrap_or(""); - - Ok(Value::Text(Arc::from(extension))) + unary_path_string_op("path_extension", args, |path| { + Arc::from(path.extension().and_then(|ext| ext.to_str()).unwrap_or("")) + }) } pub fn native_path_stem(args: Vec) -> Result { - check_arg_count("path_stem", &args, 1)?; - - let path_str = expect_text(&args[0])?; - let path = Path::new(path_str.as_ref()); - - let stem = path.file_stem().and_then(|s| s.to_str()).unwrap_or(""); - - Ok(Value::Text(Arc::from(stem))) + unary_path_string_op("path_stem", args, |path| { + Arc::from(path.file_stem().and_then(|s| s.to_str()).unwrap_or("")) + }) } pub fn native_file_size(args: Vec) -> Result { diff --git a/src/stdlib/helpers.rs b/src/stdlib/helpers.rs index 9c21a0e1..68790948 100644 --- a/src/stdlib/helpers.rs +++ b/src/stdlib/helpers.rs @@ -581,3 +581,52 @@ where let list = expect_list(&args[0])?; op(list, val) } + +/// Helper for unary path operations that return a boolean (&Path -> bool). +/// +/// Centralizes argument validation, text extraction, Path conversion, and result wrapping. +/// +/// # Arguments +/// +/// * `func_name` - Name of the function for error messages +/// * `args` - Arguments passed to the function +/// * `op` - The boolean operation to perform on the path +pub fn unary_path_bool_op( + func_name: &str, + args: Vec, + op: F, +) -> Result +where + F: FnOnce(&std::path::Path) -> bool, +{ + check_arg_count(func_name, &args, 1)?; + let path_str = expect_text(&args[0])?; + let path = std::path::Path::new(path_str.as_ref()); + Ok(Value::Bool(op(path))) +} + +/// Helper for unary path operations that return a string (&Path -> Result, RuntimeError>). +/// +/// Centralizes argument validation, text extraction, Path conversion, and result wrapping. +/// Note that the path operation itself may return an empty string or an error if the operation +/// fails (e.g., getting parent of root). +/// +/// # Arguments +/// +/// * `func_name` - Name of the function for error messages +/// * `args` - Arguments passed to the function +/// * `op` - The operation to perform on the path that yields a string representation +pub fn unary_path_string_op( + func_name: &str, + args: Vec, + op: F, +) -> Result +where + F: FnOnce(&std::path::Path) -> R, + R: Into>, +{ + check_arg_count(func_name, &args, 1)?; + let path_str = expect_text(&args[0])?; + let path = std::path::Path::new(path_str.as_ref()); + Ok(Value::Text(op(path).into())) +} diff --git a/test_helpers.rs b/test_helpers.rs new file mode 100644 index 00000000..d20bf322 --- /dev/null +++ b/test_helpers.rs @@ -0,0 +1,3 @@ +fn test() { + println!("test"); +}