packages feed

EditTimeReport-1.0: Edits.hs

-- | Provides a low level view of the log file.

module Edits ( -- * AST
               Edits, Edit(..),
               -- ** Parsing
               editsFromFile,        
               -- * Grouping
               groupWith , fileGroup,
               -- ** Predicates
               Pred,
               -- * Calendars
               Calendar(..), flatten,              
               -- ** Calendar of Edits
               calendarE, CalendarE  
             ) where


import Char
import Maybe (mapMaybe)
import Control.Applicative
import Data.List as L (groupBy)
import qualified Data.Map as D hiding (map, filter, mapMaybe)
import System.FilePath



-- | Abstract syntax for an editor log entry.
--
data Edit  = Edit {   year    :: Int
                    , month   :: Int
                    , day     :: Int
                    , hour    :: Int
                    , minute  :: Int
                    , seconds :: Int
                    , dow     :: Int     -- ^ Day of the week
                    , doy     :: Int     -- ^ Day of the year
                    , file    :: FilePath } deriving (Show, Eq)
type Edits = [Edit]




-- | Parses log files generated by timechartd.py 
-- daemon or editor.
--
editsFromFile :: FilePath -> IO Edits
editsFromFile f = parseEdits <$> readFile f


parseEdits :: String   -> Edits
parseEdit  :: String   -> Maybe Edit

parseEdits  = mapMaybe parseEdit . lines
parseEdit s = if a then Just $ Edit y m d h mi se dw dy (unwords (drop 9 w))
                   else Nothing
                   where w = words s
                         i = take 8 w
                         a = length w >= 9 && all (all isDigit) i && w !! 8 == "EDIT"
                         (y:m:d:h:mi:se:dw:dy:[]) = map read i


-- | A simple abstraction for predicates 
--
type Pred a = a -> Bool




-- | Use a function's result to group by.
--
groupWith  :: Eq a => (b -> a) -> [b] -> [[b]]
groupWith y = groupBy (\f g -> y f == y g)

-- | Group Edits on year.
--
yearGroup  :: Edits -> [Edits]
yearGroup   = groupWith year

-- | Group Edits on month.
--
monthGroup :: Edits -> [Edits]
monthGroup  = groupWith month

-- | Group Edits on day of the month.
--
dayGroup   :: Edits -> [Edits]
dayGroup    = groupWith day

-- | Group Edits on file name.
--
fileGroup  :: Edits -> [Edits]
fileGroup   = groupWith file


-- | The Calendar type is an abstraction over lists of days in 
-- lists of months in lists of years:
--
-- >      [ [ [ a ] ] ]
-- >              | | + years
-- >              | + months
-- >              + days  
--
newtype Calendar a = Calendar [[[a]]] deriving (Eq, Show)

instance Functor Calendar where
  fmap f (Calendar as) = Calendar (map (map (map f)) as)


-- Getting items out of the Calendar container
--
fromCalendar :: Calendar a -> [[[a]]]
flatten      :: Calendar a -> [a]

fromCalendar (Calendar as) = as
flatten = concat . concat . fromCalendar


-- Calendar of Edits
-- Using the grouping functions to build it.
-- Expects a chronological list of edits.
--
type CalendarE = Calendar Edits

calendarE :: Edits -> CalendarE
calendarE = Calendar . map (map dayGroup . monthGroup) . yearGroup