ginger 0.8.4.1 → 0.9.0.0
raw patch · 6 files changed
+96/−1 lines, 6 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
+ Text.Ginger.GVal: [asBytes] :: GVal m -> Maybe ByteString
+ Text.Ginger.GVal: instance Text.Ginger.GVal.FromGVal m Data.ByteString.Internal.ByteString
+ Text.Ginger.GVal: instance Text.Ginger.GVal.FromGVal m Data.ByteString.Lazy.Internal.ByteString
+ Text.Ginger.GVal: instance Text.Ginger.GVal.ToGVal m Data.ByteString.Internal.ByteString
+ Text.Ginger.GVal: instance Text.Ginger.GVal.ToGVal m Data.ByteString.Lazy.Internal.ByteString
+ Text.Ginger.Run.Builtins: gfnSplit :: Monad m => Function (Run p m h)
- Text.Ginger.GVal: GVal :: Maybe [GVal m] -> Maybe [(Text, GVal m)] -> Maybe (Text -> Maybe (GVal m)) -> Html -> Text -> Bool -> Maybe Scientific -> Maybe (Function m) -> Maybe Int -> Bool -> Maybe Value -> GVal m
+ Text.Ginger.GVal: GVal :: Maybe [GVal m] -> Maybe [(Text, GVal m)] -> Maybe (Text -> Maybe (GVal m)) -> Html -> Text -> Bool -> Maybe Scientific -> Maybe (Function m) -> Maybe ByteString -> Maybe Int -> Bool -> Maybe Value -> GVal m
Files
- ginger.cabal +1/−1
- src/Text/Ginger/GVal.hs +51/−0
- src/Text/Ginger/Run.hs +1/−0
- src/Text/Ginger/Run/Builtins.hs +19/−0
- test/Text/Ginger/PropertyTests.hs +10/−0
- test/Text/Ginger/SimulationTests.hs +14/−0
ginger.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: ginger-version: 0.8.4.1+version: 0.9.0.0 synopsis: An implementation of the Jinja2 template language in Haskell description: Ginger is Jinja, minus the most blatant pythonisms. Wants to be feature complete, but isn't quite there yet.
src/Text/Ginger/GVal.hs view
@@ -78,6 +78,11 @@ , TimeZone (..) , TimeLocale (..) )+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS+import Data.Text.Encoding (encodeUtf8, decodeUtf8)+import qualified Data.Text.Lazy.Encoding as LText import Text.Ginger.Html @@ -106,6 +111,7 @@ , asBoolean :: Bool -- ^ Get value's truthiness , asNumber :: Maybe Scientific -- ^ Convert value to a number, if possible , asFunction :: Maybe (Function m) -- ^ Access value as a callable function, if it is one+ , asBytes :: Maybe ByteString -- ^ Access as raw bytes , length :: Maybe Int -- ^ Get length of value, if it is a collection (list/dict) , isNull :: Bool -- ^ Check if the value is null , asJSON :: Maybe JSON.Value -- ^ Provide a custom JSON representation of the value@@ -122,6 +128,7 @@ return $ \k -> lookupA k <|> lookupB k , asHtml = asHtml a <> asHtml b , asText = asText a <> asText b+ , asBytes = asBytes a <> asBytes b , asBoolean = (asBoolean a || asBoolean b) && not (isNull a || isNull b) , asNumber = readMay . Text.unpack $ (asText a <> asText b) , asFunction = Nothing@@ -148,6 +155,7 @@ , asLookup = fmap (fmap marshalGVal .) (asLookup g) , asHtml = asHtml g , asText = asText g+ , asBytes = asBytes g , asBoolean = asBoolean g , asNumber = asNumber g , asFunction = Nothing@@ -173,6 +181,7 @@ , asLookup = fmap (fmap (marshalGValEx hoist unhoist) .) (asLookup g) , asHtml = asHtml g , asText = asText g+ , asBytes = asBytes g , asBoolean = asBoolean g , asNumber = asNumber g , asFunction = marshalFunction hoist unhoist <$> asFunction g@@ -202,6 +211,7 @@ , asLookup = Nothing , asHtml = unsafeRawHtml "" , asText = ""+ , asBytes = Nothing , asBoolean = False , asNumber = Nothing , asFunction = Nothing@@ -323,6 +333,7 @@ def { asHtml = mconcat . Prelude.map asHtml $ xs , asText = mconcat . Prelude.map asText $ xs+ , asBytes = mconcat . Prelude.map asBytes $ xs , asBoolean = not . List.null $ xs , isNull = False , asList = Just $ Prelude.map toGVal xs@@ -338,6 +349,7 @@ def { asHtml = mconcat . Prelude.map asHtml . HashMap.elems $ xs , asText = mconcat . Prelude.map asText . HashMap.elems $ xs+ , asBytes = mconcat . Prelude.map asBytes . HashMap.elems $ xs , asBoolean = not . HashMap.null $ xs , isNull = False , asLookup = Just (`HashMap.lookup` xs)@@ -359,6 +371,7 @@ def { asHtml = html . Text.pack . show $ x , asText = Text.pack . show $ x+ , asBytes = Just . encodeUtf8 . Text.pack . show $ x , asBoolean = x /= 0 , asNumber = Just . fromIntegral $ x , isNull = False@@ -369,6 +382,7 @@ def { asHtml = html $ scientificToText x , asText = scientificToText x+ , asBytes = Just . encodeUtf8 . scientificToText $ x , asBoolean = x /= 0 , asNumber = Just x , isNull = False@@ -382,6 +396,7 @@ in (orderedDict dayDict) { asHtml = html $ formatted , asText = formatted+ , asBytes = Just . encodeUtf8 $ formatted , asBoolean = True , asNumber = Just . fromIntegral $ julian , asList = Just (List.map snd dayDict)@@ -402,6 +417,7 @@ in (orderedDict timeDict) { asHtml = html $ formatted , asText = formatted+ , asBytes = Just . encodeUtf8 $ formatted , asBoolean = True , asNumber = Nothing , asList = Just (List.map snd timeDict)@@ -425,6 +441,7 @@ ]) { asHtml = html $ formatted , asText = formatted+ , asBytes = Just . encodeUtf8 $ formatted , asBoolean = True , asNumber = Nothing , asList = Just (List.map snd dtDict)@@ -455,6 +472,7 @@ in (dict timeLocaleDict) { asHtml = html $ formattedExample , asText = formattedExample+ , asBytes = Just . encodeUtf8 $ formattedExample , asBoolean = True , asNumber = Nothing }@@ -481,6 +499,7 @@ in (dict dtDict) { asHtml = html $ formatted , asText = formatted+ , asBytes = Just . encodeUtf8 $ formatted , asBoolean = True , asNumber = Nothing }@@ -513,6 +532,7 @@ { asHtml = if x then html "1" else html "" , asText = if x then "1" else "" , asBoolean = x+ , asBytes = Just $ if x then "1" else "0" , asNumber = Just $ if x then 1 else 0 , isNull = False , asJSON = Just (JSON.Bool x)@@ -527,6 +547,7 @@ def { asHtml = html . Text.pack $ x , asText = Text.pack x+ , asBytes = Just . encodeUtf8 . Text.pack $ x , asBoolean = not $ Prelude.null x , asNumber = readMay x , isNull = False@@ -542,6 +563,7 @@ def { asHtml = html x , asText = x+ , asBytes = Just . encodeUtf8 $ x , asBoolean = not $ Text.null x , asNumber = readMay . Text.unpack $ x , isNull = False@@ -552,11 +574,34 @@ def { asHtml = html (LText.toStrict x) , asText = LText.toStrict x+ , asBytes = Just . LBS.toStrict . LText.encodeUtf8 $ x , asBoolean = not $ LText.null x , asNumber = readMay . LText.unpack $ x , isNull = False } +instance ToGVal m ByteString where+ toGVal x =+ def+ { asHtml = html (decodeUtf8 x)+ , asText = decodeUtf8 x+ , asBytes = Just x+ , asBoolean = not $ BS.null x+ , asNumber = readMay . Text.unpack . decodeUtf8 $ x+ , isNull = False+ }++instance ToGVal m LBS.ByteString where+ toGVal x =+ def+ { asHtml = html . LText.toStrict . LText.decodeUtf8 $ x+ , asText = LText.toStrict . LText.decodeUtf8 $ x+ , asBytes = Just . LBS.toStrict $ x+ , asBoolean = not $ LBS.null x+ , asNumber = readMay . LText.unpack . LText.decodeUtf8 $ x+ , isNull = False+ }+-- -- | This instance is slightly wrong; the 'asBoolean', 'asNumber', and 'asText' -- methods all treat the HTML source as plain text. We do this to avoid parsing -- the HTML back into a 'Text' (and dealing with possible parser errors); the@@ -794,6 +839,12 @@ instance FromGVal m (GVal m) where fromGVal = Just++instance FromGVal m ByteString where+ fromGVal = asBytes++instance FromGVal m LBS.ByteString where+ fromGVal = fmap LBS.fromStrict . asBytes instance FromGVal m a => FromGVal m (Maybe a) where fromGVal = \g ->
src/Text/Ginger/Run.hs view
@@ -187,6 +187,7 @@ , ("show", fromFunction . unaryFunc $ fromString . show) , ("slice", fromFunction gfnSlice) , ("sort", fromFunction gfnSort)+ , ("split", fromFunction gfnSplit) , ("str", fromFunction . unaryFunc $ toGVal . asText) , ("sum", fromFunction . variadicNumericFunc 0 $ Prelude.sum) , ("truncate", fromFunction . unaryNumericFunc 0 $ Prelude.fromIntegral . Prelude.truncate)
src/Text/Ginger/Run/Builtins.hs view
@@ -339,6 +339,23 @@ return . toGVal $ Text.replace search replace str _ -> throwHere $ ArgumentsError (Just "replace") "expected: (str, search, replace)" +gfnSplit :: Monad m => Function (Run p m h)+gfnSplit args =+ let argValues =+ extractArgsDefL+ [ ("str", def)+ , ("sep", def)+ ]+ args+ in case argValues of+ Right [strG, sepG] -> do+ let search = asText strG+ split = case asText sepG of+ "" -> Text.words+ sep -> Text.splitOn sep+ return . toGVal . split $ search+ _ -> throwHere $ ArgumentsError (Just "split") "expected: (str, sep=null)"+ gfnCompose :: forall m p h. Monad m => Function (Run p m h) gfnCompose [] = fail "Invalid arguments to compose()" gfnCompose [(_, fG)] = return fG@@ -855,3 +872,5 @@ ) RE.blankCompOpt str++-- vim: sw=4 ts=4 expandtab
test/Text/Ginger/PropertyTests.hs view
@@ -8,6 +8,9 @@ import Test.Tasty.QuickCheck import Data.Text (Text) import qualified Data.Text as Text+import Data.ByteString (ByteString)+import qualified Data.ByteString as BS+import qualified Data.ByteString.Lazy as LBS import Data.Default (def) import qualified Data.HashMap.Strict as HashMap import Control.Exception@@ -21,6 +24,12 @@ instance Arbitrary Text where arbitrary = Text.pack <$> arbitrary +instance Arbitrary ByteString where+ arbitrary = BS.pack <$> arbitrary++instance Arbitrary LBS.ByteString where+ arbitrary = LBS.pack <$> arbitrary+ instance Arbitrary Html where arbitrary = oneof [ html <$> arbitrary@@ -100,6 +109,7 @@ , testProperty "Bool" (roundTripGValP :: Bool -> Bool) , testProperty "[Text]" (roundTripGValP :: [Text] -> Bool) , testProperty "Maybe Text" (roundTripGValP :: Maybe Text -> Bool)+ , testProperty "ByteString" (roundTripGValP :: Maybe ByteString -> Bool) , testProperty "Text" (roundTripGValP :: Text -> Bool) , testProperty "LocalTime" (roundTripGValP :: LocalTime -> Bool) , testProperty "TimeZone" (roundTripGValP :: TimeZone -> Bool)
test/Text/Ginger/SimulationTests.hs view
@@ -904,6 +904,20 @@ "{{ \"12345\"|slice(1,3) }}" "234" ]+ , testGroup "\"split\""+ [ testCase "word-splitting" $ do+ mkTestText [] []+ "{{ split('foo bar')|json(pretty=0) }}"+ "[\"foo\",\"bar\"]"+ , testCase "word-splitting, more spaces" $ do+ mkTestText [] []+ "{{ split(' foo bar ')|json(pretty=0) }}"+ "[\"foo\",\"bar\"]"+ , testCase "word-splitting, more spaces, explicit delim" $ do+ mkTestText [] []+ "{{ split(' foo bar ','')|json(pretty=0) }}"+ "[\"foo\",\"bar\"]"+ ] , testGroup "\"replace\"" [ testCase "simple case" $ do mkTestHtml [] []