Add abstraction for bot commands
This commit is contained in:
parent
c4a05d5980
commit
fd4ae38eb1
4 changed files with 74 additions and 3 deletions
|
|
@ -1,6 +1,7 @@
|
||||||
# Changelog for haboli
|
# Changelog for haboli
|
||||||
|
|
||||||
## upcoming
|
## upcoming
|
||||||
|
- add `Haboli.Euphoria.Command` module
|
||||||
- clean up project
|
- clean up project
|
||||||
- fix nick of example bot in readme
|
- fix nick of example bot in readme
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,7 @@ cabal-version: 1.12
|
||||||
--
|
--
|
||||||
-- see: https://github.com/sol/hpack
|
-- see: https://github.com/sol/hpack
|
||||||
--
|
--
|
||||||
-- hash: 9b4e31fd51c5402b511dfcd2fa3dd52e562b202b1583f6639a0e193920e0d02c
|
-- hash: bcd1c482ca0554443e9e0523bf9eb0cc65354ef37c4aec33570b5ab9a22502bf
|
||||||
|
|
||||||
name: haboli
|
name: haboli
|
||||||
version: 0.3.1.0
|
version: 0.3.1.0
|
||||||
|
|
@ -32,6 +32,7 @@ library
|
||||||
Haboli.Euphoria
|
Haboli.Euphoria
|
||||||
Haboli.Euphoria.Api
|
Haboli.Euphoria.Api
|
||||||
Haboli.Euphoria.Client
|
Haboli.Euphoria.Client
|
||||||
|
Haboli.Euphoria.Command
|
||||||
Haboli.Euphoria.Example
|
Haboli.Euphoria.Example
|
||||||
Haboli.Euphoria.WegaBorad
|
Haboli.Euphoria.WegaBorad
|
||||||
other-modules:
|
other-modules:
|
||||||
|
|
|
||||||
|
|
@ -317,8 +317,11 @@ nextEvent = do
|
||||||
Right e -> pure e
|
Right e -> pure e
|
||||||
|
|
||||||
-- | Respond to 'EventPing's according to the documentation (see
|
-- | Respond to 'EventPing's according to the documentation (see
|
||||||
-- <http://api.euphoria.io/#ping-event>). This function is meant to be wrapped
|
-- <http://api.euphoria.io/#ping-event>). Passes through all events unmodified.
|
||||||
-- directly around 'nextEvent':
|
--
|
||||||
|
-- This utility function is meant to be wrapped directly or indirectly around
|
||||||
|
-- 'nextEvent':
|
||||||
|
--
|
||||||
-- > event <- respondingToPing nextEvent
|
-- > event <- respondingToPing nextEvent
|
||||||
respondingToPing :: Client e Event -> Client e Event
|
respondingToPing :: Client e Event -> Client e Event
|
||||||
respondingToPing holdingEvent = do
|
respondingToPing holdingEvent = do
|
||||||
|
|
|
||||||
66
src/Haboli/Euphoria/Command.hs
Normal file
66
src/Haboli/Euphoria/Command.hs
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{-# LANGUAGE ExistentialQuantification #-}
|
||||||
|
{-# LANGUAGE MultiParamTypeClasses #-}
|
||||||
|
|
||||||
|
-- | This module provides an abstraction for bot commands in the form of the
|
||||||
|
-- 'Hook' type class and the 'Command' type.
|
||||||
|
|
||||||
|
module Haboli.Euphoria.Command
|
||||||
|
( Hook(..)
|
||||||
|
, Command
|
||||||
|
, cmd
|
||||||
|
, runCommand
|
||||||
|
, runCommands
|
||||||
|
, respondingToCommands
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Control.Monad
|
||||||
|
|
||||||
|
import Haboli.Euphoria.Api
|
||||||
|
import Haboli.Euphoria.Client
|
||||||
|
|
||||||
|
-- | A hook is a way to react to new messages in a room. These typically don't
|
||||||
|
-- include the messages sent by the client itself.
|
||||||
|
class Hook h where
|
||||||
|
-- | @reel h msg@ applies the hook @h@ to the 'Message' @msg@. If no further
|
||||||
|
-- hooks should be applied to this message, it should return 'True'.
|
||||||
|
-- Otherwise, it should return 'False'.
|
||||||
|
reel :: h e -> Message -> Client e Bool
|
||||||
|
|
||||||
|
-- | A wrapper around hooks that allows for heterogenous lists of hooks. In
|
||||||
|
-- other words, it lets you combine different 'Hook' instances into a single
|
||||||
|
-- list.
|
||||||
|
data Command e = forall h. (Hook h) => Command (h e)
|
||||||
|
|
||||||
|
-- | Wrap a hook. Notice how the @h@ type disappears: This function can convert
|
||||||
|
-- different 'Hook' instances into the same type.
|
||||||
|
cmd :: (Hook h) => h e -> Command e
|
||||||
|
cmd = Command
|
||||||
|
|
||||||
|
-- | Apply a 'Command' to a 'Message'. For more information, see 'reel'.
|
||||||
|
runCommand :: Command e -> Message -> Client e Bool
|
||||||
|
runCommand (Command h) = reel h
|
||||||
|
|
||||||
|
-- | Apply multiple 'Command's to a 'Message' in order until one returns 'True'.
|
||||||
|
-- All commands following that one are not applied.
|
||||||
|
runCommands :: [Command e] -> Message -> Client e Bool
|
||||||
|
runCommands [] _ = pure False
|
||||||
|
runCommands (c:cs) msg = do
|
||||||
|
abort <- runCommand c msg
|
||||||
|
if abort
|
||||||
|
then pure True
|
||||||
|
else runCommands cs msg
|
||||||
|
|
||||||
|
-- | Run a list of 'Command's on all 'EventSend's. Passes through all events
|
||||||
|
-- unmodified.
|
||||||
|
--
|
||||||
|
-- This utility function is meant to be wrapped directly or indirectly around
|
||||||
|
-- 'nextEvent':
|
||||||
|
--
|
||||||
|
-- > event <- respondingToCommands commands nextEvent
|
||||||
|
respondingToCommands :: [Command e] -> Client e Event -> Client e Event
|
||||||
|
respondingToCommands cmds holdingEvent = do
|
||||||
|
event <- holdingEvent
|
||||||
|
case event of
|
||||||
|
EventSend e -> void $ runCommands cmds $ sendMessage e
|
||||||
|
_ -> pure ()
|
||||||
|
pure event
|
||||||
Loading…
Add table
Add a link
Reference in a new issue