rat 0.4.12

REST API tool - query various REST APIs comfortably
Documentation
use config::{Config, OutputFormat, Verbosity};
use errors::*;
use utils::console::*;
use utils::output;

use clap::{App, Arg, ArgMatches, SubCommand};
use indicatif::{ProgressBar, ProgressStyle};
use serde_json;
use std::io::Write;
use tabwriter::TabWriter;

pub mod comdirect;

pub const NAME: &'static str = "stocks";


#[derive(Serialize, Debug)]
pub struct StockPrice {
    pub name: String,
    pub wkn: String,
    pub date: String,
    pub price: f32,
    pub currency: String,
}

pub fn build_sub_cli() -> App<'static, 'static> {
    SubCommand::with_name(NAME)
        .about("Stocks scrapes current stock prices from comdirect.de")
        .arg(Arg::with_name("queries")
            .index(1)
            .required(true)
            .multiple(true)
            .help("search term like company name, ISIN, WKN, or symbol"))
}

pub fn call(cli_args: Option<&ArgMatches>, config: &Config) -> Result<()> {
    let args = cli_args.unwrap();
    let queries: Vec<&str> = args.values_of("queries").unwrap().map(|x| x).collect();

    let mut progress_bar: Option<ProgressBar> = None;
    let mut progress = None;
    if config.general.output_format == OutputFormat::HUMAN && config.general.verbosity <= Verbosity::NORMAL {
        let pb = ProgressBar::new(0);
        pb.set_style(ProgressStyle::default_bar()
            .template("[{elapsed_precise}] [{bar:40.blue/blue}] {pos}/{len} ({eta}) {msg} {spinner:.blue}")
        );
        pb.set_length(queries.len() as u64);
        progress_bar = Some(pb);
        progress = Some(|str: String| {
            progress_bar.as_ref().unwrap().set_message(&str);
        });
    };

    let mut stock_prices: Vec<StockPrice> = vec![];
    for query in queries {
        let r = comdirect::scrape_stock_price(query, progress.as_ref())
            .chain_err(|| format!("Failed to get stock price for query '{}'", query))?;
        if let Some(ref pb) = progress_bar {
            pb.inc(1);
        }
        stock_prices.push(r)
    }

    if let Some(ref pb) = progress_bar {
        pb.finish_with_message("done");
    };

    output(&stock_prices, &config.general.output_format)
}

fn output(stock_prices: &[StockPrice], format: &OutputFormat) -> Result<()> {
    match *format {
        OutputFormat::HUMAN => output_human(stock_prices),
        OutputFormat::JSON => {
            let json = serde_json::to_string(stock_prices).chain_err(|| "Failed to serialize JSON")?;
            output::as_json(&json).chain_err(|| "Output failed")
        },
    }
}

fn output_human(stock_prices: &[StockPrice]) -> Result<()> {
    let mut tw = TabWriter::new(vec![]);
    for ref sp in stock_prices {
        let _ = writeln!(
            &mut tw, "{}\t({})\tis at {:7.2} {}\ton {}", sp.name, sp.wkn, sp.price, sp.currency, sp.date);
    }
    tw.flush().unwrap();
    let out_str = String::from_utf8(tw.into_inner().unwrap()).unwrap();

    msgln(format!("{}", out_str));

    Ok(())
}