Skip to content

Commit 2e789be

Browse files
committed
includes?
1 parent 5cbdf00 commit 2e789be

File tree

3 files changed

+86
-0
lines changed

3 files changed

+86
-0
lines changed

src/clojure_string.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
pub(crate) mod blank_qmark_;
22
pub(crate) mod ends_with_qmark_;
3+
pub(crate) mod includes_qmark_;
34
pub(crate) mod join;
45
pub(crate) mod lower_case;
56
pub(crate) mod reverse;

src/clojure_string/includes_qmark_.rs

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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 IncludesFn {}
11+
impl ToValue for IncludesFn {
12+
fn to_value(&self) -> Value {
13+
Value::IFn(Rc::new(self.clone()))
14+
}
15+
}
16+
impl IFn for IncludesFn {
17+
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
18+
if args.len() != 2 {
19+
return error_message::wrong_arg_count(2, args.len());
20+
} else {
21+
match (
22+
args.get(0).unwrap().to_value(),
23+
args.get(1).unwrap().to_value(),
24+
) {
25+
(Value::String(s), Value::String(substring)) => {
26+
Value::Boolean(s.contains(&substring))
27+
}
28+
_a => error_message::type_mismatch(TypeTag::String, &_a.1.to_value()),
29+
}
30+
}
31+
}
32+
}
33+
34+
#[cfg(test)]
35+
mod tests {
36+
mod reverse_tests {
37+
use crate::clojure_string::includes_qmark_::IncludesFn;
38+
use crate::ifn::IFn;
39+
use crate::value::Value;
40+
use std::rc::Rc;
41+
42+
#[test]
43+
fn hello_includes_ell() {
44+
let blank = IncludesFn {};
45+
let s = "hello";
46+
let substring = "ell";
47+
let args = vec![
48+
Rc::new(Value::String(String::from(s))),
49+
Rc::new(Value::String(String::from(substring))),
50+
];
51+
assert_eq!(Value::Boolean(true), blank.invoke(args));
52+
}
53+
54+
#[test]
55+
fn hello_does_not_include_leh() {
56+
let blank = IncludesFn {};
57+
let s = "hello";
58+
let substring = "leh";
59+
let args = vec![
60+
Rc::new(Value::String(String::from(s))),
61+
Rc::new(Value::String(String::from(substring))),
62+
];
63+
assert_eq!(Value::Boolean(false), blank.invoke(args));
64+
}
65+
66+
#[test]
67+
fn hello_includes_empty_string() {
68+
let blank = IncludesFn {};
69+
let s = "hello";
70+
let substring = "";
71+
let args = vec![
72+
Rc::new(Value::String(String::from(s))),
73+
Rc::new(Value::String(String::from(substring))),
74+
];
75+
assert_eq!(Value::Boolean(true), blank.invoke(args));
76+
}
77+
}
78+
}

src/environment.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -210,6 +210,7 @@ impl Environment {
210210
let lower_case_fn = clojure_string::lower_case::LowerCaseFn {};
211211
let starts_with_fn = clojure_string::starts_with_qmark_::StartsWithFn {};
212212
let ends_with_fn = clojure_string::ends_with_qmark_::EndsWithFn {};
213+
let includes_fn = clojure_string::includes_qmark_::IncludesFn {};
213214

214215
// Hardcoded fns
215216
let lexical_eval_fn = Value::LexicalEvalFn {};
@@ -299,6 +300,12 @@ impl Environment {
299300
ends_with_fn.to_rc_value(),
300301
);
301302

303+
environment.insert_into_namespace(
304+
&Symbol::intern("clojure.string"),
305+
Symbol::intern("includes?"),
306+
includes_fn.to_rc_value(),
307+
);
308+
302309
environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
303310
environment.insert(Symbol::intern("let"), let_macro.to_rc_value());
304311
environment.insert(Symbol::intern("str"), str_fn.to_rc_value());

0 commit comments

Comments
 (0)