packages feed

HaskellAnalysisProgram-0.1.0: src/CsvData.hs

{-|
Module      : CsvData
Description : Writing to csv file format
Copyright   : Copyright (C) 2019 S. Kamps
License     : -- This file is distributed under the  terms of the Apache License 2.0.
              For more information, see the file "LICENSE", which is included in the distribution.
Stability   : experimental
-}
{-# LANGUAGE OverloadedStrings #-}

module CsvData
  (encodeItemsToFile
  ,appendItemToFile
  ,appendDistToFile
  ,appendPopToFile
  ,MetricInfo (..)
  ,DistPair (..)
  )
  where

-- bytestring
import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString
import FileOperation
-- cassava
import Data.Csv
  ( DefaultOrdered(headerOrder)
  , Header
  , ToField(toField)
  , ToNamedRecord(toNamedRecord)
  , ToRecord (toRecord)
  , (.:)
  , (.=)
  )
import qualified Data.Csv as Cassava
import qualified Data.Text as Text
import qualified Data.Text.Encoding as TextEnc
import Data.Vector (Vector)
import qualified Data.Vector as Vector
import Settings (Settings)

-- | Contains the metric information
data MetricInfo = MetricInfo
    { identifier :: !String  -- ^ The unique identifier of this data (TODO would be nice if this could be a list)
    , relationKey :: !String -- ^ The key to this specific metric relation (E.g., LCOM)
    , value :: !Double       -- ^ The actual value associated with the identifier.
    } deriving (Show)

instance Num MetricInfo where
  (MetricInfo id1 k1 v1) * (MetricInfo _ _ v2) = MetricInfo id1 k1 (v1 * v2)

newtype DistPair = DistPair { getPair :: (Int, Int) }
  deriving (Show)

---------------------------cassava instances metric info on program level

instance ToRecord MetricInfo where
  toRecord (MetricInfo identifier relationKey value) =
    Cassava.record
      [ toField identifier
      , toField relationKey
      , toField value
      ]

instance ToNamedRecord MetricInfo where
  toNamedRecord (MetricInfo identifier relationKey value) =
    Cassava.namedRecord
      [ "Id" .= Text.pack identifier
      , "Metric" .= Text.pack relationKey
      , "Value" .= value
      ]

instance DefaultOrdered MetricInfo where
  headerOrder _ =
    Cassava.header
      [ "Id"
      , "Metric"
      , "Value"
      ]
---------------------------encode metric info on program level

-- | encode MetricInfo item to csv formatted ByteSting without header
encodeItems :: [MetricInfo]
            -> ByteString
encodeItems = Cassava.encode

-- | encode MetricInfo item to csv formatted ByteSting with header
encodeHeaderItems :: [MetricInfo]
                  -> ByteString
encodeHeaderItems = Cassava.encodeDefaultOrderedByName

-- | Creates a new file and writes supplied MetricInfo data.
encodeItemsToFile
  :: Settings     -- ^ File system settings.
  -> String       -- ^ A name. E.g., LCOM, Gini
  -> [MetricInfo] -- ^ Contains the metric information
  -> IO ()
encodeItemsToFile settings metricName mis = do
  let outputFile = metricOutputFile settings metricName
  ByteString.writeFile outputFile $ encodeHeaderItems mis

-- | Append MetricInfo to file. If supplied file does not exist, one will be created.
appendItemToFile
  :: Settings     -- ^ File system settings.
  -> String       -- ^ A name. E.g., LCOM, Gini
  -> [MetricInfo] -- ^ Contains the metric information
  -> IO ()
appendItemToFile settings metricName mi = do
  let outputFile = metricOutputFile settings metricName
  ft <- isFileThere outputFile
  if ft
    then ByteString.appendFile outputFile $ encodeItems mi
    else ByteString.writeFile outputFile $ encodeHeaderItems mi

---------------------------cassava instances metric distribution

instance ToNamedRecord DistPair where
  toNamedRecord pair =
    Cassava.namedRecord
      [ "Frequentie" .= fst (getPair pair)
      , "Value" .= snd (getPair pair)
      ]

instance DefaultOrdered DistPair where
  headerOrder _ =
    Cassava.header
      [ "Frequentie"
      , "Value"
      ]

instance ToRecord DistPair where
  toRecord pair =
    Cassava.record
      [toField (fst $ getPair pair)
      ,toField (snd $ getPair pair)
      ]

---------------------------encode metric distribution

-- | encode DistPair item to csv formatted ByteSting without header
encodeDist :: [DistPair]
            -> ByteString
encodeDist = Cassava.encode

-- | encode DistPair item to csv formatted ByteSting with header
encodeHeaderDist :: [DistPair]
                  -> ByteString
encodeHeaderDist = Cassava.encodeDefaultOrderedByName

-- | Creates a new file and writes supplied DistInfo data.
encodeDistToFile
  :: Settings -- ^ File system settings.
  -> String   -- ^ A name. E.g., LCOM, CBO, LOC
  -> DistPair -- ^ Contains the metric distribution information
  -> IO ()
encodeDistToFile settings metricName dis = do
  let outputFile = metricOutputFile settings metricName
  ByteString.writeFile outputFile $ encodeHeaderDist [dis]

-- | Append DistInfo to file. If supplied file does not exist, one will be created.
appendDistToFile
  :: Settings -- ^ File system settings.
  -> String   -- ^ A name. E.g., LCOM, CBO, LOC
  -> DistPair -- ^ Contains the metric distribution information
  -> IO ()
appendDistToFile settings metricName di = do
  let outputFile = metricOutputFile settings metricName
  ft <- isFileThere outputFile
  if ft
    then ByteString.appendFile outputFile $ encodeDist [di]
    else ByteString.writeFile outputFile $ encodeHeaderDist [di]

---------------------------cassava instances metric population

instance ToRecord Int where
  toRecord v =
    Cassava.record
      [toField v]

---------------------------encode metric population

-- | encode Int item to csv formatted ByteSting without header
encodePop :: [Int]
            -> ByteString
encodePop = Cassava.encode

-- | Creates a new file and writes supplied Int data.
encodePopToFile
  :: Settings -- ^ File system settings.
  -> String   -- ^ A name. E.g., LCOM, CBO, LOC
  -> Int   -- ^ Contains the metric metric value
  -> IO ()
encodePopToFile settings metricName pop = do
  let outputFile = metricOutputFile settings metricName
  ByteString.writeFile outputFile $ encodePop [pop]

-- | Append Int to file. If supplied file does not exist, one will be created.
appendPopToFile
  :: Settings -- ^ File system settings.
  -> String   -- ^ A name. E.g., LCOM, CBO, LOC
  -> Int -- ^ Contains the metric value
  -> IO ()
appendPopToFile settings metricName pop = do
  let outputFile = metricOutputFile settings metricName
  ft <- isFileThere outputFile
  if ft
    then ByteString.appendFile outputFile $ encodePop [pop]
    else ByteString.writeFile outputFile $ encodePop [pop]