Skip to content

Commit

Permalink
v0.5.0 update
Browse files Browse the repository at this point in the history
  • Loading branch information
Arnaud-Ceccaldi committed Nov 14, 2015
1 parent b1c7fcc commit 163e85f
Show file tree
Hide file tree
Showing 9 changed files with 188 additions and 106 deletions.
14 changes: 14 additions & 0 deletions .editorconfig
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
root = true

[*]
end_of_line = lf
insert_final_newline = true
indent_style = space
indent_size = 4
trim_trailing_whitespace = true

[*.json]
indent_size = 2

[*.md]
trim_trailing_whitespace = false
1 change: 1 addition & 0 deletions .nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v4.2.2
21 changes: 11 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ var Money = require('js-money');
There are multiple options of what to pass into the constructor to create a new Money instance:
* amount as number, currency as string
* amount as number, currency as object
* object with amount and currency fields
* object with amount and currency fields (only with `fromInteger` and `fromDecimal` methods)

Amounts can be supplied either as integers or decimal numbers.

Expand All @@ -36,13 +36,12 @@ Instances of Money are immutable and each arithmetic operation will return a new
When using decimals the library will allow only decimals with the precision allowed by the currencies smallest unit.

```javascript

var fiveEur = new Money(500, Money.EUR);
var someDollars = new Money(15.25, 'USD');
var tenDollars = new Money({amount: 100, currency: Money.USD});
var tenDollars = Money.fromInteger({ amount: 1000, currency: Money.USD });
var someDollars = Money.fromDecimal(15.25, 'USD');

// the following will fail and throw an Error since USD allows for 2 decimals
var moreDollars = new Money(15.3456, Money.USD); //
var moreDollars = Money.fromDecimal(15.3456, Money.USD);
```

The currency object hold the following properties
Expand All @@ -67,16 +66,18 @@ Arithmetic operations involving multiple objects are only possible on instances
var fiveEur = new Money(500, Money.EUR); // 5 EUR

// add
var result = fiveEur.add(250, Money.EUR); // 7.50 EUR
fiveEur.add(250, Money.EUR); // 7.50 EUR

// subtract
var result = fiveEur.subtract(470, Money.EUR); // 0.30 EUR
fiveEur.subtract(470, Money.EUR); // 0.30 EUR

// multiply
var result = fiveEur.multiply(1.2); // 6 EUR
fiveEur.multiply(1.2345); // 6.17 EUR
fiveEur.multiply(1.2345, Math.ceil); // 6.18 EUR

// divide
var result = fiveEur.divide(2); // 2.50 EUR
fiveEur.divide(2.3456); // 2.13 EUR
fiveEur.divide(2.3456, Math.ceil); // 2.14 EUR
```

### Allocating funds
Expand All @@ -88,7 +89,7 @@ var tenEur = new Money(1000, Money.EUR);

// divide 10 EUR into 3 parts
var shares = tenEur.allocate([1,1,1]);
// returns an array of money worth [334,333,333]
// returns an array of Money instances worth [334,333,333]

// split 5 EUR 70/30
var fiveEur = new Money(500, Money.EUR);
Expand Down
4 changes: 2 additions & 2 deletions bower.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "js-money",
"description": "JavaScript implementation of the Money value object.",
"version": "0.4.0",
"version": "0.5.0",
"main": "./lib",
"author": {
"name": "David Kalosi",
Expand All @@ -19,7 +19,7 @@
"url": "https://github.com/davidkalosi/js-money/issues"
},
"dependencies": {
"lodash": "*"
"lodash": "3.x.x"
},
"devDependencies": {
"mocha": "1.x.x",
Expand Down
2 changes: 1 addition & 1 deletion lib/currency.js
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,7 @@ var currencies = {
"code": "ZMK",
"name_plural": "Zambian kwachas"
}
}
};

Object.keys(currencies).forEach(function (currency) {
module.exports[currency] = currencies[currency];
Expand Down
4 changes: 1 addition & 3 deletions lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,4 @@
* file that was distributed with this source code.
*/

var money = require('./money');

module.exports = money;
module.exports = require('./money');
180 changes: 101 additions & 79 deletions lib/money.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,35 @@
var _ = require('lodash');
var currencies = require('./currency');

var isInt = function (n) {
return Number(n) === n && n % 1 === 0;
};

var decimalPlaces = function (num) {
var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);

if (!match)
return 0;

return Math.max(0,
(match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
};

var assertSameCurrency = function (left, right) {
if (left.currency !== right.currency)
throw new Error('Different currencies');
};

var assertType = function (other) {
if (!(other instanceof Money))
throw new TypeError('Instance of Money required');
};

var assertOperand = function (operand) {
if (isNaN(parseFloat(operand)) && !isFinite(operand))
throw new TypeError('Operand must be a number');
};

/**
* Creates a new Money instance.
* The created Money instances is a value object thus it is immutable.
Expand All @@ -34,33 +63,45 @@ function Money(amount, currency) {
Object.freeze(this);
}

var isInt = function(n){
return Number(n) === n && n % 1 === 0;
};
Money.fromInteger = function (amount, currency) {
if (_.isObject(amount)) {
if (amount.amount === undefined || amount.currency === undefined)
throw new TypeError('Missing required parameters amount,currency');

var decimalPlaces = function(num) {
var match = ('' + num).match(/(?:\.(\d+))?(?:[eE]([+-]?\d+))?$/);

if (!match)
return 0;

return Math.max(0,
(match[1] ? match[1].length : 0) - (match[2] ? +match[2] : 0));
};
currency = amount.currency;
amount = amount.amount;
}

var assertSameCurrency = function(left, right) {
if (left.currency !== right.currency)
throw new Error('Different currencies');
};
if (!isInt(amount))
throw new TypeError('Amount must be an integer value');

var assertType = function(other) {
if (!(other instanceof Money))
throw new TypeError('Instance of Money required');
return new Money(amount, currency);
};

var assertOperand = function(operand) {
if (isNaN(parseFloat(operand)) && !isFinite(operand))
throw new TypeError('Operand must be a number');
Money.fromDecimal = function (amount, currency) {
var multipliers = [1, 10, 100, 1000];

if (_.isObject(amount)) {
if (amount.amount === undefined || amount.currency === undefined)
throw new TypeError('Missing required parameters amount,currency');

currency = amount.currency;
amount = amount.amount;
}

if (_.isString(currency))
currency = currencies[currency];

if (!_.isPlainObject(currency))
throw new TypeError('Invalid currency');

var decimals = decimalPlaces(amount);

if (decimals > currency.decimal_digits)
throw new Error("The currency " + currency.code + " supports only "
+ currency.decimal_digits + " decimal digits");

return new Money(amount * multipliers[currency.decimal_digits], currency);
};

/**
Expand All @@ -69,7 +110,7 @@ var assertOperand = function(operand) {
* @param {Money} other
* @returns {Boolean}
*/
Money.prototype.equals = function(other) {
Money.prototype.equals = function (other) {
var self = this;
assertType(other);

Expand All @@ -83,7 +124,7 @@ Money.prototype.equals = function(other) {
* @param {Money} other
* @returns {Money}
*/
Money.prototype.add = function(other) {
Money.prototype.add = function (other) {
var self = this;
assertType(other);
assertSameCurrency(self, other);
Expand All @@ -97,7 +138,7 @@ Money.prototype.add = function(other) {
* @param {Money} other
* @returns {Money}
*/
Money.prototype.subtract = function(other) {
Money.prototype.subtract = function (other) {
var self = this;
assertType(other);
assertSameCurrency(self, other);
Expand All @@ -109,11 +150,15 @@ Money.prototype.subtract = function(other) {
* Multiplies the object by the multiplier returning a new Money instance that holds the result of the operation.
*
* @param {Number} multiplier
* @param {Function} [fn=Math.round]
* @returns {Money}
*/
Money.prototype.multiply = function(multiplier) {
Money.prototype.multiply = function (multiplier, fn) {
if (!_.isFunction(fn))
fn = Math.round;

assertOperand(multiplier);
var amount = Math.round(this.amount * multiplier);
var amount = fn(this.amount * multiplier);

return new Money(amount, this.currency);
};
Expand All @@ -122,11 +167,15 @@ Money.prototype.multiply = function(multiplier) {
* Divides the object by the multiplier returning a new Money instance that holds the result of the operation.
*
* @param {Number} divisor
* @param {Function} [fn=Math.round]
* @returns {Money}
*/
Money.prototype.divide = function(divisor) {
Money.prototype.divide = function (divisor, fn) {
if (!_.isFunction(fn))
fn = Math.round;

assertOperand(divisor);
var amount = Math.round(this.amount / divisor);
var amount = fn(this.amount / divisor);

return new Money(amount, this.currency);
};
Expand All @@ -137,17 +186,17 @@ Money.prototype.divide = function(divisor) {
* @param {Array} other
* @returns {Array.Money}
*/
Money.prototype.allocate = function(ratios) {
Money.prototype.allocate = function (ratios) {
var self = this;
var remainder = self.amount;
var results = [];
var total = 0;

ratios.forEach(function(ratio) {
ratios.forEach(function (ratio) {
total += ratio;
});

ratios.forEach(function(ratio) {
ratios.forEach(function (ratio) {
var share = Math.floor(self.amount * ratio / total)
results.push(new Money(share, self.currency));
remainder -= share;
Expand All @@ -167,7 +216,7 @@ Money.prototype.allocate = function(ratios) {
* @param {Money} other
* @returns {Number}
*/
Money.prototype.compare = function(other) {
Money.prototype.compare = function (other) {
var self = this;

assertType(other);
Expand All @@ -184,7 +233,7 @@ Money.prototype.compare = function(other) {
*
* @returns {boolean}
*/
Money.prototype.isZero = function() {
Money.prototype.isZero = function () {
return this.amount === 0;
};

Expand All @@ -193,7 +242,7 @@ Money.prototype.isZero = function() {
*
* @returns {boolean}
*/
Money.prototype.isPositive = function() {
Money.prototype.isPositive = function () {
return this.amount > 0;
};

Expand All @@ -202,54 +251,27 @@ Money.prototype.isPositive = function() {
*
* @returns {boolean}
*/
Money.prototype.isNegative = function() {
Money.prototype.isNegative = function () {
return this.amount < 0;
};

module.exports = Money;

module.exports.fromInteger = function (amount, currency) {
if (_.isObject(amount)) {
if (amount.amount === undefined || amount.currency === undefined)
throw new TypeError('Missing required parameters amount,currency');

currency = amount.currency;
amount = amount.amount;
}

if (!isInt(amount))
throw new TypeError('Amount must be an integer value');

return new Money(amount, currency);
/**
* Returns the decimal value as a float.
*
* @returns {number}
*/
Money.prototype.toDecimal = function () {
return Number(this.toString());
};

module.exports.fromDecimal = function(amount, currency) {
var multipliers = [0, 10, 100, 1000];

if (_.isObject(amount)) {
if (amount.amount === undefined || amount.currency === undefined)
throw new TypeError('Missing required parameters amount,currency');

currency = amount.currency;
amount = amount.amount;
}

if (isInt(amount))
throw new TypeError('Amount must be a decimal value');

if (_.isString(currency))
currency = currencies[currency];

if (!_.isPlainObject(currency))
throw new TypeError('Invalid currency');

var decimals = decimalPlaces(amount);

if (decimals > currency.decimal_digits)
throw new Error("The currency " + currency.code + " supports only "
+ currency.decimal_digits + " decimal digits");

return new Money(decimals > 0 ? amount * multipliers[currency.decimal_digits] : amount, currency);
/**
* Returns the decimal value as a string.
*
* @returns {string}
*/
Money.prototype.toJSON = Money.prototype.toString = function () {
var currency = currencies[this.currency];
return (this.amount / Math.pow(10, currency.decimal_digits)).toFixed(currency.decimal_digits);
};

module.exports = _.extend(module.exports, currencies);
module.exports = _.extend(Money, currencies);

0 comments on commit 163e85f

Please sign in to comment.