pub mod config;
pub mod inflections;
pub(crate) mod rules;
pub use config::InflectionConfig;
pub use inflections::Inflections;
use std::path::Path;
use std::sync::OnceLock;
static INFLECTIONS: OnceLock<Inflections> = OnceLock::new();
pub const DEFAULT_CONFIG_PATH: &str = "config/inflection.yaml";
pub fn init_inflections<F: FnOnce(&mut Inflections)>(configure: F) {
let mut base = Inflections::default();
configure(&mut base);
let _ = INFLECTIONS.set(base);
}
#[derive(Debug, thiserror::Error)]
pub enum LoadError {
#[error("failed to read inflection file `{path}`: {source}")]
Read {
path: String,
#[source]
source: std::io::Error,
},
#[error("failed to parse inflection file `{path}`: {source}")]
Parse {
path: String,
#[source]
source: serde_norway::Error,
},
}
pub fn load_inflections(path: impl AsRef<Path>) -> Result<bool, LoadError> {
let path = path.as_ref();
let mut base = Inflections::default();
let found = match std::fs::read_to_string(path) {
Ok(contents) => {
let config =
InflectionConfig::from_yaml(&contents).map_err(|source| LoadError::Parse {
path: path.display().to_string(),
source,
})?;
config.apply(&mut base);
true
}
Err(e) if e.kind() == std::io::ErrorKind::NotFound => false,
Err(source) => {
return Err(LoadError::Read {
path: path.display().to_string(),
source,
})
}
};
let _ = INFLECTIONS.set(base);
Ok(found)
}
fn global() -> &'static Inflections {
INFLECTIONS.get_or_init(Inflections::default)
}
pub struct Inflector;
impl Inflector {
pub fn pluralize(s: &str) -> String {
global().pluralize(s)
}
pub fn singularize(s: &str) -> String {
global().singularize(s)
}
pub fn camelize(s: &str) -> String {
global().camelize(s)
}
pub fn camelize_lower(s: &str) -> String {
global().camelize_lower(s)
}
pub fn underscore(s: &str) -> String {
global().underscore(s)
}
pub fn dasherize(s: &str) -> String {
global().dasherize(s)
}
pub fn humanize(s: &str) -> String {
global().humanize(s)
}
pub fn tableize(s: &str) -> String {
global().tableize(s)
}
pub fn classify(s: &str) -> String {
global().classify(s)
}
pub fn foreign_key(s: &str) -> String {
global().foreign_key(s)
}
pub fn constantize(s: &str) -> String {
global().constantize(s)
}
}