sarcasm_utils/lib.rs
1//! SaRcAsM tExT creation and validation library.
2//!
3//! This library provides utilities for creating and validating the capitalization style known as
4//! SaRcAsM tExT. It is the library behind the command line utility `sarcasm` which provides a
5//! convenient interface for day-to-day use, including automatic copying to the clipboard.
6//!
7//! All steps have been taken to make the library production ready. It has full logging via the
8//! `log` crate and code should be panic free unless otherwise noted. If a panic is found in a
9//! non-labeled function, this is a bug.
10//!
11//! Feature requests, pull requests, and issues are all welcome.
12//!
13//! # Example
14//!
15//! For more details, see [`encode_sarcasm`] and [`is_sarcasm`].
16//!
17//! ```rust,edition2018
18//! use sarcasm_utils::{StartingCase, is_sarcasm, IsSarcasm};
19//! use sarcasm_utils::encode_sarcasm;
20//!
21//! // Encoding SaRcAsM
22//! let encoded: String = encode_sarcasm("Hello!", StartingCase::Uppercase);
23//! assert_eq!(encoded, "HeLlO!");
24//!
25//! // Decoding SaRcAsM
26//! let decoded: IsSarcasm = is_sarcasm(&encoded);
27//! assert_eq!(decoded, IsSarcasm::Yes(StartingCase::Uppercase));
28//!
29//! // Matching on the type of SaRcAsM
30//! match decoded {
31//! IsSarcasm::Yes(StartingCase::Uppercase) => println!("UpPeRcAsE sArCaSm!"),
32//! IsSarcasm::Yes(StartingCase::Lowercase) => println!("lOwErCaSe SaRcAsM!"),
33//! IsSarcasm::No => println!("No sarcasm here!"),
34//! IsSarcasm::TooShort => println!("Can't tell if there's sarcasm!"),
35//! }
36//! ```
37//!
38//! # Why?
39//!
40//! Because.
41//!
42//! # Is this a joke?
43//!
44//! No.
45//!
46//! # Really?
47//!
48//! Okay, yes the purpose is silly, but this was an exercise in writing a library in rust
49//! that is designed to be robust yet easy to use. Also, it does provide some (minimal) use for
50//! someone who wants to do this kind of thing. I will do my best to maintain and attend to this
51//! library, as well as expand it with new "useful" features in the future.
52//!
53//! In short: maybe?
54//!
55//! # Be Nice
56//!
57//! Don't use this library to be jerks to people. It ruins the fun.
58
59#![deny(nonstandard_style)]
60#![deny(future_incompatible)]
61#![deny(rust_2018_idioms)]
62#![deny(unsafe_code)]
63#![warn(missing_docs)]
64#![warn(unused)]
65
66mod decode;
67mod encode;
68
69pub use decode::*;
70pub use encode::*;
71use log::{debug, error, trace};
72
73/// The case of the first letter in SaRcAsM tExT.
74#[derive(Copy, Clone, Debug, PartialEq)]
75pub enum StartingCase {
76 /// First letter is lOwErCaSe
77 Lowercase,
78 /// First letter is UpPeRcAsE
79 Uppercase,
80}
81
82#[doc(hidden)]
83impl From<char> for StartingCase {
84 fn from(c: char) -> Self {
85 trace!("Analyzing case of leading char {}", c);
86 if c.is_lowercase() {
87 debug!("Leading character {} is lowercase", c);
88 StartingCase::Lowercase
89 } else if c.is_uppercase() {
90 debug!("Leading character {} is uppercase", c);
91 StartingCase::Uppercase
92 } else {
93 let msg = format!("Invalid char {} provided to From<char> for StartingCase", c);
94 error!("{}", msg);
95 StartingCase::Uppercase
96 }
97 }
98}
99
100#[cfg(test)]
101mod tests {
102 use crate::{IsSarcasm, StartingCase};
103
104 #[test]
105 fn encode() {
106 assert_eq!(crate::encode_sarcasm("hello!", StartingCase::Uppercase), "HeLlO!");
107 assert_eq!(crate::encode_sarcasm("hello!", StartingCase::Lowercase), "hElLo!");
108 }
109
110 #[test]
111 fn multi_word_encode() {
112 assert_eq!(
113 crate::encode_sarcasm("Hello World!", StartingCase::Uppercase),
114 "HeLlO WoRlD!"
115 );
116 assert_eq!(
117 crate::encode_sarcasm("Hello World!", StartingCase::Lowercase),
118 "hElLo wOrLd!"
119 );
120 }
121
122 #[test]
123 fn encode_nothing() {
124 assert_eq!(crate::encode_sarcasm("", StartingCase::Uppercase), "");
125 assert_eq!(crate::encode_sarcasm("", StartingCase::Lowercase), "");
126 }
127
128 #[test]
129 fn decode() {
130 assert_eq!(crate::is_sarcasm("HeLlO!"), IsSarcasm::Yes(StartingCase::Uppercase));
131 assert_eq!(crate::is_sarcasm("hElLo!"), IsSarcasm::Yes(StartingCase::Lowercase));
132 }
133
134 #[test]
135 fn multi_word_decode() {
136 assert_eq!(
137 crate::is_sarcasm("HeLlO! hElLo!"),
138 IsSarcasm::Yes(StartingCase::Uppercase)
139 );
140 assert_eq!(
141 crate::is_sarcasm("hElLo! HeLlO!"),
142 IsSarcasm::Yes(StartingCase::Lowercase)
143 );
144
145 assert_eq!(
146 crate::is_sarcasm("HeLlO! HeLlO!"),
147 IsSarcasm::Yes(StartingCase::Uppercase)
148 );
149 assert_eq!(
150 crate::is_sarcasm("hElLo! hElLo!"),
151 IsSarcasm::Yes(StartingCase::Lowercase)
152 );
153 }
154
155 #[test]
156 fn empty_decode() {
157 assert_eq!(crate::is_sarcasm(""), IsSarcasm::TooShort);
158 }
159
160 #[test]
161 fn negatives_decode() {
162 assert_eq!(crate::is_sarcasm("Not Sarcasm"), IsSarcasm::No);
163 assert_eq!(crate::is_sarcasm("NoT SaRcASM"), IsSarcasm::No);
164 }
165
166 #[test]
167 fn first_character_decode() {
168 assert_eq!(crate::is_sarcasm("heLlO!"), IsSarcasm::No);
169 assert_eq!(crate::is_sarcasm("HElLo!"), IsSarcasm::No);
170 }
171}