-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathtest.hs
230 lines (200 loc) · 7.78 KB
/
test.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RecordWildCards #-}
import Options.Applicative
-- (Parser, ParserInfo)
import qualified Data.Semigroup as SG
import System.IO
import Data.Maybe (catMaybes)
import Data.List (isInfixOf)
-- import Options.Applicative
-- import Data.Semigroup ((<>))
-- import Control.Applicative
-- import Data.Csv
import qualified Data.Vector as V
-- bytestring
-- import Data.ByteString.Lazy (ByteString)
import qualified Data.ByteString.Lazy as ByteString
import qualified Data.ByteString.Lazy.UTF8 as UTF8
-- data Person = Person
-- { name :: !String
-- , salary :: !Int
-- }
import qualified Data.Csv as Cassava
-- import Network.URI (escapeURIString)
-- text
-- import Data.Text (Text)
-- import qualified Data.Text.Encoding as Text
-- vector
-- import Data.Vector (Vector)
import qualified Data.Vector as Vector
-- deriving implements automatically the obvious functions (show for Show , Eq for Eq etc)
data OptionRecord = OptionRecord { name :: !String, abbr :: !String, desc :: !String } deriving (Eq, Show)
-- To declare an instance of FromNamedRecord, we need to implement the parseNamedRecord function, which takes a map of names to fields and returns a parser of Item. The (.:) operator is a lookup operator, so m .: "Item" means that we look up a field with name Item in the map m. If there's such a field in the map, we use it as the first argument of the Item constructor, that is, we assign it to the itemName field
instance Cassava.FromNamedRecord OptionRecord where
-- (<*>) :: Applicative f => f (a -> b) -> f a -> f b
-- .: is an accessor
-- https://www.stackbuilders.com/tutorials/haskell/csv-encoding-decoding/
parseNamedRecord r = OptionRecord <$> r Cassava..: "name" <*> r Cassava..: "abbr" <*> r Cassava..: "desc"
instance Cassava.ToNamedRecord OptionRecord where
toNamedRecord OptionRecord{..} =
Cassava.namedRecord
[ "name" Cassava..= name
, "abbr" Cassava..= abbr
, "desc" Cassava..= desc
]
optionsHeader :: Cassava.Header
optionsHeader = Vector.fromList [ "name", "abbr", "desc"]
-- instance ToField OptionRecord where
-- toField Country = "International Country"
-- toField (Other otherType) = toField otherType
getFirstWord :: String -> String
getFirstWord line
| null line = []
| null $ words line = []
| otherwise = head $ words line
-- here we could do filter (/='\'') str
stripTicks :: String -> String
stripTicks w
| null w = []
| otherwise = init $ tail w
dropLinesTill :: String -> [String] -> ([String], Bool)
dropLinesTill firstWord rlines
| null rlines = ([], False)
| h == firstWord = (rlines, True)
| otherwise = dropLinesTill firstWord $ tail rlines
where h = getFirstWord $ head rlines
parseLine :: String -> Maybe OptionRecord
parseLine line
| null settings = Nothing
| length settings < 3 = Nothing
| otherwise = Just $ OptionRecord (stripTicks $ head settings) (stripTicks $ head $ tail settings) (unwords $ tail $ tail settings)
where settings = words line
stringifyRecord :: OptionRecord -> String
stringifyRecord OptionRecord { name =n , abbr=b, desc=d} = n ++ "," ++ b ++ "," ++ d
-- -- Cassava.encodeByName
-- -- initial version
-- saveRecords :: Handle -> [OptionRecord] -> IO ()
-- saveRecords out records
-- | null records = return ()
-- | otherwise = do
-- hPutStrLn out (stringifyRecord $ head records)
-- saveRecords out ( tail records )
saveRecords :: Handle -> [OptionRecord] -> IO ()
saveRecords out records
| null records = return ()
| otherwise = do
hPutStrLn out (stringifyRecord $ head records)
saveRecords out ( tail records )
encode :: String -> String -> IO ()
encode from out = do
fd <- Prelude.readFile from
let start = dropLinesTill "'aleph'" ( lines fd )
let res = dropLinesTill "'writedelay'" $ reverse $ fst start
let relevantLines = fst res
-- create entries
print $ show relevantLines
let records = map parseLine relevantLines
-- filter out nothing values
-- http://stackoverflow.com/questions/40327699/filtering-nothing-and-unpack-just
let cleanRecords = reverse $ catMaybes records
-- let records = Just ( OptionRecord "name" "abbr" "desc" ++ records
-- do
let result = Cassava.encodeByName optionsHeader cleanRecords
ByteString.writeFile out result
-- outh <- openFile "out.csv" WriteMode
-- hPutStrLn outh result
-- saveRecords outh cleanRecords
-- print records
print "hello world"
-- print $ "start=" ++ unlines start
data Sample = Sample
{ hello :: String
, quiet :: Bool
, repeat :: Int }
sample :: Parser Sample
sample = Sample
<$> strOption
( long "hello"
<> metavar "TARGET"
<> help "Target for the greeting" )
<*> switch
( long "quiet"
<> short 'q'
<> help "Whether to be quiet" )
<*> option auto
( long "repeat"
<> help "Repeats for greeting"
<> showDefault
<> value 1
<> metavar "INT" )
opts :: ParserInfo Sample
opts = info (sample <**> helper)
( fullDesc
<> progDesc "My first haskell program !!"
<> header "update options.lua" )
-- generate a new file
-- addToOptions :: [String] -> OptionRecord -> [String]
-- addToOptions lines record
-- todo append to another file
-- | name record `isInfixOf` head lines = head lines ++ "short_desc=" ++ (desc record) ++ lines
-- | null lines = []
-- | otherwise = head lines ++ addToOptions (tail lines) record
-- TODO encodeField escapeURIString
genShortDesc :: OptionRecord -> String
genShortDesc record = " short_desc=" ++ show (desc record) ++ ","
-- todo use encode ?!escapeURIString
-- escapeURIString (== '"')
-- -- todo use concatMap
-- --name record `isInfixOf` head lines =
-- insertSpecificDesc :: OptionRecord -> String -> [String]
-- insertSpecificDesc record line
-- -- concatMap (\ line -> if name record `isInfixOf` line then [line, genShortDesc record] else [line]) lines
-- | (ame record ++ "'") `isInfixOf` line = [line, genShortDesc record]
-- | otherwise = []
-- to be useed with traverse
insertAllDesc :: V.Vector OptionRecord -> String -> [String]
insertAllDesc options line
-- concatMap (\ line -> if name record `isInfixOf` line then [line, genShortDesc record] else [line]) lines
| null options = [line]
| ("full_name='" ++ name record) `isInfixOf` line = [line, genShortDesc record]
| otherwise = insertAllDesc (V.tail options) line
where record = V.head options
decode :: String -> IO ()
decode from = do
csvData <- ByteString.readFile from
fd <- readFile "options.lua"
let l = lines fd
-- let towrite = lines
-- forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
-- backslash => lambda
-- for each record
putStrLn "hello"
case Cassava.decodeByName csvData of
Left err -> putStrLn err
Right (_, v) -> Prelude.writeFile "options2.lua" (unlines full)
-- todo save results
-- (\ line v -> if name record `isInfixOf` line then [line, genShortDesc record] else [line])
where full = concatMap (insertAllDesc v) l
-- Right (_, v) -> let full = insertAllDesc v l; putStrLn full
-- return ()
-- concatMap or traverse or mapM
-- traverse (Traversable t, Applicative f) => (a -> f b) -> t a -> f (t b)
-- Data.Foldable forM_ :: (Foldable t, Monad m) => t a -> (a -> m b) -> m ()
-- print v
-- V.forM_ v $ \ p ->
-- --
-- -- putStrLn $ name p ++ show (desc p)
-- let towrite = addToOptions towrite p
-- out <- Prelude.writeFile "options2.lua"
-- TODO add sthg like
-- http://hackage.haskell.org/package/optparse-applicative
-- main :: IO
main = do
-- a priori options is of type Sample
options <- execParser opts
putStrLn $ hello options
case hello options of
"encode" -> encode "quickref.txt" "out.csv"
"decode" -> decode "out.csv"
-- case args
putStrLn "End of the program"