puffytools-0.0.0.1: src/PuffyTools/Slug.hs
{- |
Module : PuffyTools.Slug
Description : Generate slugs
Copyright : 2014, Peter Harpending
License : BSD3
Maintainer : Peter Harpending <pharpend2@gmail.com>
Stability : experimental
Portability : Linux
These generate slugs (file names).
The slug must be alphanumeric, with the exception of "-_". It also
must be between 4 and 32 chars long.
-}
module PuffyTools.Slug (
Slug,
mkSlugMaybe,
mkSlugEither,
mkRandomSlug,
mkSlugIO,
slugAcceptChars,
unSlug,
) where
import Control.Applicative
import Control.Monad
import Data.Aeson
import Data.Monoid ((<>))
import Data.Random
import Data.Text (Text)
import qualified Data.Text as T
-- |Newtype wrapper for String
newtype Slug = MkSlug { unSlug :: Text }
deriving (Eq, Show)
-- |Maybe make a Slug
mkSlugMaybe :: Text -> Maybe Slug
mkSlugMaybe s = case mkSlugEither s of
Left _ -> Nothing
Right q -> Just q
-- |Try to make a Slug, return an error if I can't
mkSlugEither :: Text -> Either String Slug
mkSlugEither s
| T.length s < 1 = Left "The slug must be at least 4 chars long."
| ftb /= s = Left $ "The slug may only contain these characters: " <> slugAcceptChars
| otherwise = Right $ MkSlug s
where
-- ftb ~ "filter badness"
ftb :: Text
ftb = T.filter (\c -> c `elem` slugAcceptChars) s
mkSlugIO :: Text -> IO Slug
mkSlugIO t = case mkSlugEither t of
Left msg -> fail msg
Right slg -> return slg
-- |Generates a random slug 32 chars long
mkRandomSlug :: IO Slug
mkRandomSlug = T.pack <$> (replicateM 32 ioc) >>= \s -> case mkSlugEither s of
Left err -> fail err
Right slg -> return slg
where
ioc :: IO Char
ioc = runRVar rvc StdRandom
rvc :: RVar Char
rvc = randomElement slugAcceptChars
-- |Acceptable characters for a slug
slugAcceptChars :: String
slugAcceptChars = ['A' .. 'Z'] <> ['a' .. 'z'] <> ['0' .. '9'] <> "-_"
instance FromJSON Slug where
parseJSON (String s) = case mkSlugEither s of
Left err -> fail err
Right slg -> return slg
parseJSON _ = fail "Slug must be of type String."
instance ToJSON Slug where
toJSON (MkSlug s) = toJSON s