Skip to content

Commit 6dda791

Browse files
committed
clojure.string/blank?
1 parent 5caf240 commit 6dda791

File tree

3 files changed

+92
-1
lines changed

3 files changed

+92
-1
lines changed

src/clojure_string.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,3 @@
11
pub (crate) mod reverse;
2-
pub (crate) mod join;
2+
pub (crate) mod join;
3+
pub (crate) mod blank_qmark_;

src/clojure_string/blank_qmark_.rs

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
use crate::ifn::IFn;
2+
use crate::value::{ToValue, Value};
3+
use std::rc::Rc;
4+
5+
use crate::error_message;
6+
use crate::type_tag::TypeTag;
7+
8+
/// clojure.string/blank? ; returns true if nil, empty or whitespace
9+
#[derive(Debug, Clone)]
10+
pub struct BlankFn {}
11+
impl ToValue for BlankFn {
12+
fn to_value(&self) -> Value {
13+
Value::IFn(Rc::new(self.clone()))
14+
}
15+
}
16+
impl IFn for BlankFn {
17+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
18+
if args.len() != 1 {
19+
return error_message::wrong_arg_count(1, args.len());
20+
} else {
21+
match args.get(0).unwrap().to_value() {
22+
Value::Nil => Value::Boolean(true),
23+
Value::String(s) => {
24+
if s.len() == 0 {
25+
Value::Boolean(true)
26+
} else {
27+
return Value::Boolean(s.chars().filter(|c| !c.is_whitespace()).collect::<Vec<char>>().len() == 0)
28+
}
29+
}
30+
Value::String(s) => Value::String(s.chars().rev().collect()),
31+
_a => error_message::type_mismatch(TypeTag::String, &_a.to_value())
32+
}
33+
}
34+
}
35+
}
36+
37+
#[cfg(test)]
38+
mod tests {
39+
mod reverse_tests {
40+
use crate::value::Value;
41+
use std::rc::Rc;
42+
use crate::clojure_string::blank_qmark_::BlankFn;
43+
use crate::ifn::IFn;
44+
45+
#[test]
46+
fn is_non_empty_string_blank() {
47+
let blank = BlankFn {};
48+
let s = "hello";
49+
let args = vec![Rc::new(Value::String(String::from(s)))];
50+
assert_eq!(Value::Boolean(false), blank.invoke(args));
51+
}
52+
53+
#[test]
54+
fn is_empty_string_blank() {
55+
let blank = BlankFn {};
56+
let s = "";
57+
let args = vec![Rc::new(Value::String(String::from(s)))];
58+
assert_eq!(Value::Boolean(true), blank.invoke(args));
59+
}
60+
61+
#[test]
62+
fn is_string_with_whitespace_only_blank() {
63+
let blank = BlankFn {};
64+
let s = " \t \n \r ";
65+
let args = vec![Rc::new(Value::String(String::from(s)))];
66+
assert_eq!(Value::Boolean(true), blank.invoke(args));
67+
}
68+
69+
#[test]
70+
fn is_string_with_whitespace_and_text_blank() {
71+
let blank = BlankFn {};
72+
let s = " \thello \n \r ";
73+
let args = vec![Rc::new(Value::String(String::from(s)))];
74+
assert_eq!(Value::Boolean(true), blank.invoke(args));
75+
}
76+
77+
#[test]
78+
fn is_nil_blank() {
79+
let blank = BlankFn {};
80+
let args = vec![Rc::new(Value::Nil)];
81+
assert_eq!(Value::Boolean(true), blank.invoke(args));
82+
}
83+
}
84+
}

src/environment.rs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ impl Environment {
205205
// clojure.string
206206
let reverse_fn = clojure_string::reverse::ReverseFn {};
207207
let join_fn = clojure_string::join::JoinFn {};
208+
let blank_fn = clojure_string::blank_qmark_::BlankFn {};
208209

209210
// Hardcoded fns
210211
let lexical_eval_fn = Value::LexicalEvalFn {};
@@ -262,6 +263,11 @@ impl Environment {
262263
Symbol::intern("join"),
263264
join_fn.to_rc_value());
264265

266+
environment.insert_into_namespace(
267+
&Symbol::intern("clojure.string"),
268+
Symbol::intern("blank?"),
269+
blank_fn.to_rc_value());
270+
265271
environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
266272
environment.insert(Symbol::intern("let"), let_macro.to_rc_value());
267273
environment.insert(Symbol::intern("str"), str_fn.to_rc_value());

0 commit comments

Comments
 (0)