Thursday, January 22, 2015

Refactored Numbers Spelling kata in Clojure

I've refactored the Numbers Spelling kata I recently did in Clojure to remove some duplication.

Before refactoring it, I had to make the old spell-out-number-over-99 and spell-out-number-up-to-99 functions similar enough for the duplication pattern to emerge.

Then I could use the same function for both cases and also made some other minor changes such as using when-not form and renaming several bindings and arguments.

This is the refactored code:

(ns number-spelling.core)
(declare
one-word-numbers
num-digits
pow
number-spelling)
(defn spell-out [number]
(if-let [one-word-number (get one-word-numbers number)]
one-word-number
(let [num-digits (num-digits number)]
(cond
(> num-digits 9)
(number-spelling number 1 9 " billion" ", ")
(> num-digits 6)
(number-spelling number 1 6 " million" ", ")
(> num-digits 3)
(number-spelling number 1 3 " thousand" ", ")
(> num-digits 2)
(number-spelling number 1 2 " hundred" " and ")
:else
(number-spelling number 10 1 "" " ")))))
(defn- number-spelling [number factor exp separator1 separator2]
(let [power-of-ten (pow 10 exp)
close-number (* factor (quot number power-of-ten))
rest-of-number (rem number power-of-ten)]
(str (spell-out close-number)
separator1
(when-not (zero? rest-of-number)
(str separator2 (spell-out rest-of-number))))))
(defn- pow [base exp]
(reduce * (repeat exp base)))
(defn- num-digits [number]
(count (str number)))
(def ^:private one-word-numbers
{0 "zero"
1 "one"
2 "two"
3 "three"
4 "four"
5 "five"
6 "six"
7 "seven"
8 "eight"
9 "nine"
10 "ten"
11 "eleven"
12 "twelve"
13 "thirteen"
14 "fourteen"
15 "fifteen"
16 "sixteen"
17 "seventeen"
18 "eightteen"
19 "nineteen"
20 "twenty"
30 "thirty"
40 "forty"
50 "fifty"
60 "sixty"
70 "seventy"
80 "eighty"
90 "ninety"})

You can find the code in this repository in GitHub.

No comments:

Post a Comment