packages feed

epub-tools-2.2: src/EpubTools/EpubName/Format/Util.hs

-- Copyright: 2008-2013 Dino Morelli
-- License: BSD3 (see LICENSE)
-- Author: Dino Morelli <dino@ui3.info>

module EpubTools.EpubName.Format.Util
   ( Globals (..)
   , EN , runEN
   , throwError
   , asks
   , scrubString
   , sanitizeString
   )
   where

import Codec.Epub2.Opf.Package
import Control.Monad.Error
import Control.Monad.Identity
import Control.Monad.Reader
import Data.Char
import Data.List ( foldl' )
import Text.Regex

import EpubTools.EpubName.Opts


data Globals = Globals
   { gOpts :: Options
   , gMetadata :: Metadata
   }

type EN a = ReaderT Globals (ErrorT String Identity) a

runEN :: Globals -> EN a -> Either String a
runEN env ev = runIdentity (runErrorT (runReaderT ev env))


{- Convenience function to make a regex replacer for a given pattern 
   and replacement string. Helps by doing the 'flip' of str and rpl
   so you can partial eval.
-}
repl :: String -> String -> String -> String
repl re rpl str = subRegex (mkRegex re) str rpl


{- Transforms a string like this:
      "the quick brown McCheeseburger" -> "TheQuickBrownMccheeseburger"
-}
camelCase :: String -> String
camelCase s = concat $ map capFirst $ words s
   where
      capFirst (first:rest) = (toUpper first) : (map toLower rest)
      capFirst _ = undefined


{- A set of common string filters that apply to any and all parts
   of every single string we process in this project.
-}
aggressiveFilters :: [(String -> String)]
aggressiveFilters =
   [ repl "[',\\?();#’]"  ""
   , repl "\\."           " "
   , repl ":"             "_"
   , filter (/= '"')
   , repl "]"             ""
   , repl "\\*"           ""
   , repl "!"             ""
   , repl "[-/]"          " "
   , repl "\\["           "_ "
   -- Decided that I like the article included in titles
   --, repl "^The "         ""
   , repl "&"             " And "
   , camelCase
   ]


{- Utility function to apply the above filters to a string, giving you
   back the transformed string
-}
scrubString :: String -> String
scrubString s = foldl' (flip id) s aggressiveFilters


{- Utility function to apply a very basic filter to make a legal filename,
   giving you back the transformed string. This is used on everything
   at the very end, just before the new filename is returned from the
   formatting machinery.
-}
sanitizeString :: String -> String
sanitizeString s = foldl' (flip id) s [ repl "/" " " ]