Skip to content

Commit 0c91c84

Browse files
authored
[New Exercise] Ledger (exercism#2398)
* Adding autogenerated files * Adding scaffolding, tests and solution * Accidentally deleted a key in `config.json` * Update proof.ci.js
1 parent 2447138 commit 0c91c84

13 files changed

Lines changed: 569 additions & 0 deletions

File tree

‎config.json‎

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2598,6 +2598,16 @@
25982598
"strings"
25992599
],
26002600
"difficulty": 2
2601+
},
2602+
{
2603+
"slug": "ledger",
2604+
"name": "Ledger",
2605+
"uuid": "8716b347-e18f-48a6-b373-426cc4ca98cb",
2606+
"practices": [],
2607+
"prerequisites": [
2608+
"string-formatting"
2609+
],
2610+
"difficulty": 5
26012611
}
26022612
]
26032613
},
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# Instructions
2+
3+
Refactor a ledger printer.
4+
5+
The ledger exercise is a refactoring exercise.
6+
There is code that prints a nicely formatted ledger, given a locale (American or Dutch) and a currency (US dollar or euro).
7+
The code however is rather badly written, though (somewhat surprisingly) it consistently passes the test suite.
8+
9+
Rewrite this code.
10+
Remember that in refactoring the trick is to make small steps that keep the tests passing.
11+
That way you can always quickly go back to a working version.
12+
Version control tools like git can help here as well.
13+
14+
Please keep a log of what changes you've made and make a comment on the exercise containing that log, this will help reviewers.
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{
2+
"root": true,
3+
"extends": "@exercism/eslint-config-javascript",
4+
"env": {
5+
"jest": true
6+
},
7+
"overrides": [
8+
{
9+
"files": [".meta/proof.ci.js", ".meta/exemplar.js", "*.spec.js"],
10+
"excludedFiles": ["custom.spec.js"],
11+
"extends": "@exercism/eslint-config-javascript/maintainers"
12+
}
13+
]
14+
}
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
/node_modules
2+
/bin/configlet
3+
/bin/configlet.exe
4+
/pnpm-lock.yaml
5+
/yarn.lock
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
{
2+
"authors": [
3+
"Cool-Katt"
4+
],
5+
"files": {
6+
"solution": [
7+
"ledger.js"
8+
],
9+
"test": [
10+
"ledger.spec.js"
11+
],
12+
"example": [
13+
".meta/proof.ci.js"
14+
]
15+
},
16+
"blurb": "Refactor a ledger printer."
17+
}
Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
class LedgerEntry {
2+
constructor(date, description, change) {
3+
this.date = new Date(date);
4+
this.description = description;
5+
this.change = change;
6+
}
7+
}
8+
9+
class FormattedLedgerEntry {
10+
constructor(entry, locale, dateFormat, currencyFormat) {
11+
this.entry = entry;
12+
this.locale = locale;
13+
this.dateFormat = dateFormat;
14+
this.currencyFormat = currencyFormat;
15+
}
16+
17+
date() {
18+
return this.entry.date.toLocaleDateString(this.locale, this.dateFormat);
19+
}
20+
21+
description(length = 25) {
22+
if (this.entry.description.length > length) {
23+
return `${this.entry.description.substring(0, length - 3)}...`;
24+
}
25+
26+
return this.entry.description.padEnd(length, ' ');
27+
}
28+
29+
change(offset = 13) {
30+
const formatted = (this.entry.change / 100).toLocaleString(
31+
this.locale,
32+
this.currencyFormat,
33+
);
34+
35+
const trailingSpace = formatted.includes(')') ? '' : ' ';
36+
return `${formatted}${trailingSpace}`.padStart(offset, ' ');
37+
}
38+
39+
toTableRow() {
40+
return [this.date(), this.description(), this.change()].join(' | ');
41+
}
42+
}
43+
44+
const OPTIONS = {
45+
HEADERS: {
46+
'en-US': ['Date', 'Description', 'Change'],
47+
'nl-NL': ['Datum', 'Omschrijving', 'Verandering'],
48+
},
49+
headerRow: function (locale) {
50+
const [date, description, change] = this.HEADERS[locale];
51+
return [
52+
date.padEnd(10, ' '),
53+
description.padEnd(25, ' '),
54+
change.padEnd(13, ' '),
55+
].join(' | ');
56+
},
57+
dateFormatOptions: function () {
58+
return {
59+
day: '2-digit',
60+
month: '2-digit',
61+
year: 'numeric',
62+
};
63+
},
64+
currencyFormatOptions: function (currency, locale) {
65+
return {
66+
style: 'currency',
67+
currency: currency,
68+
currencySign: locale === 'en-US' ? 'accounting' : 'standard',
69+
currencyDisplay: locale === 'en-US' ? 'symbol' : 'narrowSymbol',
70+
};
71+
},
72+
};
73+
74+
export const createEntry = (date, description, change) =>
75+
new LedgerEntry(date, description, change);
76+
77+
export function formatEntries(currency, locale, entries) {
78+
let dateFormat = OPTIONS.dateFormatOptions();
79+
let currencyFormat = OPTIONS.currencyFormatOptions(currency, locale);
80+
81+
let rows = entries
82+
.sort(
83+
(a, b) =>
84+
a.date - b.date ||
85+
a.change - b.change ||
86+
a.description.localeCompare(b.description),
87+
)
88+
.map((entry) => {
89+
let formattedEntry = new FormattedLedgerEntry(
90+
entry,
91+
locale,
92+
dateFormat,
93+
currencyFormat,
94+
);
95+
return formattedEntry.toTableRow();
96+
});
97+
98+
return [OPTIONS.headerRow(locale), ...rows].join('\n');
99+
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# This is an auto-generated file.
2+
#
3+
# Regenerating this file via `configlet sync` will:
4+
# - Recreate every `description` key/value pair
5+
# - Recreate every `reimplements` key/value pair, where they exist in problem-specifications
6+
# - Remove any `include = true` key/value pair (an omitted `include` key implies inclusion)
7+
# - Preserve any other key/value pair
8+
#
9+
# As user-added comments (using the # character) will be removed when this file
10+
# is regenerated, comments can be added via a `comment` key.
11+
12+
[d131ecae-a30e-436c-b8f3-858039a27234]
13+
description = "empty ledger"
14+
15+
[ce4618d2-9379-4eca-b207-9df1c4ec8aaa]
16+
description = "one entry"
17+
18+
[8d02e9cb-e6ee-4b77-9ce4-e5aec8eb5ccb]
19+
description = "credit and debit"
20+
21+
[502c4106-0371-4e7c-a7d8-9ce33f16ccb1]
22+
description = "multiple entries on same date ordered by description"
23+
include = false
24+
25+
[29dd3659-6c2d-4380-94a8-6d96086e28e1]
26+
description = "final order tie breaker is change"
27+
28+
[9b9712a6-f779-4f5c-a759-af65615fcbb9]
29+
description = "overlong description is truncated"
30+
31+
[67318aad-af53-4f3d-aa19-1293b4d4c924]
32+
description = "euros"
33+
34+
[bdc499b6-51f5-4117-95f2-43cb6737208e]
35+
description = "Dutch locale"
36+
37+
[86591cd4-1379-4208-ae54-0ee2652b4670]
38+
description = "Dutch locale and euros"
39+
40+
[876bcec8-d7d7-4ba4-82bd-b836ac87c5d2]
41+
description = "Dutch negative number with 3 digits before decimal point"
42+
43+
[29670d1c-56be-492a-9c5e-427e4b766309]
44+
description = "American negative number with 3 digits before decimal point"
45+
46+
[9c70709f-cbbd-4b3b-b367-81d7c6101de4]
47+
description = "multiple entries on same date ordered by description"
48+
reimplements = "502c4106-0371-4e7c-a7d8-9ce33f16ccb1"

‎exercises/practice/ledger/.npmrc‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
audit=false

‎exercises/practice/ledger/LICENSE‎

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2021 Exercism
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
module.exports = {
2+
presets: ['@exercism/babel-preset-javascript'],
3+
plugins: [],
4+
};

0 commit comments

Comments
 (0)