subplot 0.2.0

tools for specifying, documenting, and implementing automated acceptance tests for systems and software
Documentation
//! CLI Functionality abstractions

#![allow(unused)]

use anyhow::Result;
use serde::Serialize;
use subplot::{DataFile, Document, Style, SubplotError};

use std::convert::TryFrom;
use std::path::Path;
use std::str::FromStr;

pub fn load_document<P: AsRef<Path>>(filename: P, style: Style) -> Result<Document> {
    let filename = filename.as_ref();
    let base_path = subplot::get_basedir_from(filename)?;
    let doc = Document::from_file(&base_path, filename, style)?;

    Ok(doc)
}

pub fn extract_file<'a>(doc: &'a Document, filename: &str) -> Result<&'a DataFile> {
    for file in doc.files() {
        if file.filename() == filename {
            return Ok(file);
        }
    }
    Err(SubplotError::EmbeddedFileNotFound(filename.to_owned()).into())
}

#[derive(Serialize)]
pub struct Metadata {
    sources: Vec<String>,
    title: String,
    binding_files: Vec<String>,
    function_files: Vec<String>,
    bibliographies: Vec<String>,
    scenarios: Vec<String>,
    files: Vec<String>,
}

impl TryFrom<&mut Document> for Metadata {
    type Error = subplot::SubplotError;
    fn try_from(doc: &mut Document) -> std::result::Result<Self, Self::Error> {
        let sources: Vec<_> = doc
            .sources()
            .into_iter()
            .map(|p| filename(Some(&p)))
            .collect();
        let title = doc.meta().title().to_owned();
        let binding_files = doc
            .meta()
            .bindings_filenames()
            .into_iter()
            .map(|p| filename(Some(&p)))
            .collect();
        let function_files = doc
            .meta()
            .functions_filenames()
            .into_iter()
            .map(|p| filename(Some(&p)))
            .collect();
        let bibliographies = doc
            .meta()
            .bibliographies()
            .into_iter()
            .map(|p| filename(Some(&p)))
            .collect();
        let scenarios = doc
            .scenarios()?
            .into_iter()
            .map(|s| s.title().to_owned())
            .collect();
        let files = doc
            .files()
            .iter()
            .map(|f| f.filename().to_owned())
            .collect();
        Ok(Self {
            sources,
            title,
            binding_files,
            function_files,
            bibliographies,
            scenarios,
            files,
        })
    }
}

impl Metadata {
    fn write_list(v: &[String], prefix: &str) {
        v.iter().for_each(|entry| println!("{}: {}", prefix, entry))
    }

    pub fn write_out(&self) {
        Self::write_list(&self.sources, "source");
        println!("title: {}", self.title);
        Self::write_list(&self.binding_files, "bindings");
        Self::write_list(&self.function_files, "functions");
        Self::write_list(&self.bibliographies, "bibliography");
        Self::write_list(&self.files, "file");
        Self::write_list(&self.scenarios, "scenario");
    }
}

fn filename(name: Option<&Path>) -> String {
    let path = match name {
        None => return "".to_string(),
        Some(x) => x,
    };
    match path.to_str() {
        None => "non-UTF8 filename".to_string(),
        Some(x) => x.to_string(),
    }
}

#[derive(Debug)]
pub enum OutputFormat {
    Plain,
    Json,
}

impl FromStr for OutputFormat {
    type Err = String;

    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
        match s.to_ascii_lowercase().as_ref() {
            "plain" => Ok(OutputFormat::Plain),
            "json" => Ok(OutputFormat::Json),
            _ => Err(format!("Unknown output format: `{}`", s)),
        }
    }
}