sr-extra-1.64: Extra/Text.hs
{-# LANGUAGE CPP, RankNTypes #-}
module Extra.Text
( diffText
, camelWords
, capitalize
, Describe(describe')
, describe
, textshow
, trunc
#if !__GHCJS__
, tests
#endif
) where
import Data.Algorithm.DiffContext (getContextDiff, prettyContextDiff)
import Data.Char (isUpper, toUpper)
import Data.ListLike (groupBy)
import Data.Text (split, Text, pack, unpack)
#if !__GHCJS__
import Test.HUnit (assertEqual, Test(TestCase, TestList))
#endif
import qualified Text.PrettyPrint as HPJ
-- | Output the difference between two string in the style of diff(1). This
-- can be used with Test.HUnit.assertString: assertString (diffText ("a", "1\n2\n3\n"), ("b", "1\n3\n"))
diffText :: (String, Text) -> (String, Text) -> String
diffText (nameA, textA) (nameB, textB) =
show (prettyContextDiff
(HPJ.text nameA)
(HPJ.text nameB)
(HPJ.text . unpack)
(getContextDiff 2 (split (== '\n') textA) (split (== '\n') textB)))
-- | Convert a camel case string (no whitespace) into a natural
-- language looking phrase:
-- camelWords "aCamelCaseFOObar123" -> "A Camel Case FOObar123"
camelWords :: String -> String
camelWords s =
case groupBy (\ a b -> isUpper a == isUpper b) (dropWhile (== '_') s) of -- "aCamelCaseFOObar123"
(x : xs) -> concat $ capitalize x : map (\ (c : cs) -> if isUpper c then ' ' : c : cs else c : cs) xs
[] -> ""
#if !__GHCJS__
-- Most of these fail.
tests :: Test
tests =
TestList
[ TestCase (assertEqual "camel words 0" "A Camel Case FOO Bar 123" (camelWords "aCamelCaseFOOBar123"))
, TestCase (assertEqual "camel words 1" "My Generator" (camelWords "myGenerator"))
, TestCase (assertEqual "camel words 2" "PDF Generator" (camelWords "pDFGenerator"))
, TestCase (assertEqual "camel words 3" "PDF Generator" (camelWords "PDFGenerator"))
, TestCase (assertEqual "camel words 4" "Report PDF Generator" (camelWords "reportPDFGenerator")) ]
#endif
capitalize :: String -> String
capitalize [] = []
capitalize (c:cs) = (toUpper c) : cs
-- | Override the default description associated with the type of @a@.
-- The first argument indicates the field of the parent record that
-- contains the @a@ value, if any.
class Describe a where
describe' :: Maybe String -> a -> Maybe String
describe :: Describe a => a -> Maybe String
describe = describe' Nothing
-- | Truncate a string to avoid writing monster lines into the log.
trunc :: String -> String
trunc s = if length s > 1000 then take 1000 s ++ "..." else s
-- | The ever needed, never available show that returns a Text.
textshow :: Show a => a -> Text
textshow = pack . show