tdammers / ginger Goto Github PK
View Code? Open in Web Editor NEWA Haskell implementation of the Jinja template language.
License: MIT License
A Haskell implementation of the Jinja template language.
License: MIT License
Observed on current git repository and latest hackage release:
Using Parsec parser
Configuring ginger-0.10.1.0...
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency aeson-pretty >=0.8.7 && <0.9: using aeson-pretty-0.8.8
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency filepath >=1.3: using filepath-1.4.2.1
Dependency http-types >=0.8 && <0.11 || >=0.12: using http-types-0.12.3
Dependency mtl >=2.2: using mtl-2.2.2
Dependency parsec >=3.0: using parsec-3.1.14.0
Dependency regex-tdfa >=1.2.3 && <=1.5: using regex-tdfa-1.3.1.0
Dependency safe >=0.3: using safe-0.3.19
Dependency scientific >=0.3: using scientific-0.3.7.0
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency time >=0.1.6.0: using time-1.9.3
Dependency transformers >=0.3: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Dependency vector >=0.12.0.2 && <0.13: using vector-0.12.3.0
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency ginger -any: using ginger-0.10.1.0
Dependency optparse-applicative >=0.14.3.0 && <0.17: using
optparse-applicative-0.15.1.0
Dependency process >=1.6.5.0 && <1.7: using process-1.6.9.0
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency transformers >=0.5.6.2 && <0.6: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Dependency yaml >=0.11.0.0 && <0.12: using yaml-0.11.5.0
Dependency aeson >=1.4.2.0 && <1.6: using aeson-1.5.6.0
Dependency base >=4.8 && <5: using base-4.14.1.0
Dependency bytestring >=0.10.8.2 && <0.11: using bytestring-0.10.12.0
Dependency data-default >=0.5: using data-default-0.7.1.1
Dependency ginger -any: using ginger-0.10.1.0
Dependency mtl >=2.2.2 && <2.3: using mtl-2.2.2
Dependency tasty >=1.2 && <1.5: using tasty-1.2.3
Dependency tasty-hunit >=0.10.0.1 && <0.11: using tasty-hunit-0.10.0.3
Dependency tasty-quickcheck ==0.10.*: using tasty-quickcheck-0.10.1.2
Dependency text >=1.2.3.1 && <1.3: using text-1.2.4.1
Dependency time >=0.1.6.0: using time-1.9.3
Dependency transformers >=0.5.6.2 && <0.6: using transformers-0.5.6.2
Dependency unordered-containers >=0.2.5: using unordered-containers-0.2.14.0
Dependency utf8-string >=1.0.1.1 && <1.1: using utf8-string-1.0.2
Source component graph:
component lib
component exe:ginger dependency lib
component test:tests dependency lib
Configured component graph:
component ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include filepath-1.4.2.1
include http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
include mtl-2.2.2
include parsec-3.1.14.0
include regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
include safe-0.3.19-36AYIiBjtSLS65WmTQ35k
include scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
include text-1.2.4.1
include time-1.9.3
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
include vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
component ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
include process-1.6.9.0
include text-1.2.4.1
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
include yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
component ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include mtl-2.2.2
include tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
include tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
include tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
include text-1.2.4.1
include time-1.9.3
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Linked component graph:
unit ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include filepath-1.4.2.1
include http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
include mtl-2.2.2
include parsec-3.1.14.0
include regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
include safe-0.3.19-36AYIiBjtSLS65WmTQ35k
include scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
include text-1.2.4.1
include time-1.9.3
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
include vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
Text.Ginger=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger,Text.Ginger.AST=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.AST,Text.Ginger.GVal=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.GVal,Text.Ginger.Html=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Html,Text.Ginger.Optimizer=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Optimizer,Text.Ginger.Parse=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Parse,Text.Ginger.Run=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run,Text.Ginger.Run.Builtins=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.Builtins,Text.Ginger.Run.FuncUtils=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.FuncUtils,Text.Ginger.Run.Type=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.Type,Text.Ginger.Run.VM=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.Ginger.Run.VM,Text.PrintfA=ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo:Text.PrintfA
unit ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
include process-1.6.9.0
include text-1.2.4.1
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
include yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
unit ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
include aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
include base-4.14.1.0
include bytestring-0.10.12.0
include data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
include ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
include mtl-2.2.2
include tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
include tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
include tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
include text-1.2.4.1
include time-1.9.3
include transformers-0.5.6.2
include unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
include utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Ready component graph:
definite ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
depends aeson-pretty-0.8.8-ieY1twFXPI8cot6MF8MZ0
depends base-4.14.1.0
depends bytestring-0.10.12.0
depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
depends filepath-1.4.2.1
depends http-types-0.12.3-83JHnI2fUYa5h3vgNT9Hwz
depends mtl-2.2.2
depends parsec-3.1.14.0
depends regex-tdfa-1.3.1.0-86Ve5VgglvW23V5dPSAOm3
depends safe-0.3.19-36AYIiBjtSLS65WmTQ35k
depends scientific-0.3.7.0-2IwMamNipm4GhmqfKxrO1Z
depends text-1.2.4.1
depends time-1.9.3
depends transformers-0.5.6.2
depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
depends vector-0.12.3.0-DjRVptyTdiT3mipwWvt1jW
definite ginger-0.10.1.0-9F27pmIEmGCH0rvj1qRMKL-ginger
depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
depends base-4.14.1.0
depends bytestring-0.10.12.0
depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
depends ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
depends optparse-applicative-0.15.1.0-2hUbd3K4cmjHYvRpqoC7A4
depends process-1.6.9.0
depends text-1.2.4.1
depends transformers-0.5.6.2
depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
depends yaml-0.11.5.0-JSPy5Fxql0K85T1eoy4nPJ
definite ginger-0.10.1.0-7ADNA5QcqPfIMjoqXXCEiC-tests
depends aeson-1.5.6.0-89mRhAl4FhxDxUb2oPr1Yf
depends base-4.14.1.0
depends bytestring-0.10.12.0
depends data-default-0.7.1.1-B2xqLjZNDxg1KVbA6WyFWH
depends ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
depends mtl-2.2.2
depends tasty-1.2.3-7jQjHiJLVlG7T5lZlhi0Bc
depends tasty-hunit-0.10.0.3-5pFQPUD42om9FFVN9h9CyQ
depends tasty-quickcheck-0.10.1.2-G3SWIFemDG33gMlEXVff6g
depends text-1.2.4.1
depends time-1.9.3
depends transformers-0.5.6.2
depends unordered-containers-0.2.14.0-FjQASgh3rnkLSsvJG2xUpd
depends utf8-string-1.0.2-Lwtc54cgMl77YyeO5RGhjt
Using Cabal-3.2.1.0 compiled by ghc-8.10
Using compiler: ghc-8.10.4
Using install prefix: /usr/local
Executables installed in: /usr/local/bin
Libraries installed in:
/usr/local/lib/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0-L5phRogT5hkDDRKPTpRCGo
Dynamic Libraries installed in: /usr/local/lib/x86_64-linux-ghc-8.10.4
Private executables installed in:
/usr/local/libexec/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Data files installed in:
/usr/local/share/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Documentation installed in:
/usr/local/share/doc/x86_64-linux-ghc-8.10.4/ginger-0.10.1.0
Configuration files installed in: /usr/local/etc
Using alex version 3.2.6 found on system at: /usr/bin/alex
Using ar found on system at: /usr/bin/x86_64-pc-linux-gnu-ar
Using c2hs version 0.28.7 found on system at: /usr/bin/c2hs
Using cpphs version 1.20.9 found on system at: /usr/bin/cpphs
Using doctest version 0.16.3 found on system at: /usr/bin/doctest
Using gcc version 12.0.0 found on system at:
/usr/lib/ccache/bin/x86_64-pc-linux-gnu-gcc
Using ghc version 8.10.4 found on system at: /usr/bin/ghc
Using ghc-pkg version 8.10.4 found on system at: /usr/bin/ghc-pkg
No ghcjs found
No ghcjs-pkg found
No greencard found
Using haddock version 2.24.0 found on system at: /usr/bin/haddock
Using happy version 1.20.0 found on system at: /usr/bin/happy
Using haskell-suite found on system at: haskell-suite-dummy-location
Using haskell-suite-pkg found on system at: haskell-suite-pkg-dummy-location
No hmake found
Using hpc version 0.68 found on system at: /usr/bin/hpc
Using hsc2hs version 0.68.7 found on system at: /usr/bin/hsc2hs
Using hscolour version 1.24 found on system at: /usr/bin/HsColour
No jhc found
Using ld found on system at: /usr/bin/x86_64-pc-linux-gnu-ld
Using pkg-config version 1.6.3 found on system at: /usr/bin/pkg-config
Using runghc version 8.10.4 found on system at: /usr/bin/runghc
No strip found
Using tar found on system at: /bin/tar
No uhc found
Preprocessing library for ginger-0.10.1.0..
Building library for ginger-0.10.1.0..
[ 1 of 12] Compiling Text.Ginger.Html ( src/Text/Ginger/Html.hs, dist/build/Text/Ginger/Html.o, dist/build/Text/Ginger/Html.dyn_o )
[ 2 of 12] Compiling Text.Ginger.GVal ( src/Text/Ginger/GVal.hs, dist/build/Text/Ginger/GVal.o, dist/build/Text/Ginger/GVal.dyn_o )
src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Maybe" may never fire
because ‘.’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
|
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Maybe" may never fire
because ‘toGVal’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
|
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:816:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Maybe" may never fire
because rule "Class op fromGVal" for ‘fromGVal’ might fire first
Probable fix: add phase [n] or [~n] to the competing rule
|
816 | {-#RULES "GVal/round-trip-Maybe" fromGVal . toGVal = Just #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Either" may never fire
because ‘.’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
|
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Either" may never fire
because ‘toGVal’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
|
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:817:10: warning: [-Winline-rule-shadowing]
Rule "GVal/round-trip-Either" may never fire
because rule "Class op fromGValEither" for ‘fromGValEither’ might fire first
Probable fix: add phase [n] or [~n] to the competing rule
|
817 | {-#RULES "GVal/round-trip-Either" fromGValEither . toGVal = Right #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
Rule "GVal/text-shortcut" may never fire
because ‘.’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘.’
|
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
Rule "GVal/text-shortcut" may never fire
because ‘toGVal’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘toGVal’
|
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/GVal.hs:818:10: warning: [-Winline-rule-shadowing]
Rule "GVal/text-shortcut" may never fire
because ‘asText’ might inline first
Probable fix: add an INLINE[n] or NOINLINE[n] pragma for ‘asText’
|
818 | {-#RULES "GVal/text-shortcut" asText . toGVal = id #-}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[ 3 of 12] Compiling Text.Ginger.AST ( src/Text/Ginger/AST.hs, dist/build/Text/Ginger/AST.o, dist/build/Text/Ginger/AST.dyn_o )
[ 4 of 12] Compiling Text.Ginger.Parse ( src/Text/Ginger/Parse.hs, dist/build/Text/Ginger/Parse.o, dist/build/Text/Ginger/Parse.dyn_o )
[ 5 of 12] Compiling Text.PrintfA ( src/Text/PrintfA.hs, dist/build/Text/PrintfA.o, dist/build/Text/PrintfA.dyn_o )
[ 6 of 12] Compiling Text.Ginger.Run.Type ( src/Text/Ginger/Run/Type.hs, dist/build/Text/Ginger/Run/Type.o, dist/build/Text/Ginger/Run/Type.dyn_o )
[ 7 of 12] Compiling Text.Ginger.Run.FuncUtils ( src/Text/Ginger/Run/FuncUtils.hs, dist/build/Text/Ginger/Run/FuncUtils.o, dist/build/Text/Ginger/Run/FuncUtils.dyn_o )
[ 8 of 12] Compiling Text.Ginger.Run.VM ( src/Text/Ginger/Run/VM.hs, dist/build/Text/Ginger/Run/VM.o, dist/build/Text/Ginger/Run/VM.dyn_o )
[ 9 of 12] Compiling Text.Ginger.Run.Builtins ( src/Text/Ginger/Run/Builtins.hs, dist/build/Text/Ginger/Run/Builtins.o, dist/build/Text/Ginger/Run/Builtins.dyn_o )
src/Text/Ginger/Run/Builtins.hs:41:1: warning: [-Wdeprecations]
Module ‘Control.Monad.Error’ is deprecated:
Use "Control.Monad.Except" instead
|
41 | import Control.Monad.Error (runErrorT)
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
src/Text/Ginger/Run/Builtins.hs:855:33: warning: [-Wdeprecations]
In the use of ‘runErrorT’
(imported from Control.Monad.Error, but defined in Control.Monad.Trans.Error):
Deprecated: "Use Control.Monad.Trans.Except instead"
|
855 | let reM = runIdentity . runErrorT $
| ^^^^^^^^^
[10 of 12] Compiling Text.Ginger.Run ( src/Text/Ginger/Run.hs, dist/build/Text/Ginger/Run.o, dist/build/Text/Ginger/Run.dyn_o )
[11 of 12] Compiling Text.Ginger.Optimizer ( src/Text/Ginger/Optimizer.hs, dist/build/Text/Ginger/Optimizer.o, dist/build/Text/Ginger/Optimizer.dyn_o )
[12 of 12] Compiling Text.Ginger ( src/Text/Ginger.hs, dist/build/Text/Ginger.o, dist/build/Text/Ginger.dyn_o )
Preprocessing executable 'ginger' for ginger-0.10.1.0..
Building executable 'ginger' for ginger-0.10.1.0..
[1 of 2] Compiling Options ( cli/Options.hs, dist/build/ginger/ginger-tmp/Options.dyn_o )
[2 of 2] Compiling Main ( cli/GingerCLI.hs, dist/build/ginger/ginger-tmp/Main.dyn_o )
cli/GingerCLI.hs:120:17: warning: [-Wdeprecations]
In the use of ‘decode’ (imported from Data.Yaml):
Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
|
120 | decodeFile fn = YAML.decode <$> (openFile fn ReadMode >>= BS.hGetContents)
| ^^^^^^^^^^^
cli/GingerCLI.hs:123:25: warning: [-Wdeprecations]
In the use of ‘decode’ (imported from Data.Yaml):
Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
|
123 | decodeString = return . YAML.decode . UTF8.fromString
| ^^^^^^^^^^^
cli/GingerCLI.hs:126:15: warning: [-Wdeprecations]
In the use of ‘decode’ (imported from Data.Yaml):
Deprecated: "Please use decodeEither or decodeThrow, which provide information on how the decode failed"
|
126 | decodeStdin = YAML.decode <$> BS.getContents
| ^^^^^^^^^^^
Linking dist/build/ginger/ginger ...
Preprocessing test suite 'tests' for ginger-0.10.1.0..
Building test suite 'tests' for ginger-0.10.1.0..
[1 of 3] Compiling Text.Ginger.PropertyTests ( test/Text/Ginger/PropertyTests.hs, dist/build/tests/tests-tmp/Text/Ginger/PropertyTests.dyn_o )
[2 of 3] Compiling Text.Ginger.SimulationTests ( test/Text/Ginger/SimulationTests.hs, dist/build/tests/tests-tmp/Text/Ginger/SimulationTests.dyn_o )
[3 of 3] Compiling Main ( test/Spec.hs, dist/build/tests/tests-tmp/Main.dyn_o )
Linking dist/build/tests/tests ...
Running 1 test suites...
Test suite tests: RUNNING...
All Tests
Simulation
Smoke Test: OK
Comments
Comment does not appear in output: OK
Dashed delimiters eat whitespace
comments: OK
interpolations: OK
flow: OK
Default delimiters eat whitespace with LStripBlocks
comments: OK
interpolations: OK
flow: OK
interpolations, left-only: OK
Default delimiters eat whitespace with TrimBlocks
comments: OK
interpolations: OK
flow: OK
interpolations, right-only: OK
Plussed delimiters override LStrip/TrimBlocks
comments: OK
interpolations: OK
flow: OK
Trailing newlines
eaten after blocks: OK
not eaten after interpolations: OK
not eaten after blocks when keepTrailingNewline is on: OK
Literals
Strings
String: "foobar": OK
String: "\r\n\t\b": OK
Numbers
123: OK
3.1415: OK
Booleans
true: OK
True: OK
false: OK
False: OK
Null: OK
Simple list/object constructs
Lists: OK
Nested lists: OK
Objects: OK
Nested object/list constructs: OK
Accessing object/list members
by integer index: OK
by string key: OK
by property name: OK
multi-level mixed: OK
Function calls
print("Hello"): OK
"Hello"|print: OK
Addition
1 + 1 = 2: OK
1 + 1 = 2: OK
Subtraction
1 - 1 = 0: OK
Concatenation
1 ~ "foo" = 1foo: OK
Multiplication
5 * 5 = 25: OK
Division
24 / 6 = 4: OK
3 / 2 = 1.5: OK
Integer Division
24 // 6 = 4: OK
3 // 2 = 1: OK
Modulo
7 % 3 = 2: OK
Iteration
for x in [ "foo", "bar", "baz" ]: <x>: OK
for x in []: <x> else <no>: OK
for x in [a]: <x> else <no>: OK
The `loop` auto-variable
loop.cycle: OK
recursive loops: RuntimeErrorAt "<<unknown>>" (line 1, column 83) (TypeError ["list","dictionary"] (Just "null"))
RuntimeErrorAt "<<unknown>>" (line 1, column 83) (TypeError ["list","dictionary"] (Just "null"))
FAIL
test/Text/Ginger/SimulationTests.hs:1589:
expected: "a@1(b@2()c@2(d@3()))"
but got: "a@1(c@2(d@3())b@2())"
Conditionals
if true then "yes" else "no": OK
if false then "yes" else if false then "maybe" else "no": OK
if false then "yes" else if true then "maybe" else "no": OK
if null should be false: OK
Exceptions
try/catch, no exception: OK
try/finally, no exception: OK
try/catch, trigger arguments exception: OK
try/finally, trigger arguments exception: OK
try/catch, catch selectively (string syntax): OK
try/catch, catch selectively (identifier syntax): OK
try/catch, skip non-matching catches: OK
Switch
switch 1 of 1, 2, default: OK
switch 1 of 1, 2: OK
Comparisons
if 1 == 1 then "yes" else "no": OK
if 1 > 0 then "yes" else "no": OK
if 1 > null then "yes" else "no": OK
if 1 < 2 then "yes" else "no": OK
if null < 1 then "yes" else "no": OK
Boolean AND
AND (both) (and): OK
AND (only one) (and): OK
AND (neither) (and): OK
AND (both) (&&): OK
AND (only one) (&&): OK
AND (neither) (&&): OK
Boolean OR
OR (both) (or): OK
OR (only one) (or): OK
OR (either) (or): OK
OR (both) (||): OK
OR (only one) (||): OK
OR (either) (||): OK
Slicing brackets
from/to, both positive: OK
from/to, from negative: OK
from/to, to implicit: OK
from/to, from implicit: OK
Built-in tests
"divisibleby"
divisibleby(14,7): OK
divisibleby(14,6): OK
"even"
even(3): OK
even("2"): OK
even("3"): OK
even("two"): OK
"eq": OK
"equalto": OK
"ge": OK
"greaterthan": OK
"gt": OK
"le": OK
"lessthan": OK
"lt": OK
"ne": OK
"odd"
odd(2): OK
odd(3): OK
odd("2"): OK
odd("3"): OK
Built-in filters/functions
"abs": OK
"any"
"any" (both): OK
"any" (just one): OK
"any" (neither): OK
"all"
"all" (both): OK
"all" (just one): OK
"all" (neither): OK
"ceil"
14.1: OK
-14.1: OK
-14.8: OK
"capitalize": OK
"upper": OK
"lower": OK
"center"
extra space: OK
no extra space: OK
"compose": OK
"concat": OK
"contains"
single match: OK
multi match: OK
non-match: OK
"date"
format a date: OK
format a list as a date: OK
format a 5-element list as a date: OK
format a 3-element list as a date: OK
use correct default time (noon) with 3-element list: OK
format a string as a date: OK
format a string as a date (JSON-style formatting): OK
format a string with fractional seconds as a date (all variants): OK
format a string as a time-of-day: OK
format a string as a date, with timezone: OK
format a local-time string as a date + time, with explicit timezone: OK
format a zoned-time string as a date, with explicit timezone: OK
use a custom locale: OK
"default"
trigger default: OK
use truthy value: OK
"difference": OK
"dictsort"
by key: OK
by value: OK
"escape"
single item: OK
multiple items: OK
"equals"
two equal: OK
all equal: OK
some equal: OK
"eval"
simple: OK
with extra state: OK
outside state does not bleed into eval(): OK
standard functions available inside eval: OK
"filesizeformat"
bytes: OK
kilobytes: OK
megabytes: OK
bytes (2-based): OK
kibibytes: OK
mebibytes: OK
"filter"
simple case: OK
with extra argument: OK
"format"
jinja.pocoo.org example: OK
"map"
map function over list: OK
map function over dictionary: OK
map to extract attribute: OK
"not-equals"
all equal: OK
not all equal: OK
"floor"
14.1: OK
14.8: OK
-14.1: OK
-14.8: OK
"int"
14.1: OK
14.8: OK
-14.1: OK
-14.8: OK
"length"
list: OK
dict: OK
string: OK
"partial"
partial: OK
"printf"
%i, passed as int: OK
%i, passed as string: OK
%i, passed as float: OK
%f, passed as int: OK
%.3f, passed as int: OK
%s, string: OK
"product": OK
"ratio": OK
"round"
14.1: OK
14.8: OK
-14.1: OK
-14.8: OK
"str": OK
"sum": OK
"truncate"
14.1: OK
14.8: OK
-14.1: OK
-14.8: OK
"urlencode": OK
"sort"
simple: OK
reverse: OK
sort by key: OK
sort by key, reverse: OK
sort dictionary by keys: OK
sort by a projection function: OK
sort by a path: OK
"slice"
full positional args: OK
implicit 'to end': OK
full named args: OK
negative offset: OK
call on string subject: OK
"split"
word-splitting: OK
word-splitting, more spaces: OK
word-splitting, more spaces, explicit delim: OK
"replace"
simple case: OK
multiple replacements: OK
longer replacements: OK
deletion: OK
"zip"
lists: OK
"zipwith"
sum: OK
"json"
null: OK
[1,2,3]: OK
"in"
elem in list: OK
elem not in list: OK
elem in dict: OK
elem not in dict: OK
"apply"
sum: OK
Setting variables
plain: OK
self-referential: OK
HTML encoding
no encoding outside of constructs: OK
auto-encode inside interpolations: OK
raw filter bypasses encoding: OK
Includes
include plain: OK
include with a variable: OK
not eaten after blocks in included template when keepTrailingNewline is on: OK
include referencing an included variable: OK
Explicit Local Scopes
baseline: OK
inside local scope: OK
after exiting local scope: OK
Indentation
stripping leading spaces: OK
explicit indent string: OK
implicit indent string: OK
explicit non-whitespace indent string: OK
explicit indent string from more complex expression: OK
discarding level-0 indents: OK
indentation levels inherited at runtime (dynamic): OK
Macros
simple: OK
with args: OK
Lambdas
single arg: OK
two args: OK
Ternary operator
C syntax: OK
python syntax: OK
C syntax, nested, true/false: OK
Python syntax, nested, true/false: OK
C syntax, nested, true/true: OK
Python syntax, nested, true/true: OK
Call syntax
"caller": OK
Inheritance
inheritance: OK
multi-tier inheritance: OK
Non-HTML Output
text: OK
json: OK
Script mode
empty script block: OK
comments
simple: OK
multiple: OK
inside expressions: OK
echo: OK
expression statement: OK
grouped statements: OK
if: OK
if/else: OK
switch: OK
for: OK
for/else (loop): OK
for/else (recover): OK
set: OK
include: OK
macro: OK
Script statment blocks
baseline: OK
inside local scope: OK
after exiting block: OK
Explicit Local Scopes
baseline: OK
inside local scope: OK
after exiting local scope: OK
do expressions
single statement: OK
statement block: OK
overriding delimiters
angle brackets: OK
evil mode: OK
is-tests
basic is-test, true: OK
basic is-test, false: OK
parens-less argument syntax: OK
precedence vs booleans: OK
precedence vs addition: OK
regex module
regex.test
simple match: OK
simple match: OK
regex.match
simple match: OK
string representation of multiple matches returns only whole match: OK
html representation of multiple matches returns only whole match: OK
regex.matches
simple match: OK
Properties
Optimizer
optimizer doesn't change behavior: OK (0.03s)
+++ OK, passed 100 tests.
ToGVal / FromGVal round tripping
Int: OK
+++ OK, passed 100 tests.
Bool: OK
+++ OK, passed 100 tests.
[Text]: OK
+++ OK, passed 100 tests.
Maybe Text: OK
+++ OK, passed 100 tests.
ByteString: OK
+++ OK, passed 100 tests.
Text: OK
+++ OK, passed 100 tests.
LocalTime: OK
+++ OK, passed 100 tests.
TimeZone: OK
+++ OK, passed 100 tests.
ZonedTime: OK
+++ OK, passed 100 tests.
1 out of 307 tests failed (0.09s)
Test suite tests: FAIL
Test suite logged to: dist/test/ginger-0.10.1.0-tests.log
0 of 1 test suites (0 of 1 test cases) passed.
At the moment i only find documentation for for-loops at https://ginger.tobiasdammers.nl/guide/getting-started/ under heading "Ginger Syntax: The Basics.". I would like to loop over a dictionary. Sometimes only keys are needed, sometimes only values, sometimes both. Maybe there could be a documentation page like twig's for
on getting-started you mention that ginger is not on stackage ... in the meanwhile it appeared there:
https://www.stackage.org/lts-9.1/package/ginger-0.5.3.0
I inject content
"content": "<p>What should go into a homepage</p>\n<ul>\n<li>name and address</li>\n</ul>",
into {{ content }} and get
<p>What should go into a homepage</p>
<ul>
<li>name and address</li>
</ul>
for mustache syntax I would use {{{ context }}} to avoid the http-escaping, but I thought this would not be required for jinja2. What is it I am doing wrong?
Thank you for help!
Aeson 2 changes the way that JSON objects are represented, in order to mitigate denial-of-service attacks where an attacker provides an object that has many keys that hash to the same value. The Object
type now uses an opaque KeyMap
type instead of HashMap Text
. Currently, it may be implemented as a Map
or a HashMap
depending on a compile-time flag, but there may be additional implementations in the future. Additionally, a new Key
type is used for keys instead of Text
. It is a currently a newtype
wrapper around Text
, but it looks like that may also change in the future.
The aeson-pretty library was recently updated to support Aeson 2, so there are no more dependencies blocking ginger
. It should be easy to update ginger
to support Aeson 2, as only the rawJSONToGVal
function needs to be changed. I have experimented with an implementation that uses a data structure according to the data structure that Aeson is configured to use.
#if MIN_VERSION_aeson(2,0,0)
rawJSONToGVal (JSON.Object km) =
let keyToText = Prelude.maybe AK.toText Coercion.coerceWith AK.coercionToText
in case (AKM.coercionToHashMap, AKM.coercionToMap) of
(Just coercion, _mMapCoercion) ->
toGVal . HashMap.mapKeys keyToText $ Coercion.coerceWith (Coercion.sym coercion) km
(Nothing, Just coercion) ->
toGVal . Map.mapKeys keyToText $ Coercion.coerceWith (Coercion.sym coercion) km
(Nothing, Nothing) ->
toGVal . Map.fromList . List.map (first keyToText) $ AKM.toList km
#else
rawJSONToGVal (JSON.Object o) = toGVal o
#endif
Currently, the first case (HashMap
) or second case (Map
) should always be selected, as there are no other possibilities. If a different data structure is used in the future, this code defaults to using a Map
to avoid the denial-of-service vulnerability that use of HashMap
introduces. Alternatively, the default could use a HashMap
in order to prioritize (non-attack-scenario) performance.
What are your thoughts? If this looks like an acceptable way to add support for Aeson 2, I am happy to submit a pull request.
Rundown:
{% filter %}
tagsThis should be possible entirely at the syntax level, without touching the AST.
Currently, ginger templates can only be interpreted.
Make a backend that instead outputs TH AST so that ginger templates can be compiled right into a Haskell project.
/tmp/stack26892/ginger-0.7.3.0/src/Text/Ginger/Html.hs:24:15: error:
• No instance for (Semigroup Html)
arising from the 'deriving' clause of a data type declaration
Possible fix:
use a standalone 'deriving instance' declaration,
so you can specify the instance context yourself
• When deriving the instance for (Monoid Html)
|
24 | deriving (Monoid, Show, Eq, Ord)
| ^^^^^^
I fixed this at https://github.com/hasura/ginger. I can submit a PR if needed.
One of the optimization steps we perform is compile-time evaluation of subexpression that are completely known at compile time.
E.g., in the template <h1>{{ "hello & goodbye"|capitalize }}</h1>
, everything we need to calculate the correct output is already known at runtime - we have a string literal, the pure capitalize
function, an interpolation statement, and two literal output statements. This means that we can evaluate the entire thing at compile time, and replace it with just one literal output statement: <h1>Hello & Goodbye</h1>
.
The problem however lies in accurately determining const-ness and purity: in order to judge whether a value is pure, we need to know what's in the current scope, but the scope contains the context passed in at runtime.
A proposed solution would work as follows.
First, we define a data structure that represents our knowledge about the current execution context. Essentially, this would be a list of constraints on names in the current namespace, and such a constraint might be something like "is definitely a pure function", "is a constant value", etc.
While traversing the template AST, we can then thread this knowledge data structure through the traversal, updating it as we go. E.g., when we encounter a let
block that binds a literal to some variable, then we can add an entry to our knowledgebase that says that this variable now holds a const value. Or, when a variable is bound to a lambda expression that we can infer as pure, we add to our knowledgebase the factoid that this variable now holds a pure function.
Now, the conservative approach is to start with an empty slate: we know nothing, but we gain knowledge as we traverse the AST. However, this isn't going to be optimal in the typical use case, where all the built-in global bindings are intact - many builtin functions are in fact pure, and while the host application can change this, people will rarely do this in a way that changes contracts - so we need to cater for the possible case of changing purity semantics of builtins, but at the same time, we also don't want to miss out on the possible optimization when the semantics are intact.
A fairly simple way to solve this is to put the responsibility in the hands of the caller: simply add an argument to the parser that is used to seed the knowledge base. Host applications that never touch any of the builtins can simply pass the "default" knowledge base, telling the parser to generate code that will be correct as long as the host application does in fact stay away from the builtins. Host applications that do touch builtins could either simply pass an empty seed knowledge, or they could modify the default knowledge to reflect the changes they intend to make. Either way though, it's going to be an honor system.
To make it safer, one would have to tag GVal
s themselves with purity information, and then check whether the passed-in context matches what was declared at compile time. Since this involves deriving the seed knowledge from the context provided by the host, exposing this derivation makes sense, because then host applications can reuse the code to automatically generate the right seed knowledge for the context they intend to pass to the template. It would also require remembering the seed knowledge in the template itself, so that it becomes possible to check that the runtime context matches the compile-time promises. And if it doesn't, we can either reject the template (conservative choice), or we can run it anyway ("dangerous mode"), or we can fall back to an alternative compilate that assumes nothing (empty context), or we could simply fall back to the entirely unoptimized version of the AST.
Hello,
given the following simple template
Hello, {{name}} {{surname}}!
and function for rendering:
renderTemplate :: HashMap Text Text -> Template SourcePos -> Text
renderTemplate = easyRender
Is there any built-in way how to check that the rendered template has all variables filled in? I.e. that the given HashMap
contains keys for both existing variables name
and surname
and if not, then return some error, etc?
I tried to search source codes and documentation but didn't find anything that would help me.
Thanks a lot in advance.
When i have a nest structure of arrays and objects and do {{var}}
it concatenates all values. Instead could it print a JSON like format to see the structure? If this is not desirable with the plain {{}}
maybe a function like twig's dump could be added.
I'm trying to descend a recursive data-structure and recursively render the same template [1] Forget the recursive part, I'm unable to pass local variables to an included template. I've tried the following, and nothing works:
{% include "includes/toc.html" with tocItems = page.toc %}
{% with tocItems = page.toc %}
{% include "includes/toc.html" %}
{% endwith %}
{% scope %}
{% set tocItems = page.toc %}
{% include "includes/toc.html" %}
{% endscope %}
[1] I'm trying to generate a page's TOC -- which is why the recursion
See #48: ginger currently fails to compile on GHC 8.8 due to MonadFail
.
PR #48 suggests widening Monad
constraints to arbitrary MonadFail
instances, but I think it would be more prudent to integrate error handling into the runXXXX
functions and the Run
monad stack itself (e.g. using ExceptT
), and while we're at it, introduce a saner / more specific error type. We're going to break the API anyway, might as well use this as an opportunity for improvement.
As seen on the Stackage build server:
ginger: Process exited with ExitFailure 1: dist/build/tests/tests (pending: 146$
, failures: 0)
"urlencode":
FAIL
test/Text/Ginger/SimulationTests.hs:1294:
expected: "a%2Fb%20c"
but got: "a%2fb%20c"
1 out of 249 tests failed (0.22s)
What is your take on the severity of this? I'm not necessarily recommending that any action be taken on your part, since I think that http-types should return to uppercasing.
See also: commercialhaskell/stackage#3226
Jinja2 accepts True
as an alias for true
, and False
for false
. Let's do this too.
Ginger does not currently implement all the built-in functions, filters and tests that jinja2 defines.
For reference:
Note that in Ginger, these things are all just syntax sugar for function calls, while Jinja2 has separate namespaces for each of them - we are not looking to change this, just implementing missing things.
Right now when printing {{doesnt_exist}}
it just doesn't print anything. Rather i would like to have throw an exception or even better check on compile time. Now bugs are there and they are not notified about.
I'm planning to use ginger
as the underlying library for a static site generator. However, I'm puzzled why the only two types types implementing ContextEncodable are Text
and Html
(which itself is a newtype over Text
).
Doesn't ginger internally use lazy-text, lazy-bytestring, or a bytestring-builder? Wouldn't appending to a strict-text repeatedly be very expensive?
template:
Hello, {{ name }},\nwelcome in {{ location|upper }}!
result:
Hello, Alice,
welcome in WONDERLAND!
but if in the first line the variable is the last thing on the line, then the \n is removed:
template:
Hello, {{ name }}\nwelcome in {{ location|upper }}!
result:
Hello, Alicewelcome in WONDERLAND!
is this a bug? Or Do I need another syntax for the variable closing token?
Alex.
Jinja2 uses the is
keyword to express "test expressions". Here's the relevant Jinja2 documentation.
In Ginger, since we want tests, functions, and filter, to all be just different syntax for function calls, this is simply a matter of adding syntax sugar that turns expression is test(arg0,arg1,...)
into test(expression, arg0, arg1, ...)
, similar to the syntax sugar for filters (expression|filter(args)
→ filter(expression, args)
). Thus, it can (and should) be implemented entirely in the parser.
Hello,
First off, congrats for the work on Ginger. Being a long-time Jinja2 user I can definitely appreciate a similar template engine running on Haskell.
I managed to run the simple examples from the docs, but I'm having a hard time figuring out how to pass anything else than a HashMap Text Text
as the source of input variables.
For instance, consider this template:
Hello {{ name }},
You have {% for item in items %}{{ item }}{% if not loop.last %}, {% endif %}{% endfor %}.
I'm trying to feed this template with the following elements:
import Data.HashMap.Strict (HashMap, fromList)
data Value =
VText Text
| VList [Text]
deriving Show
context :: HashMap Text Value
context = fromList [
("name", VText "John"),
("items", VList ["car", "truck", "house", "phone"])
]
scopeLookup :: (Hashable k, Eq k, ToGVal m b) => k -> HashMap.HashMap k b -> GVal m
scopeLookup key context =
toGVal $ HashMap.lookup key context
render :: Template SourcePos -> HashMap VarName Value -> Text
render template contextMap =
let contextLookup = flip scopeLookup contextMap
context = makeContextHtml contextLookup
in htmlSource $ runGinger context template
With the code and the template above, I would expect the output to be:
Hello John,
You have car, truck, house, phone.
The problem is that Value
doesn't derive ToGVal
according to the compiler. I've tried different ways to fix it, but none has worked so far, which leads me to think that maybe I'm just doing it wrong entirely.
Is there any recommended way to inject a sum type like this, or any other way to deal with variables that can be either Text
, or [Text]
, or HashMap Text Text
?
I have the impression that the extend tag (as shown in the documentation is not implemented in ginger 0.8.4.0. Correct?
Is there a list of what is implemented or what is missing? would reduce time chasing bugs.
Nevertheless, thank you for the implementation!
I felt that the docs were missing a simple, copy + paste-able example of how to render a template. I would have made a PR but I'm not sure what file this would go in
{-# LANGUAGE OverloadedStrings #-}
module Lib where
import Data.HashMap.Strict (fromList, HashMap)
import qualified Data.HashMap.Strict as HashMap
import Data.Hashable
import Data.Text (Text)
import System.Exit (exitFailure)
import System.IO (IOMode(ReadMode), openFile, hGetContents)
import System.IO.Error (tryIOError)
import Text.Ginger
(makeContextHtml, Template, toGVal, runGinger, parseGingerFile, VarName)
import Text.Ginger.GVal (ToGVal, GVal)
import Text.Ginger.Html (htmlSource)
-- A simple hashmap that we'll use as our template context
sampleContext :: HashMap Text Text
sampleContext = fromList [("name", "Alice")]
-- Given a Template and a HashMap of context, render the template to Text
render :: Template -> HashMap VarName Text -> Text
render template contextMap =
let contextLookup = flip scopeLookup contextMap
context = makeContextHtml contextLookup
in htmlSource $ runGinger context template
-- Wrapper around HashMap.lookup that applies toGVal to the value found.
-- Any value referenced in a template, returned from within a template, or used
-- in a template context, will be a GVal
scopeLookup
:: (Hashable k, Eq k, ToGVal m b)
=> k -> HashMap.HashMap k b -> GVal m
scopeLookup key context = toGVal $ HashMap.lookup key context
loadFileMay :: FilePath -> IO (Maybe String)
loadFileMay fn =
tryIOError (loadFile fn) >>= \e ->
case e of
Right contents -> return (Just contents)
Left _ -> return Nothing
where
loadFile :: FilePath -> IO String
loadFile fn' = openFile fn' ReadMode >>= hGetContents
-- Assuming there's an html file called "base.html" in the current directory and
-- that html file's contents are `Hi, {{ name }}`, attempt to parse "base.html"
-- and print the rendered template
-- >>> run
-- "Hi, Alice"
run :: IO ()
run = do
template <- parseGingerFile loadFileMay "base.html"
case template of
Left err -> print err >> exitFailure
Right template' -> print $ render template' sampleContext
Would it be possible to add support for records that become GVal dictionaries? Maybe with GHC.Generics instances can automatically be derived. I would prefer to just put my records straight into the template instead of writing conversion functions from record to hashmap.
The Text.PrintfA module fails to build when using GHC 9.0.1, giving the following error:
• Couldn't match type ‘t’ with ‘forall r. PrintfType r => r’
Expected: PrintfTypeT -> t
Actual: PrintfTypeT -> forall r. PrintfType r => r
‘t’ is a rigid type variable bound by
the type signature for:
printfa :: forall t. PrintfType t => String -> [PrintfArgT] -> t
at src/Text/PrintfA.hs:11:1-56
• In the first argument of ‘(.)’, namely ‘unT’
In the expression:
unT . foldl (\ (T r) (P a) -> T $ r a) (T $ printf format)
In an equation for ‘printfa’:
printfa format
= unT . foldl (\ (T r) (P a) -> T $ r a) (T $ printf format)
• Relevant bindings include
printfa :: String -> [PrintfArgT] -> t
(bound at src/Text/PrintfA.hs:12:1)
|
12 | printfa format = unT . foldl (\(T r) (P a) -> T $ r a ) (T $ printf format)
| ^^^
This error has to do with simplified subsumption and is easily resolved by using a lambda instead of unT
in the implementation of printfa
. I will submit a pull request with the fix.
Hello,
I am trying to use the library in very simple way (no external files, no passing of functions, pure):
renderTemplate :: ToJSON c => Text -> c -> Either Text Text
renderTemplate template ctx = do
tpl <- tplEither
let ctxGVal :: GVal Identity = rawJSONToGVal $ toJSON ctx
let r :: Text = easyRender ctxGVal tpl
return r
where
tplEither :: Either Text (Template SourcePos)
tplEither = parseGinger nullResolver Nothing (toS template) & runIdentity & mapLeft tshow
nullResolver :: IncludeResolver Identity
nullResolver = const $ return Nothing
I am getting an error on a line with easyRender
:
Could not deduce (ToGVal
(Text.Ginger.Run.Type.Run
SourcePos (Control.Monad.Trans.Writer.Lazy.Writer Text) Text)
(GVal Identity))
arising from a use of ‘easyRender’
from the context: ToJSON c
bound by the type signature for:
renderTemplate :: forall c.
ToJSON c =>
Text -> c -> Either Text Text
I don't understand what is the problem. I would appreciate any help.
Jinja2 uses the python-style logical operators:
>>> Template('{{ False and True or False }}').render()
'False'
while ginger uses &&
and ||
and rejects and
and or
.
Ginger should use the python-style logic operators and reject &&
.
Hi!
I'm making an original built-in function like bellow. And I want to use throwError $ ArgumentsError (Just "foo") ""
. But RuntimeError
is in Text.Ginger.Run.Type
, which is not exposed.
I want RuntimeError
exposed, or are there any other good ways?
main = do
…
context = HashMap.singleton ("foo", fromFunction fooFunc)
…
fooFunc :: Function (Run SourcePos (Writer Text) Text)
fooFunc args = do
…
when invalidArguments $ throwError $ ArgumentsError (Just "foo") ""
…
from the documentation:
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
{# This is a comment. Comments are removed from the output. #}
<body>
<menu id="nav-main">
{% for item in navigation %}
<li><a href="{{ item.url }}">{{ item.label }}</a></li>
{% endfor %}
</menu>
<div class="layout-content-main">
<h1>{{ title }}</h1>
{{ body }}
</div>
</body>
</html>
how am I supposed to pass these variables -- title, naviagation, body -- to this template?
In Jinja2, the following is a type error:
{{ "2" + 2 }}
But in Ginger, we currently have a ToGVal
instance for Text
(and other string types) that tries to parse the string into a Scientific
, and if that succeeds, exposes it in the asNumber
field, which means that in Ginger, the above template prints "4"
.
So the question here is whether it is more important to keep the current convenience of being able to use numeric strings as numbers, or to be more compatible with jinja2.
I am leaning slightly towards keeping the current behavior, because the problem is essentially just being too lenient (accepting templates that Jinja2 rejects), but everything that works fine on Jinja2 will also work fine on Ginger (i.e. we accept templates that Jinja2 accepts).
Hello,
We are using Ginger to generate documents based on questionnaires where are follow-up questions leading us to recursion. For that, we use macros in the template, but the "deeper" is the questionnaire, it gets significantly slower. I found out that macros are causing this problem, the "more" is the output inside a macro, the worse it gets. I made a simple example (of course this could be written totally without any macro, but we need recursion in the template):
{%- macro lipsum() %}
<!-- some content, e.g., 5 paragraphs of lorem ipsum -->
{% endmacro -%}
{%- macro nLipsum(xs) -%}
{%- for x in xs -%}
{{ lipsum() }}
{%- endfor -%}
{%- endmacro -%}
{%- macro twiceNLipsum(xs) -%}
{{ nLipsum(xs) }}
{{ nLipsum(xs) }}
{%- endmacro -%}
{{ twiceNLipsum(xs) }}
{%- macro lipsum() %}
<!-- some content, e.g., 5 paragraphs of lorem ipsum -->
{% endmacro -%}
{%- for x in xs -%}
{{ lipsum() }}
{%- endfor -%}
{%- for x in xs -%}
{{ lipsum() }}
{%- endfor -%}
The first one takes me approx. 4.5-5 seconds but the second one less than 0.4 seconds, both with 200 calls of lipsum
macro in total (i.e. xs
of length 100). In our real case, it was around 25 seconds; by removing macros, I managed to get to something like 3 seconds, but it is still quite a lot 😞
Can we avoid this effect somehow?
Thank you in advance 😸
String
is not fast nor memory efficient, Text
is better in almost every case.
Jinja2 allows setting these special tokens to something other than the defaults {% %}
, {{ }}
, {- -}
, e.g. <% %>
etc.
See https://ginger.tobiasdammers.nl/guide/getting-started/.
Example:
template :: Template
template = either (error . show) id . runIdentity $
parseGinger nullResolver Nothing "Hello, {{ name }}, welcome in {{ location }}!"
The type signature for template
should be Template SourcePos
.
Hi,
is there any performace comparison to yesod hamlet?
AFAIK yesod hamlet is compiled by template haskell, so that the templates do not have to be reparsed on every request.
Would it make sense to use ginger in webapps eg. replacing hamlet by ginger?
thanks,
Alex.
The CLI could use a proper argument parser and more flexible arguments to support the following use cases:
The overhauled argument processing code should also provide self-documentation (--help
).
Hello
Note that, because Ginger is a dynamically typed language (or, actually, an untyped language), passing values to a template execution context requires conversion to Ginger values, represented on the Haskell side as the GVal type. The ToGVal typeclass exposes a number of convenience functions that can be used for this purpose, and there are instances for many of Haskell's standard data types.
I wanted to model a dictionary with different types of values. When i adapt the easyRender example in the manual it gets really complicated (for me personally it was anyway).
Here is the changed code with the type errors it yields: >>> CODE <<<
context :: HashMap Text (GVal (Run SourcePos (Writer Text) Text))
context = HashMap.fromList
[ ("name", toGVal ("Alice" :: Text))
, ("location", toGVal ("Wonderland" :: String))
, ("age", toGVal (155 :: Int))
]
Maybe this could be the right type ?? It typechecked on this level but still throw another type error near easyRender
Proposed was the following patch:
-- This would work with the patch below
context :: HashMap Text (GVal m)
context = HashMap.fromList
[ ("name", toGVal ("Alice" :: Text))
, ("location", toGVal ("Wonderland" :: String))
, ("age", toGVal (155 :: Int))
]
{-
--- ginger-0.10.1.0/src/Text/Ginger/GVal.hs 2001-09-09 03:46:40.000000000 +0200
+++ ginger-0.10.1.0-my/src/Text/Ginger/GVal.hs 2020-09-02 10:10:21.853396692 +0200
@@ -3,6 +3,7 @@
{-#LANGUAGE FlexibleInstances #-}
{-#LANGUAGE ScopedTypeVariables #-}
{-#LANGUAGE RankNTypes #-}
+{-#LANGUAGE TypeFamilies #-}
-- | GVal is a generic unitype value, representing the kind of values that
-- Ginger can understand.
@@ -314,7 +315,7 @@
toGVal :: a -> GVal m
-- | Trivial instance for 'GVal' itself.
-instance ToGVal m (GVal m) where
+instance (m ~ m') => ToGVal m (GVal m') where
toGVal = id
instance ToGVal m () where
-}
Supposingly the code could then look like this
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE GADTs #-}
-- ...
newtype GVal' m = GVal' { unGVal' :: GVal m }
toGVal' v = GVal' (toGVal v)
instance (m ~ m') => ToGVal m (GVal' m') where
toGVal = unGVal'
context :: HashMap Text (GVal' m)
context = HashMap.fromList
[ ("name", toGVal' ("Alice" :: Text))
, ("location", toGVal' ("Wonderland" :: String))
, ("age", toGVal' (155 :: Int))
]
I didn't look if this patch makes sense but it seemed a very helpful suggestion.
For me the documentation is not clear about how to handle this scenario. I think it's quite common to have a dictionary with different types. Think of person with age int and name string. Maybe also something in ginger can be changed to simplify types or instances, i don't know.
Other than this it looks like a really nice package, i'm eager to get my first template working :)
ginger
decided that there is no difference between functions, tests and filters. Unfortunately, there is a clash for the tests and filters lower
and upper
:
In jinja2:
|upper
returns an uppercased string which is always truthy
is upper
returns true only if the string is already uppercased
The same goes for lower
respectively
This blocks #18
While PHP deeply disgusts me in general, being able to compile Ginger templates into something that can run on a run-of-the-mill cheap shared hosting environment (which, let's face it, is still a painful reality out there) without actually having to touch any PHP code does have some use cases.
This would require:
Hi,
could you please update stackage? There is still the ginger-0.5.3.0 version.
Thanks, ALex.
Make a backend that can load data from environment variables
We need to make a special case here, because defined
cannot be implemented as a function - any argument passed to a function is evaluated before passing it in, and evaluating undefined variables simply yields null
. I can see two ways in which this could be done.
The first one is to make defined
a very restricted special case in the parser, which emits a separate kind of expression, let's say CheckDefinedE p VarName
; and the interpreter would then simply take the varname and check it against the current scope. This is easy to implement, but not very featureful: e.g., {% if foo.bar is defined %}
will not be possible this way.
The second solution would be more involved. First, we would need a way to mark functions as macros; the operations semantics would then be as follows:
Thus, a macro would decide on its own whether it wants to evaluate its arguments.
Armed with this, we would then have to implement a function that, instead of completely evaluating an expression, merely checks for definedness. This is thin ice though, there are plenty of cases where the answer isn't obvious, e.g., in {{ defined(foo(bar)) }}
, is it enough for foo
to be a function, and for bar
to be defined? Or do all identifiers that foo
closes over also need to be defined? And if so, how are we going to check this?
With 'poKeepTrailingNewline = True' the main template keeps the newline but the included templates still swallow it. Here is a sample...
my template:
line1: {{v1}}\nline2: {% include 'line2inc' %}\nline3: {{v2}}!\nline4: {% for i in [1,2,3] %}{{i}}{% endfor %}\nline5
with this include:
{% for i in [1,2,3] %}{{i}}{% endfor %}\n(2nd inc line)
produces this:
line1: v1
line2: 123(2nd inc line)
line3: v2!
line4: 123
line5
but it should keep the newline in front of '(2nd inc line)'
(Split off from #8)
Hello, is it possible to pass own function through the context to be used as function/filter?
I tried after going though the files below but couldn't get it working... Some note on that in docs would be helpful.
Lines 128 to 135 in f3732ef
ginger/src/Text/Ginger/Run/Builtins.hs
Lines 95 to 97 in f3732ef
Thanks,
Marek
The not
unary is missing.
This is easily testable with the following test case:
, testCase "if not true then \"yes\" else \"no\"" $ do
mkTestHtml [] [] "{% if not true %}yes{% else %}no{% endif %}" "no"
which is failing at the moment.
Jinja2 does support this.
The optimizer is currently quite rudimentary / incomplete. There is a lot of room for improvement here.
Need tojson filter in which {{ info | tojson }}
should interpolate JSON value of info
while rendering.
For example, my data type is
data Interpolate = Interpolate { info :: Data.Aeson.Object }
which is ToJSON
instance.
I think you're missing an "avoid" or something similar:
We do, however, some of the most blatant Pythonisms
--- ginger-0.7.1.0/test/Text/Ginger/SimulationTests.hs.~1~ 2017-09-22 11:31:28.000000000 -0400
+++ ginger-0.7.1.0/test/Text/Ginger/SimulationTests.hs 2017-09-22 17:17:26.000000000 -0400
@@ -295,7 +295,7 @@
, testCase "AND (neither)" $ do
mkTestHtml [] [] "{% if 0 && 0 %}yes{% else %}no{% endif %}" "no"
]
- , testGroup "Boolean AND"
+ , testGroup "Boolean OR"
[ testCase "OR (both)" $ do
mkTestHtml [] [] "{% if 1 || 2 %}yes{% else %}no{% endif %}" "yes"
, testCase "OR (only one)" $ do
Hi,
dateformat
only supports whole seconds but JSON date strings may include fractions ex. 2020-08-21T19:35:42.994Z
.
Use case:
Value
using toJSON
Expected behavior:
Dates can be formatted using dateformat
.
Actual behavior:
In case the date has an exact number of seconds everything works fine. However, when fractions of seconds are present ex. 2020-08-21T19:35:42.994Z
then dateformat
produces no output.
I think the only change needed would be to add %Q
to the first 4 formats here. This handles both cases:
λ> parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%Z" "2020-08-21T19:35:42.994Z" :: UTCTime
2020-08-21 19:35:42.994 UTC
it :: UTCTime
λ> parseTimeOrError False defaultTimeLocale "%Y-%m-%dT%H:%M:%S%Q%Z" "2020-08-21T19:35:42Z" :: UTCTime
2020-08-21 19:35:42 UTC
it :: UTCTime
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.