Skip to content

Commit 5caf240

Browse files
committed
clojure.string/join
1 parent c70e35a commit 5caf240

File tree

2 files changed

+105
-15
lines changed

2 files changed

+105
-15
lines changed

src/clojure_string/join.rs

Lines changed: 95 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,15 @@ use std::rc::Rc;
44

55
use crate::error_message;
66
use crate::type_tag::TypeTag;
7+
use crate::persistent_list::ToPersistentListIter;
8+
use crate::persistent_vector::ToPersistentVectorIter;
9+
use itertools::Itertools;
10+
use crate::persistent_list::PersistentList::Cons;
711

8-
/// clojure.string/reverse ; reverses a string
9-
/// (defn print-string [string] .. prints single string .. )
12+
/// clojure.string/join ; joins a coll of items together as a string
13+
/// (join
14+
/// [coll]
15+
/// [separator coll])
1016
#[derive(Debug, Clone)]
1117
pub struct JoinFn {}
1218
impl ToValue for JoinFn {
@@ -16,15 +22,42 @@ impl ToValue for JoinFn {
1622
}
1723
impl IFn for JoinFn {
1824
fn invoke(&self, args: Vec<Rc<Value>>) -> Value {
19-
if args.len() == 1 {
20-
match args.get(0).unwrap().to_value() {
21-
Value::Iseq(s) => Value::String(s.chars().rev().collect()),
22-
_a => error_message::type_mismatch(TypeTag::String, &_a.to_value())
25+
if args.len() == 1 || args.len() == 2 {
26+
let separator = if args.len() == 2 {
27+
args.get(0).unwrap().to_string()
28+
} else { String::from("") };
29+
let coll = if args.len() == 1 { args.get(0) } else { args.get(1) };
30+
match coll.unwrap().to_value() {
31+
Value::PersistentList(Cons(head, tail, count)) => {
32+
return if count == 0 {
33+
Value::String(String::from(""))
34+
} else if count == 1 {
35+
Value::String(head.to_string())
36+
} else {
37+
Value::String(
38+
String::from(
39+
head.to_string()) + separator.as_str() +
40+
tail.iter()
41+
.map(|x| x.to_string())
42+
.collect::<Vec<std::string::String>>()
43+
.join(&separator).as_str())
44+
}
45+
},
46+
Value::PersistentVector(pvec) => {
47+
return if pvec.vals.len() == 0 {
48+
Value::String(String::from(""))
49+
} else {
50+
Value::String(String::from(
51+
pvec.vals.iter()
52+
.map(|x| x.to_string())
53+
.collect::<Vec<std::string::String>>()
54+
.join(&separator).as_str()))
55+
}
56+
}
57+
_ => Value::String(String::from(""))
2358
}
24-
2559
} else {
26-
return error_message::wrong_arg_count(2, args.len());
27-
60+
return error_message::wrong_varg_count(&[1,2], args.len());
2861
}
2962
}
3063
}
@@ -34,15 +67,63 @@ mod tests {
3467
mod reverse_tests {
3568
use crate::value::Value;
3669
use std::rc::Rc;
37-
use crate::clojure_string::reverse::JoinFn;
70+
use crate::clojure_string::join::JoinFn;
3871
use crate::ifn::IFn;
72+
use crate::persistent_list::PersistentList;
73+
use crate::persistent_vector::PersistentVector;
74+
75+
#[test]
76+
fn join_empty_collection_to_empty_string() {
77+
let join = JoinFn {};
78+
let args = vec![Rc::new(Value::PersistentList(vec![].into_iter().collect::<PersistentList>()))];
79+
assert_eq!(Value::String(String::from("")), join.invoke(args));
80+
}
81+
82+
#[test]
83+
fn join_one_item_collection_to_string() {
84+
let join = JoinFn {};
85+
let s = "hello";
86+
let args = vec![Rc::new(Value::PersistentList(
87+
vec![Rc::new(Value::String(String::from(s)))].into_iter().collect::<PersistentList>()))];
88+
assert_eq!(Value::String(String::from("hello")), join.invoke(args));
89+
}
90+
91+
#[test]
92+
fn join_multiple_items_in_collection_to_string() {
93+
let join = JoinFn {};
94+
let s = "hello";
95+
let args = vec![Rc::new(Value::PersistentList(
96+
vec![Rc::new(Value::String(String::from(s))),
97+
Rc::new(Value::I32(5)),
98+
Rc::new(Value::String(String::from(s)))]
99+
.into_iter().collect::<PersistentList>()))];
100+
assert_eq!(Value::String(String::from("hello5hello")), join.invoke(args));
101+
}
102+
103+
#[test]
104+
fn join_multiple_items_in_collection_with_separator_to_string() {
105+
let join = JoinFn {};
106+
let s = "hello";
107+
let args = vec![Rc::new(Value::String(String::from(", "))),
108+
Rc::new(Value::PersistentList(
109+
vec![Rc::new(Value::String(String::from(s))),
110+
Rc::new(Value::I32(5)),
111+
Rc::new(Value::String(String::from(s)))]
112+
.into_iter().collect::<PersistentList>()))];
113+
assert_eq!(Value::String(String::from("hello, 5, hello")), join.invoke(args));
114+
}
39115

40116
#[test]
41-
fn reverse_string() {
42-
let reverse = JoinFn {};
117+
fn join_multiple_items_in_pvec_collection_with_separator_to_string() {
118+
let join = JoinFn {};
43119
let s = "hello";
44-
let args = vec![Rc::new(Value::String(String::from(s)))];
45-
assert_eq!(Value::String(String::from("olleh")), reverse.invoke(args));
120+
let args = vec![Rc::new(Value::String(String::from(", "))),
121+
Rc::new(Value::PersistentVector(
122+
vec![Rc::new(Value::String(String::from(s))),
123+
Rc::new(Value::I32(5)),
124+
Rc::new(Value::String(String::from(s)))]
125+
.into_iter().collect::<PersistentVector>()))];
126+
assert_eq!(Value::String(String::from("hello, 5, hello")), join.invoke(args));
46127
}
47128
}
48129
}

src/environment.rs

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@ impl Environment {
204204

205205
// clojure.string
206206
let reverse_fn = clojure_string::reverse::ReverseFn {};
207+
let join_fn = clojure_string::join::JoinFn {};
207208

208209
// Hardcoded fns
209210
let lexical_eval_fn = Value::LexicalEvalFn {};
@@ -251,7 +252,15 @@ impl Environment {
251252
environment.insert(Symbol::intern("rust-slurp"), slurp_fn.to_rc_value());
252253

253254
// clojure.string
254-
environment.insert(Symbol::intern("clojure_string_reverse"), reverse_fn.to_rc_value());
255+
environment.insert_into_namespace(
256+
&Symbol::intern("clojure.string"),
257+
Symbol::intern("clojure_string_"),
258+
reverse_fn.to_rc_value());
259+
260+
environment.insert_into_namespace(
261+
&Symbol::intern("clojure.string"),
262+
Symbol::intern("join"),
263+
join_fn.to_rc_value());
255264

256265
environment.insert(Symbol::intern("+"), add_fn.to_rc_value());
257266
environment.insert(Symbol::intern("let"), let_macro.to_rc_value());

0 commit comments

Comments
 (0)