hledger_parser/directive/
commodity.rs1use chumsky::prelude::*;
2
3use crate::component::amount::{amount, Amount};
4use crate::component::commodity::commodity as parse_commodity;
5use crate::component::whitespace::whitespace;
6use crate::state::State;
7use crate::utils::end_of_line;
8
9#[derive(Clone, Debug, PartialEq)]
10pub enum Commodity {
11 Amount(Amount),
12 Commodity(String),
13}
14
15pub fn commodity<'a>() -> impl Parser<'a, &'a str, Commodity, extra::Full<Rich<'a, char>, State, ()>>
16{
17 just("commodity")
18 .ignore_then(whitespace().repeated().at_least(1))
19 .ignore_then(
20 amount()
21 .map(Commodity::Amount)
22 .or(parse_commodity().map(Commodity::Commodity)),
23 )
24 .then_ignore(end_of_line())
25}
26
27#[cfg(test)]
28mod tests {
29 use rust_decimal::Decimal;
30
31 use super::*;
32
33 #[test]
34 fn with_symbol() {
35 let result = commodity()
36 .then_ignore(end())
37 .parse("commodity $1000.00")
38 .into_result();
39 assert_eq!(
40 result,
41 Ok(Commodity::Amount(Amount {
42 commodity: String::from("$"),
43 quantity: Decimal::new(100_000, 2),
44 }))
45 );
46 }
47
48 #[test]
49 fn no_symbol() {
50 let result = commodity()
51 .then_ignore(end())
52 .parse("commodity 1,000,000.0000")
53 .into_result();
54 assert_eq!(
55 result,
56 Ok(Commodity::Amount(Amount {
57 commodity: String::new(),
58 quantity: Decimal::new(10_000_000_000, 4),
59 }))
60 );
61 }
62
63 #[test]
64 fn comment() {
65 let result = commodity()
66 .then_ignore(end())
67 .parse("commodity 1. USD ; with comment")
68 .into_result();
69 assert_eq!(
70 result,
71 Ok(Commodity::Amount(Amount {
72 commodity: String::from("USD"),
73 quantity: Decimal::new(1, 0),
74 }))
75 );
76 }
77
78 #[test]
79 fn just_currency() {
80 let result = commodity()
81 .then_ignore(end())
82 .parse("commodity \"AAAA 2023\" ")
83 .into_result();
84 assert_eq!(result, Ok(Commodity::Commodity(String::from("AAAA 2023"))));
85 }
86}