Skip to content

Commit 3a46135

Browse files
authored
Merge pull request #84 from commercialhaskell/template
Add a template
2 parents e8c4cba + c8a62f1 commit 3a46135

16 files changed

+276
-0
lines changed

etc/.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/rio.hsfiles

etc/make-template.hs

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
#!/usr/bin/env stack
2+
{- stack runghc
3+
--package rio
4+
--package conduit
5+
--package project-template
6+
-- -hide-all-packages
7+
-}
8+
{-# LANGUAGE NoImplicitPrelude #-}
9+
{-# LANGUAGE OverloadedStrings #-}
10+
{-# LANGUAGE RecordWildCards #-}
11+
import Conduit
12+
import RIO
13+
import qualified RIO.ByteString as B
14+
import qualified RIO.ByteString.Lazy as BL
15+
import RIO.FilePath
16+
import RIO.Process
17+
import qualified RIO.Text as T
18+
import qualified RIO.Text.Partial as T (replace)
19+
import RIO.Time
20+
import Text.ProjectTemplate
21+
22+
data App = App
23+
{ appLogFunc :: !LogFunc
24+
, appProcessContext :: !ProcessContext
25+
}
26+
27+
instance HasLogFunc App where
28+
logFuncL = lens appLogFunc (\x y -> x { appLogFunc = y })
29+
instance HasProcessContext App where
30+
processContextL = lens appProcessContext (\x y -> x { appProcessContext = y })
31+
32+
start :: RIO App a -> IO a
33+
start inner = do
34+
appProcessContext <- mkDefaultProcessContext
35+
lo <- logOptionsHandle stderr True
36+
withLogFunc lo $ \appLogFunc -> runRIO App {..} inner
37+
38+
splitNulls :: ByteString -> [ByteString]
39+
splitNulls bs
40+
| B.null bs = []
41+
| otherwise =
42+
let (x, y) = B.break (== 0) bs
43+
in x : splitNulls (B.drop 1 y)
44+
45+
decode :: ByteString -> RIO App FilePath
46+
decode bs =
47+
case decodeUtf8' bs of
48+
Left e -> throwIO e
49+
Right x -> return $ T.unpack x
50+
51+
readReplace :: MonadIO m => FilePath -> m ByteString
52+
readReplace fp = do
53+
(year, _, _) <- toGregorian . utctDay <$> getCurrentTime
54+
(encodeUtf8 . replaces year) <$> readFileUtf8 fp
55+
where
56+
replaces year
57+
= T.replace "PROJECTNAME" "{{name}}"
58+
. T.replace "AUTHOR" "{{author-name}}{{^author-name}}Author name here{{/author-name}}"
59+
. T.replace "MAINTAINER" "{{author-email}}{{^author-email}}example@example.com{{/author-email}}"
60+
. T.replace "GITHUB" "{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}"
61+
. T.replace "DESCRIPTION" "Please see the README on Github at <https://github.com/{{github-username}}{{^github-username}}githubuser{{/github-username}}/{{name}}#readme>"
62+
. T.replace "COPYRIGHT"
63+
(T.concat
64+
[ "{{copyright}}{{^copyright}}{{year}}{{^year}}"
65+
, T.pack $ show year
66+
, "{{/year}} {{author-name}}{{^author-name}}Author name here{{/author-name}}{{/copyright}}"
67+
])
68+
69+
main :: IO ()
70+
main = start $ do
71+
let templatedir = "template"
72+
73+
-- Make sure it passes
74+
proc "stack" ["test"] runProcess_
75+
76+
rawout <- withWorkingDir templatedir
77+
$ proc "git" ["ls-files", "-z"]
78+
readProcessStdout_
79+
files <- mapM decode $ splitNulls $ BL.toStrict rawout
80+
let src = forM_ files $ \fp -> yield (fp, readFileBinary $ templatedir </> fp)
81+
runConduitRes $ src .| createTemplate .| sinkFile "rio.hsfiles"

etc/stack.yaml

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
resolver: lts-11.5
2+
packages:
3+
- template
4+
extra-deps:
5+
- ../rio

etc/template/.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
*.cabal
2+
*~
3+
*.swp
4+
tarballs/
5+
.stack-work/

etc/template/ChangeLog.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Changelog for PROJECTNAME
2+
3+
## Unreleased changes

etc/template/LICENSE

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Copyright AUTHOR (c) 2018
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 Author name here 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.

etc/template/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
# PROJECTNAME

etc/template/Setup.hs

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
import Distribution.Simple
2+
main = defaultMain

etc/template/app/Main.hs

+32
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
{-# LANGUAGE TemplateHaskell #-}
3+
module Main (main) where
4+
5+
import Import
6+
import Run
7+
import RIO.Process
8+
import Options.Applicative.Simple
9+
import qualified Paths_PROJECTNAME
10+
11+
main :: IO ()
12+
main = do
13+
(options, ()) <- simpleOptions
14+
$(simpleVersion Paths_PROJECTNAME.version)
15+
"Header for command line arguments"
16+
"Program description, also for command line arguments"
17+
(Options
18+
<$> switch ( long "verbose"
19+
<> short 'v'
20+
<> help "Verbose output?"
21+
)
22+
)
23+
empty
24+
lo <- logOptionsHandle stderr (optionsVerbose options)
25+
pc <- mkDefaultProcessContext
26+
withLogFunc lo $ \lf ->
27+
let app = App
28+
{ appLogFunc = lf
29+
, appProcessContext = pc
30+
, appOptions = options
31+
}
32+
in runRIO app run

etc/template/package.yaml

+51
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
name: PROJECTNAME
2+
version: 0.1.0.0
3+
github: GITHUB
4+
license: BSD3
5+
author: AUTHOR
6+
maintainer: MAINTAINER
7+
copyright: COPYRIGHT
8+
9+
extra-source-files:
10+
- README.md
11+
- ChangeLog.md
12+
13+
# Metadata used when publishing your package
14+
# synopsis: Short description of your package
15+
# category: Web
16+
17+
# To avoid duplicated efforts in documentation and dealing with the
18+
# complications of embedding Haddock markup inside cabal files, it is
19+
# common to point users to the README.md file.
20+
description: DESCRIPTION
21+
22+
dependencies:
23+
- base >= 4.10 && < 10
24+
- rio >= 0.1.1.0
25+
26+
library:
27+
source-dirs: src
28+
29+
executables:
30+
PROJECTNAME-exe:
31+
main: Main.hs
32+
source-dirs: app
33+
ghc-options:
34+
- -threaded
35+
- -rtsopts
36+
- -with-rtsopts=-N
37+
dependencies:
38+
- PROJECTNAME
39+
- optparse-simple
40+
41+
tests:
42+
PROJECTNAME-test:
43+
main: Spec.hs
44+
source-dirs: test
45+
ghc-options:
46+
- -threaded
47+
- -rtsopts
48+
- -with-rtsopts=-N
49+
dependencies:
50+
- PROJECTNAME
51+
- hspec

etc/template/src/Import.hs

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
module Import
3+
( module RIO
4+
, module Types
5+
) where
6+
7+
import RIO
8+
import Types

etc/template/src/Run.hs

+9
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
{-# LANGUAGE OverloadedStrings #-}
3+
module Run (run) where
4+
5+
import Import
6+
7+
run :: RIO App ()
8+
run = do
9+
logInfo "We're inside the application!"

etc/template/src/Types.hs

+22
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
module Types where
3+
4+
import RIO
5+
import RIO.Process
6+
7+
-- | Command line arguments
8+
data Options = Options
9+
{ optionsVerbose :: !Bool
10+
}
11+
12+
data App = App
13+
{ appLogFunc :: !LogFunc
14+
, appProcessContext :: !ProcessContext
15+
, appOptions :: !Options
16+
-- Add other app-specific configuration information here
17+
}
18+
19+
instance HasLogFunc App where
20+
logFuncL = lens appLogFunc (\x y -> x { appLogFunc = y })
21+
instance HasProcessContext App where
22+
processContextL = lens appProcessContext (\x y -> x { appProcessContext = y })

etc/template/src/Util.hs

+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
-- | Silly utility module, used to demonstrate how to write a test
3+
-- case.
4+
module Util
5+
( plus2
6+
) where
7+
8+
import RIO
9+
10+
plus2 :: Int -> Int
11+
plus2 = (+ 2)

etc/template/test/Spec.hs

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{-# OPTIONS_GHC -F -pgmF hspec-discover #-}

etc/template/test/UtilSpec.hs

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
{-# LANGUAGE NoImplicitPrelude #-}
2+
module UtilSpec (spec) where
3+
4+
import Import
5+
import Util
6+
import Test.Hspec
7+
import Test.Hspec.QuickCheck
8+
9+
spec :: Spec
10+
spec = do
11+
describe "plus2" $ do
12+
it "basic check" $ plus2 0 `shouldBe` 2
13+
it "overflow" $ plus2 maxBound `shouldBe` minBound + 1
14+
prop "minus 2" $ \i -> plus2 i - 2 `shouldBe` i

0 commit comments

Comments
 (0)