packages feed

clerk 0.1.0.1 → 0.1.0.2

raw patch · 5 files changed

+19/−306 lines, 5 filesdep −clerkPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies removed: clerk

API changes (from Hackage documentation)

- Example: main :: IO ()

Files

README.md view
@@ -37,7 +37,7 @@ First, we import the necessary stuff.  ```haskell-module Example (main) where+module Main (main) where import Clerk import Codec.Xlsx qualified as X import Codec.Xlsx.Formatted qualified as X@@ -288,10 +288,12 @@ Run  ```console-stack run+cd example+nix develop+cabal run ``` -to get `example-1.xlsx`.+to get `example/example-1.xlsx`.  With formulas enabled, `example-1.xlsx` looks like this: @@ -310,7 +312,7 @@ Next, run  ```sh-nix develop nix-dev/+nix develop write-settings-json codium . ```
− app/Main.hs
@@ -1,6 +0,0 @@-module Main (main) where--import Example qualified as E (main)--main :: IO ()-main = E.main
clerk.cabal view
@@ -5,7 +5,7 @@ -- see: https://github.com/sol/hpack  name:           clerk-version:        0.1.0.1+version:        0.1.0.2 synopsis:       Declaratively describe spreadsheets and generate xlsx description:    Please see the README on GitHub at <https://github.com/deemp/clerk#readme> category:       spreadsheet@@ -28,7 +28,6 @@ library   exposed-modules:       Clerk-      Example   other-modules:       Paths_clerk   hs-source-dirs:@@ -39,10 +38,8 @@       FlexibleContexts       FlexibleInstances       OverloadedStrings-      OverloadedRecordDot       GeneralizedNewtypeDeriving       RankNTypes-      ImportQualifiedPost       InstanceSigs       NamedFieldPuns       RecordWildCards@@ -54,44 +51,6 @@   build-depends:       base >=4.9.0.0 && <5.0     , bytestring >=0.10.8.0-    , containers >=0.5.0.0-    , data-default >=0.7.1.1-    , lens >=3.8 && <5.3-    , mtl >=2.1-    , text >=0.11.3.1-    , time >=1.4.0.1-    , transformers >=0.3.0.0-    , xlsx >=1.1.0.1-  default-language: Haskell2010--executable clerk-  main-is: Main.hs-  other-modules:-      Paths_clerk-  hs-source-dirs:-      app-  default-extensions:-      DataKinds-      DeriveFunctor-      FlexibleContexts-      FlexibleInstances-      OverloadedStrings-      OverloadedRecordDot-      GeneralizedNewtypeDeriving-      RankNTypes-      ImportQualifiedPost-      InstanceSigs-      NamedFieldPuns-      RecordWildCards-      TupleSections-      MonoLocalBinds-      TypeSynonymInstances-      DuplicateRecordFields-  ghc-options: -Wall -Wcompat -Widentities -Wincomplete-record-updates -Wincomplete-uni-patterns -Wmissing-export-lists -Wmissing-home-modules -Wpartial-fields -Wredundant-constraints-  build-depends:-      base >=4.9.0.0 && <5.0-    , bytestring >=0.10.8.0-    , clerk     , containers >=0.5.0.0     , data-default >=0.7.1.1     , lens >=3.8 && <5.3
src/Clerk.hs view
@@ -31,11 +31,11 @@   (|^|),   (|$|),   (<|),-  Expr(..)+  Expr (..), ) where -import Codec.Xlsx qualified as X-import Codec.Xlsx.Formatted qualified as X+import qualified Codec.Xlsx as X+import qualified Codec.Xlsx.Formatted as X import Control.Lens (Identity (runIdentity), (%~), (&), (?~)) import Control.Lens.Operators ((.~)) import Control.Monad.State (@@ -53,9 +53,9 @@ import Data.Default (Default (..)) import Data.Foldable (Foldable (..)) import Data.List (intercalate)-import Data.Map.Strict qualified as Map (Map, insert)+import qualified Data.Map.Strict as Map (Map, insert) import Data.Maybe (isJust, maybeToList)-import Data.Text qualified as T+import qualified Data.Text as T  -- Coords @@ -242,13 +242,13 @@   let columnsProperties =         Just $           (unColumnsProperties def)-            { X.cpMin = coords.col-            , X.cpMax = coords.col+            { X.cpMin = coords & col+            , X.cpMax = coords & col             , X.cpWidth = width             }   tell (Template [CellTemplate{format, mkOutput, columnsProperties}])   cell <- gets Cell-  modify (\x -> x{col = (x.col) + 1})+  modify (\x -> x{col = (x & col) + 1})   return cell  columnWidth :: ToCellData output => Double -> FormatCell -> (input -> output) -> Builder input CellData (Cell a)@@ -302,12 +302,12 @@ composeXlsx sheetBuilders = workBook'  where   getTransform x = execWriter $ unSheetBuilder x-  workBook = X.formatWorkbook ((\(name, tf') -> (name, (getTransform tf').fmTransform X.def)) <$> sheetBuilders) X.def+  workBook = X.formatWorkbook ((\(name, tf') -> (name, (getTransform tf' & fmTransform) X.def)) <$> sheetBuilders) X.def   filterWidths ws = ws & X.wsColumnsProperties %~ filter (isJust . X.cpWidth)   workBook' =     workBook       & X.xlSheets-        %~ \sheets -> zipWith (\x (name, ws) -> (name, (getTransform x).wsTransform ws & filterWidths)) (snd <$> sheetBuilders) sheets+        %~ \sheets -> zipWith (\x (name, ws) -> (name, (getTransform x & wsTransform) ws & filterWidths)) (snd <$> sheetBuilders) sheets  {- Lib. Formulas -} @@ -416,10 +416,10 @@ newtype Cell a = Cell {unCell :: Coords} deriving (Functor)  cellCol :: Cell a -> Int-cellCol (Cell c) = c.col+cellCol (Cell c) = c & col  cellRow :: Cell a -> Int-cellRow (Cell c) = c.row+cellRow (Cell c) = c & row  overCol :: (Int -> Int) -> Coords -> Coords overCol f (Coords row col) = Coords row (f col)
− src/Example.lhs
@@ -1,242 +0,0 @@- ## Example--This is a demo program that uses `clerk` to produce an `xlsx` file that looks as follows:--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/demoValues.png" width = "80%">--Alternatively, with formulas enabled:--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/demoFormulas.png" width = "80%">--This file has a sheet with several tables. These are tables for-constants' header, a table per a constant's value (three of them), volume & pressure header, volume & pressure values.-Let's see how we can construct such a sheet.-- ### Imports--First, we import the necessary stuff.--> module Example (main) where-> import Clerk-> import Codec.Xlsx qualified as X-> import Codec.Xlsx.Formatted qualified as X-> import Control.Lens ((%~), (&), (?~))-> import Data.ByteString.Lazy qualified as L-> import Data.Text qualified as T-> import Data.Time.Clock.POSIX (getPOSIXTime)-> import Control.Monad (void)-- ### Inputs--Following that, we declare a number of data types that we'll use to store the input values.--A type for constants' headers.--> data ConstantsHeader = ConstantsHeader->     { hConstant :: String->     , hSymbol :: String->     , hValue :: String->     , hUnits :: String->     }-> -> constantsHeader :: ConstantsHeader-> constantsHeader =->     ConstantsHeader->         { hConstant = "constant"->         , hSymbol = "symbol"->         , hValue = "value"->         , hUnits = "units"->         }--A type for constants' data.--> data ConstantsData a = ConstantsData->     { name :: String->     , symbol :: String->     , value :: a->     , units :: String->     }--Additionally, we declare a helper type that will store all constants together.--> data ConstantsInput = ConstantsInput->     { gas :: ConstantsData Double->     , nMoles :: ConstantsData Double->     , temperature :: ConstantsData Double->     }-> -> constants :: ConstantsInput-> constants =->     ConstantsInput->         { gas = ConstantsData "GAS CONSTANT" "R" 0.08206 "L.atm/mol.K"->         , nMoles = ConstantsData "NUMBER OF MOLES" "n" 1 "moles"->         , temperature = ConstantsData "TEMPERATURE(K)" "T" 273.2 "K"->         }--A type for the Volume & Pressure header.--> data ValuesHeader = ValuesHeader->     { hVolume :: String->     , hPressure :: String->     }-> -> valuesHeader :: ValuesHeader-> valuesHeader =->     ValuesHeader->         { hVolume = "VOLUME (L)"->         , hPressure = "PRESSURE (atm)"->         }--The last type is for volume inputs. We just generate them--> newtype Volume = Volume->     { volume :: Double->     }-> -> volumeData :: [Volume]-> volumeData = take 10 $ Volume <$> [1 ..]-- ### Styles--Following the headers and data types, we define the styles. Let's start with colors.-We select several color codes and store them into `colors`--> data Colors = Colors->     { lightBlue :: T.Text->     , lightGreen :: T.Text->     , blue :: T.Text->     , green :: T.Text->     }-> -> colors :: Colors-> colors =->     Colors->         { lightGreen = "90CCFFCC"->         , lightBlue = "90CCFFFF"->         , blue = "FF99CCFF"->         , green = "FF00FF00"->         }--Next, we convert them to `FormatCell` function--> colorBlue :: FormatCell-> colorBlue = mkColorStyle colors.blue-> -> colorLightBlue :: FormatCell-> colorLightBlue = mkColorStyle colors.lightBlue-> -> colorGreen :: FormatCell-> colorGreen = mkColorStyle colors.green-> -> colorMixed :: FormatCell-> colorMixed coords idx = mkColorStyle (if even idx then colors.lightGreen else colors.lightBlue) coords idx--Additionally, we compose a transform for the number format--> -- | allow 2 decimal digits-> nf2decimal :: FCTransform-> nf2decimal fc = fc & X.formattedFormat %~ (\ff -> ff & X.formatNumberFormat ?~ X.StdNumberFormat X.Nf2Decimal)--And a transform for centering the cell contents--> alignCenter :: FCTransform-> alignCenter = horizontalAlignment X.CellHorizontalAlignmentCenter-- ### `Builder`s--Now, we are able to compose the `Builder`s for tables.--A builder for the constants header.--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/constantsHeader.png" width = "50%">--> constantsHeaderBuilder :: Builder ConstantsHeader CellData (Coords, Coords)-> constantsHeaderBuilder = do->     tl <- columnWidth 20 (alignCenter <| colorBlue) hConstant->     columnWidth_ 8 (alignCenter <| colorBlue) hSymbol->     column_ (alignCenter <| colorBlue) hValue->     tr <- columnWidth 13 (alignCenter <| colorBlue) hUnits->     return (unCell tl, unCell tr)--A builder for a constant. We'll use this builder for each constant separately-as each constant produces cells of a specific type.--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/constants.png" width = "50%">--> constantBuilder :: forall a. ToCellData a => Builder (ConstantsData a) CellData (Coords, Cell a)-> constantBuilder = do->     topLeft <- column colorLightBlue name->     column_ colorLightBlue symbol->     value <- column (nf2decimal <| colorLightBlue) value->     column_ colorLightBlue units->     return (unCell topLeft, value)--A builder for values' header.--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/valuesHeader.png" width = "50%">--> valuesHeaderBuilder :: Builder ValuesHeader CellData Coords-> valuesHeaderBuilder = do->     tl <- columnWidth 12 colorGreen hVolume->     columnWidth_ 16 colorGreen hPressure->     return (unCell tl)--A builder for volume & pressure (formulas enabled)--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/valuesFormulas.png" width = "50%">--To pass values in a structured way, we make a helper type.--> data ConstantsValues = ConstantsValues->     { gas :: Cell Double->     , nMoles :: Cell Double->     , temperature :: Cell Double->     }--Next, we define a function to produce a builder.--> valuesBuilder :: ConstantsValues -> Builder Volume CellData ()-> valuesBuilder cv = do->     volume' <- column colorMixed volume->     let pressure' = ex cv.gas |*| ex cv.nMoles |*| ex cv.temperature |/| ex volume'->     column_ (nf2decimal <| colorMixed) (const pressure')-- ### `SheetBuilder`--The `SheetBuilder` is used to place builders onto a sheet and glue them together--> full :: SheetBuilder ()-> full = do->     (constantsHeaderTL, constantsHeaderTR) <- placeInput (Coords 2 2) constantsHeader constantsHeaderBuilder->     (gasTL, gas) <- placeInput (overRow (+ 2) constantsHeaderTL) constants.gas constantBuilder->     (nMolesTL, nMoles) <- placeInput (overRow (+ 1) gasTL) constants.nMoles constantBuilder->     temperature <- snd <$> placeInput (overRow (+ 1) nMolesTL) constants.temperature constantBuilder->     valuesHeaderTL <- placeInput (overCol (+ 2) constantsHeaderTR) valuesHeader valuesHeaderBuilder->     placeInputs_ (overRow (+ 2) valuesHeaderTL) volumeData (valuesBuilder $ ConstantsValues{..})-- ### Result--Now, we can write the result and get the spreadsheet images that you've seen at the top of this tutorial.--> writeWorksheet :: SheetBuilder a -> String -> IO ()-> writeWorksheet tb name = do->     ct <- getPOSIXTime->     let->         xlsx = composeXlsx [("List 1", void tb)]->     L.writeFile ("example-" <> name <> ".xlsx") $ X.fromXlsx ct xlsx-> -> writeEx :: IO ()-> writeEx = writeWorksheet full "1"-> -> main :: IO ()-> main = writeEx--Run--< stack run--to get `example-1.xlsx`.--With formulas enabled, `example-1.xlsx` looks like this:--<img src = "https://raw.githubusercontent.com/deemp/clerk/master/README/demoFormulas.png" width = "80%">