git.iko.soy/typeable/cassava-embed
on master help sign in
init
commit83277f16e22044be0e6e587a9b50cb6b81d67b9c authorAleksey Pirogov <astynax@users.noreply.github.com> dateTue 19 Sep 2017, 16:40 (9 years ago)
12 files changed+266
.gitignore+3 LICENSE+30 README.md+6 Setup.hs+2 cassava-embed.cabal+60 example/Main.hs+13 example/Types.hs+30 example/data.csv+3 package.yaml+53 src/Data/Csv/Embed.hs+58 stack-ghc-8.yaml+4 stack.yaml+4
.gitignorenew file+3
@@ -0,0 +1,3 @@
1+.stack-work/
2+*.hi
3+*.o
LICENSEnew file+30
@@ -0,0 +1,30 @@
1+Copyright Aleksey Pirogov (c) 2017
2+
3+All rights reserved.
4+
5+Redistribution and use in source and binary forms, with or without
6+modification, are permitted provided that the following conditions are met:
7+
8+ * Redistributions of source code must retain the above copyright
9+ notice, this list of conditions and the following disclaimer.
10+
11+ * Redistributions in binary form must reproduce the above
12+ copyright notice, this list of conditions and the following
13+ disclaimer in the documentation and/or other materials provided
14+ with the distribution.
15+
16+ * Neither the name of Aleksey Pirogov nor the names of other
17+ contributors may be used to endorse or promote products derived
18+ from this software without specific prior written permission.
19+
20+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
README.mdnew file+6
@@ -0,0 +1,6 @@
1+# cassava-embed
2+
3+This library makes possible to embed any CSV-file as a list of `cassava`-parseable records.
4+
5+Take a look at `example/` folder for more info.
6+
Setup.hsnew file+2
@@ -0,0 +1,2 @@
1+import Distribution.Simple
2+main = defaultMain
cassava-embed.cabalnew file+60
@@ -0,0 +1,60 @@
1+-- This file has been generated from package.yaml by hpack version 0.17.1.
2+--
3+-- see: https://github.com/sol/hpack
4+
5+name: cassava-embed
6+version: 0.1.0.0
7+synopsis: CSV-file embedding library
8+description: @cassava-embed@ helps to embed CSV-file using TemplateHaskell.
9+category: Text,CSV
10+homepage: https://github.com/typeable/cassava-embed#readme
11+author: Typeable.io contributors
12+maintainer: makeit@typeable.io
13+license: BSD3
14+license-file: LICENSE
15+build-type: Simple
16+cabal-version: >= 1.10
17+
18+extra-source-files:
19+ README.md
20+
21+flag build-examples
22+ description: Build example(s)
23+ manual: True
24+ default: False
25+
26+library
27+ hs-source-dirs:
28+ src
29+ build-depends:
30+ base >= 4.7 && < 5
31+ , cassava
32+ , template-haskell
33+ , bytestring
34+ , vector
35+ exposed-modules:
36+ Data.Csv.Embed
37+ default-language: Haskell2010
38+
39+executable example
40+ main-is: Main.hs
41+ hs-source-dirs:
42+ example
43+ build-depends:
44+ base >= 4.7 && < 5
45+ , cassava
46+ , template-haskell
47+ if flag(build-examples)
48+ buildable: True
49+ if impl(ghc < 8.0.1)
50+ build-depends:
51+ cassava-embed
52+ , th-lift
53+ else
54+ build-depends:
55+ cassava-embed
56+ else
57+ buildable: False
58+ other-modules:
59+ Types
60+ default-language: Haskell2010
example/Main.hsnew file+13
@@ -0,0 +1,13 @@
1+{-# LANGUAGE TemplateHaskell #-}
2+
3+module Main where
4+
5+import Data.Csv.Embed
6+import Data.Proxy
7+
8+import Types
9+
10+main :: IO ()
11+main = do
12+ print $(embedNamedRecords (Proxy :: Proxy Rec) "example/data.csv")
13+ print $(embedRecords (Proxy :: Proxy (String, Int)) "example/data.csv")
example/Types.hsnew file+30
@@ -0,0 +1,30 @@
1+{-# LANGUAGE CPP #-}
2+{-# LANGUAGE OverloadedStrings #-}
3+#if __GLASGOW_HASKELL__ >= 800
4+{-# LANGUAGE DeriveLift #-}
5+{-# LANGUAGE StandaloneDeriving #-}
6+#endif
7+{-# LANGUAGE TemplateHaskell #-}
8+
9+module Types where
10+
11+import Data.Csv
12+#if __GLASGOW_HASKELL__ < 800
13+import Language.Haskell.TH.Lift
14+#else
15+import Language.Haskell.TH.Syntax
16+#endif
17+
18+data Rec = Rec
19+ { _rKey :: !String
20+ , _rVal :: !Int
21+ } deriving (Show)
22+
23+#if __GLASGOW_HASKELL__ < 800
24+$(deriveLift ''Rec)
25+#else
26+deriving instance Lift Rec
27+#endif
28+
29+instance FromNamedRecord Rec where
30+ parseNamedRecord r = Rec <$> r .: "key" <*> r .: "val"
example/data.csvnew file+3
@@ -0,0 +1,3 @@
1+key,val
2+foo,100
3+bar,42
package.yamlnew file+53
@@ -0,0 +1,53 @@
1+name: cassava-embed
2+version: 0.1.0.0
3+synopsis: CSV-file embedding library
4+description: >
5+ @cassava-embed@ helps to embed CSV-file using TemplateHaskell.
6+homepage: https://github.com/typeable/cassava-embed#readme
7+license: BSD3
8+author: Typeable.io contributors
9+maintainer: makeit@typeable.io
10+category: Text,CSV
11+extra-source-files:
12+ - README.md
13+
14+flags:
15+ build-examples:
16+ description: Build example(s)
17+ default: false
18+ manual: true
19+
20+dependencies:
21+ - base >= 4.7 && < 5
22+ - cassava
23+ - template-haskell
24+
25+executables:
26+ example:
27+ source-dirs:
28+ - example
29+ main: Main.hs
30+ other-modules:
31+ - Types
32+ when:
33+ - condition: flag(build-examples)
34+ then:
35+ when:
36+ - condition: impl(ghc < 8.0.1)
37+ then:
38+ dependencies:
39+ - cassava-embed
40+ - th-lift
41+ else:
42+ dependencies:
43+ - cassava-embed
44+ buildable: true
45+ else:
46+ buildable: false
47+
48+library:
49+ source-dirs:
50+ - src
51+ dependencies:
52+ - bytestring
53+ - vector
src/Data/Csv/Embed.hsnew file+58
@@ -0,0 +1,58 @@
1+{-|
2+Module : Data.Csv.Embed
3+Description : CSV-file embedding library
4+License : BSD-3
5+Stability : experimental
6+Portability : POSIX
7+
8+@cassava-embed@ helps to embed CSV-file using TemplateHaskell.
9+
10+Typical usage:
11+
12+> print $(embedRecord (Proxy :: Proxy (String, Int)) "data.csv")
13+
14+-}
15+
16+module Data.Csv.Embed
17+ ( embedRecords
18+ , embedNamedRecords
19+ ) where
20+
21+import Data.ByteString.Lazy as BSL
22+import Data.Csv
23+import Data.Proxy
24+import Data.Vector
25+import Language.Haskell.TH
26+import Language.Haskell.TH.Syntax
27+
28+-- | Embeds CSV-file as list of values with type
29+-- that implements 'FromRecord'.
30+embedRecords
31+ :: (Lift a, FromRecord a)
32+ => Proxy a -- ^ type of row (proxied)
33+ -> FilePath -- ^ path to CSV-file
34+ -> ExpQ
35+embedRecords proxy path = do
36+ content <- runIO $ BSL.readFile path
37+ let
38+ Right rows = decode HasHeader content
39+ Right xs = traverse (fmap cast . runParser . parseRecord) $ toList rows
40+ ListE <$> Prelude.mapM lift xs
41+ where
42+ cast x = x `asProxyTypeOf` proxy
43+
44+-- | Embeds CSV-file as list of values with type
45+-- that implements 'FromNamedRecord'.
46+embedNamedRecords
47+ :: (Lift a, FromNamedRecord a)
48+ => Proxy a -- ^ type of row (proxied)
49+ -> FilePath -- ^ path to CSV-file
50+ -> ExpQ
51+embedNamedRecords proxy path = do
52+ content <- runIO $ BSL.readFile path
53+ let
54+ Right (_, rows) = decodeByName content
55+ Right xs = traverse (fmap cast . runParser . parseNamedRecord) $ toList rows
56+ ListE <$> Prelude.mapM lift xs
57+ where
58+ cast x = x `asProxyTypeOf` proxy
stack-ghc-8.yamlnew file+4
@@ -0,0 +1,4 @@
1+resolver: lts-8.20
2+
3+packages:
4+ - .
stack.yamlnew file+4
@@ -0,0 +1,4 @@
1+resolver: lts-6.30
2+
3+packages:
4+ - .