Skip to content

Commit

Permalink
(fix) nested each path issue [#95]
Browse files Browse the repository at this point in the history
Signed-off-by: Ning Sun <[email protected]>
  • Loading branch information
sunng87 committed Aug 7, 2016
1 parent 8cbf87a commit 84fd531
Show file tree
Hide file tree
Showing 3 changed files with 80 additions and 31 deletions.
1 change: 1 addition & 0 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ impl Context {
///
/// If you want to navigate from top level, set the base path to `"."`
pub fn navigate(&self, base_path: &str, relative_path: &str) -> &Json {
debug!("visiting path: {:?}/{:?}", base_path, relative_path);
let mut path_stack: VecDeque<&str> = VecDeque::new();
parse_json_visitor(&mut path_stack, base_path);
parse_json_visitor(&mut path_stack, relative_path);
Expand Down
96 changes: 65 additions & 31 deletions src/helpers/helper_each.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,9 @@ impl HelperDef for EachHelper {

match template {
Some(t) => {
let path = rc.get_path().clone();

rc.promote_local_vars();
if let Some(path_root) = value.path_root() {
let local_path_root = format!("{}/{}", path, path_root);
let local_path_root = format!("{}/{}", rc.get_path(), path_root);
rc.set_local_path_root(local_path_root);
}

Expand All @@ -40,35 +38,43 @@ impl HelperDef for EachHelper {
&Json::Array(ref list) => {
let len = list.len();
for i in 0..len {
rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
rc.set_local_var("@index".to_string(), i.to_json());
let mut local_rc = rc.derive();
local_rc.set_local_var("@first".to_string(), (i == 0usize).to_json());
local_rc.set_local_var("@last".to_string(), (i == len - 1).to_json());
local_rc.set_local_var("@index".to_string(), i.to_json());

if let Some(inner_path) = value.path() {
let new_path = format!("{}/{}.[{}]", path, inner_path, i);
debug!("each value {:?}", new_path);
rc.set_path(new_path);
let new_path = format!("{}/{}.[{}]",
local_rc.get_path(),
inner_path,
i);
debug!("each path {:?}", new_path);
local_rc.set_path(new_path);
}
try!(t.render(c, r, rc));
try!(t.render(c, r, &mut local_rc));
}
Ok(())
}
&Json::Object(ref obj) => {
let mut first: bool = true;
for k in obj.keys() {
rc.set_local_var("@first".to_string(), first.to_json());
let mut local_rc = rc.derive();
local_rc.set_local_var("@first".to_string(), first.to_json());
if first {
first = false;
}

rc.set_local_var("@key".to_string(), k.to_json());
local_rc.set_local_var("@key".to_string(), k.to_json());

if let Some(inner_path) = value.path() {
let new_path = format!("{}/{}.[{}]", path, inner_path, k);
rc.set_path(new_path);
let new_path = format!("{}/{}.[{}]",
local_rc.get_path(),
inner_path,
k);
local_rc.set_path(new_path);
}

try!(t.render(c, r, rc));
try!(t.render(c, r, &mut local_rc));
}

Ok(())
Expand All @@ -77,7 +83,7 @@ impl HelperDef for EachHelper {
Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
}
};
rc.set_path(path);

rc.demote_local_vars();
rendered
}
Expand All @@ -99,11 +105,9 @@ impl HelperDef for EachHelper {

match template {
Some(t) => {
let path = rc.get_path().clone();

rc.promote_local_vars();
if let Some(path_root) = value.path_root() {
let local_path_root = format!("{}/{}", path, path_root);
let local_path_root = format!("{}/{}", rc.get_path(), path_root);
rc.set_local_path_root(local_path_root);
}

Expand All @@ -112,35 +116,45 @@ impl HelperDef for EachHelper {
&Json::Array(ref list) => {
let len = list.len();
for i in 0..len {
rc.set_local_var("@first".to_string(), value::to_value(&(i == 0usize)));
rc.set_local_var("@last".to_string(), value::to_value(&(i == len - 1)));
rc.set_local_var("@index".to_string(), value::to_value(&i));
let mut local_rc = rc.derive();
local_rc.set_local_var("@first".to_string(),
value::to_value(&(i == 0usize)));
local_rc.set_local_var("@last".to_string(),
value::to_value(&(i == len - 1)));
local_rc.set_local_var("@index".to_string(), value::to_value(&i));

if let Some(inner_path) = value.path() {
let new_path = format!("{}/{}.[{}]", path, inner_path, i);
let new_path = format!("{}/{}.[{}]",
local_rc.get_path(),
inner_path,
i);
debug!("each value {:?}", new_path);
rc.set_path(new_path);
local_rc.set_path(new_path);
}
try!(t.render(c, r, rc));
try!(t.render(c, r, &mut local_rc));
}
Ok(())
}
&Json::Object(ref obj) => {
let mut first: bool = true;
for k in obj.keys() {
rc.set_local_var("@first".to_string(), value::to_value(&first));
let mut local_rc = rc.derive();
local_rc.set_local_var("@first".to_string(), value::to_value(&first));
if first {
first = false;
}

rc.set_local_var("@key".to_string(), value::to_value(&k));
local_rc.set_local_var("@key".to_string(), value::to_value(&k));
if let Some(inner_path) = value.path() {
let new_path = format!("{}/{}.[{}]", path, inner_path, k);
let new_path = format!("{}/{}.[{}]",
local_rc.get_path(),
inner_path,
k);
debug!("each value {:?}", new_path);
rc.set_path(new_path);
local_rc.set_path(new_path);
}

try!(t.render(c, r, rc));
try!(t.render(c, r, &mut local_rc));
}

Ok(())
Expand All @@ -149,7 +163,7 @@ impl HelperDef for EachHelper {
Err(RenderError::new(format!("Param type is not iterable: {:?}", template)))
}
};
rc.set_path(path);
// rc.set_path(path);
rc.demote_local_vars();
rendered
}
Expand Down Expand Up @@ -239,6 +253,25 @@ mod test {
assert_eq!(r1.ok().unwrap(), "100:200".to_string());
}

#[test]
#[cfg(all(feature = "rustc_ser_type", not(feature = "serde_type")))]
fn test_nested_each() {

let json_str = r#"{"a": [{"b": true}], "b": [[1, 2, 3],[4, 5]]}"#;

let data = Json::from_str(json_str).unwrap();
let t0 = Template::compile("{{#each b}}{{#if ../a}}{{#each this}}{{this}}{{/each}}{{/if}}{{/each}}".to_string())
.ok()
.unwrap();

let mut handlebars = Registry::new();
handlebars.register_template("t0", t0);

let r1 = handlebars.render("t0", &data);
assert_eq!(r1.ok().unwrap(), "12345".to_string());
}


#[test]
fn test_nested_array() {
let t0 = Template::compile("{{#each this.[0]}}{{this}}{{/each}}".to_owned()).ok().unwrap();
Expand Down Expand Up @@ -281,4 +314,5 @@ mod test {

assert_eq!(r0_sp, vec!["", "-baz", "foo-bar"]);
}

}
14 changes: 14 additions & 0 deletions src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,20 @@ impl<'a> RenderContext<'a> {
}
}

pub fn derive(&mut self) -> RenderContext {
RenderContext {
partials: self.partials.clone(),
path: self.path.clone(),
local_path_root: self.local_path_root.clone(),
local_variables: self.local_variables.clone(),
default_var: self.default_var.clone(),
writer: self.writer,
current_template: self.current_template.clone(),
root_template: self.root_template.clone(),
disable_escape: self.disable_escape,
}
}

pub fn get_partial(&self, name: &String) -> Option<Template> {
match self.partials.get(name) {
Some(t) => Some(t.clone()),
Expand Down

0 comments on commit 84fd531

Please sign in to comment.