Index: Cargo.toml ================================================================== --- Cargo.toml +++ Cargo.toml @@ -1,8 +1,8 @@ [package] name = "sidoc" -version = "0.1.1" +version = "0.1.2" edition = "2021" license = "0BSD" # https://crates.io/category_slugs categories = [ "template-engine" ] keywords = [ "text", "document", "html" ] Index: src/builder.rs ================================================================== --- src/builder.rs +++ src/builder.rs @@ -31,10 +31,97 @@ } else { self.scope_stack.push(None); } self } + + /// Wrap [`Builder::scope()`] and [`Builder::exit()`]. + /// + /// Initialize a new scope, call caller-supplied closure, and automatically + /// exit scope before returning. + /// + /// ``` + /// use std::sync::Arc; + /// use sidoc::{Builder, RenderContext}; + /// + /// let mut bldr = Builder::new(); + /// + /// bldr + /// .line("") + /// .autoscope("", Some(""), |bldr| { + /// bldr.autoscope("", Some(""), |bldr| { + /// bldr.line("hello"); + /// }); + /// }); + /// + /// let doc = bldr.build().unwrap(); + /// let mut r = RenderContext::new(); + /// r.doc("root", Arc::new(doc)); + /// let buf = r.render("root").unwrap(); + /// + /// assert_eq!( + /// buf, + /// "\n\n \n hello\n \n\n" + /// ); + /// ``` + #[allow(clippy::needless_pass_by_value)] + pub fn autoscope( + &mut self, + begin_line: L, + term_line: Option, + f: F + ) -> &mut Self + where + F: FnOnce(&mut Self) + { + self.scope(begin_line, term_line); + f(self); + self.exit(); + self + } + + /// Same as [`Builder::autoscope()`], but only init scope and call closure if + /// predicate is true. + #[allow(clippy::needless_pass_by_value)] + pub fn autoscope_if( + &mut self, + pred: bool, + begin_line: L, + term_line: Option, + f: F + ) -> &mut Self + where + F: FnOnce(&mut Self) + { + if pred { + self.scope(begin_line, term_line); + f(self); + self.exit(); + } + self + } + + /// Same as [`Builder::autoscope()`], but only init scope and call closure if + /// `opt` is `Some(T)`. `T` will be passed to the closure. + #[allow(clippy::needless_pass_by_value)] + pub fn autoscope_opt( + &mut self, + opt: Option, + begin_line: L, + term_line: Option, + f: F + ) -> &mut Self + where + F: FnOnce(&mut Self, T) + { + if let Some(o) = opt { + self.scope(begin_line, term_line); + f(self, o); + self.exit(); + } + self + } /// Leave a previously entered scope. /// /// If the `scope()` call that created the current scope /// ADDED tests/simple_html.rs Index: tests/simple_html.rs ================================================================== --- /dev/null +++ tests/simple_html.rs @@ -0,0 +1,77 @@ +use std::sync::Arc; + +use sidoc::{Builder, RenderContext}; + +#[test] +fn simple_html() { + let mut bldr = Builder::new(); + + bldr.line(""); + bldr.scope("", Some("")).exit(); + + let doc = bldr.build().unwrap(); + + let mut r = RenderContext::new(); + + r.doc("hello", Arc::new(doc)); + + let buf = r.render("hello").unwrap(); + + assert_eq!(buf, "\n\n\n"); +} + + +#[test] +fn simple_html_head() { + let mut bldr = Builder::new(); + + bldr + .line("") + .scope("", Some("")) + .scope("", Some("")) + .exit() + .exit(); + + let doc = bldr.build().unwrap(); + + let mut r = RenderContext::new(); + + r.doc("root", Arc::new(doc)); + + let buf = r.render("root").unwrap(); + + assert_eq!( + buf, + "\n\n \n \n\n" + ); +} + + +#[test] +fn autoscope() { + let mut bldr = Builder::new(); + + bldr + .line("") + .autoscope("", Some(""), |bldr| { + bldr.autoscope("", Some(""), |bldr| { + bldr.line("hello"); + }); + }); + + let doc = bldr.build().unwrap(); + + let mut r = RenderContext::new(); + + r.doc("root", Arc::new(doc)); + + let buf = r.render("root").unwrap(); + + assert_eq!( + buf, + "\n\n \n hello\n \ + \n\n" + ); +} + +// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : DELETED tests/simple_http.rs Index: tests/simple_http.rs ================================================================== --- tests/simple_http.rs +++ /dev/null @@ -1,49 +0,0 @@ -use std::sync::Arc; - -use sidoc::{Builder, RenderContext}; - -#[test] -fn simple_html() { - let mut bldr = Builder::new(); - - bldr.line(""); - bldr.scope("", Some("")).exit(); - - let doc = bldr.build().unwrap(); - - let mut r = RenderContext::new(); - - r.doc("hello", Arc::new(doc)); - - let buf = r.render("hello").unwrap(); - - assert_eq!(buf, "\n\n\n"); -} - - -#[test] -fn simple_html_head() { - let mut bldr = Builder::new(); - - bldr - .line("") - .scope("", Some("")) - .scope("", Some("")) - .exit() - .exit(); - - let doc = bldr.build().unwrap(); - - let mut r = RenderContext::new(); - - r.doc("root", Arc::new(doc)); - - let buf = r.render("root").unwrap(); - - assert_eq!( - buf, - "\n\n \n \n\n" - ); -} - -// vim: set ft=rust et sw=2 ts=2 sts=2 cinoptions=2 tw=79 : Index: www/changelog.md ================================================================== --- www/changelog.md +++ www/changelog.md @@ -2,20 +2,36 @@ ⚠️ indicates a breaking change. ## [Unreleased] -[Details](/vdiff?from=sidoc-0.1.0&to=trunk) +[Details](/vdiff?from=sidoc-0.1.1&to=trunk) ### Added -- Derive `Default` on `Doc` and `RenderContext` +- `Builder::autoscope()` is a helper for adding scopes that will automatically + be closed. +- `Builder::autoscope_if()` is a variant of `Builder::autoscope()` that will + only add a scope, and call callback, if a predicate is true. +- `Builder::autoscope_opt()` is another variant of `Builder::autoscope()` that + will only add scope, and call callback, if an input option paramter is + `Some(T)`. ### Changed ### Removed +--- + +## [0.1.1] - 2024-11-07 + +[Details](/vdiff?from=sidoc-0.1.0&to=sidoc-0.1.1) + +### Added + +- Derive `Default` on `Doc` and `RenderContext` + --- ## [0.1.0] - 2020-09-12 Initial release