packages feed

lambdabot-4.0: Plugin/Fact.hs

--
-- Module    : Fact
-- Copyright : 2003 Shae Erisson
-- Copyright : 2005-06 Don Stewart
--
-- License:     lGPL
--
-- Quick ugly hack to get factoids in lambdabot.  This is a rewrite of
-- Shae's original code to use internal module states. jlouis
--
module Plugin.Fact (theModule) where

import Plugin
import qualified Data.Map as M
import qualified Data.ByteString.Char8 as P

------------------------------------------------------------------------

PLUGIN Fact

type FactState  = M.Map P.ByteString P.ByteString
type FactWriter = FactState -> LB ()
type Fact m a   = ModuleT FactState m a

instance Module FactModule FactState where

  moduleCmds   _ = ["fact","fact-set","fact-delete"
                   ,"fact-cons","fact-snoc","fact-update"]
  moduleHelp _ s = case s of
    "fact"        -> "fact <fact>, Retrieve a fact from the database"
    "fact-set"    -> "Define a new fact, guard if exists"
    "fact-update" -> "Define a new fact, overwriting"
    "fact-delete" -> "Delete a fact from the database"
    "fact-cons"   -> "cons information to fact"
    "fact-snoc"   -> "snoc information to fact"
    _             -> "Store and retrieve facts from a database"

  moduleDefState _  = return $ M.empty
  moduleSerialize _ = Just mapPackedSerial

  process_ _ cmd rest =
        list $ withMS $ \factFM writer -> case words rest of
            []         -> return "I can not handle empty facts."
            (fact:dat) -> processCommand factFM writer
                                (P.pack $ lowerCaseString fact)
                                cmd
                                (P.pack $ unwords dat)

------------------------------------------------------------------------

processCommand :: FactState -> FactWriter
               -> P.ByteString -> String -> P.ByteString -> Fact LB String
processCommand factFM writer fact cmd dat = case cmd of
        "fact"        -> return $ getFact factFM fact
        "fact-set"    -> updateFact True factFM writer fact dat
        "fact-update" -> updateFact False factFM writer fact dat
        "fact-cons"   -> alterFact ((dat `P.append` (P.pack " ")) `P.append`) factFM writer fact
        "fact-snoc"   -> alterFact (P.append ((P.pack " ") `P.append` dat))   factFM writer fact
        "fact-delete" -> writer ( M.delete fact factFM ) >> return "Fact deleted."
        _ -> return "Unknown command."

updateFact :: Bool -> FactState -> FactWriter -> P.ByteString -> P.ByteString -> Fact LB String
updateFact guarded factFM writer fact dat =
    if guarded && M.member fact factFM
        then return "Fact already exists, not updating"
        else writer ( M.insert fact dat factFM ) >> return "Fact recorded."

alterFact :: (P.ByteString -> P.ByteString)
          -> FactState -> FactWriter -> P.ByteString -> Fact LB String
alterFact f factFM writer fact =
    case M.lookup fact factFM of
        Nothing -> return "A fact must exist to alter it"
        Just x  -> do writer $ M.insert fact (f x) factFM
                      return "Fact altered."

getFact :: M.Map P.ByteString P.ByteString -> P.ByteString -> String
getFact fm fact = case M.lookup fact fm of
        Nothing -> "I know nothing about " ++ P.unpack fact
        Just x  -> P.unpack fact ++ ": " ++ P.unpack x