Skip to content

Commit

Permalink
Implement Template Fragment #82
Browse files Browse the repository at this point in the history
Signed-off-by: David Krause (enthus1ast) <[email protected]>
  • Loading branch information
David Krause (enthus1ast) committed Sep 16, 2024
1 parent 64b91e8 commit 708dbc6
Show file tree
Hide file tree
Showing 7 changed files with 52 additions and 55 deletions.
2 changes: 1 addition & 1 deletion nimja.nimble
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Package

version = "0.9.1"
version = "0.10.0"

author = "David Krause"
description = "typed and compiled template engine inspired by jinja2, twig and onionhammer/nim-templates for Nim."
Expand Down
9 changes: 4 additions & 5 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -806,7 +806,7 @@ So a "users detail page" would render the whole thing.
```
tmplf("user.nimja", baseDir = getScriptDir())
```

But if you want to display a user somewhere else, you can just render the `user` block:

userlist.nimja
Expand Down Expand Up @@ -1216,10 +1216,9 @@ Changelog
- 0.?.?
- Added context to `importnimja`
## DONE
- 0.9.1
- Template fragments (good for htmx); Render specific blocks from a template
all procs (`tmpls`, `tmplf`, `compileTemplateString` and `compileTemplateFile`)
got a "blockToRender" parameter, when set, only the given block is rendered.
- 0.10.0
- Possible Breaking Change.
- Template fragments (good for htmx); Render specific blocks from a template all procs (`tmpls`, `tmplf`, `compileTemplateString` and `compileTemplateFile`) got a "blockToRender" parameter, when set, only the given block is rendered.
- 0.9.0
- BREAKING CHANGE!
- in order to fix #15 & #89 and to enable nimja components imported from other modules,
Expand Down
34 changes: 17 additions & 17 deletions src/nimja/parser.nim
Original file line number Diff line number Diff line change
Expand Up @@ -727,7 +727,6 @@ proc compile(str: string, blockToRender: string = ""): seq[NwtNode] =
blocks[nwtn.blockName] = nwtn.blockBody
if blockToRender == "":
var base = templateCache[0]
# return fillBlocks(base).condenseStrings() # ast condense after blocks are filled # TODO remove
result = fillBlocks(base).condenseStrings() # ast condense after blocks are filled
else:
if blocks.contains(blockToRender):
Expand All @@ -738,7 +737,6 @@ proc compile(str: string, blockToRender: string = ""): seq[NwtNode] =
quit()
# echo result


proc generatePreallocatedStringDef(len: int): NimNode =
# dumpAstGen:
# when result is string:
Expand Down Expand Up @@ -810,13 +808,14 @@ template tmplsMacroImpl() =
alias.add body
result.add alias

macro compileTemplateStr*(str: typed, baseDir: static string = "", iter: static bool = false,
varname: static string = "result", blockToRender: static string = "", context: untyped = nil): untyped =
macro compileTemplateStr*(str: typed, baseDir: static string = "",
blockToRender: static string = "", iter: static bool = false,
varname: static string = "result", context: untyped = nil): untyped =
## Compiles a Nimja template from a string.
##
## .. code-block:: Nim
## proc yourFunc(yourParams: bool): string =
## compileTemplateString("{%if yourParams%}TRUE{%endif%}")
## compileTemplateStr("{%if yourParams%}TRUE{%endif%}")
##
## echo yourFunc(true)
##
Expand All @@ -826,15 +825,15 @@ macro compileTemplateStr*(str: typed, baseDir: static string = "", iter: static
##
## .. code-block:: nim
## iterator yourIter(yourParams: bool): string =
## compileTemplateString("{%for idx in 0 .. 100%}{{idx}}{%endfor%}", iter = true)
## compileTemplateStr("{%for idx in 0 .. 100%}{{idx}}{%endfor%}", iter = true)
##
## for elem in yourIter(true):
## echo elem
##
## `varname` specifies the variable that is appended to.
##
##
## A context can be supplied to the `compileTemplateString` (also `compileTemplateFile`), to override variable names:
## A context can be supplied to the `compileTemplateStr` (also `compileTemplateFile`), to override variable names:
##
## .. code-block:: nim
## block:
Expand All @@ -845,7 +844,7 @@ macro compileTemplateStr*(str: typed, baseDir: static string = "", iter: static
## var rax = Rax(aa: "aaaa", bb: 13.37)
## var foo = 123
## proc render(): string =
## compileTemplateString("{{node.bb}}{{baa}}", {node: rax, baa: foo})
## compileTemplateStr("{{node.bb}}{{baa}}", {node: rax, baa: foo})
##

# Please note, currently the context **cannot be** procs/funcs etc.
Expand All @@ -855,8 +854,9 @@ macro compileTemplateStr*(str: typed, baseDir: static string = "", iter: static
tmplsMacroImpl()
doCompile(str.strVal, blockToRender, result)

macro compileTemplateFile*(path: static string, baseDir: static string = "", iter: static bool = false,
varname: static string = "result", blockToRender: static string = "", context: untyped = nil): untyped =
macro compileTemplateFile*(path: static string, baseDir: static string = "",
blockToRender: static string = "", iter: static bool = false,
varname: static string = "result", context: untyped = nil): untyped =
## Compiles a Nimja template from a file.
##
## .. code-block:: nim
Expand All @@ -878,7 +878,7 @@ macro compileTemplateFile*(path: static string, baseDir: static string = "", ite
##
## `varname` specifies the variable that is appended to.
##
## A context can be supplied to the `compileTemplateFile` (also `compileTemplateString`), to override variable names:
## A context can be supplied to the `compileTemplateFile` (also `compileTemplateStr`), to override variable names:
##
## .. code-block:: nim
## block:
Expand All @@ -898,9 +898,9 @@ macro compileTemplateFile*(path: static string, baseDir: static string = "", ite
tmplsMacroImpl()
doCompile(str, blockToRender, result)

template tmplsImpl(str: static string, baseDir: static string, blockToRender: static string = ""): string =
template tmplsImpl(str: static string, baseDir: static string, blockToRender: static string): string =
var nimjaTmplsVar: string
compileTemplateStr(str, baseDir, varname = astToStr nimjaTmplsVar, blockToRender = blockToRender)
compileTemplateStr(str, baseDir, blockToRender, varname = astToStr nimjaTmplsVar)
nimjaTmplsVar

macro tmpls*(str: static string, baseDir: static string = "",
Expand All @@ -926,12 +926,12 @@ macro tmpls*(str: static string, baseDir: static string = "",
result.add quote do:
tmplsImpl(`str`, `baseDir`, `blockToRender`)

template tmplfImpl(path: static string, baseDir: static string = "",): string =
template tmplfImpl(path: static string, baseDir: static string = "", blockToRender: static string = ""): string =
var nimjaTmplfVar: string
compileTemplateFile(path, baseDir, varname = astToStr nimjaTmplfVar)
compileTemplateFile(path, baseDir, blockToRender, varname = astToStr nimjaTmplfVar)
nimjaTmplfVar

macro tmplf*(str: static string, baseDir: static string = "", context: untyped = nil): string =
macro tmplf*(str: static string, baseDir: static string = "", blockToRender: static string = "", context: untyped = nil): string =
## Compiles a Nimja template file and returns directly.
## Can be used inline, without a wrapper proc.
##
Expand All @@ -950,4 +950,4 @@ macro tmplf*(str: static string, baseDir: static string = "", context: untyped =
##
tmplsMacroImpl()
result.add quote do:
tmplfImpl(`str`, `baseDir`)
tmplfImpl(`str`, `baseDir`, `blockToRender`)
10 changes: 5 additions & 5 deletions tests/basic/test_case.nim
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,14 @@ suite "case":
aaa, bbb, ccc, ddd
var foo: Foo = aaa
var isNothing: bool
check "AAA" == tmplf("case" / "case2.nimja", getScriptDir(), {ee: foo})
check "BBB" == tmplf("case" / "case2.nimja", getScriptDir(), {ee: Foo.bbb})
check "CCC" == tmplf("case" / "case2.nimja", getScriptDir(), {ee: ccc})
check "AAA" == tmplf("case" / "case2.nimja", baseDir = getScriptDir(), context = {ee: foo})
check "BBB" == tmplf("case" / "case2.nimja", baseDir = getScriptDir(), context = {ee: Foo.bbb})
check "CCC" == tmplf("case" / "case2.nimja", baseDir = getScriptDir(), context = {ee: ccc})

isNothing = true
check "nothing" == tmplf("case" / "case2.nimja", getScriptDir(), {ee: ddd})
check "nothing" == tmplf("case" / "case2.nimja", baseDir = getScriptDir(), context = {ee: ddd})

isNothing = false
check "something" == tmplf("case" / "case2.nimja", getScriptDir(), {ee: ddd})
check "something" == tmplf("case" / "case2.nimja", baseDir = getScriptDir(), context = {ee: ddd})


2 changes: 1 addition & 1 deletion tests/basic/test_case_missing.nim
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,4 @@ include ../../src/nimja/parser
type Foo = enum
aaa, bbb, ccc, ddd
var foo: Foo = aaa
discard tmplf("case" / "case3.nimja", baseDir = getScriptDir(), {ee: ddd})
discard tmplf("case" / "case3.nimja", baseDir = getScriptDir(), context = {ee: ddd})
44 changes: 21 additions & 23 deletions tests/basic/test_fragments.nim
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,10 @@ suite "fragments":
{% block second %}second block{% endblock %}
BUG
""", blockToRender = blockToRender)

check "first block" == foo("first")
check "second block" == foo("second")


test "compileTemplateStr with inner block":
proc foo(blockToRender: static string): string =
compileTemplateStr("""
Expand All @@ -28,6 +28,7 @@ suite "fragments":
check "first inner block" == foo("first")
check " inner " == foo("inner")


test "compileTemplateStr simple with self":
proc foo(blockToRender: static string): string =
compileTemplateStr("""
Expand All @@ -37,7 +38,6 @@ suite "fragments":
{% block inner %} inner {% endblock %}
BUG
""", blockToRender = blockToRender)

check "first inner block" == foo("first")
check "second inner block" == foo("second")

Expand All @@ -51,19 +51,17 @@ suite "fragments":
{% block inner %} {{ii}} {% endblock %}
BUG
""", blockToRender = blockToRender)

check "first 1337 block" == foo(1337, "first")
check "second 1337 block" == foo(1337, "second")


test "compileTemplateFile simple":
proc foo(fileToRender: static string, blockToRender: static string): string =
compileTemplateFile(fileToRender, blockToRender = blockToRender, baseDir = getScriptDir())
check "title from index" == foo("fragments/index.nimja", "title") ## TODO test this error message!
check "content from index" == foo("fragments/index.nimja", "content") ## TODO test this error message!

check "title to replace" == foo("fragments/base.nimja", "title") ## TODO test this error message!
check "content to replace" == foo("fragments/base.nimja", "content") ## TODO test this error message!
check "title from index" == foo("fragments/index.nimja", "title")
check "content from index" == foo("fragments/index.nimja", "content")
check "title to replace" == foo("fragments/base.nimja", "title")
check "content to replace" == foo("fragments/base.nimja", "content")


test "importnimja simple":
Expand All @@ -73,26 +71,26 @@ suite "fragments":
result = result.strip()
check "title from index" == foo("fragments/index.nimja", "title")
check "content from index" == foo("fragments/index.nimja", "content")

check "title to replace" == foo("fragments/base.nimja", "title")
check "content to replace" == foo("fragments/base.nimja", "content")


# test "tmpls":
# check "title" == tmpls("bug{%block title%}title{%endblock%}bug", baseDir = getScriptDir(), blockToRender = "title")
# echo tmpls("bug{%block title%}title{%endblock%}bug",
# check "titleinner" == tmpls("bug{%block title%}title{%block inner%}inner{%endblock%}{%endblock%}bug",
# baseDir = getScriptDir(), blockToRender = "title")
# check "inner" == tmpls("bug{%block title%}title{%block inner%}inner{%endblock%}{%endblock%}bug",
# baseDir = getScriptDir(), blockToRender = "inner")
test "tmpls":
check "title" == tmpls("bug{%block title%}title{%endblock%}bug",
baseDir = getScriptDir(), blockToRender = "title")

check "titleinner" == tmpls("bug{%block title%}title{%block inner%}inner{%endblock%}{%endblock%}bug",
baseDir = getScriptDir(), blockToRender = "title")

check "inner" == tmpls("bug{%block title%}title{%block inner%}inner{%endblock%}{%endblock%}bug",
baseDir = getScriptDir(), blockToRender = "inner")

# check "title from index" == tmpls("{% importnimja fragments/index.nimja}", baseDir = getScriptDir() , blockToRender = "title")
# check "content from index" == foo("fragments/index.nimja", "content")
#
# check "title to replace" == foo("fragments/base.nimja", "title")
# check "content to replace" == foo("fragments/base.nimja", "content")
test "tmplf":
check "title from index" == tmplf("fragments/index.nimja", blockToRender = "title", baseDir = getScriptDir())
check "content from index" == tmplf("fragments/index.nimja", blockToRender = "content", baseDir = getScriptDir())
check "title to replace" == tmplf("fragments/base.nimja", blockToRender = "title", baseDir = getScriptDir())
check "content to replace" == tmplf("fragments/base.nimja", blockToRender = "content", baseDir = getScriptDir())


# test "tmplf":
# discard

# suite "fragments stolen":
6 changes: 3 additions & 3 deletions tests/basic/test_tmplf_with_context.nim
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ block:
var ii = 123
doAssert "idx: 123, aa: aaaa, nodes: aaaa, 13.37" ==
tmplf(
"tmplf_with_context.nimja", getScriptDir(),
{
"tmplf_with_context.nimja", baseDir = getScriptDir(),
context = {
idx: ii,
aa: rax.aa,
nodes: rax
Expand All @@ -32,4 +32,4 @@ block:
bb: float
var rax = Rax(aa: "aaaa", bb: 13.37)
var foo = 123
doAssert "13.37123" == tmpls("""{% if node.aa == "aaaa" %}{{node.bb}}{% endif %}{{baa}}""", getScriptDir(), {node: rax, baa: foo})
doAssert "13.37123" == tmpls("""{% if node.aa == "aaaa" %}{{node.bb}}{% endif %}{{baa}}""", baseDir = getScriptDir(), context = {node: rax, baa: foo})

0 comments on commit 708dbc6

Please sign in to comment.