From cedbf4ce52abe30e65edd8aea22b8db8ca409f97 Mon Sep 17 00:00:00 2001 From: Vaclav Svejcar Date: Mon, 12 Apr 2021 19:03:21 +0200 Subject: [PATCH] =?UTF-8?q?[#66]=C2=A0Extend=20the=20TemplateRef=20concept?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Headroom/Command/Readers.hs | 4 +- src/Headroom/Command/Run.hs | 48 ++++++++++++------- src/Headroom/Configuration/Types.hs | 29 +---------- src/Headroom/HeaderFn.hs | 3 +- src/Headroom/Template.hs | 39 +++++++-------- src/Headroom/Template/Mustache.hs | 17 ++++--- src/Headroom/Template/TemplateRef.hs | 37 +++++++------- src/Headroom/Types.hs | 41 ++++++++++++---- src/Headroom/Variables.hs | 3 +- .../FileSupport/Haskell/HaddockSpec.hs | 5 +- test/Headroom/FileSupport/HaskellSpec.hs | 4 +- test/Headroom/Template/MustacheSpec.hs | 19 ++++---- test/Headroom/Template/TemplateRefSpec.hs | 9 ++-- 13 files changed, 134 insertions(+), 124 deletions(-) diff --git a/src/Headroom/Command/Readers.hs b/src/Headroom/Command/Readers.hs index 97360a8..7c17c68 100644 --- a/src/Headroom/Command/Readers.hs +++ b/src/Headroom/Command/Readers.hs @@ -31,7 +31,6 @@ import Headroom.Data.Regex ( Regex(..) , compile ) import Headroom.FileType.Types ( FileType(..) ) -import Headroom.Meta ( TemplateType ) import Headroom.Template.TemplateRef ( TemplateRef(..) , mkTemplateRef ) @@ -77,8 +76,7 @@ regexReader = -- | Reader for 'TemplateRef'. templateRefReader :: ReadM TemplateRef templateRefReader = - let parse input = mapLeft displayException - (mkTemplateRef @TemplateType . T.pack $ input) + let parse input = mapLeft displayException (mkTemplateRef . T.pack $ input) in eitherReader parse diff --git a/src/Headroom/Command/Run.hs b/src/Headroom/Command/Run.hs index 0b17e51..470a36f 100644 --- a/src/Headroom/Command/Run.hs +++ b/src/Headroom/Command/Run.hs @@ -5,6 +5,7 @@ {-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE OverloadedStrings #-} +{-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StrictData #-} @@ -35,6 +36,7 @@ module Headroom.Command.Run ) where +import Data.String.Interpolate ( i ) import Data.Time.Calendar ( toGregorian ) import Data.Time.Clock ( getCurrentTime ) import Data.Time.Clock.POSIX ( getPOSIXTime ) @@ -360,24 +362,28 @@ loadTemplateRefs :: forall a env => [TemplateRef] -- ^ template references -> RIO env (Map FileType a) -- ^ map of templates loadTemplateRefs refs = do - fs <- viewL - n <- viewL - allRefs <- concat <$> mapM (getAllRefs fs) refs - refsWTp <- (\rs -> [ (ft, ref) | (Just ft, ref) <- rs ]) <$> zipRs allRefs - refsWCtn <- mapM (loadContent fs n) (filterPreferred refsWTp) + fileSystem <- viewL + network <- viewL + allRefs <- concat <$> mapM (getAllRefs fileSystem) refs + refsWTp <- (\rs -> [ (ft, ref) | (Just ft, ref) <- rs ]) <$> zipRs allRefs + refsWCtn <- mapM (loadContent fileSystem network) (filterPreferred refsWTp) M.fromList <$> mapM loadTemplate refsWCtn where zipRs = \rs -> fmap (`zip` rs) . mapM getFileType $ rs exts = toList $ templateExtensions @a getAllRefs = \fs ref -> case ref of LocalTemplateRef p -> fmap LocalTemplateRef <$> fsFindFilesByExts fs p exts - UriTemplateRef _ -> pure [ref] + _ -> pure [ref] loadContent = \fs n (ft, ref) -> (ft, ref, ) <$> case ref of - LocalTemplateRef path -> fsLoadFile fs path - UriTemplateRef uri -> nDownloadContent n uri - loadTemplate = - \(ft, ref, c) -> (ft, ) <$> parseTemplate @a (Just . renderRef $ ref) c - getFileType = typeOfTemplate . T.unpack . renderRef + InlineRef content -> pure content + LocalTemplateRef path -> fsLoadFile fs path + UriTemplateRef uri -> nDownloadContent n uri + BuiltInRef lt ft' -> pure $ licenseTemplate lt ft' + loadTemplate = \(ft, ref, c) -> (ft, ) <$> parseTemplate @a ref c + getFileType = \case + InlineRef _ -> pure Nothing + BuiltInRef _ ft -> pure . Just $ ft + other -> typeOfTemplate . T.unpack . renderRef $ other filterPreferred rs = mapMaybe (L.headMaybe . L.sort) . L.groupBy (\x y -> fst x == fst y) $ rs @@ -389,7 +395,9 @@ loadBuiltInTemplates :: (HasLogFunc env) -> RIO env (Map FileType TemplateType) -- ^ map of file types and templates loadBuiltInTemplates licenseType = do logInfo $ "Using built-in templates for license: " <> displayShow licenseType - parsed <- mapM (\(t, r) -> (t, ) <$> parseTemplate Nothing r) rawTemplates + parsed <- mapM + (\(t, r) -> (t, ) <$> parseTemplate (BuiltInRef licenseType t) r) + rawTemplates pure $ M.fromList parsed where rawTemplates = fmap (\ft -> (ft, template ft)) (allValues @FileType) @@ -404,12 +412,16 @@ loadTemplates :: ( Has CtConfiguration env => RIO env (Map FileType HeaderTemplate) loadTemplates = do Configuration {..} <- viewL @CtConfiguration - fromRefs <- loadTemplateRefs @TemplateType cTemplateRefs - builtIn <- case cBuiltInTemplates of - Just licenseType -> loadBuiltInTemplates licenseType - _ -> pure M.empty - pure $ M.mapWithKey (extractHeaderTemplate cLicenseHeaders) - (builtIn <> fromRefs) + let allRefs = builtInRefs cBuiltInTemplates <> cTemplateRefs + templates <- loadTemplateRefs @TemplateType allRefs + logInfo . display . T.intercalate "\n" . stats . M.toList $ templates + pure $ M.mapWithKey (extractHeaderTemplate cLicenseHeaders) templates + where + stats = + fmap (\(ft, t) -> [i|Using #{ft} template: #{renderRef . templateRef $ t}|]) + builtInRefs = \case + Just lt -> fmap (BuiltInRef lt) $ allValues @FileType + _ -> [] -- | Takes path to the template file and returns detected type of the template. diff --git a/src/Headroom/Configuration/Types.hs b/src/Headroom/Configuration/Types.hs index 30f118a..ed37f1b 100644 --- a/src/Headroom/Configuration/Types.hs +++ b/src/Headroom/Configuration/Types.hs @@ -83,13 +83,13 @@ import Data.String.Interpolate ( i , iii ) import Generic.Data ( Generically(..) ) -import Headroom.Data.EnumExtra ( EnumExtra(..) ) import Headroom.Data.Regex ( Regex(..) ) import Headroom.Data.Serialization ( aesonOptions ) import Headroom.FileType.Types ( FileType ) import Headroom.Meta ( webDocConfigCurr ) import Headroom.Template.TemplateRef ( TemplateRef ) -import Headroom.Types ( fromHeadroomError +import Headroom.Types ( LicenseType(..) + , fromHeadroomError , toHeadroomError ) import Headroom.Variables.Types ( Variables(..) ) @@ -148,31 +148,6 @@ instance FromJSON LineComment' where parseJSON = genericParseJSON aesonOptions ---------------------------------- LicenseType -------------------------------- - --- | Supported type of open source license. -data LicenseType - = Apache2 - -- ^ support for /Apache-2.0/ license - | BSD3 - -- ^ support for /BSD-3-Clause/ license - | GPL2 - -- ^ support for /GNU GPL2/ license - | GPL3 - -- ^ support for /GNU GPL3/ license - | MIT - -- ^ support for /MIT/ license - | MPL2 - -- ^ support for /MPL2/ license - deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show) - -instance FromJSON LicenseType where - parseJSON = \case - String s -> case textToEnum s of - Just licenseType -> pure licenseType - _ -> error $ "Unknown license type: " <> T.unpack s - other -> error $ "Invalid value for run mode: " <> show other - ----------------------------------- RunMode ---------------------------------- -- | Represents what action should the @run@ command perform. diff --git a/src/Headroom/HeaderFn.hs b/src/Headroom/HeaderFn.hs index 472670a..d987611 100644 --- a/src/Headroom/HeaderFn.hs +++ b/src/Headroom/HeaderFn.hs @@ -51,6 +51,7 @@ import Headroom.HeaderFn.UpdateCopyright ( SelectedAuthors(..) , updateCopyright ) import Headroom.Template ( Template(..) ) +import Headroom.Template.TemplateRef ( TemplateRef(..) ) import Headroom.Types ( CurrentYear(..) ) import Headroom.Variables.Types ( Variables(..) ) import Lens.Micro ( traverseOf ) @@ -159,7 +160,7 @@ compileTemplates vars configs = configs & traverseOf authorsL compileAuthors' authorsL = hfcsUpdateCopyrightL . hfcConfigL . uccSelectedAuthorsL compileAuthors' = mapM . mapM $ compileAuthor compileAuthor author = do - parsed <- parseTemplate @a (Just $ "author " <> author) author + parsed <- parseTemplate @a (InlineRef author) author renderTemplate vars parsed diff --git a/src/Headroom/Template.hs b/src/Headroom/Template.hs index 8aad36f..c89b05d 100644 --- a/src/Headroom/Template.hs +++ b/src/Headroom/Template.hs @@ -29,6 +29,7 @@ module Headroom.Template where import Data.String.Interpolate ( iii ) +import Headroom.Template.TemplateRef ( TemplateRef(..) ) import Headroom.Types ( fromHeadroomError , toHeadroomError ) @@ -41,53 +42,45 @@ import qualified RIO.Text as T class Template a where -- | Returns list of supported file extensions for this template type. - templateExtensions :: NonEmpty Text - -- ^ list of supported file extensions + templateExtensions :: NonEmpty Text -- ^ list of supported file extensions -- | Parses template from given raw text. parseTemplate :: MonadThrow m - => Maybe Text - -- ^ name of the template (optional) - -> Text - -- ^ raw template text - -> m a - -- ^ parsed template + => TemplateRef -- ^ reference to template source + -> Text -- ^ raw template text + -> m a -- ^ parsed template -- | Renders parsed template and replaces all variables with actual values. renderTemplate :: MonadThrow m - => Variables - -- ^ values of variables to replace - -> a - -- ^ parsed template to render - -> m Text - -- ^ rendered template text + => Variables -- ^ values of variables to replace + -> a -- ^ parsed template to render + -> m Text -- ^ rendered template text -- | Returns the raw text of the template, same that has been parsed by -- 'parseTemplate' method. - rawTemplate :: a - -- ^ template for which to return raw template text - -> Text - -- ^ raw template text + rawTemplate :: a -- ^ template for which to return raw template text + -> Text -- ^ raw template text + + + templateRef :: a -> TemplateRef ------------------------------ PUBLIC FUNCTIONS ------------------------------ -- | Returns empty template of selected type. emptyTemplate :: (MonadThrow m, Template a) => m a -emptyTemplate = parseTemplate Nothing T.empty +emptyTemplate = parseTemplate (InlineRef T.empty) T.empty --------------------------------- ERROR TYPES -------------------------------- -- | Error during processing template. data TemplateError - = MissingVariables Text [Text] - -- ^ missing variable values - | ParseError Text - -- ^ error parsing raw template text + = MissingVariables Text [Text] -- ^ missing variable values + | ParseError Text -- ^ error parsing raw template text deriving (Eq, Show, Typeable) diff --git a/src/Headroom/Template/Mustache.hs b/src/Headroom/Template/Mustache.hs index e33d984..7959f96 100644 --- a/src/Headroom/Template/Mustache.hs +++ b/src/Headroom/Template/Mustache.hs @@ -24,6 +24,9 @@ where import Headroom.Template ( Template(..) , TemplateError(..) ) +import Headroom.Template.TemplateRef ( TemplateRef + , renderRef + ) import Headroom.Variables.Types ( Variables(..) ) import RIO import qualified RIO.Text as T @@ -35,6 +38,7 @@ import Text.Mustache.Render ( SubstitutionError(..) ) data Mustache = Mustache { mCompiledTemplate :: MU.Template , mRawTemplate :: Text + , mTemplateRef :: TemplateRef } deriving Show @@ -48,17 +52,18 @@ instance Template Mustache where parseTemplate = parseTemplate' renderTemplate = renderTemplate' rawTemplate = mRawTemplate + templateRef = mTemplateRef -parseTemplate' :: MonadThrow m => Maybe Text -> Text -> m Mustache -parseTemplate' name raw = case MU.compileTemplate templateName raw of - Left err -> throwM . ParseError $ tshow err - Right res -> pure $ Mustache res raw - where templateName = T.unpack . fromMaybe T.empty $ name +parseTemplate' :: MonadThrow m => TemplateRef -> Text -> m Mustache +parseTemplate' ref raw = + case MU.compileTemplate (T.unpack $ renderRef ref) raw of + Left err -> throwM . ParseError $ tshow err + Right res -> pure $ Mustache res raw ref renderTemplate' :: MonadThrow m => Variables -> Mustache -> m Text -renderTemplate' (Variables variables) (Mustache t@(MU.Template name _ _) _) = +renderTemplate' (Variables variables) (Mustache t@(MU.Template name _ _) _ _) = case MU.checkedSubstitute t variables of ([], rendered) -> pure rendered (errs, rendered) -> diff --git a/src/Headroom/Template/TemplateRef.hs b/src/Headroom/Template/TemplateRef.hs index c1940d1..9da4cf2 100644 --- a/src/Headroom/Template/TemplateRef.hs +++ b/src/Headroom/Template/TemplateRef.hs @@ -6,7 +6,6 @@ {-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE QuasiQuotes #-} {-# LANGUAGE RecordWildCards #-} -{-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE StrictData #-} {-# LANGUAGE TypeApplications #-} {-# LANGUAGE ViewPatterns #-} @@ -39,15 +38,16 @@ where import Data.Aeson ( FromJSON(..) , Value(String) ) -import Data.String.Interpolate ( iii ) +import Data.String.Interpolate ( i + , iii + ) import Headroom.Data.EnumExtra ( textToEnum ) import Headroom.Data.Regex ( match , re ) import Headroom.FileType.Types ( FileType(..) ) -import Headroom.Meta ( TemplateType ) -import Headroom.Template ( Template(..) ) -import Headroom.Types ( fromHeadroomError +import Headroom.Types ( LicenseType + , fromHeadroomError , toHeadroomError ) import RIO @@ -62,14 +62,16 @@ import qualified Text.URI as URI -- | Reference to the template (e.g. local file, URI address). data TemplateRef - = LocalTemplateRef FilePath -- ^ template path on local file system + = InlineRef Text + | LocalTemplateRef FilePath -- ^ template path on local file system | UriTemplateRef URI -- ^ remote template URI adress + | BuiltInRef LicenseType FileType deriving (Eq, Ord, Show) instance FromJSON TemplateRef where parseJSON = \case - String s -> maybe (error $ T.unpack s) pure (mkTemplateRef @TemplateType s) + String s -> maybe (error $ T.unpack s) pure (mkTemplateRef s) other -> error $ "Invalid value for template reference: " <> show other @@ -79,17 +81,12 @@ instance FromJSON TemplateRef where -- valid URL with either @http@ or @https@ as protocol, it considers it as -- 'UriTemplateRef', otherwise it creates 'LocalTemplateRef'. -- --- >>> :set -XTypeApplications --- >>> import Headroom.Template.Mustache (Mustache) --- >>> mkTemplateRef @Mustache "/path/to/haskell.mustache" :: Maybe TemplateRef +-- >>> mkTemplateRef "/path/to/haskell.mustache" :: Maybe TemplateRef -- Just (LocalTemplateRef "/path/to/haskell.mustache") -- --- >>> :set -XTypeApplications --- >>> import Headroom.Template.Mustache (Mustache) --- >>> mkTemplateRef @Mustache "https://foo.bar/haskell.mustache" :: Maybe TemplateRef +-- >>> mkTemplateRef "https://foo.bar/haskell.mustache" :: Maybe TemplateRef -- Just (UriTemplateRef (URI {uriScheme = Just "https", uriAuthority = Right (Authority {authUserInfo = Nothing, authHost = "foo.bar", authPort = Nothing}), uriPath = Just (False,"haskell.mustache" :| []), uriQuery = [], uriFragment = Nothing})) -mkTemplateRef :: forall a m - . (Template a, MonadThrow m) +mkTemplateRef :: MonadThrow m => Text -- ^ input text -> m TemplateRef -- ^ created 'TemplateRef' (or error) mkTemplateRef raw = case match [re|(^\w+):\/\/|] raw of @@ -98,10 +95,8 @@ mkTemplateRef raw = case match [re|(^\w+):\/\/|] raw of _ -> pure . LocalTemplateRef . T.unpack $ raw where uriTemplateRef = extractFileType >> UriTemplateRef <$> mkURI raw - exts = templateExtensions @a extractFileType = case match [re|(\w+)\.(\w+)$|] raw of - Just (_ : (textToEnum @FileType -> (Just ft )) : e : _) | e `elem` exts -> - pure ft + Just (_ : (textToEnum @FileType -> (Just ft )) : _ : _) -> pure ft _ -> throwM $ UnrecognizedTemplateName raw @@ -110,8 +105,10 @@ mkTemplateRef raw = case match [re|(^\w+):\/\/|] raw of -- | Renders given 'TemplateRef' into human-friendly text. renderRef :: TemplateRef -- ^ 'TemplateRef' to render -> Text -- ^ rendered text -renderRef (LocalTemplateRef path) = T.pack path -renderRef (UriTemplateRef uri ) = URI.render uri +renderRef (InlineRef content) = [i||] +renderRef (LocalTemplateRef path ) = T.pack path +renderRef (UriTemplateRef uri ) = URI.render uri +renderRef (BuiltInRef lt ft ) = [i||] --------------------------------- ERROR TYPES -------------------------------- diff --git a/src/Headroom/Types.hs b/src/Headroom/Types.hs index 7663039..feb2395 100644 --- a/src/Headroom/Types.hs +++ b/src/Headroom/Types.hs @@ -1,4 +1,6 @@ +{-# LANGUAGE DeriveAnyClass #-} {-# LANGUAGE ExistentialQuantification #-} +{-# LANGUAGE LambdaCase #-} {-# LANGUAGE NoImplicitPrelude #-} {-# LANGUAGE StrictData #-} @@ -22,11 +24,17 @@ module Headroom.Types , toHeadroomError -- * Other Data Types , CurrentYear(..) + , LicenseType(..) ) where +import Data.Aeson ( FromJSON(..) + , Value(String) + ) import Data.Typeable ( cast ) +import Headroom.Data.EnumExtra ( EnumExtra(..) ) import RIO +import qualified RIO.Text as T -- | Top-level of the /Headroom/ exception hierarchy. @@ -41,19 +49,15 @@ instance Exception HeadroomError where -- | Wraps given exception into 'HeadroomError'. toHeadroomError :: Exception e - => e - -- ^ exception to wrap - -> SomeException - -- ^ wrapped exception + => e -- ^ exception to wrap + -> SomeException -- ^ wrapped exception toHeadroomError = toException . HeadroomError -- | Unwraps given exception from 'HeadroomError'. fromHeadroomError :: Exception e - => SomeException - -- ^ exception to unwrap - -> Maybe e - -- ^ unwrapped exception + => SomeException -- ^ exception to unwrap + -> Maybe e -- ^ unwrapped exception fromHeadroomError e = do HeadroomError he <- fromException e cast he @@ -61,7 +65,24 @@ fromHeadroomError e = do -- | Wraps the value of current year. newtype CurrentYear = CurrentYear - { unCurrentYear :: Integer - -- ^ value of current year + { unCurrentYear :: Integer -- ^ value of current year } deriving (Eq, Show) + + +-- | Supported type of open source license. +data LicenseType + = Apache2 -- ^ support for /Apache-2.0/ license + | BSD3 -- ^ support for /BSD-3-Clause/ license + | GPL2 -- ^ support for /GNU GPL2/ license + | GPL3 -- ^ support for /GNU GPL3/ license + | MIT -- ^ support for /MIT/ license + | MPL2 -- ^ support for /MPL2/ license + deriving (Bounded, Enum, EnumExtra, Eq, Ord, Show) + +instance FromJSON LicenseType where + parseJSON = \case + String s -> case textToEnum s of + Just licenseType -> pure licenseType + _ -> error $ "Unknown license type: " <> T.unpack s + other -> error $ "Invalid value for run mode: " <> show other diff --git a/src/Headroom/Variables.hs b/src/Headroom/Variables.hs index df0137c..493e2a0 100644 --- a/src/Headroom/Variables.hs +++ b/src/Headroom/Variables.hs @@ -32,6 +32,7 @@ where import Data.String.Interpolate ( iii ) import Headroom.Template ( Template(..) ) +import Headroom.Template.TemplateRef ( TemplateRef(..) ) import Headroom.Types ( CurrentYear(..) , fromHeadroomError , toHeadroomError @@ -102,7 +103,7 @@ compileVariables variables@(Variables kvs) = do pure $ mkVariables compiled where compileVariable (key, value) = do - parsed <- parseTemplate @a (Just $ "variable " <> key) value + parsed <- parseTemplate @a (InlineRef value) value rendered <- renderTemplate variables parsed pure (key, rendered) diff --git a/test/Headroom/FileSupport/Haskell/HaddockSpec.hs b/test/Headroom/FileSupport/Haskell/HaddockSpec.hs index 2aa3f86..52860cf 100644 --- a/test/Headroom/FileSupport/Haskell/HaddockSpec.hs +++ b/test/Headroom/FileSupport/Haskell/HaddockSpec.hs @@ -25,6 +25,7 @@ import Headroom.FileType.Types ( FileType(..) ) import Headroom.IO.FileSystem ( loadFile ) import Headroom.Template ( Template(..) ) import Headroom.Template.Mustache ( Mustache(..) ) +import Headroom.Template.TemplateRef ( TemplateRef(..) ) import RIO import RIO.FilePath ( () ) import Test.Hspec @@ -36,7 +37,9 @@ spec = do describe "extractOffsets" $ do it "extract offsets for selected fields of module header" $ do - template <- parseTemplate @Mustache Nothing $ licenseTemplate BSD3 Haskell + template <- + parseTemplate @Mustache (BuiltInRef BSD3 Haskell) + $ licenseTemplate BSD3 Haskell let syntax = BlockComment [re|^{-\||] [re|(?) ) @@ -63,7 +64,8 @@ spec = do describe "fsExtractTemplateData" $ do it "provides correct custom data for Haskell" $ do - template <- parseTemplate @Mustache Nothing (licenseTemplate BSD3 Haskell) + template <- parseTemplate @Mustache (BuiltInRef BSD3 Haskell) + (licenseTemplate BSD3 Haskell) let o = Just 14 td = HaskellTemplateData' HaddockOffsets { hoCopyright = o } expected = HaskellTemplateData td diff --git a/test/Headroom/Template/MustacheSpec.hs b/test/Headroom/Template/MustacheSpec.hs index c5863d6..caaa99e 100644 --- a/test/Headroom/Template/MustacheSpec.hs +++ b/test/Headroom/Template/MustacheSpec.hs @@ -10,6 +10,7 @@ where import Headroom.Template import Headroom.Template.Mustache +import Headroom.Template.TemplateRef ( TemplateRef(..) ) import Headroom.Variables ( mkVariables ) import RIO import Test.Hspec @@ -20,7 +21,7 @@ spec = do describe "parseTemplate" $ do it "parses Mustache template from raw text" $ do let template = "Hello, {{ name }}" - parsed = parseTemplate @Mustache (Just "template") template + parsed = parseTemplate @Mustache (InlineRef template) template parsed `shouldSatisfy` isJust @@ -28,29 +29,31 @@ spec = do it "renders template with given variables" $ do let template = "Hello, {{ name }}" variables = mkVariables [("name", "John")] - parsed = parseTemplate @Mustache (Just "template") template + parsed = parseTemplate @Mustache (InlineRef template) template rendered = parsed >>= renderTemplate variables rendered `shouldBe` Just "Hello, John" it "fails if not enough variables is provided" $ do let template = "Hello, {{ name }} {{ surname }}" variables = mkVariables [("name", "John")] - parsed = parseTemplate @Mustache (Just "test") template - let err (MissingVariables "test" ["surname"]) = True - err _ = False + parsed = parseTemplate @Mustache (InlineRef template) template + let + err (MissingVariables "" ["surname"]) + = True + err _ = False (parsed >>= renderTemplate variables) `shouldThrow` err it "renders template with conditionally set variable" $ do let template = "Foo {{#bar}}{{bar}}{{/bar}}{{^bar}}BAR{{/bar}}" variables = mempty - parsed = parseTemplate @Mustache (Just "template") template + parsed = parseTemplate @Mustache (InlineRef template) template rendered = parsed >>= renderTemplate variables rendered `shouldBe` Just "Foo BAR" it "fails if non-existing variable is used with inverted sections" $ do let template = "Foo {{bar}}{{^bar}}BAR{{/bar}}" variables = mkVariables [("xx", "yy")] - parsed = parseTemplate @Mustache (Just "template") template + parsed = parseTemplate @Mustache (InlineRef template) template rendered = parsed >>= renderTemplate variables rendered `shouldBe` Nothing @@ -58,5 +61,5 @@ spec = do describe "rawTemplate" $ do it "returns raw template text for already parsed template" $ do let template = "Hello, {{ name }}" - parsed = parseTemplate @Mustache (Just "template") template + parsed = parseTemplate @Mustache (InlineRef template) template fmap rawTemplate parsed `shouldBe` Just template diff --git a/test/Headroom/Template/TemplateRefSpec.hs b/test/Headroom/Template/TemplateRefSpec.hs index a0bf25f..414c73f 100644 --- a/test/Headroom/Template/TemplateRefSpec.hs +++ b/test/Headroom/Template/TemplateRefSpec.hs @@ -11,7 +11,6 @@ where import qualified Data.Aeson as Aeson -import Headroom.Template.Mustache ( Mustache ) import Headroom.Template.TemplateRef import RIO import qualified RIO.List as L @@ -26,22 +25,22 @@ spec = do it "creates valid reference to local Haskell template" $ do let raw = "/path/to/some/haskell.mustache" expected = LocalTemplateRef "/path/to/some/haskell.mustache" - mkTemplateRef @Mustache raw `shouldBe` Just expected + mkTemplateRef raw `shouldBe` Just expected it "creates valid reference to HTTP Haskell template" $ do let raw = "http://foo/haskell.mustache" expected = UriTemplateRef [uri|http://foo/haskell.mustache|] - mkTemplateRef @Mustache raw `shouldBe` Just expected + mkTemplateRef raw `shouldBe` Just expected it "throws error if URI is valid but protocol is not supported" $ do let raw = "foo://foo/haskell.mustache" - mkTemplateRef @Mustache raw `shouldThrow` \case + mkTemplateRef raw `shouldThrow` \case (UnsupportedUriProtocol _ _) -> True _ -> False it "throws error if URI is valid but file type is not supported" $ do let raw = "http://foo/bar.mustache" - mkTemplateRef @Mustache raw `shouldThrow` \case + mkTemplateRef raw `shouldThrow` \case (UnrecognizedTemplateName _) -> True _ -> False