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}