aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGregor Kleen <gkleen@yggdrasil.li>2016-01-10 04:43:42 +0000
committerGregor Kleen <gkleen@yggdrasil.li>2016-01-10 04:43:42 +0000
commit6ec3c805ea2cd629a75641530de30ab39a191409 (patch)
tree9a63c2edbe6834a17a67b055279024b7ec31eb3a
parent0bb617ff93d242d20e9e63f44664f38a653898d4 (diff)
downloadthermoprint-6ec3c805ea2cd629a75641530de30ab39a191409.tar
thermoprint-6ec3c805ea2cd629a75641530de30ab39a191409.tar.gz
thermoprint-6ec3c805ea2cd629a75641530de30ab39a191409.tar.bz2
thermoprint-6ec3c805ea2cd629a75641530de30ab39a191409.tar.xz
thermoprint-6ec3c805ea2cd629a75641530de30ab39a191409.zip
First stab at API
-rw-r--r--spec/src/Thermoprint/API.hs21
-rw-r--r--spec/src/Thermoprint/Printout.hs28
-rw-r--r--spec/test/Thermoprint/PrintoutSpec.hs17
-rw-r--r--spec/thermoprint-spec.cabal8
-rw-r--r--spec/thermoprint-spec.nix14
5 files changed, 82 insertions, 6 deletions
diff --git a/spec/src/Thermoprint/API.hs b/spec/src/Thermoprint/API.hs
new file mode 100644
index 0000000..f2ffd02
--- /dev/null
+++ b/spec/src/Thermoprint/API.hs
@@ -0,0 +1,21 @@
1{-# LANGUAGE GeneralizedNewtypeDeriving, NoDeriveAnyClass #-}
2{-# LANGUAGE TypeOperators, DataKinds #-}
3
4module Thermoprint.API
5 ( PrinterId(..)
6 , JobId(..)
7 , ThermoprintAPI
8 ) where
9
10import Thermoprint.Printout
11
12import Servant.API
13import Data.Aeson
14
15newtype PrinterId = PrinterId Integer
16 deriving (Show, Eq, FromText, ToText, FromJSON, ToJSON)
17
18newtype JobId = JobId Integer
19 deriving (Show, Eq, FromText, ToText, FromJSON, ToJSON)
20
21type ThermoprintAPI = "print" :> Capture "printerId" PrinterId :> ReqBody '[JSON] Printout :> Post '[JSON] JobId
diff --git a/spec/src/Thermoprint/Printout.hs b/spec/src/Thermoprint/Printout.hs
index 32c403c..d9d9902 100644
--- a/spec/src/Thermoprint/Printout.hs
+++ b/spec/src/Thermoprint/Printout.hs
@@ -23,6 +23,9 @@ import Data.ByteString.Lazy (ByteString)
23 23
24import GHC.Generics (Generic) 24import GHC.Generics (Generic)
25import Control.DeepSeq (NFData) 25import Control.DeepSeq (NFData)
26import Data.Aeson (FromJSON(..), ToJSON(..), Value(..))
27import qualified Data.Aeson as JSON (encode, decode)
28import Data.Aeson.Types (typeMismatch)
26 29
27import Test.QuickCheck.Arbitrary (Arbitrary(..), CoArbitrary, genericShrink) 30import Test.QuickCheck.Arbitrary (Arbitrary(..), CoArbitrary, genericShrink)
28import Test.QuickCheck.Modifiers (NonNegative(..)) 31import Test.QuickCheck.Modifiers (NonNegative(..))
@@ -32,6 +35,7 @@ import Test.QuickCheck (forAll, Property)
32 35
33 36
34import qualified Data.Text.Lazy as TL (split, null, pack, filter, intercalate, map) 37import qualified Data.Text.Lazy as TL (split, null, pack, filter, intercalate, map)
38import qualified Data.Text as T (pack)
35import Data.Char (isSpace) 39import Data.Char (isSpace)
36 40
37import Data.Monoid (Monoid(..), (<>)) 41import Data.Monoid (Monoid(..), (<>))
@@ -42,7 +46,13 @@ import Data.Sequence as Seq (fromList, null, singleton)
42 46
43import Data.Function (on) 47import Data.Function (on)
44 48
45import Data.Foldable (toList) 49import Data.Foldable (toList, fold)
50
51import Data.Encoding (encodeLazyByteStringExplicit, decodeLazyByteString)
52import Data.Encoding.UTF8
53import qualified Data.ByteString.Base64.Lazy as Base64 (encode, decode)
54
55import Prelude hiding (fold)
46 56
47 57
48-- | A 'Printout' is a sequence of visually seperated 'Paragraph's 58-- | A 'Printout' is a sequence of visually seperated 'Paragraph's
@@ -58,11 +68,23 @@ data Chunk = Cooked Block -- ^ text semantically structured to be rendered in ac
58 | Raw ByteString -- ^ direct instructions to the printer 68 | Raw ByteString -- ^ direct instructions to the printer
59 deriving (Generic, NFData, Show, CoArbitrary) 69 deriving (Generic, NFData, Show, CoArbitrary)
60 70
71instance FromJSON Chunk where
72 parseJSON s@(String _) = Raw <$> ((either fail return . decodeBase64) =<< parseJSON s)
73 where
74 decodeBase64 :: String -> Either String ByteString
75 decodeBase64 s = (either (Left . show) Right . encodeLazyByteStringExplicit UTF8Strict $ s) >>= Base64.decode
76 parseJSON o@(Object _) = Cooked <$> parseJSON o
77 parseJSON v = typeMismatch "Chunk" v
78
79instance ToJSON Chunk where
80 toJSON (Raw bs) = String . T.pack . decodeLazyByteString UTF8Strict . Base64.encode $ bs
81 toJSON (Cooked block) = toJSON block
82
61-- | 'Block' is the entry point for our structured document format 83-- | 'Block' is the entry point for our structured document format
62data Block = Line Line -- ^ a single 'Line' of text 84data Block = Line Line -- ^ a single 'Line' of text
63 | VSpace Integer -- ^ vertical space of height equivalent to 'Integer' lines 85 | VSpace Integer -- ^ vertical space of height equivalent to 'Integer' lines
64 | NewlSep (Seq Block) -- ^ A sequence of 'Block's seperated by newlines 86 | NewlSep (Seq Block) -- ^ A sequence of 'Block's seperated by newlines
65 deriving (Generic, NFData, Show, CoArbitrary) 87 deriving (Generic, NFData, Show, CoArbitrary, FromJSON, ToJSON)
66 88
67{- | A 'Line' is one of: 89{- | A 'Line' is one of:
68 90
@@ -75,7 +97,7 @@ We don't export all constructors and instead encourage the use of 'text'.
75data Line = Word Text 97data Line = Word Text
76 | HSpace Integer 98 | HSpace Integer
77 | SpaceSep (Seq Line) 99 | SpaceSep (Seq Line)
78 deriving (Generic, NFData, Show, CoArbitrary) 100 deriving (Generic, NFData, Show, CoArbitrary, FromJSON, ToJSON)
79 101
80instance Monoid Block where 102instance Monoid Block where
81 mempty = NewlSep mempty 103 mempty = NewlSep mempty
diff --git a/spec/test/Thermoprint/PrintoutSpec.hs b/spec/test/Thermoprint/PrintoutSpec.hs
index 5a48496..b92d76a 100644
--- a/spec/test/Thermoprint/PrintoutSpec.hs
+++ b/spec/test/Thermoprint/PrintoutSpec.hs
@@ -1,9 +1,26 @@
1{-# LANGUAGE StandaloneDeriving #-}
2
1module Thermoprint.PrintoutSpec (spec) where 3module Thermoprint.PrintoutSpec (spec) where
2 4
3import Test.Hspec 5import Test.Hspec
4import Test.Hspec.QuickCheck (prop) 6import Test.Hspec.QuickCheck (prop)
5import Thermoprint.Printout 7import Thermoprint.Printout
6 8
9import Data.Aeson (fromJSON, ToJSON(..), Result(..))
10import Data.Function (on)
11
12import Control.DeepSeq (($!!), force)
13
14-- Equality via cotext on Block
15instance Eq Block where
16 (==) = (==) `on` cotext
17-- Structural equality for Chunk
18deriving instance Eq Chunk
19
7spec :: Spec 20spec :: Spec
8spec = do 21spec = do
9 prop "prop_text" prop_text 22 prop "prop_text" prop_text
23 prop "json" prop_json
24 where
25 prop_json :: Printout -> Bool
26 prop_json p = force $ (== Success p) . fromJSON . toJSON $!! p
diff --git a/spec/thermoprint-spec.cabal b/spec/thermoprint-spec.cabal
index c4599c8..426244e 100644
--- a/spec/thermoprint-spec.cabal
+++ b/spec/thermoprint-spec.cabal
@@ -19,6 +19,7 @@ cabal-version: >=1.10
19library 19library
20 hs-source-dirs: src 20 hs-source-dirs: src
21 exposed-modules: Thermoprint.Printout 21 exposed-modules: Thermoprint.Printout
22 , Thermoprint.API
22 -- other-modules: 23 -- other-modules:
23 -- other-extensions: 24 -- other-extensions:
24 extensions: DeriveGeneric 25 extensions: DeriveGeneric
@@ -33,6 +34,10 @@ library
33 , quickcheck-instances >=0.3.11 && <4 34 , quickcheck-instances >=0.3.11 && <4
34 , Cabal >=1.22.4 && <2 35 , Cabal >=1.22.4 && <2
35 , cabal-test-quickcheck >=0.1.6 && <1 36 , cabal-test-quickcheck >=0.1.6 && <1
37 , servant >=0.4.4 && <1
38 , aeson >=0.9.0 && <1
39 , base64-bytestring >=1.0.0 && <2
40 , encoding >=0.8 && <1
36 -- hs-source-dirs: 41 -- hs-source-dirs:
37 default-language: Haskell2010 42 default-language: Haskell2010
38 43
@@ -44,4 +49,5 @@ Test-Suite tests
44 , thermoprint-spec -any 49 , thermoprint-spec -any
45 , hspec >=2.2.1 && <3 50 , hspec >=2.2.1 && <3
46 , QuickCheck >=2.8.1 && <3 51 , QuickCheck >=2.8.1 && <3
47 , quickcheck-instances >=0.3.11 && <4 \ No newline at end of file 52 , quickcheck-instances >=0.3.11 && <4
53 , aeson >=0.9.0 && <1 \ No newline at end of file
diff --git a/spec/thermoprint-spec.nix b/spec/thermoprint-spec.nix
index 82f018a..ea903ba 100644
--- a/spec/thermoprint-spec.nix
+++ b/spec/thermoprint-spec.nix
@@ -1,9 +1,19 @@
1{ mkDerivation, base, bytestring, containers, stdenv, text, QuickCheck, quickcheck-instances, cabal-test-quickcheck, hspec }: 1{ mkDerivation, aeson, base, base64-bytestring, bytestring, Cabal
2, cabal-test-quickcheck, containers, deepseq, encoding, hspec
3, QuickCheck, quickcheck-instances, servant, stdenv, text
4}:
2mkDerivation { 5mkDerivation {
3 pname = "thermoprint-spec"; 6 pname = "thermoprint-spec";
4 version = "1.0.0"; 7 version = "1.0.0";
5 src = ./.; 8 src = ./.;
6 libraryHaskellDepends = [ base bytestring containers text QuickCheck quickcheck-instances cabal-test-quickcheck hspec ]; 9 libraryHaskellDepends = [
10 aeson base base64-bytestring bytestring Cabal cabal-test-quickcheck
11 containers deepseq encoding QuickCheck quickcheck-instances servant
12 text
13 ];
14 testHaskellDepends = [
15 base hspec QuickCheck quickcheck-instances
16 ];
7 homepage = "http://dirty-haskell.org/tags/thermoprint.html"; 17 homepage = "http://dirty-haskell.org/tags/thermoprint.html";
8 description = "A specification of the API and the payload datatypes and associated utilities"; 18 description = "A specification of the API and the payload datatypes and associated utilities";
9 license = stdenv.lib.licenses.publicDomain; 19 license = stdenv.lib.licenses.publicDomain;