feat: Migrate SAL to Cargo workspace
- Migrate individual modules to independent crates - Refactor dependencies for improved modularity - Update build system and testing infrastructure - Update documentation to reflect new structure
This commit is contained in:
@@ -9,14 +9,14 @@ license = "Apache-2.0"
|
||||
|
||||
[dependencies]
|
||||
# Regex support for text replacement
|
||||
regex = "1.8.1"
|
||||
regex = { workspace = true }
|
||||
# Template engine for text rendering
|
||||
tera = "1.19.0"
|
||||
# Serialization support for templates
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde = { workspace = true }
|
||||
# Rhai scripting support
|
||||
rhai = { version = "1.12.0", features = ["sync"] }
|
||||
rhai = { workspace = true }
|
||||
|
||||
[dev-dependencies]
|
||||
# For temporary files in tests
|
||||
tempfile = "3.5"
|
||||
tempfile = { workspace = true }
|
||||
|
@@ -18,7 +18,7 @@
|
||||
* # Examples
|
||||
*
|
||||
* ```
|
||||
* use sal::text::dedent;
|
||||
* use sal_text::dedent;
|
||||
*
|
||||
* let indented = " line 1\n line 2\n line 3";
|
||||
* let dedented = dedent(indented);
|
||||
@@ -103,7 +103,7 @@ pub fn dedent(text: &str) -> String {
|
||||
* # Examples
|
||||
*
|
||||
* ```
|
||||
* use sal::text::prefix;
|
||||
* use sal_text::prefix;
|
||||
*
|
||||
* let text = "line 1\nline 2\nline 3";
|
||||
* let prefixed = prefix(text, " ");
|
||||
|
@@ -1,17 +1,33 @@
|
||||
|
||||
|
||||
pub fn name_fix(text: &str) -> String {
|
||||
let mut result = String::with_capacity(text.len());
|
||||
|
||||
|
||||
let mut last_was_underscore = false;
|
||||
for c in text.chars() {
|
||||
// Keep only ASCII characters
|
||||
if c.is_ascii() {
|
||||
// Replace specific characters with underscore
|
||||
if c.is_whitespace() || c == ',' || c == '-' || c == '"' || c == '\'' ||
|
||||
c == '#' || c == '!' || c == '(' || c == ')' || c == '[' || c == ']' ||
|
||||
c == '=' || c == '+' || c == '<' || c == '>' || c == '@' || c == '$' ||
|
||||
c == '%' || c == '^' || c == '&' || c == '*' {
|
||||
if c.is_whitespace()
|
||||
|| c == ','
|
||||
|| c == '-'
|
||||
|| c == '"'
|
||||
|| c == '\''
|
||||
|| c == '#'
|
||||
|| c == '!'
|
||||
|| c == '('
|
||||
|| c == ')'
|
||||
|| c == '['
|
||||
|| c == ']'
|
||||
|| c == '='
|
||||
|| c == '+'
|
||||
|| c == '<'
|
||||
|| c == '>'
|
||||
|| c == '@'
|
||||
|| c == '$'
|
||||
|| c == '%'
|
||||
|| c == '^'
|
||||
|| c == '&'
|
||||
|| c == '*'
|
||||
{
|
||||
// Only add underscore if the last character wasn't an underscore
|
||||
if !last_was_underscore {
|
||||
result.push('_');
|
||||
@@ -25,7 +41,7 @@ pub fn name_fix(text: &str) -> String {
|
||||
}
|
||||
// Non-ASCII characters are simply skipped
|
||||
}
|
||||
|
||||
|
||||
// Convert to lowercase
|
||||
return result.to_lowercase();
|
||||
}
|
||||
@@ -35,17 +51,17 @@ pub fn path_fix(text: &str) -> String {
|
||||
if text.ends_with('/') {
|
||||
return text.to_string();
|
||||
}
|
||||
|
||||
|
||||
// Find the last '/' to extract the filename part
|
||||
match text.rfind('/') {
|
||||
Some(pos) => {
|
||||
// Extract the path and filename parts
|
||||
let path = &text[..=pos];
|
||||
let filename = &text[pos+1..];
|
||||
|
||||
let filename = &text[pos + 1..];
|
||||
|
||||
// Apply name_fix to the filename part only
|
||||
return format!("{}{}", path, name_fix(filename));
|
||||
},
|
||||
}
|
||||
None => {
|
||||
// No '/' found, so the entire text is a filename
|
||||
return name_fix(text);
|
||||
@@ -67,12 +83,12 @@ mod tests {
|
||||
assert_eq!(name_fix("Quotes\"'"), "quotes_");
|
||||
assert_eq!(name_fix("Brackets[]<>"), "brackets_");
|
||||
assert_eq!(name_fix("Operators=+-"), "operators_");
|
||||
|
||||
|
||||
// Test non-ASCII characters removal
|
||||
assert_eq!(name_fix("Café"), "caf");
|
||||
assert_eq!(name_fix("Résumé"), "rsum");
|
||||
assert_eq!(name_fix("Über"), "ber");
|
||||
|
||||
|
||||
// Test lowercase conversion
|
||||
assert_eq!(name_fix("UPPERCASE"), "uppercase");
|
||||
assert_eq!(name_fix("MixedCase"), "mixedcase");
|
||||
@@ -82,18 +98,26 @@ mod tests {
|
||||
fn test_path_fix() {
|
||||
// Test path ending with /
|
||||
assert_eq!(path_fix("/path/to/directory/"), "/path/to/directory/");
|
||||
|
||||
|
||||
// Test single filename
|
||||
assert_eq!(path_fix("filename.txt"), "filename.txt");
|
||||
assert_eq!(path_fix("UPPER-file.md"), "upper_file.md");
|
||||
|
||||
|
||||
// Test path with filename
|
||||
assert_eq!(path_fix("/path/to/File Name.txt"), "/path/to/file_name.txt");
|
||||
assert_eq!(path_fix("./relative/path/to/DOCUMENT-123.pdf"), "./relative/path/to/document_123.pdf");
|
||||
assert_eq!(path_fix("/absolute/path/to/Résumé.doc"), "/absolute/path/to/rsum.doc");
|
||||
|
||||
assert_eq!(
|
||||
path_fix("./relative/path/to/DOCUMENT-123.pdf"),
|
||||
"./relative/path/to/document_123.pdf"
|
||||
);
|
||||
assert_eq!(
|
||||
path_fix("/absolute/path/to/Résumé.doc"),
|
||||
"/absolute/path/to/rsum.doc"
|
||||
);
|
||||
|
||||
// Test path with special characters in filename
|
||||
assert_eq!(path_fix("/path/with/[special]<chars>.txt"), "/path/with/_special_chars_.txt");
|
||||
assert_eq!(
|
||||
path_fix("/path/with/[special]<chars>.txt"),
|
||||
"/path/with/_special_chars_.txt"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -26,7 +26,7 @@ impl TemplateBuilder {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use sal::text::TemplateBuilder;
|
||||
/// use sal_text::TemplateBuilder;
|
||||
///
|
||||
/// let builder = TemplateBuilder::open("templates/example.html");
|
||||
/// ```
|
||||
@@ -62,7 +62,7 @@ impl TemplateBuilder {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use sal::text::TemplateBuilder;
|
||||
/// use sal_text::TemplateBuilder;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let builder = TemplateBuilder::open("templates/example.html")?
|
||||
@@ -93,7 +93,7 @@ impl TemplateBuilder {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use sal::text::TemplateBuilder;
|
||||
/// use sal_text::TemplateBuilder;
|
||||
/// use std::collections::HashMap;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
@@ -155,7 +155,7 @@ impl TemplateBuilder {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use sal::text::TemplateBuilder;
|
||||
/// use sal_text::TemplateBuilder;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let result = TemplateBuilder::open("templates/example.html")?
|
||||
@@ -195,7 +195,7 @@ impl TemplateBuilder {
|
||||
/// # Example
|
||||
///
|
||||
/// ```no_run
|
||||
/// use sal::text::TemplateBuilder;
|
||||
/// use sal_text::TemplateBuilder;
|
||||
///
|
||||
/// fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// TemplateBuilder::open("templates/example.html")?
|
||||
|
@@ -106,7 +106,7 @@ fn test_dedent_and_prefix_combination() {
|
||||
let indented = " def function():\n print('hello')\n return True";
|
||||
let dedented = dedent(indented);
|
||||
let prefixed = prefix(&dedented, ">>> ");
|
||||
|
||||
|
||||
let expected = ">>> def function():\n>>> print('hello')\n>>> return True";
|
||||
assert_eq!(prefixed, expected);
|
||||
}
|
||||
@@ -120,7 +120,7 @@ fn test_dedent_real_code_example() {
|
||||
return result
|
||||
else:
|
||||
return None"#;
|
||||
|
||||
|
||||
let dedented = dedent(code);
|
||||
let expected = "\nif condition:\n for item in items:\n process(item)\n return result\nelse:\n return None";
|
||||
assert_eq!(dedented, expected);
|
||||
|
Reference in New Issue
Block a user