2009-05-29 12:23:59 +04:00
|
|
|
#!/usr/bin/env runhaskell
|
2014-09-11 00:07:53 +04:00
|
|
|
{-
|
2015-10-10 21:51:07 +03:00
|
|
|
generatejournal.hs NUMTXNS NUMACCTS ACCTDEPTH [--chinese|--mixed]
|
2009-05-29 12:23:59 +04:00
|
|
|
|
2015-10-10 21:51:07 +03:00
|
|
|
Outputs a dummy journal file with the specified number of
|
|
|
|
transactions, number of accounts, and account tree depth. By default
|
|
|
|
it uses only ascii characters, with --chinese it uses wide chinese
|
|
|
|
characters, or with --mixed it uses both. These files are used for
|
|
|
|
testing, benchmarking, profiling, etc.
|
2009-05-29 12:23:59 +04:00
|
|
|
-}
|
|
|
|
|
|
|
|
module Main
|
|
|
|
where
|
2015-10-10 21:51:07 +03:00
|
|
|
import Data.Char
|
|
|
|
import Data.List
|
2009-05-29 12:23:59 +04:00
|
|
|
import Data.Time.Calendar
|
2015-10-10 21:51:07 +03:00
|
|
|
import Data.Time.LocalTime
|
2009-05-29 12:23:59 +04:00
|
|
|
import Numeric
|
2015-10-10 21:51:07 +03:00
|
|
|
import System.Environment
|
|
|
|
import Text.Printf
|
|
|
|
-- import Hledger.Utils.Debug
|
2009-05-29 12:23:59 +04:00
|
|
|
|
|
|
|
main = do
|
2015-10-10 21:51:07 +03:00
|
|
|
rawargs <- getArgs
|
|
|
|
let (opts,args) = partition (isPrefixOf "-") rawargs
|
2009-05-29 12:23:59 +04:00
|
|
|
let [numtxns, numaccts, acctdepth] = map read args :: [Int]
|
|
|
|
today <- getCurrentDay
|
|
|
|
let (year,_,_) = toGregorian today
|
|
|
|
let d = fromGregorian (year-1) 1 1
|
|
|
|
let dates = iterate (addDays 1) d
|
2015-10-10 21:51:07 +03:00
|
|
|
let accts = pair $ cycle $ take numaccts $ uniqueAccountNames opts acctdepth
|
2009-05-29 12:23:59 +04:00
|
|
|
mapM_ (\(n,d,(a,b)) -> putStr $ showtxn n d a b) $ take numtxns $ zip3 [1..] dates accts
|
|
|
|
return ()
|
|
|
|
|
|
|
|
showtxn :: Int -> Day -> String -> String -> String
|
|
|
|
showtxn txnno date acct1 acct2 =
|
|
|
|
printf "%s transaction %d\n %-40s %2d\n %-40s %2d\n\n" d txnno acct1 amt acct2 (-amt)
|
|
|
|
where
|
|
|
|
d = show date
|
|
|
|
amt = 1::Int
|
|
|
|
|
2015-10-10 21:51:07 +03:00
|
|
|
uniqueAccountNames :: [String] -> Int -> [String]
|
|
|
|
uniqueAccountNames opts depth =
|
|
|
|
mkacctnames uniquenames
|
|
|
|
where
|
|
|
|
mkacctnames names = mkacctnamestodepth some ++ mkacctnames rest
|
|
|
|
where
|
|
|
|
(some, rest) = splitAt depth names
|
|
|
|
-- mkacctnamestodepth ["a", "b", "c"] = ["a","a:b","a:b:c"]
|
|
|
|
mkacctnamestodepth :: [String] -> [String]
|
|
|
|
mkacctnamestodepth [] = []
|
|
|
|
mkacctnamestodepth (a:as) = a : map ((a++":")++) (mkacctnamestodepth as)
|
|
|
|
uniquenames
|
|
|
|
| "--mixed" `elem` opts = concat $ zipWith (\a b -> [a,b]) uniqueNamesHex uniqueNamesWide
|
|
|
|
| "--chinese" `elem` opts = uniqueNamesWide
|
|
|
|
| otherwise = uniqueNamesHex
|
|
|
|
|
|
|
|
uniqueNamesHex = map hex [1..] where hex = flip showHex ""
|
|
|
|
|
|
|
|
uniqueNamesWide = concat [sequences n wideChars | n <- [1..]]
|
|
|
|
|
|
|
|
-- Get the sequences of specified size starting at each element of a list,
|
|
|
|
-- cycling it if needed to fill the last sequence. If the list's elements
|
|
|
|
-- are unique, then the sequences will be too.
|
|
|
|
sequences :: Show a => Int -> [a] -> [[a]]
|
|
|
|
sequences n l = go l
|
|
|
|
where
|
|
|
|
go [] = []
|
|
|
|
go l' = s : go (tail l')
|
|
|
|
where
|
|
|
|
s' = take n l'
|
|
|
|
s | length s' == n = s'
|
|
|
|
| otherwise = take n (l' ++ cycle l)
|
2009-05-29 12:23:59 +04:00
|
|
|
|
2015-10-10 21:51:07 +03:00
|
|
|
wideChars = map chr [0x3400..0x4db0]
|
2009-05-29 12:23:59 +04:00
|
|
|
|
|
|
|
|
|
|
|
pair :: [a] -> [(a,a)]
|
|
|
|
pair [] = []
|
|
|
|
pair [a] = [(a,a)]
|
2009-09-22 20:51:27 +04:00
|
|
|
pair (a:b:rest) = (a,b):pair rest
|
2009-05-29 12:23:59 +04:00
|
|
|
|
|
|
|
getCurrentDay :: IO Day
|
|
|
|
getCurrentDay = do
|
|
|
|
t <- getZonedTime
|
|
|
|
return $ localDay (zonedTimeToLocalTime t)
|
|
|
|
|