Comments (13)
from ginger.
This happens on the Haskell side of things; you need to pass context variables in when calling runGinger
. http://hackage.haskell.org/package/ginger-0.5.1.2/docs/Text-Ginger-Run.html explains things in some more detail; however, essentially what you need to do is write a context lookup function which returns a suitable GVal
value for each variable name, then you use one of the makeContext
functions to turn it into a GingerContext
, and then you pass that to the runGinger(M)
function. E.g.:
let contextLookup varName =
case varName of
"username" -> toGVal username
"imageURL" -> toGVal imageURL
_ -> def -- def for GVal is equivalent to a NULL value
context = makeContext contextLookup
htmlSource $ runGinger context template
Alternatively, you can write your context object as any dictionary-like data type that has a ToGVal
instance, and use the easyRender(M)
API.
from ginger.
This should probably be fixed in the documentation.
from ginger.
Is there any way to create a parent/child template?
from ginger.
Sure. You have two options here: {% include %}
and {% extend %}
/{% block %}
.
{% include %}
is just a dumb inclusion mechanism; it picks up the file you reference and injects it at the current position, similar to how #include
works in C.
{% extends %}
and {% block %}
implement "template inheritance". It works as follows:
- First, you write a parent template. This is just a regular template, but you can wrap blocks that you want to be able to override in
{% block block_name %}
/{% endblock %}
. - Then you write the child template; this is not a regular template, it starts with an
{% extends %}
statement, and after that, only{% block %}
statements are allowed, which override blocks of the same name from the parent template.
For example, you might write a parent template like so:
<!DOCTYPE html>
<html>
<head>
<title>{% block title %}My Super Fun Site{% endblock %}</title>
</head>
<body>
<header>My Super Fun Site</header>
<main>
<h1>{% block main_header %}Hello!{% endblock %}</h1>
{% block content %}
{% endblock %}
</main>
<footer>
Copyright (c) 2017 myself. All Rights Reserved.
</footer>
</body>
</html>
And then you can have a child template that overrides some of these blocks:
{% extends 'master.html' %}
{%- block title %}This is a different title.{% endblock -%}
{%- block content %}
Lorem ipsum dolor sit amet adipiscing elit. And so on.
{% endblock -%}
This will render a page using the same structure as the master template, but overriding the title
and content
blocks.
In order for this to work correctly, you need to tell the template loader how to load the parent template; the CLI contained in the main repo demonstrates this; you need to pass an IncludeResolver
to parseGinger
(or parseGingerFile
), which is essentially a function that takes a file name and monadically return source code. The actual type is SourceName -> m (Maybe Source)
, with Monad m
; however both Source
and SourceName
are aliases for String
, and m
is usually IO
or something similar.
Hope that clears things up.
from ginger.
thanks, I'll try.
from ginger.
how is your library better compared to https://github.com/sourrust/karver ?
from ginger.
@tdammers up
from ginger.
how is your library better compared to https://github.com/sourrust/karver ?
Well, the most important differences should be obvious (ish) from the API and its types; anyway, from what I can gather from Karver's documentation, here's a (probably incomplete) list of what Ginger does differently (though whether that is necessarily better is debatable and depends on priorities and context):
- Effectful templates. This was a big one for me, because I want template to be able to trigger effects such as loading additional data from the backend, getting the current time, etc. At the same time, I still wanted to keep things sandboxable, so Ginger doesn't just come with a truckload of I/O primitives, instead it allows you to parametrize your template loaders and runners over arbitrary monads, and then you can pass your effectful functions in as context variables.
- Multi-tagged unitype context variables. For lack of a better word. Karver's context object is a hashmap of
Text
toText
; Ginger has a more sophisticated unitype that can express functions, lists, hashmaps, numbers, booleans, null, strings, and encoded HTML. The last one is especially important, because being able to tag HTML as "already encoded" means you hardly ever have to worry about XSS anymore. It also allows us to do things like write a|markdown
filter that takes a raw string, interprets it as markdown, and spits out pre-encoded HTML - without the tag-level distinction between text and HTML, the template engine would HTML-encode the markdown output, which is not what you want. - Separate parsing and running steps. This is important for two reasons; one, you can cache parsed templates, avoiding a re-parse on future usages (and you can precompile all your templates at startup, reducing per-request overhead further, and catching template syntax errors early); and two, you can control effects for the parsing and running stages individually, that is, you can have effectful parses (for loading external templates, e.g. using
{% include %}
) but keep the running stage pure, or you can hook extra effects into the running stage that you don't need for parsing, or you can use an alternative loader mechanism (such as an in-memory hashmap of template names to template sources) for the parser while keeping the interpreter in plainIO
. - More complete implementation of the Jinja2 language. Ginger implements most of the core Jinja2 syntax; I deviated only with features that don't make sense in a language like Haskell (the "blatant Pythonisms" mentioned elsewhere), or where I truly believe that making things simpler would be better (this is why filters, functions, and tests are all the same thing in Ginger -
{{ foo|bar }}
and{{ bar(foo) }}
compile to exactly the same thing). - More programming features in the template language. Ginger is, in fact, a full-blown dynamic programming language; you can define your own functions, there's variables with scopes and all, there's a complete expression sublanguage (and it's used in every place you'd expect to put a variable, so you can, for example, loop over the output of a function that you call on a sublist of a context variable filtered through a function returned from another function call, if you want), you can even drop into "script mode" and write a Ginger flavor that's similar to a Python/JavaScript hybrid.
The only real problem I see with Karver is that it uses unsafePerformIO
to load included templates from disk - IMO this is really really really not what you should use unsafePerformIO
for.
Hope that clears things up a little.
from ginger.
thanks.
from ginger.
Is there a MVP of returning an html file to a client?
in this code, how is "index.html", assuming that's the name of an html file, supposed to be passed to it?
loadFile fn = openFile fn ReadMode >>= hGetContents
loadFileMay fn =
tryIOError (loadFile fn) >>= \e ->
case e of
Right contents ->
return (Just contents)
Left err -> do
print err -- remove this line if you want to fail silently
return Nothing
from ginger.
that's not a library, but a pain. part of code here, part there, setup this, adjust that. how to run it after all? in the documentation -- nothing.
in https://github.com/sourrust/karver everything is comprehensible.
from ginger.
Also, this has long gone beyond the scope of "how am I supposed to pass these variables -- title, naviagation, body -- to this template?", so I'm closing this.
from ginger.
Related Issues (20)
- Use Text instead of String in parser HOT 2
- Not using bytestring-builder internally? HOT 2
- Passing local variables while including a template? HOT 5
- Fraction of second in date
- Add support for records as GVal HOT 3
- Need help with (untyped ?) / heterogeneous dictionary as context to template
- a way to display a structured variable HOT 2
- Add documentation for for-loops HOT 2
- don't ignore non-existent variables HOT 3
- Best way to deal with lists and maps as variables HOT 1
- test/Text/Ginger/SimulationTests.hs:1589 "recursive loops" test fails: expected: "a@1(b@2()c@2(d@3()))" but got: "a@1(c@2(d@3())b@2())"
- How to render a template given template text and context with ToJSON? HOT 1
- GHC 9 build fails HOT 1
- Aeson 2 support HOT 8
- Local date handling accounting for DST HOT 5
- Lack of dependency constraints in old versions cause build failures
- join function? HOT 3
- Expired certificate in Ginger Docs
- Publish current version to Hackage? HOT 1
- Expressions in include statements for recursive templates?
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from ginger.