Skip to content

Commit

Permalink
move options into own struct
Browse files Browse the repository at this point in the history
  • Loading branch information
carderne committed Apr 9, 2024
1 parent 93a036b commit bd36286
Show file tree
Hide file tree
Showing 7 changed files with 120 additions and 62 deletions.
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ rust_decimal = "1.33.1"

[lib]
name = "bean_rs"
crate-type = ["cdylib"]
crate-type = ["cdylib", "lib"]

[[bin]]
name = "bean-rs"
Expand Down
71 changes: 33 additions & 38 deletions src/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,33 @@ pub type CcyBal = HashMap<Ccy, Decimal>;
pub type AccBal = HashMap<Account, CcyBal>;
pub type AccStatuses = HashMap<Account, (bool, Vec<Ccy>)>;

pub struct Options {
pub title: String,
pub operating_currency: String,
}

impl Default for Options {
fn default() -> Self {
Self {
title: "".to_string(),
operating_currency: "".to_string(),
}
}
}

impl Options {
pub fn update_from_entry(&mut self, entry: Pair<Rule>) {
let mut pairs = entry.clone().into_inner();
let key = pairs.next().unwrap().as_str();
let val = pairs.next().unwrap().as_str().to_string();
match key {
"title" => self.title = val,
"operating_currency" => self.operating_currency = val,
_ => panic!("Other options not handled yet"),
}
}
}

#[derive(Clone, Debug, Default)]
pub struct DebugLine {
pub line: usize,
Expand Down Expand Up @@ -105,37 +132,6 @@ impl fmt::Display for ConfigCustom {
}
}

#[derive(Debug, PartialEq)]
pub struct ConfigOption {
pub date: NaiveDate,
pub key: String,
pub val: String,
pub debug: DebugLine,
}

impl ConfigOption {
pub fn from_entry(entry: Pair<Rule>) -> Self {
let mut pairs = entry.clone().into_inner();
let key = pairs.next().unwrap().as_str().to_string();
let val = pairs.next().unwrap().as_str().to_string();
let (line, _) = entry.line_col();
let debug = DebugLine { line };
let date = NaiveDate::parse_from_str(BASE_DATE, DATE_FMT).unwrap();
Self {
date,
key,
val,
debug,
}
}
}

impl fmt::Display for ConfigOption {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{key} {val}", key = self.key, val = self.val,)
}
}

#[derive(Debug, Clone, PartialEq)]
pub struct Metadata {
pub key: String,
Expand Down Expand Up @@ -459,7 +455,6 @@ impl fmt::Display for Document {
}
}


#[derive(Debug, PartialEq)]
pub struct Note {
pub date: NaiveDate,
Expand Down Expand Up @@ -737,7 +732,6 @@ impl fmt::Display for Transaction {
#[derive(Debug)]
pub enum Directive {
ConfigCustom(ConfigCustom),
ConfigOption(ConfigOption),
Commodity(Commodity),
Open(Open),
Close(Close),
Expand All @@ -754,7 +748,6 @@ impl Directive {
pub fn date(&self) -> &NaiveDate {
match self {
Directive::ConfigCustom(d) => &d.date,
Directive::ConfigOption(d) => &d.date,
Directive::Commodity(d) => &d.date,
Directive::Open(d) => &d.date,
Directive::Close(d) => &d.date,
Expand All @@ -774,7 +767,6 @@ impl Directive {
Directive::Open(_) => -2,
Directive::Balance(_) => -1,
Directive::ConfigCustom(_) => 0,
Directive::ConfigOption(_) => 0,
Directive::Commodity(_) => 0,
Directive::Pad(_) => 0,
Directive::Price(_) => 0,
Expand All @@ -791,7 +783,6 @@ impl fmt::Display for Directive {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Directive::ConfigCustom(d) => write!(f, "{d}"),
Directive::ConfigOption(d) => write!(f, "{d}"),
Directive::Commodity(d) => write!(f, "{d}"),
Directive::Open(d) => write!(f, "{d}"),
Directive::Close(d) => write!(f, "{d}"),
Expand All @@ -809,13 +800,17 @@ impl fmt::Display for Directive {
#[cfg(test)]
mod tests {
use super::*;
use crate::loader;
use crate::{ledger::Ledger, loader};

#[test]
fn test_open() {
let text = r#"2023-01-01 open Assets:Bank GBP"#;
let entries = loader::load(&text);
let (dirs, _) = loader::consume(entries);
let Ledger {
dirs,
errs: _,
opts: _,
} = loader::consume(entries);
let date = NaiveDate::parse_from_str("2023-01-01", DATE_FMT).unwrap();
let a = &Open {
date,
Expand Down
8 changes: 8 additions & 0 deletions src/ledger.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use crate::data::{Directive, Options};
use crate::error::BeanError;

pub struct Ledger {
pub dirs: Vec<Directive>,
pub errs: Vec<BeanError>,
pub opts: Options,
}
30 changes: 18 additions & 12 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,45 +2,51 @@
//!
//! `bean-rs` is a [beancount](https://github.com/beancount/beancount) clone (one day...) in Rust
mod book;
mod data;
pub mod book;
pub mod data;
pub mod error;
mod grammar;
mod loader;
pub mod ledger;
pub mod loader;
pub mod utils;

use pyo3::prelude::*;

use data::AccBal;

use crate::data::Directive;
use crate::error::BeanError;
use crate::ledger::Ledger;

/// Loads the provided text into a Vec of Directives
/// containing opens, closes, transactions etc
pub fn load(text: String) -> (Vec<Directive>, Vec<BeanError>) {
pub fn load(text: String) -> Ledger {
let entries = loader::load(&text);
let (dirs, errs) = loader::consume(entries);
let mut dirs = dirs;
let ledger = loader::consume(entries);
let mut dirs = ledger.dirs;
loader::sort(&mut dirs);
book::balance_transactions(&mut dirs);
utils::debug_directives(&dirs);
(dirs, errs)
Ledger {
dirs,
errs: ledger.errs,
opts: ledger.opts,
}
}

/// Check and calculate balances for file at path
pub fn balance(path: &String) -> (AccBal, Vec<BeanError>) {
pub fn balance(path: &str) -> (AccBal, Vec<BeanError>) {
let text = std::fs::read_to_string(path).expect("cannot read file");
let (mut dirs, mut errs) = load(text);
let (bals, book_errs) = book::get_balances(&mut dirs);
let mut ledger = load(text);
let (bals, book_errs) = book::get_balances(&mut ledger.dirs);
let mut errs = ledger.errs;
errs.extend(book_errs);
(bals, errs)
}

/// Formats the sum of two numbers as string.
#[pyfunction]
fn py_balance(path: &str) -> PyResult<String> {
balance(&path.to_string());
balance(path);
Ok("Ok".to_string())
}

Expand Down
26 changes: 17 additions & 9 deletions src/loader.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ use log::debug;
use pest::iterators::Pairs;
use pest::Parser;

use crate::data::Directive;
use crate::data::{self, DebugLine};
use crate::data::{Directive, Options};
use crate::error::{BeanError, ErrorType};
use crate::grammar::{BeanParser, Rule};
use crate::ledger::Ledger;
use crate::utils;

/// Parse the text using Pest
Expand All @@ -23,16 +24,15 @@ pub fn load(data: &str) -> Pairs<'_, Rule> {
}

/// Convert the AST Pest Pairs into a Vec of Directives
pub fn consume(entries: Pairs<'_, Rule>) -> (Vec<Directive>, Vec<BeanError>) {
pub fn consume(entries: Pairs<'_, Rule>) -> Ledger {
let mut errs: Vec<BeanError> = Vec::with_capacity(entries.len());
let mut dirs: Vec<Directive> = Vec::new();
let mut opts = Options::default();
for entry in entries {
debug!("{:?}\t{:?}", entry.as_rule(), entry.as_span(),);
match entry.as_rule() {
Rule::option => {
dirs.push(Directive::ConfigOption(data::ConfigOption::from_entry(
entry,
)));
opts.update_from_entry(entry);
}
Rule::custom => {
dirs.push(Directive::ConfigCustom(data::ConfigCustom::from_entry(
Expand Down Expand Up @@ -86,7 +86,7 @@ pub fn consume(entries: Pairs<'_, Rule>) -> (Vec<Directive>, Vec<BeanError>) {
}
};
}
(dirs, errs)
Ledger { dirs, errs, opts }
}

/// Sort the Directives by date and `order` inplace
Expand All @@ -104,7 +104,11 @@ mod tests {
fn test_parse() {
let text = r#"2023-01-01 open Assets:Bank GBP"#;
let entries = load(&text);
let (dirs, _) = consume(entries);
let Ledger {
dirs,
errs: _,
opts: _,
} = consume(entries);
let got = &dirs[0];
match got {
Directive::Open(_) => (),
Expand All @@ -118,8 +122,12 @@ mod tests {
2023-01-01 foo
"#;
let entries = load(&text);
let (_, bad) = consume(entries);
assert!(bad.len() == 1);
let Ledger {
dirs: _,
errs,
opts: _,
} = consume(entries);
assert!(errs.len() == 1);
}

#[test]
Expand Down
1 change: 1 addition & 0 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ use std::process::Termination;

use clap::{Parser, Subcommand};

// extern crate bean_rs;
use bean_rs::balance;
use bean_rs::error::BeanError;
use bean_rs::utils;
Expand Down
44 changes: 42 additions & 2 deletions tests/integration_test.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,49 @@
use bean_rs;
use std::collections::HashMap;

use bean_rs::data::AccBal;
use bean_rs::ledger::Ledger;
use bean_rs::{balance, load};
use rust_decimal::Decimal;

#[test]
fn test_load() {
let text = std::fs::read_to_string("example.bean").expect("cannot read file");
let (dirs, _) = bean_rs::load(text);
let Ledger {
dirs,
errs: _,
opts: _,
} = load(text);
bean_rs::utils::print_directives(&dirs);
// TODO check the output!
}

#[test]
fn test_balance() {
let (bals, _) = balance("example.bean");
let want: AccBal = HashMap::from([
(
"Assets:Invest".to_string(),
HashMap::from([("GOO".to_string(), Decimal::new(111, 0))]),
),
(
"Income:Job".to_string(),
HashMap::from([("GBP".to_string(), Decimal::new(-1000, 0))]),
),
(
"Equity:Bals".to_string(),
HashMap::from([("GOO".to_string(), Decimal::new(-111, 0))]),
),
(
"Assets:Bank".to_string(),
HashMap::from([("GBP".to_string(), Decimal::new(86000, 2))]),
),
(
"Expenses:Food".to_string(),
HashMap::from([
("USD".to_string(), Decimal::new(4000, 2)),
("GBP".to_string(), Decimal::new(100, 0)),
]),
),
]);
assert!(bals.eq(&want));
}

0 comments on commit bd36286

Please sign in to comment.