Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
89fe646d0e | ||
|
|
b35136944c | ||
|
|
4d41c454a1 | ||
|
|
18ba758c0c | ||
|
|
3aedd01b08 | ||
|
|
235dd4e611 | ||
|
|
adf09c2cc4 | ||
|
|
a44ecc5e24 | ||
|
|
9980a095ed | ||
|
|
1d6a4aa7f3 | ||
|
|
8988ad9146 | ||
|
|
59d48ec154 | ||
|
|
be990538bc | ||
|
|
55c8806186 | ||
|
|
0ecf899b56 | ||
|
|
2f06fd221d | ||
|
|
f1227da9ca | ||
|
|
38db3c8d8f | ||
|
|
2b9a21c28b | ||
|
|
84c487dba5 | ||
|
|
6345e3d5d8 | ||
|
|
0ca03b7f21 | ||
|
|
482f42dca7 | ||
|
|
996bad94f1 | ||
|
|
4ca0b54de2 | ||
|
|
3738088dde | ||
|
|
1ec9e93f16 | ||
|
|
9534218797 | ||
|
|
d7d3d1a4fd | ||
|
|
86c4fe316e | ||
|
|
d5ac42268f | ||
|
|
df26e9d265 | ||
|
|
cb5f2d7d15 | ||
|
|
152ea76bda | ||
|
|
36ab31a17c | ||
|
|
768cb47fac | ||
|
|
427ad12603 | ||
|
|
1ca2ffc378 | ||
|
|
9e6b71c464 | ||
|
|
2f4e963e41 | ||
|
|
05af939963 | ||
|
|
8af7974c8f | ||
|
|
f7cfd5d835 | ||
|
|
cc495fa589 | ||
|
|
9c5d166f31 |
14
ChangeLog.md
14
ChangeLog.md
@@ -1,5 +1,19 @@
|
|||||||
# Changelog for mtlstats
|
# Changelog for mtlstats
|
||||||
|
|
||||||
|
## 0.9.0
|
||||||
|
- Bugfix: Display lifetime stats in report, not YTD
|
||||||
|
- Force expected capitalization on player/goalie names
|
||||||
|
- Don't show lifetime totals in report
|
||||||
|
- Sort players in YTD and lifetime reports by points
|
||||||
|
- Moved player/goalie creation/editing to edit submenu
|
||||||
|
|
||||||
|
## 0.8.0
|
||||||
|
- Bugfix: removed quotation marks from goalie names in report
|
||||||
|
- Allow lower case player names
|
||||||
|
- Don't show players without points in game report
|
||||||
|
- Removed unnecessary goalie statistics from game report
|
||||||
|
- Fixed goalie average calculation
|
||||||
|
|
||||||
## 0.7.0
|
## 0.7.0
|
||||||
- Shortened views to fit within 25 lines
|
- Shortened views to fit within 25 lines
|
||||||
- Implemented goalie reports
|
- Implemented goalie reports
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
name: mtlstats
|
name: mtlstats
|
||||||
version: 0.7.0
|
version: 0.9.0
|
||||||
github: "mtlstats/mtlstats"
|
github: "mtlstats/mtlstats"
|
||||||
license: GPL-3
|
license: GPL-3
|
||||||
author: "Jonathan Lamothe"
|
author: "Jonathan Lamothe"
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ module Mtlstats.Actions
|
|||||||
, removeChar
|
, removeChar
|
||||||
, createPlayer
|
, createPlayer
|
||||||
, createGoalie
|
, createGoalie
|
||||||
|
, edit
|
||||||
, editPlayer
|
, editPlayer
|
||||||
, editGoalie
|
, editGoalie
|
||||||
, addPlayer
|
, addPlayer
|
||||||
@@ -82,7 +83,7 @@ removeChar = inputBuffer %~ \case
|
|||||||
-- | Starts player creation mode
|
-- | Starts player creation mode
|
||||||
createPlayer :: ProgState -> ProgState
|
createPlayer :: ProgState -> ProgState
|
||||||
createPlayer = let
|
createPlayer = let
|
||||||
callback = modify $ progMode .~ MainMenu
|
callback = modify edit
|
||||||
cps = newCreatePlayerState
|
cps = newCreatePlayerState
|
||||||
& cpsSuccessCallback .~ callback
|
& cpsSuccessCallback .~ callback
|
||||||
& cpsFailureCallback .~ callback
|
& cpsFailureCallback .~ callback
|
||||||
@@ -91,12 +92,16 @@ createPlayer = let
|
|||||||
-- | Starts goalie creation mode
|
-- | Starts goalie creation mode
|
||||||
createGoalie :: ProgState -> ProgState
|
createGoalie :: ProgState -> ProgState
|
||||||
createGoalie = let
|
createGoalie = let
|
||||||
callback = modify $ progMode .~ MainMenu
|
callback = modify edit
|
||||||
cgs = newCreateGoalieState
|
cgs = newCreateGoalieState
|
||||||
& cgsSuccessCallback .~ callback
|
& cgsSuccessCallback .~ callback
|
||||||
& cgsFailureCallback .~ callback
|
& cgsFailureCallback .~ callback
|
||||||
in progMode .~ CreateGoalie cgs
|
in progMode .~ CreateGoalie cgs
|
||||||
|
|
||||||
|
-- | Launches the edit menu
|
||||||
|
edit :: ProgState -> ProgState
|
||||||
|
edit = progMode .~ EditMenu
|
||||||
|
|
||||||
-- | Starts the player editing process
|
-- | Starts the player editing process
|
||||||
editPlayer :: ProgState -> ProgState
|
editPlayer :: ProgState -> ProgState
|
||||||
editPlayer = progMode .~ EditPlayer newEditPlayerState
|
editPlayer = progMode .~ EditPlayer newEditPlayerState
|
||||||
|
|||||||
@@ -44,6 +44,7 @@ dispatch s = case s^.progMode of
|
|||||||
MainMenu -> mainMenuC
|
MainMenu -> mainMenuC
|
||||||
NewSeason -> newSeasonC
|
NewSeason -> newSeasonC
|
||||||
NewGame gs -> newGameC gs
|
NewGame gs -> newGameC gs
|
||||||
|
EditMenu -> editMenuC
|
||||||
CreatePlayer cps
|
CreatePlayer cps
|
||||||
| null $ cps^.cpsNumber -> getPlayerNumC
|
| null $ cps^.cpsNumber -> getPlayerNumC
|
||||||
| null $ cps^.cpsName -> getPlayerNameC
|
| null $ cps^.cpsName -> getPlayerNameC
|
||||||
@@ -70,6 +71,9 @@ newSeasonC = Controller
|
|||||||
return True
|
return True
|
||||||
}
|
}
|
||||||
|
|
||||||
|
editMenuC :: Controller
|
||||||
|
editMenuC = menuController editMenu
|
||||||
|
|
||||||
getPlayerNumC :: Controller
|
getPlayerNumC :: Controller
|
||||||
getPlayerNumC = Controller
|
getPlayerNumC = Controller
|
||||||
{ drawController = drawPrompt playerNumPrompt
|
{ drawController = drawPrompt playerNumPrompt
|
||||||
|
|||||||
@@ -26,6 +26,7 @@ module Mtlstats.Format
|
|||||||
, left
|
, left
|
||||||
, right
|
, right
|
||||||
, centre
|
, centre
|
||||||
|
, padRight
|
||||||
, overlay
|
, overlay
|
||||||
, month
|
, month
|
||||||
, labelTable
|
, labelTable
|
||||||
@@ -87,6 +88,16 @@ centre n str = let
|
|||||||
pad = replicate pLen ' '
|
pad = replicate pLen ' '
|
||||||
in take n $ pad ++ str ++ repeat ' '
|
in take n $ pad ++ str ++ repeat ' '
|
||||||
|
|
||||||
|
-- | Pads text on the right with spaces to fit a minimum width
|
||||||
|
padRight
|
||||||
|
:: Int
|
||||||
|
-- ^ The width to pad to
|
||||||
|
-> String
|
||||||
|
-- ^ The text to pad
|
||||||
|
-> String
|
||||||
|
padRight width str =
|
||||||
|
overlay str $ replicate width ' '
|
||||||
|
|
||||||
-- | Overlays one string on top of another
|
-- | Overlays one string on top of another
|
||||||
overlay
|
overlay
|
||||||
:: String
|
:: String
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ module Mtlstats.Menu (
|
|||||||
newSeasonMenu,
|
newSeasonMenu,
|
||||||
gameMonthMenu,
|
gameMonthMenu,
|
||||||
gameTypeMenu,
|
gameTypeMenu,
|
||||||
gameGoalieMenu
|
gameGoalieMenu,
|
||||||
|
editMenu
|
||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.IO.Class (liftIO)
|
import Control.Monad.IO.Class (liftIO)
|
||||||
@@ -113,14 +114,8 @@ mainMenu = Menu "*** MAIN MENU ***" True
|
|||||||
modify startNewSeason >> return True
|
modify startNewSeason >> return True
|
||||||
, MenuItem '2' "New Game" $
|
, MenuItem '2' "New Game" $
|
||||||
modify startNewGame >> return True
|
modify startNewGame >> return True
|
||||||
, MenuItem '3' "Create Player" $
|
, MenuItem '3' "Edit" $
|
||||||
modify createPlayer >> return True
|
modify edit >> return True
|
||||||
, MenuItem '4' "Create Goalie" $
|
|
||||||
modify createGoalie >> return True
|
|
||||||
, MenuItem '5' "Edit Player" $
|
|
||||||
modify editPlayer >> return True
|
|
||||||
, MenuItem '6' "Edit Goalie" $
|
|
||||||
modify editGoalie >> return True
|
|
||||||
, MenuItem 'X' "Exit" $ do
|
, MenuItem 'X' "Exit" $ do
|
||||||
db <- gets $ view database
|
db <- gets $ view database
|
||||||
liftIO $ do
|
liftIO $ do
|
||||||
@@ -186,3 +181,18 @@ gameGoalieMenu s = let
|
|||||||
(\(ch, (gid, goalie)) -> MenuItem ch (goalieSummary goalie) $
|
(\(ch, (gid, goalie)) -> MenuItem ch (goalieSummary goalie) $
|
||||||
modify $ GI.setGameGoalie gid) $
|
modify $ GI.setGameGoalie gid) $
|
||||||
zip ['1'..] goalies
|
zip ['1'..] goalies
|
||||||
|
|
||||||
|
-- | The edit menu
|
||||||
|
editMenu :: Menu ()
|
||||||
|
editMenu = Menu "*** EDIT ***" ()
|
||||||
|
[ MenuItem '1' "Create Player" $
|
||||||
|
modify createPlayer
|
||||||
|
, MenuItem '2' "Create Goalie" $
|
||||||
|
modify createGoalie
|
||||||
|
, MenuItem '3' "Edit Player" $
|
||||||
|
modify editPlayer
|
||||||
|
, MenuItem '4' "Edit Goalie" $
|
||||||
|
modify editGoalie
|
||||||
|
, MenuItem 'R' "Return to Main Menu" $
|
||||||
|
modify backHome
|
||||||
|
]
|
||||||
|
|||||||
@@ -26,25 +26,25 @@ module Mtlstats.Menu.EditGoalie
|
|||||||
) where
|
) where
|
||||||
|
|
||||||
import Control.Monad.Trans.State (modify)
|
import Control.Monad.Trans.State (modify)
|
||||||
import Data.Maybe (maybe)
|
|
||||||
import Lens.Micro ((.~))
|
import Lens.Micro ((.~))
|
||||||
|
|
||||||
|
import Mtlstats.Actions
|
||||||
import Mtlstats.Types
|
import Mtlstats.Types
|
||||||
import Mtlstats.Types.Menu
|
import Mtlstats.Types.Menu
|
||||||
|
|
||||||
-- | The 'Goalie' edit menu
|
-- | The 'Goalie' edit menu
|
||||||
editGoalieMenu :: Menu ()
|
editGoalieMenu :: Menu ()
|
||||||
editGoalieMenu = Menu "*** EDIT GOALTENDER ***" () $ map
|
editGoalieMenu = Menu "*** EDIT GOALTENDER ***" () $ map
|
||||||
(\(key, label, val) -> MenuItem key label $ modify $ maybe
|
(\(ch, label, mode) -> MenuItem ch label $
|
||||||
(progMode .~ MainMenu)
|
modify $ case mode of
|
||||||
(progMode.editGoalieStateL.egsMode .~)
|
Nothing -> edit
|
||||||
val)
|
Just m -> progMode.editGoalieStateL.egsMode .~ m)
|
||||||
-- key, label, value
|
-- key, label, value
|
||||||
[ ( '1', "Edit number", Just EGNumber )
|
[ ( '1', "Edit number", Just EGNumber )
|
||||||
, ( '2', "Edit name", Just EGName )
|
, ( '2', "Edit name", Just EGName )
|
||||||
, ( '3', "Edit YTD stats", Just EGYtd )
|
, ( '3', "Edit YTD stats", Just EGYtd )
|
||||||
, ( '4', "Edit Lifetime stats", Just EGLifetime )
|
, ( '4', "Edit Lifetime stats", Just EGLifetime )
|
||||||
, ( 'R', "Return to Main Menu", Nothing )
|
, ( 'R', "Return to Edit Menu", Nothing )
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | The 'Goalie' YTD edit menu
|
-- | The 'Goalie' YTD edit menu
|
||||||
|
|||||||
@@ -28,22 +28,24 @@ module Mtlstats.Menu.EditPlayer
|
|||||||
import Control.Monad.Trans.State (modify)
|
import Control.Monad.Trans.State (modify)
|
||||||
import Lens.Micro ((.~))
|
import Lens.Micro ((.~))
|
||||||
|
|
||||||
|
import Mtlstats.Actions
|
||||||
import Mtlstats.Types
|
import Mtlstats.Types
|
||||||
import Mtlstats.Types.Menu
|
import Mtlstats.Types.Menu
|
||||||
|
|
||||||
-- | The 'Player' edit menu
|
-- | The 'Player' edit menu
|
||||||
editPlayerMenu :: Menu ()
|
editPlayerMenu :: Menu ()
|
||||||
editPlayerMenu = Menu "*** EDIT PLAYER ***" () $ map
|
editPlayerMenu = Menu "*** EDIT PLAYER ***" () $ map
|
||||||
(\(ch, label, mode) -> MenuItem ch label $ case mode of
|
(\(ch, label, mode) -> MenuItem ch label $
|
||||||
Nothing -> modify $ progMode .~ MainMenu
|
modify $ case mode of
|
||||||
Just m -> modify $ progMode.editPlayerStateL.epsMode .~ m)
|
Nothing -> edit
|
||||||
|
Just m -> progMode.editPlayerStateL.epsMode .~ m)
|
||||||
-- key, label, value
|
-- key, label, value
|
||||||
[ ( '1', "Edit number", Just EPNumber )
|
[ ( '1', "Edit number", Just EPNumber )
|
||||||
, ( '2', "Edit name", Just EPName )
|
, ( '2', "Edit name", Just EPName )
|
||||||
, ( '3', "Edit position", Just EPPosition )
|
, ( '3', "Edit position", Just EPPosition )
|
||||||
, ( '4', "Edit YTD stats", Just EPYtd )
|
, ( '4', "Edit YTD stats", Just EPYtd )
|
||||||
, ( '5', "Edit lifetime stats", Just EPLifetime )
|
, ( '5', "Edit lifetime stats", Just EPLifetime )
|
||||||
, ( 'R', "Finished editing", Nothing )
|
, ( 'R', "Return to Edit Menu", Nothing )
|
||||||
]
|
]
|
||||||
|
|
||||||
-- | The 'Player' YTD stats edit menu
|
-- | The 'Player' YTD stats edit menu
|
||||||
|
|||||||
@@ -28,6 +28,8 @@ module Mtlstats.Prompt (
|
|||||||
promptControllerWith,
|
promptControllerWith,
|
||||||
promptController,
|
promptController,
|
||||||
strPrompt,
|
strPrompt,
|
||||||
|
ucStrPrompt,
|
||||||
|
namePrompt,
|
||||||
numPrompt,
|
numPrompt,
|
||||||
selectPrompt,
|
selectPrompt,
|
||||||
-- * Individual prompts
|
-- * Individual prompts
|
||||||
@@ -46,7 +48,7 @@ import Control.Monad.Extra (whenJust)
|
|||||||
import Control.Monad.Trans.State (gets, modify)
|
import Control.Monad.Trans.State (gets, modify)
|
||||||
import Data.Char (isDigit, toUpper)
|
import Data.Char (isDigit, toUpper)
|
||||||
import Data.Foldable (forM_)
|
import Data.Foldable (forM_)
|
||||||
import Lens.Micro ((^.), (&), (.~), (?~))
|
import Lens.Micro ((^.), (&), (.~), (?~), (%~))
|
||||||
import Lens.Micro.Extras (view)
|
import Lens.Micro.Extras (view)
|
||||||
import Text.Read (readMaybe)
|
import Text.Read (readMaybe)
|
||||||
import qualified UI.NCurses as C
|
import qualified UI.NCurses as C
|
||||||
@@ -68,10 +70,8 @@ promptHandler p (C.EventCharacter '\n') = do
|
|||||||
val <- gets $ view inputBuffer
|
val <- gets $ view inputBuffer
|
||||||
modify $ inputBuffer .~ ""
|
modify $ inputBuffer .~ ""
|
||||||
promptAction p val
|
promptAction p val
|
||||||
promptHandler p (C.EventCharacter c) = let
|
promptHandler p (C.EventCharacter c) =
|
||||||
c' = toUpper c
|
modify $ inputBuffer %~ promptProcessChar p c
|
||||||
in when (promptCharCheck p c') $
|
|
||||||
modify $ addChar c'
|
|
||||||
promptHandler _ (C.EventSpecialKey C.KeyBackspace) =
|
promptHandler _ (C.EventSpecialKey C.KeyBackspace) =
|
||||||
modify removeChar
|
modify removeChar
|
||||||
promptHandler p (C.EventSpecialKey k) =
|
promptHandler p (C.EventSpecialKey k) =
|
||||||
@@ -112,11 +112,32 @@ strPrompt
|
|||||||
-> Prompt
|
-> Prompt
|
||||||
strPrompt pStr act = Prompt
|
strPrompt pStr act = Prompt
|
||||||
{ promptDrawer = drawSimplePrompt pStr
|
{ promptDrawer = drawSimplePrompt pStr
|
||||||
, promptCharCheck = const True
|
, promptProcessChar = \ch -> (++ [ch])
|
||||||
, promptAction = act
|
, promptAction = act
|
||||||
, promptSpecialKey = const $ return ()
|
, promptSpecialKey = const $ return ()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
-- | Creates an upper case string prompt
|
||||||
|
ucStrPrompt
|
||||||
|
:: String
|
||||||
|
-- ^ The prompt string
|
||||||
|
-> (String -> Action ())
|
||||||
|
-- ^ The callback function for the result
|
||||||
|
-> Prompt
|
||||||
|
ucStrPrompt pStr act = (strPrompt pStr act)
|
||||||
|
{ promptProcessChar = \ch -> (++ [toUpper ch]) }
|
||||||
|
|
||||||
|
-- | Creates a prompt which forces capitalization of input to
|
||||||
|
-- accomodate a player or goalie name
|
||||||
|
namePrompt
|
||||||
|
:: String
|
||||||
|
-- ^ The prompt string
|
||||||
|
-> (String -> Action ())
|
||||||
|
-- ^ The callback function for the result
|
||||||
|
-> Prompt
|
||||||
|
namePrompt pStr act = (strPrompt pStr act)
|
||||||
|
{ promptProcessChar = capitalizeName }
|
||||||
|
|
||||||
-- | Builds a numeric prompt
|
-- | Builds a numeric prompt
|
||||||
numPrompt
|
numPrompt
|
||||||
:: String
|
:: String
|
||||||
@@ -126,7 +147,9 @@ numPrompt
|
|||||||
-> Prompt
|
-> Prompt
|
||||||
numPrompt pStr act = Prompt
|
numPrompt pStr act = Prompt
|
||||||
{ promptDrawer = drawSimplePrompt pStr
|
{ promptDrawer = drawSimplePrompt pStr
|
||||||
, promptCharCheck = isDigit
|
, promptProcessChar = \ch str -> if isDigit ch
|
||||||
|
then str ++ [ch]
|
||||||
|
else str
|
||||||
, promptAction = \inStr -> forM_ (readMaybe inStr) act
|
, promptAction = \inStr -> forM_ (readMaybe inStr) act
|
||||||
, promptSpecialKey = const $ return ()
|
, promptSpecialKey = const $ return ()
|
||||||
}
|
}
|
||||||
@@ -146,7 +169,7 @@ selectPrompt params = Prompt
|
|||||||
in "F" ++ show n ++ ") " ++ desc)
|
in "F" ++ show n ++ ") " ++ desc)
|
||||||
results
|
results
|
||||||
C.moveCursor row col
|
C.moveCursor row col
|
||||||
, promptCharCheck = const True
|
, promptProcessChar = spProcessChar params
|
||||||
, promptAction = \sStr -> if null sStr
|
, promptAction = \sStr -> if null sStr
|
||||||
then spCallback params Nothing
|
then spCallback params Nothing
|
||||||
else do
|
else do
|
||||||
@@ -175,12 +198,12 @@ playerNumPrompt = numPrompt "Player number: " $
|
|||||||
|
|
||||||
-- | Prompts for a new player's name
|
-- | Prompts for a new player's name
|
||||||
playerNamePrompt :: Prompt
|
playerNamePrompt :: Prompt
|
||||||
playerNamePrompt = strPrompt "Player name: " $
|
playerNamePrompt = namePrompt "Player name: " $
|
||||||
modify . (progMode.createPlayerStateL.cpsName .~)
|
modify . (progMode.createPlayerStateL.cpsName .~)
|
||||||
|
|
||||||
-- | Prompts for a new player's position
|
-- | Prompts for a new player's position
|
||||||
playerPosPrompt :: Prompt
|
playerPosPrompt :: Prompt
|
||||||
playerPosPrompt = strPrompt "Player position: " $
|
playerPosPrompt = ucStrPrompt "Player position: " $
|
||||||
modify . (progMode.createPlayerStateL.cpsPosition .~)
|
modify . (progMode.createPlayerStateL.cpsPosition .~)
|
||||||
|
|
||||||
-- | Prompts tor the goalie's number
|
-- | Prompts tor the goalie's number
|
||||||
@@ -190,7 +213,7 @@ goalieNumPrompt = numPrompt "Goalie number: " $
|
|||||||
|
|
||||||
-- | Prompts for the goalie's name
|
-- | Prompts for the goalie's name
|
||||||
goalieNamePrompt :: Prompt
|
goalieNamePrompt :: Prompt
|
||||||
goalieNamePrompt = strPrompt "Goalie name: " $
|
goalieNamePrompt = namePrompt "Goalie name: " $
|
||||||
modify . (progMode.createGoalieStateL.cgsName .~)
|
modify . (progMode.createGoalieStateL.cgsName .~)
|
||||||
|
|
||||||
-- | Selects a player (creating one if necessary)
|
-- | Selects a player (creating one if necessary)
|
||||||
@@ -207,6 +230,7 @@ selectPlayerPrompt pStr callback = selectPrompt SelectParams
|
|||||||
, spSearch = \sStr db -> playerSearch sStr (db^.dbPlayers)
|
, spSearch = \sStr db -> playerSearch sStr (db^.dbPlayers)
|
||||||
, spSearchExact = \sStr db -> fst <$> playerSearchExact sStr (db^.dbPlayers)
|
, spSearchExact = \sStr db -> fst <$> playerSearchExact sStr (db^.dbPlayers)
|
||||||
, spElemDesc = playerSummary
|
, spElemDesc = playerSummary
|
||||||
|
, spProcessChar = capitalizeName
|
||||||
, spCallback = callback
|
, spCallback = callback
|
||||||
, spNotFound = \sStr -> do
|
, spNotFound = \sStr -> do
|
||||||
mode <- gets (^.progMode)
|
mode <- gets (^.progMode)
|
||||||
@@ -235,6 +259,7 @@ selectGoaliePrompt pStr callback = selectPrompt SelectParams
|
|||||||
, spSearch = \sStr db -> goalieSearch sStr (db^.dbGoalies)
|
, spSearch = \sStr db -> goalieSearch sStr (db^.dbGoalies)
|
||||||
, spSearchExact = \sStr db -> fst <$> goalieSearchExact sStr (db^.dbGoalies)
|
, spSearchExact = \sStr db -> fst <$> goalieSearchExact sStr (db^.dbGoalies)
|
||||||
, spElemDesc = goalieSummary
|
, spElemDesc = goalieSummary
|
||||||
|
, spProcessChar = capitalizeName
|
||||||
, spCallback = callback
|
, spCallback = callback
|
||||||
, spNotFound = \sStr -> do
|
, spNotFound = \sStr -> do
|
||||||
mode <- gets (^.progMode)
|
mode <- gets (^.progMode)
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ editPlayerNamePrompt = strPrompt "Player name: " $
|
|||||||
|
|
||||||
-- | Prompt to edit a player's position
|
-- | Prompt to edit a player's position
|
||||||
editPlayerPosPrompt :: Prompt
|
editPlayerPosPrompt :: Prompt
|
||||||
editPlayerPosPrompt = strPrompt "Player position: " $
|
editPlayerPosPrompt = ucStrPrompt "Player position: " $
|
||||||
editPlayer . (pPosition .~)
|
editPlayer . (pPosition .~)
|
||||||
|
|
||||||
-- | Prompt to edit a player's year-to-date goals
|
-- | Prompt to edit a player's year-to-date goals
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ gameDayPrompt = numPrompt "Day of month: " $
|
|||||||
|
|
||||||
-- | Prompts for the other team name
|
-- | Prompts for the other team name
|
||||||
otherTeamPrompt :: Prompt
|
otherTeamPrompt :: Prompt
|
||||||
otherTeamPrompt = strPrompt "Other team: " $
|
otherTeamPrompt = ucStrPrompt "Other team: " $
|
||||||
modify . (progMode.gameStateL.otherTeam .~)
|
modify . (progMode.gameStateL.otherTeam .~)
|
||||||
|
|
||||||
-- | Prompts for the home score
|
-- | Prompts for the home score
|
||||||
|
|||||||
@@ -21,8 +21,10 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
module Mtlstats.Report (report, gameDate) where
|
module Mtlstats.Report (report, gameDate) where
|
||||||
|
|
||||||
|
import Data.List (sortOn)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Data.Maybe (fromMaybe, mapMaybe)
|
import Data.Maybe (fromMaybe, mapMaybe)
|
||||||
|
import Data.Ord (Down (Down))
|
||||||
import Lens.Micro ((^.))
|
import Lens.Micro ((^.))
|
||||||
|
|
||||||
import Mtlstats.Config
|
import Mtlstats.Config
|
||||||
@@ -125,15 +127,18 @@ gameStatsReport width s = let
|
|||||||
Just (g, stats))
|
Just (g, stats))
|
||||||
(M.toList $ gs^.gameGoalieStats)
|
(M.toList $ gs^.gameGoalieStats)
|
||||||
|
|
||||||
in playerReport width "GAME" playerStats
|
criteria (_, ps) = psPoints ps > 0
|
||||||
|
|
||||||
|
in filteredPlayerReport width "GAME" criteria True playerStats
|
||||||
++ [""]
|
++ [""]
|
||||||
++ goalieReport width goalieStats
|
++ gameGoalieReport width goalieStats
|
||||||
|
|
||||||
yearToDateStatsReport :: Int -> ProgState -> [String]
|
yearToDateStatsReport :: Int -> ProgState -> [String]
|
||||||
yearToDateStatsReport width s = let
|
yearToDateStatsReport width s = let
|
||||||
db = s^.database
|
db = s^.database
|
||||||
|
|
||||||
playerStats = map (\p -> (p, p^.pYtd))
|
playerStats = sortOn (Down . psPoints . snd)
|
||||||
|
$ map (\p -> (p, p^.pYtd))
|
||||||
$ filter playerIsActive
|
$ filter playerIsActive
|
||||||
$ db^.dbPlayers
|
$ db^.dbPlayers
|
||||||
|
|
||||||
@@ -141,23 +146,24 @@ yearToDateStatsReport width s = let
|
|||||||
$ filter goalieIsActive
|
$ filter goalieIsActive
|
||||||
$ db^.dbGoalies
|
$ db^.dbGoalies
|
||||||
|
|
||||||
in playerReport width "YEAR TO DATE" playerStats
|
in playerReport width "YEAR TO DATE" True playerStats
|
||||||
++ [""]
|
++ [""]
|
||||||
++ goalieReport width goalieStats
|
++ goalieReport width True goalieStats
|
||||||
|
|
||||||
lifetimeStatsReport :: Int -> ProgState -> [String]
|
lifetimeStatsReport :: Int -> ProgState -> [String]
|
||||||
lifetimeStatsReport width s = let
|
lifetimeStatsReport width s = let
|
||||||
db = s^.database
|
db = s^.database
|
||||||
|
|
||||||
playerStats = map (\p -> (p, p^.pYtd))
|
playerStats = sortOn (Down . psPoints . snd)
|
||||||
|
$ map (\p -> (p, p^.pLifetime))
|
||||||
$ db^.dbPlayers
|
$ db^.dbPlayers
|
||||||
|
|
||||||
goalieStats = map (\g -> (g, g^.gYtd))
|
goalieStats = map (\g -> (g, g^.gLifetime))
|
||||||
$ db^.dbGoalies
|
$ db^.dbGoalies
|
||||||
|
|
||||||
in playerReport width "LIFETIME" playerStats
|
in playerReport width "LIFETIME" False playerStats
|
||||||
++ [""]
|
++ [""]
|
||||||
++ goalieReport width goalieStats
|
++ goalieReport width False goalieStats
|
||||||
|
|
||||||
gameDate :: GameState -> String
|
gameDate :: GameState -> String
|
||||||
gameDate gs = fromMaybe "" $ do
|
gameDate gs = fromMaybe "" $ do
|
||||||
@@ -166,9 +172,25 @@ gameDate gs = fromMaybe "" $ do
|
|||||||
d <- padNum 2 <$> gs^.gameDay
|
d <- padNum 2 <$> gs^.gameDay
|
||||||
Just $ m ++ " " ++ d ++ " " ++ y
|
Just $ m ++ " " ++ d ++ " " ++ y
|
||||||
|
|
||||||
playerReport :: Int -> String -> [(Player, PlayerStats)] -> [String]
|
playerReport
|
||||||
playerReport width label ps = let
|
:: Int
|
||||||
|
-> String
|
||||||
|
-> Bool
|
||||||
|
-> [(Player, PlayerStats)]
|
||||||
|
-> [String]
|
||||||
|
playerReport width label =
|
||||||
|
filteredPlayerReport width label (const True)
|
||||||
|
|
||||||
|
filteredPlayerReport
|
||||||
|
:: Int
|
||||||
|
-> String
|
||||||
|
-> ((Player, PlayerStats) -> Bool)
|
||||||
|
-> Bool
|
||||||
|
-> [(Player, PlayerStats)]
|
||||||
|
-> [String]
|
||||||
|
filteredPlayerReport width label criteria showTotals ps = let
|
||||||
tStats = foldl addPlayerStats newPlayerStats $ map snd ps
|
tStats = foldl addPlayerStats newPlayerStats $ map snd ps
|
||||||
|
fps = filter criteria ps
|
||||||
|
|
||||||
rHeader =
|
rHeader =
|
||||||
[ centre width (label ++ " STATISTICS")
|
[ centre width (label ++ " STATISTICS")
|
||||||
@@ -196,7 +218,7 @@ playerReport width label ps = let
|
|||||||
[ CellText $ show (p^.pNumber) ++ " "
|
[ CellText $ show (p^.pNumber) ++ " "
|
||||||
, CellText $ p^.pName
|
, CellText $ p^.pName
|
||||||
] ++ statsCells stats)
|
] ++ statsCells stats)
|
||||||
ps
|
fps
|
||||||
|
|
||||||
separator = replicate 2 (CellText "") ++ replicate 4 (CellFill '-')
|
separator = replicate 2 (CellText "") ++ replicate 4 (CellFill '-')
|
||||||
|
|
||||||
@@ -205,23 +227,35 @@ playerReport width label ps = let
|
|||||||
, CellText ""
|
, CellText ""
|
||||||
] ++ statsCells tStats
|
] ++ statsCells tStats
|
||||||
|
|
||||||
table = overlayLast (label ++ " TOTALS")
|
olayText = if showTotals
|
||||||
|
then label ++ " TOTALS"
|
||||||
|
else ""
|
||||||
|
|
||||||
|
table = overlayLast olayText
|
||||||
$ map (centre width)
|
$ map (centre width)
|
||||||
$ complexTable ([right, left] ++ repeat right)
|
$ complexTable ([right, left] ++ repeat right)
|
||||||
$ tHeader : body ++ [separator, totals]
|
$ tHeader : body ++ if showTotals
|
||||||
|
then [separator, totals]
|
||||||
|
else []
|
||||||
|
|
||||||
in rHeader ++ table
|
in rHeader ++ table
|
||||||
|
|
||||||
goalieReport :: Int -> [(Goalie, GoalieStats)] -> [String]
|
goalieReport
|
||||||
goalieReport width goalieData = let
|
:: Int
|
||||||
olayText = "GOALTENDING TOTALS"
|
-> Bool
|
||||||
|
-> [(Goalie, GoalieStats)]
|
||||||
|
-> [String]
|
||||||
|
goalieReport width showTotals goalieData = let
|
||||||
|
olayText = if showTotals
|
||||||
|
then "GOALTENDING TOTALS"
|
||||||
|
else ""
|
||||||
|
|
||||||
tData = foldl addGoalieStats newGoalieStats
|
tData = foldl addGoalieStats newGoalieStats
|
||||||
$ map snd goalieData
|
$ map snd goalieData
|
||||||
|
|
||||||
header =
|
header =
|
||||||
[ CellText "NO."
|
[ CellText "NO."
|
||||||
, CellText $ left (length olayText) "GOALTENDER"
|
, CellText $ padRight (length olayText) "GOALTENDER"
|
||||||
, CellText "GP"
|
, CellText "GP"
|
||||||
, CellText " MIN"
|
, CellText " MIN"
|
||||||
, CellText " GA"
|
, CellText " GA"
|
||||||
@@ -240,7 +274,7 @@ goalieReport width goalieData = let
|
|||||||
body = map
|
body = map
|
||||||
(\(goalie, stats) ->
|
(\(goalie, stats) ->
|
||||||
[ CellText $ show (goalie^.gNumber) ++ " "
|
[ CellText $ show (goalie^.gNumber) ++ " "
|
||||||
, CellText $ show $ goalie^.gName
|
, CellText $ goalie^.gName
|
||||||
] ++ rowCells stats)
|
] ++ rowCells stats)
|
||||||
goalieData
|
goalieData
|
||||||
|
|
||||||
@@ -253,4 +287,30 @@ goalieReport width goalieData = let
|
|||||||
in map (centre width)
|
in map (centre width)
|
||||||
$ overlayLast olayText
|
$ overlayLast olayText
|
||||||
$ complexTable ([right, left] ++ repeat right)
|
$ complexTable ([right, left] ++ repeat right)
|
||||||
$ header : body ++ [separator, summary]
|
$ header : body ++ if showTotals
|
||||||
|
then [separator, summary]
|
||||||
|
else []
|
||||||
|
|
||||||
|
gameGoalieReport :: Int -> [(Goalie, GoalieStats)] -> [String]
|
||||||
|
gameGoalieReport width goalieData = let
|
||||||
|
header =
|
||||||
|
[ CellText "NO."
|
||||||
|
, CellText "GOALTENDER"
|
||||||
|
, CellText " MIN"
|
||||||
|
, CellText " GA"
|
||||||
|
, CellText " AVE"
|
||||||
|
]
|
||||||
|
|
||||||
|
body = map
|
||||||
|
(\(goalie, stats) ->
|
||||||
|
[ CellText $ show (goalie^.gNumber) ++ " "
|
||||||
|
, CellText $ goalie^.gName
|
||||||
|
, CellText $ show $ stats^.gsMinsPlayed
|
||||||
|
, CellText $ show $ stats^.gsGoalsAllowed
|
||||||
|
, CellText $ showFloating $ gsAverage stats
|
||||||
|
])
|
||||||
|
goalieData
|
||||||
|
|
||||||
|
in map (centre width)
|
||||||
|
$ complexTable ([right, left] ++ repeat right)
|
||||||
|
$ header : body
|
||||||
|
|||||||
@@ -192,6 +192,7 @@ import Data.Aeson
|
|||||||
, (.!=)
|
, (.!=)
|
||||||
, (.=)
|
, (.=)
|
||||||
)
|
)
|
||||||
|
import Data.Char (toUpper)
|
||||||
import Data.List (isInfixOf)
|
import Data.List (isInfixOf)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
import Data.Maybe (listToMaybe)
|
import Data.Maybe (listToMaybe)
|
||||||
@@ -229,6 +230,7 @@ data ProgMode
|
|||||||
= MainMenu
|
= MainMenu
|
||||||
| NewSeason
|
| NewSeason
|
||||||
| NewGame GameState
|
| NewGame GameState
|
||||||
|
| EditMenu
|
||||||
| CreatePlayer CreatePlayerState
|
| CreatePlayer CreatePlayerState
|
||||||
| CreateGoalie CreateGoalieState
|
| CreateGoalie CreateGoalieState
|
||||||
| EditPlayer EditPlayerState
|
| EditPlayer EditPlayerState
|
||||||
@@ -238,6 +240,7 @@ instance Show ProgMode where
|
|||||||
show MainMenu = "MainMenu"
|
show MainMenu = "MainMenu"
|
||||||
show NewSeason = "NewSeason"
|
show NewSeason = "NewSeason"
|
||||||
show (NewGame _) = "NewGame"
|
show (NewGame _) = "NewGame"
|
||||||
|
show EditMenu = "EditMenu"
|
||||||
show (CreatePlayer _) = "CreatePlayer"
|
show (CreatePlayer _) = "CreatePlayer"
|
||||||
show (CreateGoalie _) = "CreateGoalie"
|
show (CreateGoalie _) = "CreateGoalie"
|
||||||
show (EditPlayer _) = "EditPlayer"
|
show (EditPlayer _) = "EditPlayer"
|
||||||
@@ -601,8 +604,8 @@ instance ToJSON GameStats where
|
|||||||
data Prompt = Prompt
|
data Prompt = Prompt
|
||||||
{ promptDrawer :: ProgState -> C.Update ()
|
{ promptDrawer :: ProgState -> C.Update ()
|
||||||
-- ^ Draws the prompt to the screen
|
-- ^ Draws the prompt to the screen
|
||||||
, promptCharCheck :: Char -> Bool
|
, promptProcessChar :: Char -> String -> String
|
||||||
-- ^ Determines whether or not the character is valid
|
-- ^ Modifies the string based on the character entered
|
||||||
, promptAction :: String -> Action ()
|
, promptAction :: String -> Action ()
|
||||||
-- ^ Action to perform when the value is entered
|
-- ^ Action to perform when the value is entered
|
||||||
, promptSpecialKey :: C.Key -> Action ()
|
, promptSpecialKey :: C.Key -> Action ()
|
||||||
@@ -621,6 +624,8 @@ data SelectParams a = SelectParams
|
|||||||
-- ^ Search function looking for an exact match
|
-- ^ Search function looking for an exact match
|
||||||
, spElemDesc :: a -> String
|
, spElemDesc :: a -> String
|
||||||
-- ^ Provides a string description of an element
|
-- ^ Provides a string description of an element
|
||||||
|
, spProcessChar :: Char -> String -> String
|
||||||
|
-- ^ Processes a character entered by the user
|
||||||
, spCallback :: Maybe Int -> Action ()
|
, spCallback :: Maybe Int -> Action ()
|
||||||
-- ^ The function when the selection is made
|
-- ^ The function when the selection is made
|
||||||
, spNotFound :: String -> Action ()
|
, spNotFound :: String -> Action ()
|
||||||
@@ -904,7 +909,7 @@ playerSearch
|
|||||||
-- ^ The matching players with their index numbers
|
-- ^ The matching players with their index numbers
|
||||||
playerSearch sStr =
|
playerSearch sStr =
|
||||||
filter match . zip [0..]
|
filter match . zip [0..]
|
||||||
where match (_, p) = sStr `isInfixOf` (p^.pName)
|
where match (_, p) = map toUpper sStr `isInfixOf` map toUpper (p^.pName)
|
||||||
|
|
||||||
-- | Searches for a player by exact match on name
|
-- | Searches for a player by exact match on name
|
||||||
playerSearchExact
|
playerSearchExact
|
||||||
@@ -967,8 +972,9 @@ goalieSearch
|
|||||||
-- ^ The list to search
|
-- ^ The list to search
|
||||||
-> [(Int, Goalie)]
|
-> [(Int, Goalie)]
|
||||||
-- ^ The search results with their corresponding index numbers
|
-- ^ The search results with their corresponding index numbers
|
||||||
goalieSearch sStr = filter (\(_, goalie) -> sStr `isInfixOf` (goalie^.gName)) .
|
goalieSearch sStr =
|
||||||
zip [0..]
|
filter match . zip [0..]
|
||||||
|
where match (_, g) = map toUpper sStr `isInfixOf` map toUpper (g^.gName)
|
||||||
|
|
||||||
-- | Searches a list of goalies for an exact match
|
-- | Searches a list of goalies for an exact match
|
||||||
goalieSearchExact
|
goalieSearchExact
|
||||||
@@ -1008,4 +1014,10 @@ addGoalieStats g1 g2 = GoalieStats
|
|||||||
|
|
||||||
-- | Determines a goalie's average goals allowed per game.
|
-- | Determines a goalie's average goals allowed per game.
|
||||||
gsAverage :: GoalieStats -> Rational
|
gsAverage :: GoalieStats -> Rational
|
||||||
gsAverage gs = fromIntegral (gs^.gsGoalsAllowed) / fromIntegral (gs^.gsGames)
|
gsAverage gs = let
|
||||||
|
allowed = fromIntegral $ gs^.gsGoalsAllowed
|
||||||
|
mins = fromIntegral $ gs^.gsMinsPlayed
|
||||||
|
gLen = fromIntegral gameLength
|
||||||
|
in if mins == 0
|
||||||
|
then 0
|
||||||
|
else allowed / mins * gLen
|
||||||
|
|||||||
@@ -19,8 +19,15 @@ along with this program. If not, see <https://www.gnu.org/licenses/>.
|
|||||||
|
|
||||||
-}
|
-}
|
||||||
|
|
||||||
module Mtlstats.Util (nth, modifyNth, updateMap, slice) where
|
module Mtlstats.Util
|
||||||
|
( nth
|
||||||
|
, modifyNth
|
||||||
|
, updateMap
|
||||||
|
, slice
|
||||||
|
, capitalizeName
|
||||||
|
) where
|
||||||
|
|
||||||
|
import Data.Char (isSpace, toUpper)
|
||||||
import qualified Data.Map as M
|
import qualified Data.Map as M
|
||||||
|
|
||||||
-- | Attempt to select the element from a list at a given index
|
-- | Attempt to select the element from a list at a given index
|
||||||
@@ -75,3 +82,25 @@ slice
|
|||||||
-- ^ The list to take a subset of
|
-- ^ The list to take a subset of
|
||||||
-> [a]
|
-> [a]
|
||||||
slice offset len = take len . drop offset
|
slice offset len = take len . drop offset
|
||||||
|
|
||||||
|
-- | Name capitalization function for a player
|
||||||
|
capitalizeName
|
||||||
|
:: Char
|
||||||
|
-- ^ The character being input
|
||||||
|
-> String
|
||||||
|
-- ^ The current string
|
||||||
|
-> String
|
||||||
|
-- ^ The resulting string
|
||||||
|
capitalizeName ch str = str ++ [ch']
|
||||||
|
where
|
||||||
|
ch' = if lockFlag str
|
||||||
|
then toUpper ch
|
||||||
|
else ch
|
||||||
|
lockFlag "" = True
|
||||||
|
lockFlag (c:cs)
|
||||||
|
| c == ',' = lockFlag' cs
|
||||||
|
| otherwise = lockFlag cs
|
||||||
|
lockFlag' "" = True
|
||||||
|
lockFlag' (c:cs)
|
||||||
|
| isSpace c = lockFlag' cs
|
||||||
|
| otherwise = False
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ spec = describe "Mtlstats.Actions" $ do
|
|||||||
removeCharSpec
|
removeCharSpec
|
||||||
createPlayerSpec
|
createPlayerSpec
|
||||||
createGoalieSpec
|
createGoalieSpec
|
||||||
|
editSpec
|
||||||
editPlayerSpec
|
editPlayerSpec
|
||||||
editGoalieSpec
|
editGoalieSpec
|
||||||
addPlayerSpec
|
addPlayerSpec
|
||||||
@@ -198,6 +199,12 @@ createGoalieSpec = describe "createGoalie" $
|
|||||||
s = createGoalie newProgState
|
s = createGoalie newProgState
|
||||||
in show (s^.progMode) `shouldBe` "CreateGoalie"
|
in show (s^.progMode) `shouldBe` "CreateGoalie"
|
||||||
|
|
||||||
|
editSpec :: Spec
|
||||||
|
editSpec = describe "edit" $
|
||||||
|
it "should change the mode to EditMenu" $ let
|
||||||
|
ps = edit newProgState
|
||||||
|
in show (ps^.progMode) `shouldBe` "EditMenu"
|
||||||
|
|
||||||
editPlayerSpec :: Spec
|
editPlayerSpec :: Spec
|
||||||
editPlayerSpec = describe "editPlayer" $
|
editPlayerSpec = describe "editPlayer" $
|
||||||
it "should change the mode appropriately" $ let
|
it "should change the mode appropriately" $ let
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ spec = describe "Mtlstats.Format" $ do
|
|||||||
leftSpec
|
leftSpec
|
||||||
rightSpec
|
rightSpec
|
||||||
centreSpec
|
centreSpec
|
||||||
|
padRightSpec
|
||||||
overlaySpec
|
overlaySpec
|
||||||
monthSpec
|
monthSpec
|
||||||
labelTableSpec
|
labelTableSpec
|
||||||
@@ -98,6 +99,16 @@ centreSpec = describe "centre" $ do
|
|||||||
it "should truncate the text" $
|
it "should truncate the text" $
|
||||||
centre 2 "foo" `shouldBe` "fo"
|
centre 2 "foo" `shouldBe` "fo"
|
||||||
|
|
||||||
|
padRightSpec :: Spec
|
||||||
|
padRightSpec = describe "padRight" $ mapM_
|
||||||
|
(\(label, width, str, expected) -> context label $
|
||||||
|
it ("should be " ++ show expected) $
|
||||||
|
padRight width str `shouldBe` expected)
|
||||||
|
-- label, width, input string, expected
|
||||||
|
[ ( "text shorter", 5, "foo", "foo " )
|
||||||
|
, ( "text longer", 3, "foobar", "foobar" )
|
||||||
|
]
|
||||||
|
|
||||||
overlaySpec :: Spec
|
overlaySpec :: Spec
|
||||||
overlaySpec = describe "overlay" $ do
|
overlaySpec = describe "overlay" $ do
|
||||||
|
|
||||||
|
|||||||
@@ -591,7 +591,7 @@ playerSearchSpec = describe "playerSearch" $ mapM_
|
|||||||
ps = [joe, bob, steve]
|
ps = [joe, bob, steve]
|
||||||
in playerSearch sStr ps `shouldBe` expected)
|
in playerSearch sStr ps `shouldBe` expected)
|
||||||
-- search, result
|
-- search, result
|
||||||
[ ( "Joe", [(0, joe)] )
|
[ ( "joe", [(0, joe)] )
|
||||||
, ( "o", [(0, joe), (1, bob)] )
|
, ( "o", [(0, joe), (1, bob)] )
|
||||||
, ( "e", [(0, joe), (2, steve)] )
|
, ( "e", [(0, joe), (2, steve)] )
|
||||||
, ( "x", [] )
|
, ( "x", [] )
|
||||||
@@ -725,8 +725,8 @@ goalieSearchSpec = describe "goalieSearch" $ do
|
|||||||
goalieSearch "x" goalies `shouldBe` []
|
goalieSearch "x" goalies `shouldBe` []
|
||||||
|
|
||||||
context "exact match" $
|
context "exact match" $
|
||||||
it "should return Steve" $
|
it "should return Bob" $
|
||||||
goalieSearch "Bob" goalies `shouldBe` [result 1]
|
goalieSearch "bob" goalies `shouldBe` [result 1]
|
||||||
|
|
||||||
goalieSearchExactSpec :: Spec
|
goalieSearchExactSpec :: Spec
|
||||||
goalieSearchExactSpec = describe "goalieSearchExact" $ do
|
goalieSearchExactSpec = describe "goalieSearchExact" $ do
|
||||||
@@ -813,16 +813,21 @@ addGoalieStatsSpec = describe "addGoalieStats" $ let
|
|||||||
actual `shouldBe` expected
|
actual `shouldBe` expected
|
||||||
|
|
||||||
gsAverageSpec :: Spec
|
gsAverageSpec :: Spec
|
||||||
gsAverageSpec = describe "gsAverage" $ let
|
gsAverageSpec = describe "gsAverage" $ mapM_
|
||||||
|
(\(label, stats, expected) -> context label $
|
||||||
|
it ("should be " ++ show expected) $
|
||||||
|
gsAverage stats `shouldBe` expected)
|
||||||
|
|
||||||
|
-- label, stats, expected
|
||||||
|
[ ( "with minutes", gs, 3 % 2 )
|
||||||
|
, ( "no minutes", newGoalieStats , 0 )
|
||||||
|
]
|
||||||
|
|
||||||
|
where
|
||||||
gs = newGoalieStats
|
gs = newGoalieStats
|
||||||
& gsGames .~ 2
|
& gsMinsPlayed .~ 2 * gameLength
|
||||||
& gsGoalsAllowed .~ 3
|
& gsGoalsAllowed .~ 3
|
||||||
|
|
||||||
expected = 3 % 2
|
|
||||||
|
|
||||||
in it ("should be " ++ show expected) $
|
|
||||||
gsAverage gs `shouldBe` expected
|
|
||||||
|
|
||||||
joe :: Player
|
joe :: Player
|
||||||
joe = newPlayer 2 "Joe" "center"
|
joe = newPlayer 2 "Joe" "center"
|
||||||
|
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ spec = describe "Mtlstats.Util" $ do
|
|||||||
modifyNthSpec
|
modifyNthSpec
|
||||||
updateMapSpec
|
updateMapSpec
|
||||||
sliceSpec
|
sliceSpec
|
||||||
|
capitalizeNameSpec
|
||||||
|
|
||||||
nthSpec :: Spec
|
nthSpec :: Spec
|
||||||
nthSpec = describe "nth" $ mapM_
|
nthSpec = describe "nth" $ mapM_
|
||||||
@@ -93,3 +94,23 @@ sliceSpec = describe "slice" $ do
|
|||||||
context "negative offset" $
|
context "negative offset" $
|
||||||
it "should return the correct number of elements from the beginning" $
|
it "should return the correct number of elements from the beginning" $
|
||||||
slice (-10) 2 list `shouldBe` [2, 4]
|
slice (-10) 2 list `shouldBe` [2, 4]
|
||||||
|
|
||||||
|
capitalizeNameSpec :: Spec
|
||||||
|
capitalizeNameSpec = describe "capitalizeName" $ mapM_
|
||||||
|
(\(label, ch, str, expected) -> context label $
|
||||||
|
it ("should be " ++ expected) $
|
||||||
|
capitalizeName ch str `shouldBe` expected)
|
||||||
|
-- label, character, string, expected
|
||||||
|
[ ( "initial lower", 'a', "", "A" )
|
||||||
|
, ( "initial upper", 'A', "", "A" )
|
||||||
|
, ( "initial non-alpha", '0', "", "0" )
|
||||||
|
, ( "pre-comma lower", 'a', "A", "AA" )
|
||||||
|
, ( "pre-comma upper", 'A', "A", "AA" )
|
||||||
|
, ( "pre-comma non-alpha", '0', "A", "A0" )
|
||||||
|
, ( "post-comma first lower", 'a', "FOO, ", "FOO, A" )
|
||||||
|
, ( "post-comma first upper", 'A', "FOO, ", "FOO, A" )
|
||||||
|
, ( "post-comma first non-alpha", '0', "FOO, ", "FOO, 0" )
|
||||||
|
, ( "unrestricted upper", 'A', "FOO, A", "FOO, AA" )
|
||||||
|
, ( "unrestricted lower", 'a', "FOO, A", "FOO, Aa" )
|
||||||
|
, ( "unrestricted non-alpha", '0', "FOO, A", "FOO, A0" )
|
||||||
|
]
|
||||||
|
|||||||
Reference in New Issue
Block a user