Skip to content

Commit 1fec3b7

Browse files
committed
WIP
1 parent 59efe9f commit 1fec3b7

File tree

7 files changed

+276
-0
lines changed

7 files changed

+276
-0
lines changed

rhine-cassava/CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# Revision history for rhine-cassava
2+
3+
## 0.8.1.1 -- YYYY-mm-dd
4+
5+
* First version. Released on an unsuspecting world.

rhine-cassava/LICENSE

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
Copyright (c) 2023 Manuel Bärenz
2+
3+
Permission is hereby granted, free of charge, to any person obtaining
4+
a copy of this software and associated documentation files (the
5+
"Software"), to deal in the Software without restriction, including
6+
without limitation the rights to use, copy, modify, merge, publish,
7+
distribute, sublicense, and/or sell copies of the Software, and to
8+
permit persons to whom the Software is furnished to do so, subject to
9+
the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included
12+
in all copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17+
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18+
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19+
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20+
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

rhine-cassava/rhine-cassava.cabal

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
cabal-version: 3.0
2+
-- The cabal-version field refers to the version of the .cabal specification,
3+
-- and can be different from the cabal-install (the tool) version and the
4+
-- Cabal (the library) version you are using. As such, the Cabal (the library)
5+
-- version used must be equal or greater than the version stated in this field.
6+
-- Starting from the specification version 2.2, the cabal-version field must be
7+
-- the first thing in the cabal file.
8+
9+
-- Initial package description 'rhine-cassava' generated by
10+
-- 'cabal init'. For further documentation, see:
11+
-- http://haskell.org/cabal/users-guide/
12+
--
13+
-- The name of the package.
14+
name: rhine-cassava
15+
16+
-- The package version.
17+
-- See the Haskell package versioning policy (PVP) for standards
18+
-- guiding when and how versions should be incremented.
19+
-- https://pvp.haskell.org
20+
-- PVP summary: +-+------- breaking API changes
21+
-- | | +----- non-breaking API additions
22+
-- | | | +--- code changes with no API change
23+
version: 1.0
24+
25+
-- A short (one-line) description of the package.
26+
-- synopsis:
27+
28+
-- A longer description of the package.
29+
-- description:
30+
31+
-- The license under which the package is released.
32+
license: MIT
33+
34+
-- The file containing the license text.
35+
license-file: LICENSE
36+
37+
-- The package author(s).
38+
author: Manuel Bärenz
39+
40+
-- An email address to which users can send suggestions, bug reports, and patches.
41+
maintainer: [email protected]
42+
43+
-- A copyright notice.
44+
-- copyright:
45+
category: FRP
46+
build-type: Simple
47+
48+
-- Extra doc files to be distributed with the package, such as a CHANGELOG or a README.
49+
extra-doc-files: CHANGELOG.md
50+
51+
-- Extra source files to be distributed with the package, such as examples, or a tutorial module.
52+
-- extra-source-files:
53+
54+
common warnings
55+
ghc-options: -Wall
56+
if flag(dev)
57+
ghc-options: -Werror
58+
59+
flag dev
60+
description: Enable warnings as errors. Active on ci.
61+
default: False
62+
manual: True
63+
64+
library
65+
-- Import common warning flags.
66+
import: warnings
67+
68+
-- Modules exported by the library.
69+
exposed-modules: FRP.Rhine.Clock.Csv
70+
71+
-- Modules included in this library but not exported.
72+
-- other-modules:
73+
74+
-- LANGUAGE extensions used by modules in this package.
75+
-- other-extensions:
76+
77+
-- Other library packages from which modules are imported.
78+
build-depends: base >= 4.11 && < 4.18
79+
, rhine == 1.0
80+
, transformers >= 0.5
81+
, cassava ^>= 0.5.3
82+
, bytestring ^>= 0.11.4
83+
, vector ^>= 0.12
84+
85+
-- Directories containing source files.
86+
hs-source-dirs: src
87+
88+
-- Base language which the package is written in.
89+
default-language: Haskell2010
90+
91+
default-extensions:
92+
FlexibleInstances
93+
MultiParamTypeClasses
94+
NamedFieldPuns
95+
TypeFamilies
96+
97+
test-suite rhine-cassava-test
98+
-- Import common warning flags.
99+
import: warnings
100+
101+
-- Base language which the package is written in.
102+
default-language: Haskell2010
103+
104+
-- Modules included in this executable, other than Main.
105+
-- other-modules:
106+
107+
-- LANGUAGE extensions used by modules in this package.
108+
-- other-extensions:
109+
110+
-- The interface type and version of the test suite.
111+
type: exitcode-stdio-1.0
112+
113+
-- Directories containing source files.
114+
hs-source-dirs: test
115+
116+
-- The entrypoint to the test suite.
117+
main-is: Main.hs
118+
119+
-- Test dependencies.
120+
build-depends:
121+
base >= 4.11 && < 4.18
122+
, hspec ^>= 2.11
123+
, transformers
124+
, bytestring
125+
, vector
126+
, directory
127+
, cassava
128+
, rhine
129+
, rhine-cassava
130+
131+
default-extensions:
132+
Arrows
133+
ImportQualifiedPost
134+
OverloadedLists
135+
OverloadedStrings
136+
TypeApplications
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
module FRP.Rhine.Clock.Csv (
2+
CsvClock,
3+
csvClock,
4+
)
5+
where
6+
7+
-- bytestring
8+
import Data.ByteString
9+
10+
-- vector
11+
import Data.Vector
12+
13+
-- cassava
14+
import Data.Csv
15+
16+
-- rhine
17+
18+
import Control.Monad.Trans.Except
19+
import FRP.Rhine (GetClockProxy)
20+
import FRP.Rhine.Clock
21+
import FRP.Rhine.Clock.File
22+
23+
{- | Similar to 'File', but ticks at every line of a CSV file,
24+
and returns a parsed record.
25+
26+
Additionally to an end-of-file error, it can also return a parse error as a 'String'.
27+
-}
28+
newtype CsvClock = CsvClock (File String (Vector Record))
29+
30+
-- | Create a 'CsvClock' from a file path.
31+
csvClock :: FilePath -> CsvClock
32+
csvClock filename =
33+
CsvClock
34+
File
35+
{ action = fmap (decode NoHeader . fromStrict) . Data.ByteString.hGetLine
36+
, filename
37+
}
38+
39+
instance Clock (ExceptT (Either String FileException) IO) CsvClock where
40+
type Time CsvClock = Integer
41+
type Tag CsvClock = Vector Record
42+
initClock (CsvClock fileClock) = initClock fileClock
43+
44+
instance GetClockProxy CsvClock

rhine-cassava/test/Main.hs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
module Main (main) where
2+
3+
-- bytestring
4+
import Data.ByteString
5+
import Data.ByteString qualified as ByteString
6+
7+
-- directory
8+
import System.Directory (removeFile)
9+
10+
-- hspec
11+
import Test.Hspec
12+
13+
-- vector
14+
import Data.Vector (Vector)
15+
16+
-- cassava
17+
import Data.Csv (Record)
18+
19+
-- rhine
20+
import FRP.Rhine
21+
import FRP.Rhine.Clock.Csv
22+
import FRP.Rhine.Clock.File (FileException)
23+
24+
main :: IO ()
25+
main = hspec $ do
26+
it "Can read a file" $ do
27+
let bytestring = "hi,this\nis,dog\n" :: ByteString
28+
filepath = "testfile.csv"
29+
ByteString.writeFile filepath bytestring
30+
Right result <- runExceptT @(Either String FileException) $ (flip embed [(), ()] =<<) $ eraseClock $ tagS @@ csvClock filepath
31+
removeFile filepath
32+
result `shouldBe` ([Just [["hi", "this"]], Just [["is", "dog"]]] :: [Maybe (Vector Record)])

rhine/rhine.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ library
8585
exposed-modules:
8686
FRP.Rhine
8787
FRP.Rhine.Clock
88+
FRP.Rhine.Clock.File
8889
FRP.Rhine.Clock.FixedStep
8990
FRP.Rhine.Clock.Periodic
9091
FRP.Rhine.Clock.Proxy

rhine/src/FRP/Rhine/Clock/File.hs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
module FRP.Rhine.Clock.File where
2+
3+
-- base
4+
import Data.Bifunctor (first)
5+
import System.IO
6+
import System.IO.Error
7+
8+
-- transformers
9+
import Control.Monad.Trans.Class
10+
import Control.Monad.Trans.Except
11+
12+
-- rhine
13+
import FRP.Rhine.Clock
14+
import FRP.Rhine.Clock.Proxy
15+
16+
-- | A clock that opens a file and extracts data of type @a@ from it.
17+
data File e a = File
18+
{ filename :: String
19+
, action :: Handle -> IO (Either e a)
20+
}
21+
22+
instance GetClockProxy (File e a)
23+
24+
data FileException = EndOfFile
25+
deriving (Show)
26+
27+
instance Clock (ExceptT (Either e FileException) IO) (File e a) where
28+
type Time (File e a) = Integer
29+
type Tag (File e a) = a
30+
initClock File {filename, action} = lift $ do
31+
handle <- openFile filename ReadMode
32+
let getLineHandle = arrM $ const $ ExceptT $ do
33+
catchIOError (Data.Bifunctor.first Left <$> action handle) $ \e -> do
34+
hClose handle
35+
if isEOFError e
36+
then return $ Left $ Right EndOfFile
37+
else ioError e
38+
return (count &&& getLineHandle, 0)

0 commit comments

Comments
 (0)