git_release_name/
phrase.rs1use adjectives;
2use adverbs;
3use case::Case;
4use nouns;
5use sha::{ParseShaError, Sha};
6use std::fmt::{Display, Error, Formatter};
7use std::str::FromStr;
8
9#[derive(Debug, Eq, PartialEq, Clone)]
14pub struct Phrase {
15 adj: String,
16 adv: String,
17 noun: String,
18 format: Case,
19}
20
21impl Phrase {
22 pub fn with_case(mut self, f: Case) -> Self {
35 self.format = f;
36 self
37 }
38
39 pub fn adjective(&self) -> &str {
51 &self.adj
52 }
53
54 pub fn adverb(&self) -> &str {
66 &self.adv
67 }
68
69 pub fn noun(&self) -> &str {
81 &self.noun
82 }
83
84 pub fn case(&self) -> Case {
96 self.format
97 }
98}
99
100#[derive(Debug, Eq, PartialEq, Clone, Copy)]
102pub enum ParsePhraseError {
103 WordNotFound,
105 Sha(ParseShaError),
106 #[doc(hidden)]
107 __NonExhaustive,
108}
109
110fn lookup(index: usize, words: &[&str]) -> Result<String, ParsePhraseError> {
111 words
112 .get(index % words.len())
113 .map(|s| s.to_string())
114 .ok_or(ParsePhraseError::WordNotFound)
115}
116
117impl FromStr for Phrase {
118 type Err = ParsePhraseError;
119
120 fn from_str(sha: &str) -> Result<Phrase, Self::Err> {
121 let sha = if sha.len() < 8 { &sha } else { &sha[..8] };
122 let sha: Sha = sha.parse().map_err(|e| ParsePhraseError::Sha(e))?;
123
124 let adv = lookup(sha.adverb(), &adverbs::WORDS)?;
125 let adj = lookup(sha.adjective(), &adjectives::WORDS)?;
126 let noun = lookup(sha.noun(), &nouns::WORDS)?;
127
128 Ok(Phrase {
129 adv,
130 adj,
131 noun,
132 format: Case::Lower,
133 })
134 }
135}
136
137impl Display for Phrase {
138 fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
139 use inflector::Inflector;
140
141 let ret = format!("{} {} {}", self.adv, self.adj, self.noun);
142 match self.format {
143 Case::Snake => write!(f, "{}", ret.to_snake_case()),
144 Case::Kebab => write!(f, "{}", ret.to_kebab_case()),
145 Case::Pascal => write!(f, "{}", ret.to_pascal_case()),
146 Case::Camel => write!(f, "{}", ret.to_camel_case()),
147 Case::Title => write!(f, "{}", ret.to_title_case()),
148 Case::Sentence => write!(f, "{}", ret.to_sentence_case()),
149 Case::Lower => write!(f, "{}", ret),
150 Case::Upper => write!(f, "{}", ret.to_uppercase()),
151 }
152 }
153}
154
155#[cfg(test)]
156mod tests {
157 use super::*;
158
159 fn make_simple_phrase() -> Phrase {
160 "0a00a00a".parse::<Phrase>().expect("Invalid phrase")
161 }
162
163 #[test]
164 fn a_phrase_can_be_generated_from_a_str() {
165 let phrase = make_simple_phrase();
166 assert_eq!("immeasurably endways borings", format!("{}", phrase));
167 }
168
169 #[test]
170 fn it_pads_the_string() {
171 let unpadded = "abc".parse::<Phrase>().expect("Invalid phrase");
172 let padded = "00000abc".parse::<Phrase>().expect("Invalid phrase");
173 assert_eq!(padded, unpadded);
174 }
175
176 #[test]
177 fn it_only_respects_first_eight() {
178 let overflow = "00000abcffff".parse::<Phrase>().expect("Invalid phrase");
179 let underflow = "abc".parse::<Phrase>().expect("Invalid phrase");
180 assert_eq!(overflow, underflow);
181 }
182
183 #[test]
184 fn a_phrase_can_be_formatted_as_snake_case() {
185 let phrase = make_simple_phrase().with_case(Case::Snake);
186 assert_eq!("immeasurably_endways_borings", format!("{}", phrase));
187 }
188
189 #[test]
190 fn a_phrase_can_be_formatted_as_kebab_case() {
191 let phrase = make_simple_phrase().with_case(Case::Kebab);
192 assert_eq!("immeasurably-endways-borings", format!("{}", phrase));
193 }
194
195 #[test]
196 fn a_phrase_can_be_formatted_as_camel_case() {
197 let phrase = make_simple_phrase().with_case(Case::Camel);
198 assert_eq!("immeasurablyEndwaysBorings", format!("{}", phrase));
199 }
200
201 #[test]
202 fn a_phrase_can_be_formatted_as_pascal_case() {
203 let phrase = make_simple_phrase().with_case(Case::Pascal);
204 assert_eq!("ImmeasurablyEndwaysBorings", format!("{}", phrase));
205 }
206
207 #[test]
208 fn a_phrase_can_be_formatted_as_title_case() {
209 let phrase = make_simple_phrase().with_case(Case::Title);
210 assert_eq!("Immeasurably Endways Borings", format!("{}", phrase));
211 }
212
213 #[test]
214 fn a_phrase_can_be_formatted_as_capital_case() {
215 let phrase = make_simple_phrase().with_case(Case::Sentence);
216 assert_eq!("Immeasurably endways borings", format!("{}", phrase));
217 }
218
219 #[test]
220 fn a_phrase_can_be_formatted_as_upper_case() {
221 let phrase = make_simple_phrase().with_case(Case::Upper);
222 assert_eq!("IMMEASURABLY ENDWAYS BORINGS", format!("{}", phrase));
223 }
224
225 #[test]
226 fn a_phrase_can_be_formatted_as_lower_case() {
227 let phrase = make_simple_phrase().with_case(Case::Lower);
228 assert_eq!("immeasurably endways borings", format!("{}", phrase));
229 }
230}