derive_builder 0.4.2

Rust macro to automatically implement the builder pattern for arbitrary structs.
Documentation
#[cfg(feature = "logging")]
#[macro_use]
extern crate log;
#[cfg(feature = "logging")]
extern crate env_logger;
extern crate skeptic;

#[cfg(not(feature = "logging"))]
#[macro_use]
mod log_disabled {
    include!("../src/log_disabled.rs");
}

fn main() {
    println!("INFO: Run with `RUST_LOG=build_script_build=trace` for debug information.");
    #[cfg(feature = "logging")]
    env_logger::init().unwrap();

    let mut files = generate_doc_tpl_tests().unwrap();
    files.push("README.md".to_string());

    let files_ref: Vec<&str> = files.iter().map(|x| x.as_str()).collect();

    skeptic::generate_doc_tests(files_ref.as_slice());
}

const DOC_TPL_HEADER: &'static str = r###"
//////////////////////////////////////////////////////////////////
// START of Header
// NOTE:
// - This file is auto-generated by the `build.rs` script.
// - The following skeptic-template is a Rust format specifier,
//   so braces are treated specially, and need to be escaped
//   with double-braces.
//   See: https://github.com/brson/rust-skeptic#skeptic-templates
```rust,skeptic-template
#[macro_use]
extern crate derive_builder;

#[derive(Builder)]
struct Foo {{
    #[allow(dead_code)]
    default: bool,
}}

fn main() {{
   {}
}}
```
// END of Header
//////////////////////////////////////////////////////////////////

"###;

use std::error::Error;
use std::path::PathBuf;
use std::env;
use std::fs::{File, DirBuilder};
use std::ffi::OsStr;
use std::io::{Write, Read};

const DOC_TPL_DIR: &'static str = "src/doc_tpl/";
const DOC_TPL_OUT_DIR: &'static str = "doc_tpl/";

fn generate_doc_tpl_tests() -> Result<Vec<String>, Box<Error>> {
    trace!("Generating doc template tests");
    let root_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR")?);
    let mut tpl_dir = root_dir;
    tpl_dir.push(DOC_TPL_DIR);
    let mut out_dir = PathBuf::from(env::var("OUT_DIR")?);
    out_dir.push(DOC_TPL_OUT_DIR);

    if !out_dir.is_dir() {
        trace!("Create out dir {:?}", out_dir);
        DirBuilder::new().create(&out_dir)?;
    }

    let docs = tpl_dir.read_dir().expect(&format!("Could not open {}", tpl_dir.display()));

    let mut files = Vec::<String>::new();

    for doc in docs {
        let path: PathBuf = doc?.path();

        let filename = match path.file_name() {
            Some(filename) if path.extension() == Some(&OsStr::new("md")) => filename,
            _ => {
                trace!("Skipping dir entry {:?}", path.display());
                continue;
            }
        };

        trace!("Create tests for {:?}", path.display());
        let mut reader = File::open(&path)?;

        println!("cargo:rerun-if-changed={}", path.display());
        let mut out_file = out_dir.clone();
        out_file.push(filename);

        trace!("Will write into {:?}", out_file.display());

        let mut out = File::create(&out_file)?;
        out.write_all(DOC_TPL_HEADER.as_bytes())?;

        let mut tpl = String::new();
        reader.read_to_string(&mut tpl)?;
        let tpl = tpl.replace("{struct_name}", "Foo")
            .replace("{builder_name}", "FooBuilder")
            .replace("{field_name}", "default");
        out.write_all(tpl.as_ref())?;

        trace!("{:?}",
               &[&out_file.to_str().expect("Path must not be empty")]);

        files.push(out_file.to_str().expect("Path must not be empty").to_string());
    }

    Ok(files)
}