Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

Enhance comparison of monetary amounts, enhance min & max #2

Merged
merged 5 commits into from

2 participants

@bpoweski

Good day,

I've added support for >, >=, < and <= using the underlying Joda money methods. In addition, I've overloaded the airity of max and min to for consistency with how clojure.core/max and clojure.core/min behave with additional arguments.

@michaelklishin

Good idea. Can we type hint the return values?

@michaelklishin michaelklishin merged commit 69399e5 into clojurewerkz:master
@michaelklishin

I released 1.1.0 with this change in. Thank you.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
View
17 ChangeLog.md
@@ -1,7 +1,22 @@
## Changes between 1.0.0 and 1.1.0
-No changes yet.
+It is possible to compare monetary amounts using >, >=, < and <=.
+```clojure
+(require '[clojurewerkz.money.amounts :as ma])
+(require '[clojurewerkz.money.currencies :as mc])
+
+(ma/< (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100))
+;= false
+
+(ma/<= (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 120))
+;= true
+
+(ma/>= (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 120))
+;= false
+
+(ma/> (ma/amount-of mc/USD 200) (ma/amount-of mc/USD 100))
+;= true
## Changes between 1.0.0-beta2 and 1.0.0
View
20 README.md
@@ -111,6 +111,25 @@ It is possible to add up all monies in a collection or sequence using `clojurewe
;= USD 110
```
+It is possible to compare monetary amounts using >, >=, < and <=.
+
+```clojure
+(require '[clojurewerkz.money.amounts :as ma])
+(require '[clojurewerkz.money.currencies :as mc])
+
+(ma/< (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100))
+;= false
+
+(ma/<= (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 120))
+;= true
+
+(ma/>= (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 100) (ma/amount-of mc/USD 120))
+;= false
+
+(ma/> (ma/amount-of mc/USD 200) (ma/amount-of mc/USD 100))
+;= true
+```
+
### Rounding
`clojurewerkz.money.amounts/round` is a function that performs rounding of
@@ -139,7 +158,6 @@ monetary values using one of the rounding modes:
```
-
### Currencies
Currency units use their ISO-4217 codes and represented by `org.joda.money.CurrencyUnit` instances.
View
72 src/clojure/clojurewerkz/money/amounts.clj
@@ -1,6 +1,6 @@
(ns clojurewerkz.money.amounts
"Operations on monetary amounts, including conversion, parsing, and predicates"
- (:refer-clojure :exclude [zero? max min])
+ (:refer-clojure :exclude [zero? max min > >= < <=])
(:require [clojurewerkz.money.conversion :as cnv])
(:import [org.joda.money Money BigMoney CurrencyUnit MoneyUtils]
[java.math RoundingMode BigDecimal]))
@@ -128,14 +128,72 @@
(.abs money))
(defn ^Money max
- "Returns the greater of the two money amounts"
- [^Money a ^Money b]
- (MoneyUtils/max a b))
+ "Returns the greatest of the given money amounts"
+ ([a] a)
+ ([^Money a ^Money b]
+ (MoneyUtils/max a b))
+ ([a b & more]
+ (reduce max (max a b) more)))
(defn ^Money min
- "Returns the lesser of the two money amounts"
- [^Money a ^Money b]
- (MoneyUtils/min a b))
+ "Returns the least of the given money amounts"
+ ([a] a)
+ ([^Money a ^Money b]
+ (MoneyUtils/min a b))
+ ([a b & more]
+ (reduce min (min a b) more)))
+
+(defn ^boolean >
+ "Returns true if the given money amounts are in monotonically decreasing order,
+ otherwise false."
+ ([a] a)
+ ([^Money a ^Money b]
+ (.isGreaterThan a b))
+ ([a b & more]
+ (if (> a b)
+ (if (next more)
+ (recur a (first more) (next more))
+ (> b (first more)))
+ false)))
+
+(defn ^boolean >=
+ "Returns true if the given money amounts are in monotonically non-increasing order,
+ otherwise false."
+ ([a] a)
+ ([^Money a ^Money b]
+ (or (.isGreaterThan a b) (= a b)))
+ ([a b & more]
+ (if (>= a b)
+ (if (next more)
+ (recur b (first more) (next more))
+ (>= b (first more)))
+ false)))
+
+(defn ^boolean <
+ "Returns true if the given money amounts are in monotonically decreasing order,
+ otherwise false."
+ ([a] a)
+ ([^Money a ^Money b]
+ (.isLessThan a b))
+ ([a b & more]
+ (if (< a b)
+ (if (next more)
+ (recur a (first more) (next more))
+ (< b (first more)))
+ false)))
+
+(defn ^boolean <=
+ "Returns true if the given money amounts are in monotonically non-decreasing order,
+ otherwise false."
+ ([a] a)
+ ([^Money a ^Money b]
+ (or (.isLessThan a b) (= a b)))
+ ([a b & more]
+ (if (<= a b)
+ (if (next more)
+ (recur a (first more) (next more))
+ (<= b (first more)))
+ false)))
(defn ^Money round
"Rounds monetary amount using the given scale and rounding mode.
View
55 test/clojurewerkz/money/amounts_test.clj
@@ -216,14 +216,65 @@
(deftest test-max
+ (is (= (ams/amount-of cu/USD 10) (ams/max (ams/amount-of cu/USD 10))))
+ (is (= (ams/amount-of cu/GBP 3) (ams/max (ams/amount-of cu/GBP 3))))
(are [a b c] (is (= c (ams/max a b)))
(ams/amount-of cu/USD 10) (ams/amount-of cu/USD 20) (ams/amount-of cu/USD 20)
- (ams/amount-of cu/GBP 30) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 30)))
+ (ams/amount-of cu/GBP 30) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 30))
+ (are [a b c d] (is (= d (ams/max a b c)))
+ (ams/amount-of cu/USD 5) (ams/amount-of cu/USD 20) (ams/amount-of cu/USD 10) (ams/amount-of cu/USD 20)
+ (ams/amount-of cu/GBP 8) (ams/amount-of cu/GBP 3) (ams/amount-of cu/GBP 6) (ams/amount-of cu/GBP 8)))
(deftest test-min
+ (is (= (ams/amount-of cu/USD 10) (ams/min (ams/amount-of cu/USD 10))))
+ (is (= (ams/amount-of cu/GBP 3) (ams/min (ams/amount-of cu/GBP 3))))
(are [a b c] (is (= c (ams/min a b)))
(ams/amount-of cu/USD 10) (ams/amount-of cu/USD 20) (ams/amount-of cu/USD 10)
- (ams/amount-of cu/GBP 30) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 10)))
+ (ams/amount-of cu/GBP 30) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 10))
+ (are [a b c d] (is (= d (ams/min a b c)))
+ (ams/amount-of cu/USD 5) (ams/amount-of cu/USD 20) (ams/amount-of cu/USD 10) (ams/amount-of cu/USD 5)
+ (ams/amount-of cu/GBP 8) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 10) (ams/amount-of cu/GBP 8)))
+
+(deftest test-gt
+ (is (ams/> (ams/amount-of cu/USD 10)))
+ (is (ams/> (ams/amount-of cu/GBP 4)))
+ (is (ams/> (ams/amount-of cu/USD 10) (ams/amount-of cu/USD 8)))
+ (is (ams/> (ams/amount-of cu/GBP 4) (ams/amount-of cu/GBP 2)))
+ (is (not (ams/> (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 8))))
+ (is (ams/> (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 7)))
+ (is (ams/> (ams/amount-of cu/GBP 3) (ams/amount-of cu/GBP 2)))
+ (is (ams/> (ams/amount-of cu/GBP 3) (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 1))))
+
+(deftest test-gte
+ (is (ams/>= (ams/amount-of cu/USD 10)))
+ (is (ams/>= (ams/amount-of cu/GBP 4)))
+ (is (ams/>= (ams/amount-of cu/USD 10) (ams/amount-of cu/USD 10)))
+ (is (ams/>= (ams/amount-of cu/USD 10) (ams/amount-of cu/USD 9)))
+ (is (ams/>= (ams/amount-of cu/GBP 4) (ams/amount-of cu/GBP 2)))
+ (is (ams/>= (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 8)))
+ (is (ams/>= (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 7)))
+ (is (ams/>= (ams/amount-of cu/GBP 3) (ams/amount-of cu/GBP 2)))
+ (is (ams/>= (ams/amount-of cu/GBP 3) (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 1) (ams/amount-of cu/GBP 1))))
+
+(deftest test-lt
+ (is (ams/< (ams/amount-of cu/USD 10)))
+ (is (ams/< (ams/amount-of cu/GBP 4)))
+ (is (ams/< (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 10)))
+ (is (ams/< (ams/amount-of cu/GBP 1) (ams/amount-of cu/GBP 4)))
+ (is (not (ams/< (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 8))))
+ (is (ams/< (ams/amount-of cu/USD 3) (ams/amount-of cu/USD 4)))
+ (is (ams/< (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 4)))
+ (is (ams/< (ams/amount-of cu/GBP 1) (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 30))))
+
+(deftest test-lte
+ (is (ams/<= (ams/amount-of cu/USD 10)))
+ (is (ams/<= (ams/amount-of cu/GBP 4)))
+ (is (ams/<= (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 10)))
+ (is (ams/<= (ams/amount-of cu/GBP 1) (ams/amount-of cu/GBP 4)))
+ (is (ams/<= (ams/amount-of cu/USD 8) (ams/amount-of cu/USD 8)))
+ (is (ams/<= (ams/amount-of cu/USD 3) (ams/amount-of cu/USD 4)))
+ (is (ams/<= (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 4)))
+ (is (ams/<= (ams/amount-of cu/GBP 1) (ams/amount-of cu/GBP 2) (ams/amount-of cu/GBP 30))))
(deftest test-multiplication
(let [oa (ams/amount-of cu/USD 100)
Something went wrong with that request. Please try again.