doido_core/inflector/
mod.rs1pub mod config;
2pub mod inflections;
3pub(crate) mod rules;
4
5pub use config::InflectionConfig;
6pub use inflections::Inflections;
7
8use std::path::Path;
9use std::sync::OnceLock;
10
11static INFLECTIONS: OnceLock<Inflections> = OnceLock::new();
12
13pub const DEFAULT_CONFIG_PATH: &str = "config/inflection.yaml";
15
16pub fn init_inflections<F: FnOnce(&mut Inflections)>(configure: F) {
26 let mut base = Inflections::default();
27 configure(&mut base);
28 let _ = INFLECTIONS.set(base);
30}
31
32#[derive(Debug, thiserror::Error)]
34pub enum LoadError {
35 #[error("failed to read inflection file `{path}`: {source}")]
36 Read {
37 path: String,
38 #[source]
39 source: std::io::Error,
40 },
41 #[error("failed to parse inflection file `{path}`: {source}")]
42 Parse {
43 path: String,
44 #[source]
45 source: serde_norway::Error,
46 },
47}
48
49pub fn load_inflections(path: impl AsRef<Path>) -> Result<bool, LoadError> {
61 let path = path.as_ref();
62 let mut base = Inflections::default();
63
64 let found = match std::fs::read_to_string(path) {
65 Ok(contents) => {
66 let config =
67 InflectionConfig::from_yaml(&contents).map_err(|source| LoadError::Parse {
68 path: path.display().to_string(),
69 source,
70 })?;
71 config.apply(&mut base);
72 true
73 }
74 Err(e) if e.kind() == std::io::ErrorKind::NotFound => false,
75 Err(source) => {
76 return Err(LoadError::Read {
77 path: path.display().to_string(),
78 source,
79 })
80 }
81 };
82
83 let _ = INFLECTIONS.set(base);
85 Ok(found)
86}
87
88fn global() -> &'static Inflections {
89 INFLECTIONS.get_or_init(Inflections::default)
90}
91
92pub struct Inflector;
96
97impl Inflector {
98 pub fn pluralize(s: &str) -> String {
99 global().pluralize(s)
100 }
101 pub fn singularize(s: &str) -> String {
102 global().singularize(s)
103 }
104 pub fn camelize(s: &str) -> String {
105 global().camelize(s)
106 }
107 pub fn camelize_lower(s: &str) -> String {
108 global().camelize_lower(s)
109 }
110 pub fn underscore(s: &str) -> String {
111 global().underscore(s)
112 }
113 pub fn dasherize(s: &str) -> String {
114 global().dasherize(s)
115 }
116 pub fn humanize(s: &str) -> String {
117 global().humanize(s)
118 }
119 pub fn tableize(s: &str) -> String {
120 global().tableize(s)
121 }
122 pub fn classify(s: &str) -> String {
123 global().classify(s)
124 }
125 pub fn foreign_key(s: &str) -> String {
126 global().foreign_key(s)
127 }
128 pub fn constantize(s: &str) -> String {
129 global().constantize(s)
130 }
131}