Skip to content

Commit 12be277

Browse files
committed
Add decimalMark combinator to customize used decimal mark
Usage: > format (precision 3 <> decimalMark ',') pi "3,142"
1 parent a846402 commit 12be277

File tree

2 files changed

+34
-9
lines changed

2 files changed

+34
-9
lines changed

Diff for: src/Text/Format.purs

+21-8
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module Text.Format
77
, zeroFill
88
, signed
99
, precision
10+
, decimalMark
1011
, class Format
1112
, format
1213
) where
@@ -18,7 +19,7 @@ import Data.Unfoldable (replicate)
1819
import Data.Int as Int
1920
import Data.Maybe (Maybe(..), fromMaybe)
2021
import Data.Monoid (class Monoid)
21-
import Data.String (length, fromCharArray, dropWhile)
22+
import Data.String (length, fromCharArray, dropWhile, singleton, replace, Pattern(..), Replacement(..))
2223
import Math (round, pow, abs)
2324

2425
-- | Pad a string on the left up to a given maximum length. The padding
@@ -32,6 +33,7 @@ type PropertiesRecord =
3233
, padChar :: Maybe Char
3334
, signed :: Maybe Boolean
3435
, precision :: Maybe Int
36+
, decimalMark :: Maybe Char
3537
}
3638

3739
default :: PropertiesRecord
@@ -40,6 +42,7 @@ default =
4042
, padChar: Nothing
4143
, signed: Nothing
4244
, precision: Nothing
45+
, decimalMark: Nothing
4346
}
4447

4548
data Properties = Properties PropertiesRecord
@@ -49,17 +52,19 @@ instance eqProperties :: Eq Properties where
4952
rec1.width == rec2.width &&
5053
rec1.padChar == rec2.padChar &&
5154
rec1.signed == rec2.signed &&
52-
rec1.precision == rec2.precision
55+
rec1.precision == rec2.precision &&
56+
rec1.decimalMark == rec2.decimalMark
5357

5458
instance semigroupProperties :: Semigroup Properties where
5559
append (Properties rec1) (Properties rec2) = Properties rec
5660
where
5761
-- These are combined such that options to the right take precedence:
5862
-- width 3 <> width 4 == width 4
59-
rec = { width: rec2.width <|> rec1.width
60-
, padChar: rec2.padChar <|> rec1.padChar
61-
, signed: rec2.signed <|> rec1.signed
62-
, precision: rec2.precision <|> rec1.precision
63+
rec = { width: rec2.width <|> rec1.width
64+
, padChar: rec2.padChar <|> rec1.padChar
65+
, signed: rec2.signed <|> rec1.signed
66+
, precision: rec2.precision <|> rec1.precision
67+
, decimalMark: rec2.decimalMark <|> rec1.decimalMark
6368
}
6469

6570
instance monoidProperties :: Monoid Properties where
@@ -82,6 +87,10 @@ signed = Properties (default { signed = Just true })
8287
precision :: Int -> Properties
8388
precision digits = Properties (default { precision = Just digits })
8489

90+
-- | Delimiter character. Gets ignored for non-numeric types.
91+
decimalMark :: Char -> Properties
92+
decimalMark char = Properties (default { decimalMark = Just char })
93+
8594
-- | A class for types that can be formatted using the specified properties.
8695
class Format a where
8796
format :: Properties -> a -> String
@@ -141,11 +150,15 @@ instance formatNumber :: Format Number where
141150
isSigned = fromMaybe false rec.signed
142151
padChar = fromMaybe ' ' rec.padChar
143152
nonNegative = num >= 0.0
144-
numAbsStr' = show (abs num)
153+
numAbsStr'' = show (abs num)
154+
numAbsStr' = case rec.decimalMark of
155+
Nothing -> numAbsStr''
156+
Just d -> replace (Pattern ".") (Replacement (singleton d)) numAbsStr''
145157
numAbsStr = case rec.precision of
146158
Nothing -> numAbsStr'
147159
Just p -> numAbsStr' <> paddedZeros p
148-
paddedZeros p = let d = length (dropWhile (_ /= '.') numAbsStr') - 1
160+
usedDelimiter = fromMaybe '.' rec.decimalMark
161+
paddedZeros p = let d = length (dropWhile (_ /= usedDelimiter) numAbsStr') - 1
149162
in fromCharArray (replicate (p - d) '0')
150163
numSgn = if nonNegative
151164
then (if isSigned then "+" else "")

Diff for: test/Main.purs

+13-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import Prelude
55
import Data.Monoid (mempty)
66
import Math (pi)
77

8-
import Text.Format (width, signed, zeroFill, precision, format)
8+
import Text.Format (width, signed, zeroFill, precision, decimalMark, format)
99

1010
import Control.Monad.Eff (Eff)
1111
import Control.Monad.Eff.Console (CONSOLE)
@@ -78,6 +78,9 @@ main = runTest do
7878
equal "+123" $ format signed 123
7979
equal "-123" $ format signed (-123)
8080

81+
test "Int: format (precision, decimalMark)" do
82+
equal "123,00" $ format (precision 2 <> decimalMark ',') 123
83+
8184
test "Number: format" do
8285
equal "3.14" $ format mempty 3.14
8386
equal "-3.14" $ format mempty (-3.14)
@@ -108,6 +111,10 @@ main = runTest do
108111
equal "3.0" $ format (precision 1) 3
109112
equal "3.000" $ format (precision 3) 3
110113

114+
test "Number: format (precision, decimalMark)" do
115+
equal "3" $ format (precision 0 <> decimalMark ',') pi
116+
equal "3,1" $ format (precision 1 <> decimalMark ',') pi
117+
111118
test "Number: format (width, precision)" do
112119
equal " 3.14" $ format (width 6 <> precision 2) pi
113120
equal " 3" $ format (width 6 <> precision 0) pi
@@ -119,10 +126,15 @@ main = runTest do
119126
equal "+03.14" $ format (width 6 <> precision 2 <> signed <> zeroFill) pi
120127
equal "+3.142" $ format (width 6 <> precision 3 <> signed <> zeroFill) pi
121128

129+
test "Number: format (width, precision, signed, zeroFill, decimalMark)" do
130+
equal "+03,14" $ format (width 6 <> precision 2 <> signed <> zeroFill <> decimalMark ',') pi
131+
equal "+3,142" $ format (width 6 <> precision 3 <> signed <> zeroFill <> decimalMark ',') pi
132+
122133
test "Handling of zero" do
123134
equal "0" $ format mempty 0
124135
equal "0" $ format (precision 0) 0.0
125136
equal "0.00" $ format (precision 2) 0.0
137+
equal "0,00" $ format (precision 2 <> decimalMark ',') 0.0
126138
equal "+0" $ format signed 0
127139
equal "+0.0" $ format signed 0.0
128140
equal "+0.00" $ format (signed <> precision 2) 0

0 commit comments

Comments
 (0)