summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Wiegley <johnw@newartisans.com>2012-03-09 20:02:53 -0600
committerJohn Wiegley <johnw@newartisans.com>2012-03-09 20:02:53 -0600
commit2df8edc71c1e805fd54c2208b2b66bdde0460c59 (patch)
tree8a5aefa71d8713c4fe7d91df02f8046d18a9fe8c
parentcbc7bd337bf523e9424c789a87be1d4a360740b2 (diff)
downloadfork-ledger-2df8edc71c1e805fd54c2208b2b66bdde0460c59.tar.gz
fork-ledger-2df8edc71c1e805fd54c2208b2b66bdde0460c59.tar.bz2
fork-ledger-2df8edc71c1e805fd54c2208b2b66bdde0460c59.zip
Improved the behavior of -X
-rw-r--r--src/system.hh.in2
-rw-r--r--src/value.cc101
-rwxr-xr-xtest/RegressTests.py2
-rw-r--r--test/baseline/opt-exchange.test57
-rw-r--r--test/regress/83B4A0E5.test43
5 files changed, 192 insertions, 13 deletions
diff --git a/src/system.hh.in b/src/system.hh.in
index fcc8e2ce..a38deb1f 100644
--- a/src/system.hh.in
+++ b/src/system.hh.in
@@ -185,6 +185,8 @@ typedef std::ostream::pos_type ostream_pos_type;
#include <boost/regex.hpp>
#endif // HAVE_BOOST_REGEX_UNICODE
+#include <boost/tokenizer.hpp>
+
#include <boost/tuple/tuple.hpp>
#include <boost/tuple/tuple_comparison.hpp>
diff --git a/src/value.cc b/src/value.cc
index 6e1ed79d..87b31cd6 100644
--- a/src/value.cc
+++ b/src/value.cc
@@ -1436,21 +1436,96 @@ value_t value_t::exchange_commodities(const std::string& commodities,
const bool add_prices,
const optional<datetime_t>& moment)
{
- scoped_array<char> buf(new char[commodities.length() + 1]);
-
- std::strcpy(buf.get(), commodities.c_str());
-
- for (char * p = std::strtok(buf.get(), ",");
- p;
- p = std::strtok(NULL, ",")) {
- if (commodity_t * commodity =
- commodity_pool_t::current_pool->parse_price_expression(p, add_prices,
- moment)) {
- value_t result = value(moment, *commodity);
- if (! result.is_null())
- return result;
+ if (type() == SEQUENCE) {
+ value_t temp;
+ foreach (value_t& value, as_sequence_lval())
+ temp.push_back(value.exchange_commodities(commodities, add_prices, moment));
+ return temp;
+ }
+
+ // If we are repricing to just a single commodity, with no price
+ // expression, skip the expensive logic below.
+ if (commodities.find(',') == string::npos &&
+ commodities.find('=') == string::npos)
+ return value(moment, *commodity_pool_t::current_pool->find_or_create(commodities));
+
+ std::vector<commodity_t *> comms;
+ std::vector<bool> force;
+
+ typedef tokenizer<char_separator<char> > tokenizer;
+ tokenizer tokens(commodities, char_separator<char>(","));
+
+ foreach (const string& name, tokens) {
+ string::size_type name_len = name.length();
+
+ if (commodity_t * commodity = commodity_pool_t::current_pool
+ ->parse_price_expression(name[name_len - 1] == '!' ?
+ string(name, 0, name_len - 1) :
+ name, add_prices, moment)) {
+ DEBUG("commodity.exchange", "Pricing for commodity: " << commodity->symbol());
+ comms.push_back(&commodity->referent());
+ force.push_back(name[name_len - 1] == '!');
+ }
+ }
+
+ int index = 0;
+ foreach (commodity_t * comm, comms) {
+ switch (type()) {
+ case AMOUNT:
+ DEBUG("commodity.exchange", "We have an amount: " << as_amount_lval());
+ if (! force[index] &&
+ std::find(comms.begin(), comms.end(),
+ &as_amount_lval().commodity().referent()) != comms.end())
+ break;
+
+ DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
+ if (optional<amount_t> val = as_amount_lval().value(moment, *comm)) {
+ DEBUG("commodity.exchange", "Re-priced amount is: " << *val);
+ return *val;
+ }
+ DEBUG("commodity.exchange", "Was unable to find a price");
+ break;
+
+ case BALANCE: {
+ balance_t temp;
+ bool repriced = false;
+
+ DEBUG("commodity.exchange", "We have a balance: " << as_balance_lval());
+ foreach (const balance_t::amounts_map::value_type& pair,
+ as_balance_lval().amounts) {
+ DEBUG("commodity.exchange", "We have a balance amount of commodity: "
+ << pair.first->symbol() << " == "
+ << pair.second.commodity().symbol());
+ if (! force[index] &&
+ std::find(comms.begin(), comms.end(),
+ &pair.first->referent()) != comms.end()) {
+ temp += pair.second;
+ } else {
+ DEBUG("commodity.exchange", "Referent doesn't match, pricing...");
+ if (optional<amount_t> val = pair.second.value(moment, *comm)) {
+ DEBUG("commodity.exchange", "Re-priced member amount is: " << *val);
+ temp += *val;
+ repriced = true;
+ } else {
+ DEBUG("commodity.exchange", "Was unable to find price");
+ temp += pair.second;
+ }
+ }
+ }
+
+ if (repriced) {
+ DEBUG("commodity.exchange", "Re-priced balance is: " << temp);
+ return temp;
+ }
}
+
+ default:
+ break;
+ }
+
+ ++index;
}
+
return *this;
}
diff --git a/test/RegressTests.py b/test/RegressTests.py
index da5d92ca..a22e35bf 100755
--- a/test/RegressTests.py
+++ b/test/RegressTests.py
@@ -149,6 +149,8 @@ class RegressFile(object):
harness.success()
else:
harness.failure(os.path.basename(self.filename))
+ print "STDERR:"
+ print p.stderr.read()
else:
if success: print
if test['exitcode']:
diff --git a/test/baseline/opt-exchange.test b/test/baseline/opt-exchange.test
index cfc48c3f..f5d73f78 100644
--- a/test/baseline/opt-exchange.test
+++ b/test/baseline/opt-exchange.test
@@ -53,6 +53,63 @@ test reg --exchange=' C, A '
Assets:Brokerage -75 A 75 A
09-Jan-01 January 1st, 2009 (3) Assets:Brokerage 100 A 175 A
Assets:Brokerage -100 A 75 A
+09-Jan-02 Commodities revalued <Revalued> 225 A
+ -1800 C 300 A
+ -1800 C
+09-Jan-02 January 2nd, 2009 Assets:Brokerage 500 C 300 A
+ -1300 C
+ Assets:Brokerage -500 C 300 A
+ -1800 C
+09-Jan-03 January 3rd, 2009 Assets:Brokerage 600 C 300 A
+ -1200 C
+ Assets:Brokerage -600 C 300 A
+ -1800 C
+09-Jan-04 January 4th, 2009 Assets:Brokerage 300 A 600 A
+ -1800 C
+ Assets:Brokerage -2400 C 600 A
+ -4200 C
+09-Jan-05 January 5th, 2009 Assets:Brokerage 1280 C 600 A
+ -2920 C
+ Assets:Brokerage -1280 C 600 A
+ -4200 C
+09-Jan-06 Commodities revalued <Revalued> 2040 C 600 A
+ -2160 C
+09-Jan-06 January 6th, 2009 Assets:Brokerage 155 A 755 A
+ -2160 C
+ Assets:Brokerage -186 C 755 A
+ -2346 C
+09-Jan-07 Commodities revalued <Revalued> -86 C 755 A
+ -2432 C
+09-Jan-07 January 7th, 2009 Assets:Brokerage 155 A 910 A
+ -2432 C
+ Assets:Brokerage -200 C 910 A
+ -2632 C
+09-Jan-08 Commodities revalued <Revalued> -5613 C 910 A
+ -8245 C
+09-Jan-08 January 8th, 2009 Assets:Brokerage 155 A 1065 A
+ -8245 C
+ Assets:Brokerage -200 C 1065 A
+ -8445 C
+09-Jan-09 Commodities revalued <Revalued> -2800 C 1065 A
+ -11245 C
+09-Jan-09 January 9th, 2009 Assets:Brokerage 200 C 1065 A
+ -11045 C
+ Assets:Brokerage -155 A 910 A
+ -11045 C
+09-Jan-10 January 10th, 2009 Assets:Brokerage 200 C 910 A
+ -10845 C
+ Assets:Brokerage -155 A 755 A
+ -10845 C
+end test
+
+
+test reg --exchange=' C!, A '
+09-Jan-01 January 1st, 2009 (1) Assets:Brokerage 100 A 100 A
+ Assets:Brokerage -50 A 50 A
+09-Jan-01 January 1st, 2009 (2) Assets:Brokerage 100 A 150 A
+ Assets:Brokerage -75 A 75 A
+09-Jan-01 January 1st, 2009 (3) Assets:Brokerage 100 A 175 A
+ Assets:Brokerage -100 A 75 A
09-Jan-02 Commodities revalued <Revalued> 0 600 C
09-Jan-02 January 2nd, 2009 Assets:Brokerage 500 C 1100 C
Assets:Brokerage -500 C 600 C
diff --git a/test/regress/83B4A0E5.test b/test/regress/83B4A0E5.test
new file mode 100644
index 00000000..f9402a2d
--- /dev/null
+++ b/test/regress/83B4A0E5.test
@@ -0,0 +1,43 @@
+P 2012-03-01 EUR $2
+P 2012-03-01 GBP $2
+
+2012-03-05 KFC
+ Expenses:Food 10 EUR
+ Assets:Cash
+
+2012-03-10 KFC
+ Expenses:Food 10 GBP
+ Assets:Cash
+
+test reg food
+12-Mar-05 KFC Expenses:Food 10 EUR 10 EUR
+12-Mar-10 KFC Expenses:Food 10 GBP 10 EUR
+ 10 GBP
+end test
+
+test reg food -V
+12-Mar-05 KFC Expenses:Food $20 $20
+12-Mar-10 KFC Expenses:Food $20 $40
+end test
+
+test reg food -X '$'
+12-Mar-05 KFC Expenses:Food $20 $20
+12-Mar-10 KFC Expenses:Food $20 $40
+end test
+
+test reg food -X '$,GBP'
+12-Mar-05 KFC Expenses:Food $20 $20
+12-Mar-10 KFC Expenses:Food 10 GBP $20
+ 10 GBP
+end test
+
+test reg food -X '$!,GBP'
+12-Mar-05 KFC Expenses:Food $20 $20
+12-Mar-10 KFC Expenses:Food $20 $40
+end test
+
+test reg food -X '$,EUR'
+12-Mar-05 KFC Expenses:Food 10 EUR 10 EUR
+12-Mar-10 KFC Expenses:Food $20 $20
+ 10 EUR
+end test