diff --git a/CHANGELOG.md b/CHANGELOG.md index 7253668..6cf14bb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ New features: Bugfixes: Other improvements: +- Added module documentation for Data.Formatter.DateTime and Data.Formatter.Number (#73 by @ntwilson) ## [v7.0.0](https://github.com/purescript-contrib/purescript-formatters/releases/tag/v7.0.0) - 2022-04-28 diff --git a/src/Data/Formatter/DateTime.purs b/src/Data/Formatter/DateTime.purs index 801cfa2..0983e4d 100644 --- a/src/Data/Formatter/DateTime.purs +++ b/src/Data/Formatter/DateTime.purs @@ -1,3 +1,27 @@ +-- | This is a subset of common format/parse strings currently supported. +-- | +-- | + `YYYY` - Full Year (1999) +-- | + `YY` - 2 digit year (99) +-- | + `MMMM` - Full Month (January) +-- | + `MMM` - Short Month (Jan) +-- | + `DD` - Padded Day (02) +-- | + `D` - Day of month (2) +-- | + `X` - Unix Timestamp (1506875681) +-- | + `E` - Day of Week (2) +-- | + `dddd` - DOW Name (Monday) +-- | + `ddd` - DOW Name Short (Mon) +-- | + `HH` - 24 Hour (13) +-- | + `hh` - 12 Hour (1) +-- | + `a` - Meridiem (am/pm) +-- | + `mm` - Minutes Padded (02) +-- | + `m` - Minutes (2) +-- | + `ss` - Seconds Padded (02) +-- | + `s` - Seconds (2) +-- | + `S` - MilliSeconds (4) +-- | + `SS` - MilliSeconds (04) +-- | + `SSS` - MilliSeconds (004) +-- | +-- | Full list is defined [here](https://github.com/slamdata/purescript-formatters/blob/master/src/Data/Formatter/DateTime.purs) module Data.Formatter.DateTime ( Formatter , FormatterCommand(..) @@ -48,6 +72,8 @@ import Parsing.Combinators as PC import Parsing.String as PS import Parsing.String.Basic as PSB +-- | One part of a DateTime `Formatter`. Use `Placeholder` for +-- | any static portion of the format, such as whitespace or separators `-` or `:`. data FormatterCommand = YearFull | YearTwoDigits @@ -79,6 +105,10 @@ derive instance genericFormatter :: Generic FormatterCommand _ instance showFormatter :: Show FormatterCommand where show = genericShow +-- | A description of a string format for dates and times. +-- | Functions such as `format` and `unformat` use a `Formatter` +-- | such as `(YearFull : MonthTwoDigits : DayOfMonthTwoDigits : Nil)` +-- | in place of a format string such as `"YYYYMMDD"`. type Formatter = List.List FormatterCommand printFormatterCommand :: FormatterCommand -> String @@ -107,9 +137,15 @@ printFormatterCommand = case _ of Milliseconds -> "SSS" Placeholder s -> s +-- | The format string representation of a `Formatter`. +-- | +-- | `show (Hours24 : MinutesTwoDigits : Nil) = "(Hours24 : MinutesTwoDigits : Nil)"` +-- | +-- | while `printFormatter (Hours24 : MinutesTwoDigits : Nil) = "HHmm"`. printFormatter :: Formatter -> String printFormatter = foldMap printFormatterCommand +-- | Attempt to parse a `String` as a `Formatter`. parseFormatString :: String -> Either String Formatter parseFormatString = runP formatParser @@ -212,16 +248,26 @@ padQuadrupleDigit i | i < 1000 = "0" <> (show i) | otherwise = show i +-- | Format a DateTime according to the format defined in the given `Formatter`. format :: Formatter -> DT.DateTime -> String format f d = foldMap (formatCommand d) f +-- | Format a DateTime according to the format defined in the given format string. +-- | If the format string is empty or contains a reserved character such as a single "M" or "H", +-- | will return a `Left` value. +-- | Note that any non-reserved `Char` is treated as a placeholder, so while "yyyy-MM-dd" might +-- | not produce the format you want (since "yyyy" isn't a recognized format), +-- | it will still return a `Right` value. formatDateTime :: String -> DT.DateTime -> Either String String formatDateTime pattern datetime = parseFormatString pattern <#> (_ `format` datetime) +-- | Attempt to parse a String as a DateTime according to the format defined in the +-- | given `Formatter`. unformat :: Formatter -> String -> Either String DT.DateTime unformat = runP <<< unformatParser +-- | Before or after noon (AM/PM) data Meridiem = AM | PM derive instance eqMeridiem :: Eq Meridiem @@ -410,6 +456,8 @@ unformatCommandParser = case _ of v <- p lift $ modify_ (flip f (Just v)) +-- | A `ParserT` for `String`s that parses a `DateTime` +-- | according to the format defined in the given `Formatter`. unformatParser :: forall m. Monad m => Formatter -> P.ParserT String m DT.DateTime unformatParser f = do acc <- P.mapParserT unState $ foldMap unformatCommandParser f @@ -419,6 +467,9 @@ unformatParser f = do unState s = case runState s initialAccum of Tuple (Tuple e state) res -> pure (Tuple (e $> res) state) +-- | Attempt to parse a `String` as a `DateTime` according to the format defined in the +-- | given format string. Returns a `Left` value if the given format string was empty, or +-- | if the date string fails to parse according to the format. unformatDateTime :: String -> String -> Either String DT.DateTime unformatDateTime pattern str = parseFormatString pattern >>= (_ `unformat` str) diff --git a/src/Data/Formatter/Number.purs b/src/Data/Formatter/Number.purs index e425e99..30665e3 100644 --- a/src/Data/Formatter/Number.purs +++ b/src/Data/Formatter/Number.purs @@ -1,7 +1,37 @@ +-- | Formatter has following properties +-- | + Number of digits before dot +-- | + Number of digits after dot +-- | + Should sign be printed for positive numbers +-- | + Should thousands be separated by comma +-- | + Should output string have abbreviations (like `K` or `M`) +-- | + What decimal-separator character should be used (default '.') +-- | + What thousand-group-separator character should be used (default '+') +-- | +-- | **Note:** The parser will return a formatter with the default separator-characters - use `withSeparators` to override this after parsing. +-- | +-- | Number will be padded with zeros to have at least this number of leading zeros. This doesn't restrict number to have more digits then leading zeros in format string. +-- | + `0000.0` will show 4 digits: `12 → "0012.0"`, `1234 → "1234.0"` +-- | + `00.0` will show only 2 digits : `12 → "12.0"`, `1234 → "1234.0"` +-- | +-- | Number of digits after dot is set by number of trailing zeros (note the rounding) +-- | + `0.000` will show 3 digits: `0.12345 → "0.123"`, `12.98765 → "12.988"` +-- | + `0.0` will show only 1 digit: `0.12345 → "0.1"`, `12.98765 → "13.0"` +-- | +-- | If number is lesser then zero `-` is always printed. Otherwise you could specify `+` in format string +-- | + `+0`: `12.0 → "+12"`, `-34.8 → "-35"` +-- | + `0`: `12.0 → "12"`, `-34.8 → "-35"` +-- | +-- | Thousands separator is specified as `,0` please note that this `0` isn't counted as leading. +-- | + `00,0`: `1234567890 → "1,234,567,890.0", `1 → "1.0"` +-- | +-- | For abbreviation one could use `a` flag. In general it tries to find the closest power of thousand and +-- | then use formatter to result of division of input number and that power. +-- | + `0a`: `1234567 → "1M"`, `1 → "1"` +-- | -- | This module has no support of percents and currencies. -- | Please, note that using simple formatter that tabulates number with -- | zeros and put commas between thousands should be enough for everything --- | because one could just compose it with `flip append "%"` or whatever +-- | because one could just compose it with `flip append "%"` or whatever. module Data.Formatter.Number ( Formatter(..) , withSeparators @@ -37,6 +67,17 @@ import Parsing.Combinators as PC import Parsing.String as PS import Parsing.String.Basic as PSB +-- | Defines a format for printing/parsing numbers. +-- | +-- | `comma`: use a ',' for a thousands separator +-- | +-- | `before`: the minimum number of characters to print before the decimal point +-- | +-- | `after`: the total number of characters to print after the decimal point +-- | +-- | `abbreviations`: "31600.0" → "32K"; "31600000.0" → "32M" +-- | +-- | `sign`: always print a sign, including a `+` for positive numbers newtype Formatter = Formatter { comma :: Boolean , before :: Int @@ -63,6 +104,7 @@ instance showFormatter :: Show Formatter where derive instance eqFormatter :: Eq Formatter +-- | The format string representation of a `Formatter`. printFormatter :: Formatter -> String printFormatter (Formatter f) = (if f.sign then "+" else "") @@ -72,6 +114,8 @@ printFormatter (Formatter f) = <> (repeat "0" f.after) <> (if f.abbreviations then "a" else "") +-- | Attempt to parse a `String` as a `Formatter`, +-- | using an interpretation inspired by [numeral.js](http://numeraljs.com/#format) parseFormatString :: String -> Either String Formatter parseFormatString = runP formatParser @@ -100,7 +144,7 @@ formatParser = do -- means of showing an integer potentially larger than +/- 2 billion. foreign import showNumberAsInt :: Number -> String --- | Formats a number according to the format object provided. +-- | Format a `Number` according to the `Formatter` provided. -- | Due to the nature of floating point numbers, may yield unpredictable results for extremely -- | large or extremely small numbers, such as numbers whose absolute values are ≥ 1e21 or ≤ 1e-21, -- | or when formatting with > 20 digits after the decimal place. @@ -174,9 +218,13 @@ format (Formatter f) num = do <> shownInt <> leftovers +-- | Attempt to parse a `String` as a `Number` according to the format defined in the +-- | given `Formatter`. unformat :: Formatter -> String -> Either String Number unformat = runP <<< unformatParser +-- | A `ParserT` for `String`s that parses a `Number` +-- | according to the format defined in the given `Formatter`. unformatParser :: Formatter -> P.Parser String Number unformatParser (Formatter f) = do minus <- PC.optionMaybe $ PC.try $ PS.string "-" @@ -252,9 +300,16 @@ unformatParser (Formatter f) = do * sign * (before + after / Number.pow 10.0 (Int.toNumber f.after)) +-- | Format a Number according to the format defined in the given format string. +-- | If the format string fails to parse, will return a `Left` value. +-- | The interpretation of the format string is inspired by [numeral.js](http://numeraljs.com/#format) formatNumber :: String -> Number -> Either String String formatNumber pattern number = parseFormatString pattern <#> flip format number +-- | Attempt to parse a `String` as a `Number` according to the format defined in the +-- | given format string. Returns a `Left` value if the given format string fails to parse, or +-- | if the number string fails to parse according to the format. +-- | The interpretation of the format string is inspired by [numeral.js](http://numeraljs.com/#format) unformatNumber :: String -> String -> Either String Number unformatNumber pattern str = parseFormatString pattern >>= flip unformat str