diff --git a/README.md b/README.md index bcfee63..3cfcb84 100644 --- a/README.md +++ b/README.md @@ -20,32 +20,38 @@ extern crate orgize; ## Example +### Using Parser + +Orgize parser acts like a event-based parser, which means it returns an +`Iterator` of `Event` s. + ```rust use orgize::Parser; -let parser = Parser::new( - r"* Title 1 +let parser = Parser::new(r#"* Title 1 *Section 1* ** Title 2 _Section 2_ * Title 3 /Section 3/ * Title 4 -=Section 4=", -); +=Section 4="#); for event in parser { // handling the event } ``` -Alternatively, you can use the built-in render. +### Using Render + +You can use the built-in `HtmlRender` to generate html string directly: ```rust -use orgize::export::DefaultHtmlRender; -use std::io::Cursor; +use orgize::export::HtmlRender; +use std::io::{Cursor, Result}; -let contents = r"* Title 1 +fn main() -> Result<()> { + let contents = r"* Title 1 *Section 1* ** Title 2 _Section 2_ @@ -54,14 +60,96 @@ _Section 2_ * Title 4 =Section 4="; -let cursor = Cursor::new(Vec::new()); -let mut render = DefaultHtmlRender::new(cursor, &contents); + let mut cursor = Cursor::new(Vec::new()); + let mut render = HtmlRender::default(&mut cursor, &contents); -render - .render() - .expect("something went wrong rendering the file"); - -let result = String::from_utf8(render.into_writer().into_inner()).expect("invalid utf-8"); + render.render()?; + + assert_eq!( + String::from_utf8(cursor.into_inner()).unwrap(), + "

Title 1

Section 1

\ +

Title 2

Section 2

\ +

Title 3

Section 3

\ +

Title 4

Section 4

" + ); + + Ok(()) +} +``` + +### Custom HtmlHandler + +You can create your own handler by implementing `HtmlHandler` trait and passing +it to the `HtmlRender`. + +The following example demonstrates how to add an anchor for every headline and +use your own error type. + +```rust +use orgize::{export::*, headline::Headline}; +use slugify::slugify; +use std::io::{Cursor, Error as IOError, Write}; +use std::string::FromUtf8Error; + +// custom error type +#[derive(Debug)] +enum Error { + IO(IOError), + Headline, + Utf8(FromUtf8Error), +} + +// From trait is required for custom error type +impl From for Error { + fn from(err: IOError) -> Error { + Error::IO(err) + } +} + +struct CustomHtmlHandler; + +impl HtmlHandler for CustomHtmlHandler { + fn headline_beg(&mut self, w: &mut W, hdl: Headline) -> Result<(), Error> { + if hdl.level > 6 { + Err(Error::Headline) + } else { + write!( + w, + r##""##, + hdl.level, + slugify!(hdl.title), + )?; + self.escape(w, hdl.title)?; + Ok(write!(w, "", hdl.level)?) + } + } +} + +fn main() -> Result<(), Error> { + let contents = r"* Title 1 +*Section 1* +** Title 2 +_Section 2_ +* Title 3 +/Section 3/ +* Title 4 +=Section 4="; + + let mut cursor = Cursor::new(Vec::new()); + let mut render = HtmlRender::new(CustomHtmlHandler, &mut cursor, &contents); + + render.render()?; + + assert_eq!( + String::from_utf8(cursor.into_inner()).map_err(Error::Utf8)?, + "

Title 1

Section 1

\ +

Title 2

Section 2

\ +

Title 3

Section 3

\ +

Title 4

Section 4

" + ); + + Ok(()) +} ``` ## License diff --git a/src/lib.rs b/src/lib.rs index efb0b59..50d1df7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,33 +1,41 @@ //! A Rust library for parsing orgmode files. //! -//! ## Example +//! # Using Parser +//! +//! Orgize parser acts like a event-based parser, which means it +//! returns an `Iterator` of [`Event`] s. +//! +//! [`Event`]: enum.Event.html //! //! ```rust //! use orgize::Parser; //! -//! let parser = Parser::new( -//! r"* Title 1 +//! let parser = Parser::new(r#"* Title 1 //! *Section 1* //! ** Title 2 //! _Section 2_ //! * Title 3 //! /Section 3/ //! * Title 4 -//! =Section 4=", -//! ); +//! =Section 4="#); //! //! for event in parser { //! // handling the event //! } //! ``` //! -//! Alternatively, you can use the built-in render directly: +//! # Using Render +//! +//! You can use the built-in [`HtmlRender`] to generate html string directly: +//! +//! [`HtmlRender`]: export/struct.HtmlRender.html //! //! ```rust //! use orgize::export::HtmlRender; -//! use std::io::Cursor; +//! use std::io::{Cursor, Result}; //! -//! let contents = r"* Title 1 +//! fn main() -> Result<()> { +//! let contents = r"* Title 1 //! *Section 1* //! ** Title 2 //! _Section 2_ @@ -36,41 +44,76 @@ //! * Title 4 //! =Section 4="; //! -//! let mut cursor = Cursor::new(Vec::new()); -//! let mut render = HtmlRender::default(&mut cursor, &contents); +//! let mut cursor = Cursor::new(Vec::new()); +//! let mut render = HtmlRender::default(&mut cursor, &contents); //! -//! render -//! .render() -//! .expect("something went wrong rendering the file"); +//! render.render()?; //! -//! let result = String::from_utf8(cursor.into_inner()).expect("invalid utf-8"); +//! assert_eq!( +//! String::from_utf8(cursor.into_inner()).unwrap(), +//! "

Title 1

Section 1

\ +//!

Title 2

Section 2

\ +//!

Title 3

Section 3

\ +//!

Title 4

Section 4

" +//! ); +//! +//! Ok(()) +//! } //! ``` //! -//! or `impl HtmlHandler` to create your own render. The following example -//! add an anchor to every headline. +//! # Custom HtmlHandler +//! +//! You can create your own handler by implementing [`HtmlHandler`] trait and passing +//! it to the [`HtmlRender`]. +//! +//! The following example demonstrates how to add an anchor for every headline and use +//! your own error type. +//! +//! [`HtmlHandler`]: export/trait.HtmlHandler.html +//! [`HtmlRender`]: export/struct.HtmlRender.html //! //! ```rust -//! use std::io::{Cursor, Error, Result, Write}; -//! -//! use orgize::export::*; -//! use orgize::headline::Headline; +//! use orgize::{export::*, headline::Headline}; //! use slugify::slugify; +//! use std::io::{Cursor, Error as IOError, Write}; +//! use std::string::FromUtf8Error; +//! +//! // custom error type +//! #[derive(Debug)] +//! enum Error { +//! IO(IOError), +//! Headline, +//! Utf8(FromUtf8Error), +//! } +//! +//! // From trait is required for custom error type +//! impl From for Error { +//! fn from(err: IOError) -> Error { +//! Error::IO(err) +//! } +//! } //! //! struct CustomHtmlHandler; //! //! impl HtmlHandler for CustomHtmlHandler { -//! fn headline_beg(&mut self, w: &mut W, hdl: Headline) -> Result<()> { -//! write!( -//! w, -//! r##"{2}"##, -//! if hdl.level <= 6 { hdl.level } else { 6 }, -//! slugify!(hdl.title), -//! hdl.title, -//! ) +//! fn headline_beg(&mut self, w: &mut W, hdl: Headline) -> Result<(), Error> { +//! if hdl.level > 6 { +//! Err(Error::Headline) +//! } else { +//! write!( +//! w, +//! r##""##, +//! hdl.level, +//! slugify!(hdl.title), +//! )?; +//! self.escape(w, hdl.title)?; +//! Ok(write!(w, "", hdl.level)?) +//! } //! } //! } //! -//! let contents = r"* Title 1 +//! fn main() -> Result<(), Error> { +//! let contents = r"* Title 1 //! *Section 1* //! ** Title 2 //! _Section 2_ @@ -79,18 +122,23 @@ //! * Title 4 //! =Section 4="; //! -//! let mut cursor = Cursor::new(Vec::new()); +//! let mut cursor = Cursor::new(Vec::new()); +//! let mut render = HtmlRender::new(CustomHtmlHandler, &mut cursor, &contents); //! -//! let mut render = HtmlRender::new(CustomHtmlHandler, &mut cursor, &contents); +//! render.render()?; //! -//! render -//! .render() -//! .expect("something went wrong rendering the file"); +//! assert_eq!( +//! String::from_utf8(cursor.into_inner()).map_err(Error::Utf8)?, +//! "

Title 1

Section 1

\ +//!

Title 2

Section 2

\ +//!

Title 3

Section 3

\ +//!

Title 4

Section 4

" +//! ); //! -//! let result = String::from_utf8(cursor.into_inner()).expect("invalid utf-8"); +//! Ok(()) +//! } //! ``` -#[warn(missing_docs)] pub mod elements; pub mod export; pub mod headline; diff --git a/tests/html.rs b/tests/html.rs index ec8484c..c5393bb 100644 --- a/tests/html.rs +++ b/tests/html.rs @@ -3,20 +3,22 @@ extern crate orgize; use orgize::export::HtmlRender; use std::io::Cursor; -macro_rules! parse_assert { - ($content:expr, $expected:expr) => {{ - let mut cursor = Cursor::new(Vec::new()); - let mut render = HtmlRender::default(&mut cursor, $content); - render.render().expect("render error"); - let s = String::from_utf8(cursor.into_inner()).expect("invalid utf-8"); - assert_eq!(s, $expected); - }}; +macro_rules! html_test { + ($name:ident, $content:expr, $expected:expr) => { + #[test] + fn $name() { + let mut cursor = Cursor::new(Vec::new()); + let mut render = HtmlRender::default(&mut cursor, $content); + render.render().expect("render error"); + let s = String::from_utf8(cursor.into_inner()).expect("invalid utf-8"); + assert_eq!(s, $expected); + } + }; } -#[test] -fn emphasis() { - parse_assert!( - r#"* Title 1 +html_test!( + emphasis, + r#"* Title 1 *Section 1* ** Title 2 _Section 2_ @@ -24,19 +26,15 @@ _Section 2_ /Section 3/ * Title 4 =Section 4="#, - concat!( - "

Title 1

Section 1

", - "

Title 2

Section 2

", - "

Title 3

Section 3

", - "

Title 4

Section 4

" - ) - ) -} + "

Title 1

Section 1

\ +

Title 2

Section 2

\ +

Title 3

Section 3

\ +

Title 4

Section 4

" +); -#[test] -fn list() { - parse_assert!( - r#"+ 1 +html_test!( + list, + r#"+ 1 + 2 @@ -45,12 +43,9 @@ fn list() { - 4 + 5"#, - concat!( - "
    ", - "
  • 1

  • ", - "
  • 2

    • 3

    • 4

  • ", - "
  • 5

  • ", - "
" - ) - ) -} + "
    \ +
  • 1

  • \ +
  • 2

    • 3

    • 4

  • \ +
  • 5

  • \ +
" +);